diff --git a/key.go b/key.go index c5b04e9b1e..e2415a994f 100644 --- a/key.go +++ b/key.go @@ -199,6 +199,18 @@ const ( KeyPgDown KeyDelete KeySpace + KeyCtrlUp + KeyCtrlDown + KeyCtrlRight + KeyCtrlLeft + KeyShiftUp + KeyShiftDown + KeyShiftRight + KeyShiftLeft + KeyCtrlShiftUp + KeyCtrlShiftDown + KeyCtrlShiftLeft + KeyCtrlShiftRight KeyF1 KeyF2 KeyF3 @@ -224,7 +236,7 @@ const ( // Mappings for control keys and other special keys to friendly consts. var keyNames = map[KeyType]string{ // Control keys. - keyNUL: "ctrl+@", // also ctrl+` + keyNUL: "ctrl+@", // also ctrl+` (that's ctrl+backtick) keySOH: "ctrl+a", keySTX: "ctrl+b", keyETX: "ctrl+c", @@ -259,46 +271,127 @@ var keyNames = map[KeyType]string{ keyDEL: "backspace", // Other keys. - KeyRunes: "runes", - KeyUp: "up", - KeyDown: "down", - KeyRight: "right", - KeySpace: " ", // for backwards compatibility - KeyLeft: "left", - KeyShiftTab: "shift+tab", - KeyHome: "home", - KeyEnd: "end", - KeyPgUp: "pgup", - KeyPgDown: "pgdown", - KeyDelete: "delete", - KeyF1: "f1", - KeyF2: "f2", - KeyF3: "f3", - KeyF4: "f4", - KeyF5: "f5", - KeyF6: "f6", - KeyF7: "f7", - KeyF8: "f8", - KeyF9: "f9", - KeyF10: "f10", - KeyF11: "f11", - KeyF12: "f12", - KeyF13: "f13", - KeyF14: "f14", - KeyF15: "f15", - KeyF16: "f16", - KeyF17: "f17", - KeyF18: "f18", - KeyF19: "f19", - KeyF20: "f20", + KeyRunes: "runes", + KeyUp: "up", + KeyDown: "down", + KeyRight: "right", + KeySpace: " ", // for backwards compatibility + KeyLeft: "left", + KeyShiftTab: "shift+tab", + KeyHome: "home", + KeyEnd: "end", + KeyPgUp: "pgup", + KeyPgDown: "pgdown", + KeyDelete: "delete", + KeyCtrlUp: "ctrl+up", + KeyCtrlDown: "ctrl+down", + KeyCtrlRight: "ctrl+right", + KeyCtrlLeft: "ctrl+left", + KeyShiftUp: "shift+up", + KeyShiftDown: "shift+down", + KeyShiftRight: "shift+right", + KeyShiftLeft: "shift+left", + KeyCtrlShiftUp: "ctrl+shift+up", + KeyCtrlShiftDown: "ctrl+shift+down", + KeyCtrlShiftLeft: "ctrl+shift+left", + KeyCtrlShiftRight: "ctrl+shift+right", + KeyF1: "f1", + KeyF2: "f2", + KeyF3: "f3", + KeyF4: "f4", + KeyF5: "f5", + KeyF6: "f6", + KeyF7: "f7", + KeyF8: "f8", + KeyF9: "f9", + KeyF10: "f10", + KeyF11: "f11", + KeyF12: "f12", + KeyF13: "f13", + KeyF14: "f14", + KeyF15: "f15", + KeyF16: "f16", + KeyF17: "f17", + KeyF18: "f18", + KeyF19: "f19", + KeyF20: "f20", } // Sequence mappings. var sequences = map[string]Key{ - "\x1b[A": {Type: KeyUp}, - "\x1b[B": {Type: KeyDown}, - "\x1b[C": {Type: KeyRight}, - "\x1b[D": {Type: KeyLeft}, + // Arrow keys + "\x1b[A": {Type: KeyUp}, + "\x1b[B": {Type: KeyDown}, + "\x1b[C": {Type: KeyRight}, + "\x1b[D": {Type: KeyLeft}, + "\x1b[1;2A": {Type: KeyShiftUp}, + "\x1b[1;2B": {Type: KeyShiftDown}, + "\x1b[1;2C": {Type: KeyShiftRight}, + "\x1b[1;2D": {Type: KeyShiftLeft}, + "\x1b[OA": {Type: KeyShiftUp}, // DECCKM + "\x1b[OB": {Type: KeyShiftDown}, // DECCKM + "\x1b[OC": {Type: KeyShiftRight}, // DECCKM + "\x1b[OD": {Type: KeyShiftLeft}, // DECCKM + "\x1b[a": {Type: KeyShiftUp}, // urxvt + "\x1b[b": {Type: KeyShiftDown}, // urxvt + "\x1b[c": {Type: KeyShiftRight}, // urxvt + "\x1b[d": {Type: KeyShiftLeft}, // urxvt + "\x1b[1;3A": {Type: KeyUp, Alt: true}, + "\x1b[1;3B": {Type: KeyDown, Alt: true}, + "\x1b[1;3C": {Type: KeyRight, Alt: true}, + "\x1b[1;3D": {Type: KeyLeft, Alt: true}, + "\x1b\x1b[A": {Type: KeyUp, Alt: true}, // urxvt + "\x1b\x1b[B": {Type: KeyDown, Alt: true}, // urxvt + "\x1b\x1b[C": {Type: KeyRight, Alt: true}, // urxvt + "\x1b\x1b[D": {Type: KeyLeft, Alt: true}, // urxvt + "\x1b[1;4A": {Type: KeyShiftUp, Alt: true}, + "\x1b[1;4B": {Type: KeyShiftDown, Alt: true}, + "\x1b[1;4C": {Type: KeyShiftRight, Alt: true}, + "\x1b[1;4D": {Type: KeyShiftLeft, Alt: true}, + "\x1b\x1b[a": {Type: KeyShiftUp, Alt: true}, // urxvt + "\x1b\x1b[b": {Type: KeyShiftDown, Alt: true}, // urxvt + "\x1b\x1b[c": {Type: KeyShiftRight, Alt: true}, // urxvt + "\x1b\x1b[d": {Type: KeyShiftLeft, Alt: true}, // urxvt + "\x1b[1;5A": {Type: KeyCtrlUp}, + "\x1b[1;5B": {Type: KeyCtrlDown}, + "\x1b[1;5C": {Type: KeyCtrlRight}, + "\x1b[1;5D": {Type: KeyCtrlLeft}, + "\x1b[Oa": {Type: KeyCtrlUp, Alt: true}, // urxvt + "\x1b[Ob": {Type: KeyCtrlDown, Alt: true}, // urxvt + "\x1b[Oc": {Type: KeyCtrlRight, Alt: true}, // urxvt + "\x1b[Od": {Type: KeyCtrlLeft, Alt: true}, // urxvt + "\x1b[1;6A": {Type: KeyCtrlShiftUp}, + "\x1b[1;6B": {Type: KeyCtrlShiftDown}, + "\x1b[1;6C": {Type: KeyCtrlShiftRight}, + "\x1b[1;6D": {Type: KeyCtrlShiftLeft}, + "\x1b[1;7A": {Type: KeyCtrlUp, Alt: true}, + "\x1b[1;7B": {Type: KeyCtrlDown, Alt: true}, + "\x1b[1;7C": {Type: KeyCtrlRight, Alt: true}, + "\x1b[1;7D": {Type: KeyCtrlLeft, Alt: true}, + "\x1b[1;8A": {Type: KeyCtrlShiftUp, Alt: true}, + "\x1b[1;8B": {Type: KeyCtrlShiftDown, Alt: true}, + "\x1b[1;8C": {Type: KeyCtrlShiftRight, Alt: true}, + "\x1b[1;8D": {Type: KeyCtrlShiftLeft, Alt: true}, + + // Miscellaneous keys + "\x1b[Z": {Type: KeyShiftTab}, + "\x1b[3~": {Type: KeyDelete}, + "\x1b[3;3~": {Type: KeyDelete, Alt: true}, + "\x1b[1~": {Type: KeyHome}, + "\x1b[1;3H~": {Type: KeyHome, Alt: true}, + "\x1b[4~": {Type: KeyEnd}, + "\x1b[1;3F~": {Type: KeyEnd, Alt: true}, + "\x1b[5~": {Type: KeyPgUp}, + "\x1b[5;3~": {Type: KeyPgUp, Alt: true}, + "\x1b[6~": {Type: KeyPgDown}, + "\x1b[6;3~": {Type: KeyPgDown, Alt: true}, + "\x1b[7~": {Type: KeyHome}, // urxvt + "\x1b[8~": {Type: KeyEnd}, // urxvt + "\x1b\x1b[3~": {Type: KeyDelete, Alt: true}, // urxvt + "\x1b\x1b[5~": {Type: KeyPgUp, Alt: true}, // urxvt + "\x1b\x1b[6~": {Type: KeyPgDown, Alt: true}, // urxvt + "\x1b\x1b[7~": {Type: KeyHome, Alt: true}, // urxvt + "\x1b\x1b[8~": {Type: KeyEnd, Alt: true}, // urxvt // Function keys, X11 "\x1bOP": {Type: KeyF1}, // vt100 @@ -367,28 +460,8 @@ var sequences = map[string]Key{ // Hex code mappings. var hexes = map[string]Key{ - "1b5b5a": {Type: KeyShiftTab}, - "1b5b337e": {Type: KeyDelete}, - "1b0d": {Type: KeyEnter, Alt: true}, - "1b7f": {Type: KeyBackspace, Alt: true}, - "1b5b48": {Type: KeyHome}, - "1b5b377e": {Type: KeyHome}, // urxvt - "1b5b313b3348": {Type: KeyHome, Alt: true}, - "1b1b5b377e": {Type: KeyHome, Alt: true}, // urxvt - "1b5b46": {Type: KeyEnd}, - "1b5b387e": {Type: KeyEnd}, // urxvt - "1b5b313b3346": {Type: KeyEnd, Alt: true}, - "1b1b5b387e": {Type: KeyEnd, Alt: true}, // urxvt - "1b5b357e": {Type: KeyPgUp}, - "1b5b353b337e": {Type: KeyPgUp, Alt: true}, - "1b1b5b357e": {Type: KeyPgUp, Alt: true}, // urxvt - "1b5b367e": {Type: KeyPgDown}, - "1b5b363b337e": {Type: KeyPgDown, Alt: true}, - "1b1b5b367e": {Type: KeyPgDown, Alt: true}, // urxvt - "1b5b313b3341": {Type: KeyUp, Alt: true}, - "1b5b313b3342": {Type: KeyDown, Alt: true}, - "1b5b313b3343": {Type: KeyRight, Alt: true}, - "1b5b313b3344": {Type: KeyLeft, Alt: true}, + "1b0d": {Type: KeyEnter, Alt: true}, + "1b7f": {Type: KeyBackspace, Alt: true}, // Powershell "1b4f41": {Type: KeyUp, Alt: false}, @@ -408,7 +481,7 @@ func readInputs(input io.Reader) ([]Msg, error) { return nil, err } - // See if it's a mouse event. For now we're parsing X10-type mouse events + // Check if it's a mouse event. For now we're parsing X10-type mouse events // only. mouseEvent, err := parseX10MouseEvents(buf[:numBytes]) if err == nil { @@ -419,14 +492,14 @@ func readInputs(input io.Reader) ([]Msg, error) { return m, nil } - // Is it a special sequence, like an arrow key? + // Is it a sequence, like an arrow key? if k, ok := sequences[string(buf[:numBytes])]; ok { return []Msg{ KeyMsg(k), }, nil } - // Some of these need special handling + // Some of these need special handling. hex := fmt.Sprintf("%x", buf[:numBytes]) if k, ok := hexes[hex]; ok { return []Msg{ @@ -434,8 +507,8 @@ func readInputs(input io.Reader) ([]Msg, error) { }, nil } - // Is the alt key pressed? The buffer will be prefixed with an escape - // sequence if so. + // Is the alt key pressed? If so, the buffer will be prefixed with an + // escape. if numBytes > 1 && buf[0] == 0x1b { // Now remove the initial escape sequence and re-process to get the // character being pressed in combination with alt. @@ -483,7 +556,7 @@ func readInputs(input io.Reader) ([]Msg, error) { // If it's a space, override the type with KeySpace (but still include the // rune). - if len(runes) == 1 && runes[0] == ' ' { + if runes[0] == ' ' { return []Msg{ KeyMsg(Key{Type: KeySpace, Runes: runes}), }, nil