// key HandleFunc for the http /key endpoint. This only happens if the client // doesn't support websockets. func (t *tbfe) key(w http.ResponseWriter, req *http.Request) { log.Debug("key: %s", req) kc := req.FormValue("keyCode") var kp keys.KeyPress v, _ := strconv.ParseInt(kc, 10, 32) if req.FormValue("altKey") == "true" { kp.Alt = true } if req.FormValue("ctrlKey") == "true" { kp.Ctrl = true } if req.FormValue("metaKey") == "true" { kp.Super = true } if req.FormValue("shiftKey") == "true" { kp.Shift = true } if !kp.Shift { v = int64(unicode.ToLower(rune(v))) } kp.Key = keys.Key(v) kp.Text = string(v) backend.GetEditor().HandleInput(kp) }
func (t *tbfe) handleInput(ev termbox.Event) { if ev.Key == termbox.KeyCtrlQ { t.shutdown <- true } var kp keys.KeyPress if ev.Ch != 0 { kp.Key = keys.Key(ev.Ch) } else if v2, ok := lut[ev.Key]; ok { kp = v2 } else { return } t.editor.HandleInput(kp) }
func (t *tbfe) WebsocketServer(ws *websocket.Conn) { clients = append(clients, ws) // Send status message if t.status_message != "" { websocket.JSON.Send(ws, map[string]string{"type": "statusMessage", "msg": t.status_message}) } // Send cursor position websocket.JSON.Send(ws, t.GetSelectionMessage(backend.GetEditor().ActiveWindow().ActiveView())) // Send editor content var buf bytes.Buffer t.render(bufio.NewWriter(&buf)) websocket.Message.Send(ws, buf.Bytes()) buf.Reset() var data map[string]interface{} var kp keys.KeyPress for { err := websocket.JSON.Receive(ws, &data) if err != nil { log.Error(err) return } //log.LogDebug("Received: %s", data) msgType := data["type"].(string) if msgType == "key" { kp.Alt = data["altKey"].(bool) kp.Ctrl = data["ctrlKey"].(bool) kp.Super = data["metaKey"].(bool) kp.Shift = data["shiftKey"].(bool) if keyName, ok := data["key"].(string); ok { if utf8.RuneCountInString(keyName) == 1 { // One char r, _ := utf8.DecodeRuneInString(keyName) kp.Key = keys.Key(int64(r)) } else { // TODO: automatic lookup instead of this manual lookup // See https://github.com/limetext/lime/pull/421/files#r19269236 keymap := map[string]keys.Key{ "ArrowLeft": keys.Left, "ArrowUp": keys.Up, "ArrowRight": keys.Right, "ArrowDown": keys.Down, "Left": keys.Left, "Up": keys.Up, "Right": keys.Right, "Down": keys.Down, "Enter": keys.Enter, "Escape": keys.Escape, "Backspace": keys.Backspace, "Delete": keys.Delete, "Del": keys.Delete, // Deprecated: some old browsers still use "Del" instead of "Delete" "KeypadEnter": keys.KeypadEnter, "F1": keys.F1, "F2": keys.F2, "F3": keys.F3, "F4": keys.F4, "F5": keys.F5, "F6": keys.F6, "F7": keys.F7, "F8": keys.F8, "F9": keys.F9, "F10": keys.F10, "F11": keys.F11, "F12": keys.F12, "Insert": keys.Insert, "PageUp": keys.PageUp, "PageDown": keys.PageDown, "Home": keys.Home, "End": keys.End, "Break": keys.Break, } if key, ok := keymap[keyName]; ok { kp.Key = key } else { log.Debug("Unknown key: %s", keyName) continue } } } else { v := int64(data["keyCode"].(float64)) if !kp.Shift { v = int64(unicode.ToLower(rune(v))) } kp.Key = keys.Key(v) } backend.GetEditor().HandleInput(kp) } else if msgType == "command" { command := data["name"].(string) //args := data["args"].([]string) //TODO: add arguments support ed := backend.GetEditor() go ed.RunCommand(command, make(backend.Args)) } else { log.Info("Unhandled message type: %s", msgType) } } }
func (t *tbfe) loop() { var ( ed = t.setupEditor() c = ed.Console() w = ed.NewWindow() v *backend.View ) // Assuming that all extra arguments are files if files := flag.Args(); len(files) > 0 { for _, file := range files { v = createNewView(file, w) } } else { v = w.NewFile() } c.Buffer().AddCallback(t.scroll) t.setupCallbacks(v) path := "../../3rdparty/bundles/TextMate-Themes/Monokai.tmTheme" if sc, err := textmate.LoadTheme(path); err != nil { log4go.Error(err) return } else { scheme = sc } setColorMode() setSchemeSettings() // We start the renderThread here, after we have done our setup of termbox. // That way, we do not clash with our output. go t.renderthread() evchan := make(chan termbox.Event, 32) defer func() { close(evchan) }() go func() { for { evchan <- termbox.PollEvent() } }() { w, h := termbox.Size() t.lock.Lock() if *showConsole { t.layout[v] = layout{0, 0, w, h - *consoleHeight - 4, Region{}, 0} t.layout[c] = layout{0, h - *consoleHeight - 2, w, *consoleHeight - 1, Region{}, 0} } else { t.layout[v] = layout{0, 0, w, h - 3, Region{}, 0} } t.lock.Unlock() t.Show(v, Region{1, 1}) } t.Show(v, Region{100, 100}) t.Show(v, Region{1, 1}) go func() { ed.Init() sublime.Init() }() for { p := util.Prof.Enter("mainloop") blink_phase := time.Second if p, ok := ed.Settings().Get("caret_blink_phase", 1.0).(float64); ok { blink_phase = time.Duration(float64(time.Second) * p) } // Divided by two since we're only doing a simple toggle blink timer := time.NewTimer(blink_phase / 2) select { case ev := <-evchan: mp := util.Prof.Enter("evchan") limit := 3 loop: switch ev.Type { case termbox.EventError: log4go.Debug("error occured") return case termbox.EventResize: // We have to resize our layouts... // There is currently duplicate code for calculating the layout: // during initialization (above), and here. Not nice if *showConsole { view_layout := t.layout[v] view_layout.height = ev.Height - *consoleHeight - 4 view_layout.width = ev.Width console_layout := t.layout[c] console_layout.y = ev.Height - *consoleHeight - 2 console_layout.width = ev.Width t.layout[v] = view_layout t.layout[c] = console_layout } else { view_layout := t.layout[v] view_layout.height = ev.Height - 3 view_layout.width = ev.Width t.layout[v] = view_layout } // Ensure that the new visible region is recalculated t.Show(v, t.VisibleRegion(v)) case termbox.EventKey: var kp keys.KeyPress if ev.Ch != 0 { kp.Key = keys.Key(ev.Ch) } else if v2, ok := lut[ev.Key]; ok { kp = v2 } else { break } if ev.Key == termbox.KeyCtrlQ { return } ed.HandleInput(kp) blink = false } if len(evchan) > 0 { limit-- ev = <-evchan goto loop } mp.Exit() case <-timer.C: // TODO(q): Shouldn't redraw if blink is disabled... blink = !blink t.render() } timer.Stop() p.Exit() } }