diff --git a/man/man1/fzf.1 b/man/man1/fzf.1 index 67fc1684..e8d33642 100644 --- a/man/man1/fzf.1 +++ b/man/man1/fzf.1 @@ -1473,12 +1473,22 @@ e.g. .br \fIalt\-right\fR .br +\fIalt\-home\fR +.br +\fIalt\-end\fR +.br +\fIalt\-backspace\fR (\fIalt\-bspace\fR \fIalt\-bs\fR) +.br +\fIalt\-delete\fR +.br +\fIalt\-page\-up\fR +.br +\fIalt\-page\-down\fR +.br \fIalt\-enter\fR .br \fIalt\-space\fR .br -\fIalt\-backspace\fR (\fIalt\-bspace\fR \fIalt\-bs\fR) -.br \fItab\fR .br \fIshift\-tab\fR (\fIbtab\fR) @@ -1505,6 +1515,26 @@ e.g. .br \fIpage\-down\fR (\fIpgdn\fR) .br +\fIctrl\-up\fR +.br +\fIctrl\-down\fR +.br +\fIctrl\-left\fR +.br +\fIctrl\-right\fR +.br +\fIctrl\-home\fR +.br +\fIctrl\-end\fR +.br +\fIctrl\-backspace\fR (\fIctrl\-bspace\fR \fIctrl\-bs\fR) +.br +\fIctrl\-delete\fR +.br +\fIctrl\-page\-up\fR +.br +\fIctrl\-page\-down\fR +.br \fIshift\-up\fR .br \fIshift\-down\fR @@ -1513,8 +1543,16 @@ e.g. .br \fIshift\-right\fR .br +\fIshift\-home\fR +.br +\fIshift\-end\fR +.br \fIshift\-delete\fR .br +\fIshift\-page\-up\fR +.br +\fIshift\-page\-down\fR +.br \fIalt\-shift\-up\fR .br \fIalt\-shift\-down\fR @@ -1523,6 +1561,72 @@ e.g. .br \fIalt\-shift\-right\fR .br +\fIalt\-shift\-home\fR +.br +\fIalt\-shift\-end\fR +.br +\fIalt\-shift\-delete\fR +.br +\fIalt\-shift\-page\-up\fR +.br +\fIalt\-shift\-page\-down\fR +.br +\fIctrl\-alt\-up\fR +.br +\fIctrl\-alt\-down\fR +.br +\fIctrl\-alt\-left\fR +.br +\fIctrl\-alt\-right\fR +.br +\fIctrl\-alt\-home\fR +.br +\fIctrl\-alt\-end\fR +.br +\fIctrl\-alt\-backspace\fR (\fIctrl\-alt\-bspace\fR \fIctrl\-alt\-bs\fR) +.br +\fIctrl\-alt\-delete\fR +.br +\fIctrl\-alt\-page\-up\fR +.br +\fIctrl\-alt\-page\-down\fR +.br +\fIctrl\-shift\-up\fR +.br +\fIctrl\-shift\-down\fR +.br +\fIctrl\-shift\-left\fR +.br +\fIctrl\-shift\-right\fR +.br +\fIctrl\-shift\-home\fR +.br +\fIctrl\-shift\-end\fR +.br +\fIctrl\-shift\-delete\fR +.br +\fIctrl\-shift\-page\-up\fR +.br +\fIctrl\-shift\-page\-down\fR +.br +\fIctrl\-alt\-shift\-up\fR +.br +\fIctrl\-alt\-shift\-down\fR +.br +\fIctrl\-alt\-shift\-left\fR +.br +\fIctrl\-alt\-shift\-right\fR +.br +\fIctrl\-alt\-shift\-home\fR +.br +\fIctrl\-alt\-shift\-end\fR +.br +\fIctrl\-alt\-shift\-delete\fR +.br +\fIctrl\-alt\-shift\-page\-up\fR +.br +\fIctrl\-alt\-shift\-page\-down\fR +.br \fIleft\-click\fR .br \fIright\-click\fR @@ -1547,6 +1651,8 @@ e.g. .br or any single character +Note that some terminal emulators may not support \fIctrl-*\fR bindings. + .SS AVAILABLE EVENTS: \fIstart\fR .RS @@ -1699,7 +1805,7 @@ A key or an event can be bound to one or more of the following actions. \fBaccept\-non\-empty\fR (same as \fBaccept\fR except that it prevents fzf from exiting without selection) \fBaccept\-or\-print\-query\fR (same as \fBaccept\fR except that it prints the query when there's no match) \fBbackward\-char\fR \fIctrl\-b left\fR - \fBbackward\-delete\-char\fR \fIctrl\-h bspace\fR + \fBbackward\-delete\-char\fR \fIctrl\-h ctrl\-bspace bspace\fR \fBbackward\-delete\-char/eof\fR (same as \fBbackward\-delete\-char\fR except aborts fzf if query is empty) \fBbackward\-kill\-word\fR \fIalt\-bs\fR \fBbackward\-word\fR \fIalt\-b shift\-left\fR diff --git a/src/options.go b/src/options.go index e15d43d6..f8cb578f 100644 --- a/src/options.go +++ b/src/options.go @@ -974,8 +974,6 @@ func parseKeyChords(str string, message string) (map[tui.Event]string, []tui.Eve add(tui.Backspace) case "ctrl-space": add(tui.CtrlSpace) - case "ctrl-delete": - add(tui.CtrlDelete) case "ctrl-^", "ctrl-6": add(tui.CtrlCaret) case "ctrl-/", "ctrl-_": @@ -1022,6 +1020,10 @@ func parseKeyChords(str string, message string) (map[tui.Event]string, []tui.Eve list = append(list, evt) case "alt-bs", "alt-bspace", "alt-backspace": add(tui.AltBackspace) + case "ctrl-bs", "ctrl-bspace", "ctrl-backspace": + add(tui.CtrlBackspace) + case "ctrl-alt-bs", "ctrl-alt-bspace", "ctrl-alt-backspace": + add(tui.CtrlAltBackspace) case "alt-up": add(tui.AltUp) case "alt-down": @@ -1030,6 +1032,16 @@ func parseKeyChords(str string, message string) (map[tui.Event]string, []tui.Eve add(tui.AltLeft) case "alt-right": add(tui.AltRight) + case "alt-home": + add(tui.AltHome) + case "alt-end": + add(tui.AltEnd) + case "alt-delete": + add(tui.AltDelete) + case "alt-page-up": + add(tui.AltPageUp) + case "alt-page-down": + add(tui.AltPageDown) case "tab": add(tui.Tab) case "btab", "shift-tab": @@ -1056,6 +1068,88 @@ func parseKeyChords(str string, message string) (map[tui.Event]string, []tui.Eve add(tui.AltShiftLeft) case "alt-shift-right", "shift-alt-right": add(tui.AltShiftRight) + case "alt-shift-home", "shift-alt-home": + add(tui.AltShiftHome) + case "alt-shift-end", "shift-alt-end": + add(tui.AltShiftEnd) + case "alt-shift-delete", "shift-alt-delete": + add(tui.AltShiftDelete) + case "alt-shift-page-up", "shift-alt-page-up": + add(tui.AltShiftPageUp) + case "alt-shift-page-down", "shift-alt-page-down": + add(tui.AltShiftPageDown) + case "ctrl-up": + add(tui.CtrlUp) + case "ctrl-down": + add(tui.CtrlDown) + case "ctrl-right": + add(tui.CtrlRight) + case "ctrl-left": + add(tui.CtrlLeft) + case "ctrl-home": + add(tui.CtrlHome) + case "ctrl-end": + add(tui.CtrlEnd) + case "ctrl-delete": + add(tui.CtrlDelete) + case "ctrl-page-up": + add(tui.CtrlPageUp) + case "ctrl-page-down": + add(tui.CtrlPageDown) + case "ctrl-alt-up", "alt-ctrl-up": + add(tui.CtrlAltUp) + case "ctrl-alt-down", "alt-ctrl-down": + add(tui.CtrlAltDown) + case "ctrl-alt-right", "alt-ctrl-right": + add(tui.CtrlAltRight) + case "ctrl-alt-left", "alt-ctrl-left": + add(tui.CtrlAltLeft) + case "ctrl-alt-home", "alt-ctrl-home": + add(tui.CtrlAltHome) + case "ctrl-alt-end", "alt-ctrl-end": + add(tui.CtrlAltEnd) + case "ctrl-alt-delete", "alt-ctrl-delete": + add(tui.CtrlAltDelete) + case "ctrl-alt-page-up", "alt-ctrl-page-up": + add(tui.CtrlAltPageUp) + case "ctrl-alt-page-down", "alt-ctrl-page-down": + add(tui.CtrlAltPageDown) + case "ctrl-shift-up", "shift-ctrl-up": + add(tui.CtrlShiftUp) + case "ctrl-shift-down", "shift-ctrl-down": + add(tui.CtrlShiftDown) + case "ctrl-shift-right", "shift-ctrl-right": + add(tui.CtrlShiftRight) + case "ctrl-shift-left", "shift-ctrl-left": + add(tui.CtrlShiftLeft) + case "ctrl-shift-home", "shift-ctrl-home": + add(tui.CtrlShiftHome) + case "ctrl-shift-end", "shift-ctrl-end": + add(tui.CtrlShiftEnd) + case "ctrl-shift-delete", "shift-ctrl-delete": + add(tui.CtrlShiftDelete) + case "ctrl-shift-page-up", "shift-ctrl-page-up": + add(tui.CtrlShiftPageUp) + case "ctrl-shift-page-down", "shift-ctrl-page-down": + add(tui.CtrlShiftPageDown) + case "ctrl-alt-shift-up": + add(tui.CtrlAltShiftUp) + case "ctrl-alt-shift-down": + add(tui.CtrlAltShiftDown) + case "ctrl-alt-shift-right": + add(tui.CtrlAltShiftRight) + case "ctrl-alt-shift-left": + add(tui.CtrlAltShiftLeft) + case "ctrl-alt-shift-home": + add(tui.CtrlAltShiftHome) + case "ctrl-alt-shift-end": + add(tui.CtrlAltShiftEnd) + case "ctrl-alt-shift-delete": + add(tui.CtrlAltShiftDelete) + case "ctrl-alt-shift-page-up": + add(tui.CtrlAltShiftPageUp) + case "ctrl-alt-shift-page-down": + add(tui.CtrlAltShiftPageDown) case "shift-up": add(tui.ShiftUp) case "shift-down": @@ -1064,8 +1158,16 @@ func parseKeyChords(str string, message string) (map[tui.Event]string, []tui.Eve add(tui.ShiftLeft) case "shift-right": add(tui.ShiftRight) + case "shift-home": + add(tui.ShiftHome) + case "shift-end": + add(tui.ShiftEnd) case "shift-delete": add(tui.ShiftDelete) + case "shift-page-up": + add(tui.ShiftPageUp) + case "shift-page-down": + add(tui.ShiftPageDown) case "left-click": add(tui.LeftClick) case "right-click": diff --git a/src/terminal.go b/src/terminal.go index dfcc7f3d..f3f5298b 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -782,6 +782,7 @@ func defaultKeymap() map[tui.Event][]*action { add(tui.CtrlF, actForwardChar) add(tui.CtrlH, actBackwardDeleteChar) add(tui.Backspace, actBackwardDeleteChar) + add(tui.CtrlBackspace, actBackwardDeleteChar) add(tui.Tab, actToggleDown) add(tui.ShiftTab, actToggleUp) add(tui.CtrlJ, actDown) diff --git a/src/tui/eventtype_string.go b/src/tui/eventtype_string.go index 9d4aa77d..08b5c21f 100644 --- a/src/tui/eventtype_string.go +++ b/src/tui/eventtype_string.go @@ -37,86 +37,137 @@ func _() { _ = x[CtrlZ-26] _ = x[Esc-27] _ = x[CtrlSpace-28] - _ = x[CtrlDelete-29] - _ = x[CtrlBackSlash-30] - _ = x[CtrlRightBracket-31] - _ = x[CtrlCaret-32] - _ = x[CtrlSlash-33] - _ = x[ShiftTab-34] - _ = x[Backspace-35] - _ = x[Delete-36] - _ = x[PageUp-37] - _ = x[PageDown-38] - _ = x[Up-39] - _ = x[Down-40] - _ = x[Left-41] - _ = x[Right-42] - _ = x[Home-43] - _ = x[End-44] - _ = x[Insert-45] - _ = x[ShiftUp-46] - _ = x[ShiftDown-47] - _ = x[ShiftLeft-48] - _ = x[ShiftRight-49] - _ = x[ShiftDelete-50] - _ = x[F1-51] - _ = x[F2-52] - _ = x[F3-53] - _ = x[F4-54] - _ = x[F5-55] - _ = x[F6-56] - _ = x[F7-57] - _ = x[F8-58] - _ = x[F9-59] - _ = x[F10-60] - _ = x[F11-61] - _ = x[F12-62] - _ = x[AltBackspace-63] - _ = x[AltUp-64] - _ = x[AltDown-65] - _ = x[AltLeft-66] - _ = x[AltRight-67] - _ = x[AltShiftUp-68] - _ = x[AltShiftDown-69] - _ = x[AltShiftLeft-70] - _ = x[AltShiftRight-71] - _ = x[Alt-72] - _ = x[CtrlAlt-73] - _ = x[Invalid-74] - _ = x[Fatal-75] - _ = x[BracketedPasteBegin-76] - _ = x[BracketedPasteEnd-77] - _ = x[Mouse-78] - _ = x[DoubleClick-79] - _ = x[LeftClick-80] - _ = x[RightClick-81] - _ = x[SLeftClick-82] - _ = x[SRightClick-83] - _ = x[ScrollUp-84] - _ = x[ScrollDown-85] - _ = x[SScrollUp-86] - _ = x[SScrollDown-87] - _ = x[PreviewScrollUp-88] - _ = x[PreviewScrollDown-89] - _ = x[Resize-90] - _ = x[Change-91] - _ = x[BackwardEOF-92] - _ = x[Start-93] - _ = x[Load-94] - _ = x[Focus-95] - _ = x[One-96] - _ = x[Zero-97] - _ = x[Result-98] - _ = x[Jump-99] - _ = x[JumpCancel-100] - _ = x[ClickHeader-101] - _ = x[ClickFooter-102] - _ = x[Multi-103] + _ = x[CtrlBackSlash-29] + _ = x[CtrlRightBracket-30] + _ = x[CtrlCaret-31] + _ = x[CtrlSlash-32] + _ = x[ShiftTab-33] + _ = x[Backspace-34] + _ = x[Delete-35] + _ = x[PageUp-36] + _ = x[PageDown-37] + _ = x[Up-38] + _ = x[Down-39] + _ = x[Left-40] + _ = x[Right-41] + _ = x[Home-42] + _ = x[End-43] + _ = x[Insert-44] + _ = x[ShiftUp-45] + _ = x[ShiftDown-46] + _ = x[ShiftLeft-47] + _ = x[ShiftRight-48] + _ = x[ShiftDelete-49] + _ = x[ShiftHome-50] + _ = x[ShiftEnd-51] + _ = x[ShiftPageUp-52] + _ = x[ShiftPageDown-53] + _ = x[F1-54] + _ = x[F2-55] + _ = x[F3-56] + _ = x[F4-57] + _ = x[F5-58] + _ = x[F6-59] + _ = x[F7-60] + _ = x[F8-61] + _ = x[F9-62] + _ = x[F10-63] + _ = x[F11-64] + _ = x[F12-65] + _ = x[AltBackspace-66] + _ = x[AltUp-67] + _ = x[AltDown-68] + _ = x[AltLeft-69] + _ = x[AltRight-70] + _ = x[AltDelete-71] + _ = x[AltHome-72] + _ = x[AltEnd-73] + _ = x[AltPageUp-74] + _ = x[AltPageDown-75] + _ = x[AltShiftUp-76] + _ = x[AltShiftDown-77] + _ = x[AltShiftLeft-78] + _ = x[AltShiftRight-79] + _ = x[AltShiftDelete-80] + _ = x[AltShiftHome-81] + _ = x[AltShiftEnd-82] + _ = x[AltShiftPageUp-83] + _ = x[AltShiftPageDown-84] + _ = x[CtrlUp-85] + _ = x[CtrlDown-86] + _ = x[CtrlLeft-87] + _ = x[CtrlRight-88] + _ = x[CtrlHome-89] + _ = x[CtrlEnd-90] + _ = x[CtrlBackspace-91] + _ = x[CtrlDelete-92] + _ = x[CtrlPageUp-93] + _ = x[CtrlPageDown-94] + _ = x[Alt-95] + _ = x[CtrlAlt-96] + _ = x[CtrlAltUp-97] + _ = x[CtrlAltDown-98] + _ = x[CtrlAltLeft-99] + _ = x[CtrlAltRight-100] + _ = x[CtrlAltHome-101] + _ = x[CtrlAltEnd-102] + _ = x[CtrlAltBackspace-103] + _ = x[CtrlAltDelete-104] + _ = x[CtrlAltPageUp-105] + _ = x[CtrlAltPageDown-106] + _ = x[CtrlShiftUp-107] + _ = x[CtrlShiftDown-108] + _ = x[CtrlShiftLeft-109] + _ = x[CtrlShiftRight-110] + _ = x[CtrlShiftHome-111] + _ = x[CtrlShiftEnd-112] + _ = x[CtrlShiftDelete-113] + _ = x[CtrlShiftPageUp-114] + _ = x[CtrlShiftPageDown-115] + _ = x[CtrlAltShiftUp-116] + _ = x[CtrlAltShiftDown-117] + _ = x[CtrlAltShiftLeft-118] + _ = x[CtrlAltShiftRight-119] + _ = x[CtrlAltShiftHome-120] + _ = x[CtrlAltShiftEnd-121] + _ = x[CtrlAltShiftDelete-122] + _ = x[CtrlAltShiftPageUp-123] + _ = x[CtrlAltShiftPageDown-124] + _ = x[Invalid-125] + _ = x[Fatal-126] + _ = x[BracketedPasteBegin-127] + _ = x[BracketedPasteEnd-128] + _ = x[Mouse-129] + _ = x[DoubleClick-130] + _ = x[LeftClick-131] + _ = x[RightClick-132] + _ = x[SLeftClick-133] + _ = x[SRightClick-134] + _ = x[ScrollUp-135] + _ = x[ScrollDown-136] + _ = x[SScrollUp-137] + _ = x[SScrollDown-138] + _ = x[PreviewScrollUp-139] + _ = x[PreviewScrollDown-140] + _ = x[Resize-141] + _ = x[Change-142] + _ = x[BackwardEOF-143] + _ = x[Start-144] + _ = x[Load-145] + _ = x[Focus-146] + _ = x[One-147] + _ = x[Zero-148] + _ = x[Result-149] + _ = x[Jump-150] + _ = x[JumpCancel-151] + _ = x[ClickHeader-152] + _ = x[ClickFooter-153] + _ = x[Multi-154] } -const _EventType_name = "RuneCtrlACtrlBCtrlCCtrlDCtrlECtrlFCtrlGCtrlHTabCtrlJCtrlKCtrlLEnterCtrlNCtrlOCtrlPCtrlQCtrlRCtrlSCtrlTCtrlUCtrlVCtrlWCtrlXCtrlYCtrlZEscCtrlSpaceCtrlDeleteCtrlBackSlashCtrlRightBracketCtrlCaretCtrlSlashShiftTabBackspaceDeletePageUpPageDownUpDownLeftRightHomeEndInsertShiftUpShiftDownShiftLeftShiftRightShiftDeleteF1F2F3F4F5F6F7F8F9F10F11F12AltBackspaceAltUpAltDownAltLeftAltRightAltShiftUpAltShiftDownAltShiftLeftAltShiftRightAltCtrlAltInvalidFatalBracketedPasteBeginBracketedPasteEndMouseDoubleClickLeftClickRightClickSLeftClickSRightClickScrollUpScrollDownSScrollUpSScrollDownPreviewScrollUpPreviewScrollDownResizeChangeBackwardEOFStartLoadFocusOneZeroResultJumpJumpCancelClickHeaderClickFooterMulti" +const _EventType_name = "RuneCtrlACtrlBCtrlCCtrlDCtrlECtrlFCtrlGCtrlHTabCtrlJCtrlKCtrlLEnterCtrlNCtrlOCtrlPCtrlQCtrlRCtrlSCtrlTCtrlUCtrlVCtrlWCtrlXCtrlYCtrlZEscCtrlSpaceCtrlBackSlashCtrlRightBracketCtrlCaretCtrlSlashShiftTabBackspaceDeletePageUpPageDownUpDownLeftRightHomeEndInsertShiftUpShiftDownShiftLeftShiftRightShiftDeleteShiftHomeShiftEndShiftPageUpShiftPageDownF1F2F3F4F5F6F7F8F9F10F11F12AltBackspaceAltUpAltDownAltLeftAltRightAltDeleteAltHomeAltEndAltPageUpAltPageDownAltShiftUpAltShiftDownAltShiftLeftAltShiftRightAltShiftDeleteAltShiftHomeAltShiftEndAltShiftPageUpAltShiftPageDownCtrlUpCtrlDownCtrlLeftCtrlRightCtrlHomeCtrlEndCtrlBackspaceCtrlDeleteCtrlPageUpCtrlPageDownAltCtrlAltCtrlAltUpCtrlAltDownCtrlAltLeftCtrlAltRightCtrlAltHomeCtrlAltEndCtrlAltBackspaceCtrlAltDeleteCtrlAltPageUpCtrlAltPageDownCtrlShiftUpCtrlShiftDownCtrlShiftLeftCtrlShiftRightCtrlShiftHomeCtrlShiftEndCtrlShiftDeleteCtrlShiftPageUpCtrlShiftPageDownCtrlAltShiftUpCtrlAltShiftDownCtrlAltShiftLeftCtrlAltShiftRightCtrlAltShiftHomeCtrlAltShiftEndCtrlAltShiftDeleteCtrlAltShiftPageUpCtrlAltShiftPageDownInvalidFatalBracketedPasteBeginBracketedPasteEndMouseDoubleClickLeftClickRightClickSLeftClickSRightClickScrollUpScrollDownSScrollUpSScrollDownPreviewScrollUpPreviewScrollDownResizeChangeBackwardEOFStartLoadFocusOneZeroResultJumpJumpCancelClickHeaderClickFooterMulti" -var _EventType_index = [...]uint16{0, 4, 9, 14, 19, 24, 29, 34, 39, 44, 47, 52, 57, 62, 67, 72, 77, 82, 87, 92, 97, 102, 107, 112, 117, 122, 127, 132, 135, 144, 154, 167, 183, 192, 201, 209, 218, 224, 230, 238, 240, 244, 248, 253, 257, 260, 266, 273, 282, 291, 301, 312, 314, 316, 318, 320, 322, 324, 326, 328, 330, 333, 336, 339, 351, 356, 363, 370, 378, 388, 400, 412, 425, 428, 435, 442, 447, 466, 483, 488, 499, 508, 518, 528, 539, 547, 557, 566, 577, 592, 609, 615, 621, 632, 637, 641, 646, 649, 653, 659, 663, 673, 684, 695, 700} +var _EventType_index = [...]uint16{0, 4, 9, 14, 19, 24, 29, 34, 39, 44, 47, 52, 57, 62, 67, 72, 77, 82, 87, 92, 97, 102, 107, 112, 117, 122, 127, 132, 135, 144, 157, 173, 182, 191, 199, 208, 214, 220, 228, 230, 234, 238, 243, 247, 250, 256, 263, 272, 281, 291, 302, 311, 319, 330, 343, 345, 347, 349, 351, 353, 355, 357, 359, 361, 364, 367, 370, 382, 387, 394, 401, 409, 418, 425, 431, 440, 451, 461, 473, 485, 498, 512, 524, 535, 549, 565, 571, 579, 587, 596, 604, 611, 624, 634, 644, 656, 659, 666, 675, 686, 697, 709, 720, 730, 746, 759, 772, 787, 798, 811, 824, 838, 851, 863, 878, 893, 910, 924, 940, 956, 973, 989, 1004, 1022, 1040, 1060, 1067, 1072, 1091, 1108, 1113, 1124, 1133, 1143, 1153, 1164, 1172, 1182, 1191, 1202, 1217, 1234, 1240, 1246, 1257, 1262, 1266, 1271, 1274, 1278, 1284, 1288, 1298, 1309, 1320, 1325} func (i EventType) String() string { if i < 0 || i >= EventType(len(_EventType_index)-1) { diff --git a/src/tui/light.go b/src/tui/light.go index 54abbe5c..ec93e67e 100644 --- a/src/tui/light.go +++ b/src/tui/light.go @@ -335,6 +335,8 @@ func (r *LightRenderer) GetChar() Event { return Event{CtrlQ, 0, nil} case 127: return Event{Backspace, 0, nil} + case 8: + return Event{CtrlBackspace, 0, nil} case 0: return Event{CtrlSpace, 0, nil} case 28: @@ -381,6 +383,9 @@ func (r *LightRenderer) escSequence(sz *int) Event { } *sz = 2 + if r.buffer[1] == 8 { + return Event{CtrlAltBackspace, 0, nil} + } if r.buffer[1] >= 1 && r.buffer[1] <= 'z'-'a'+1 { return CtrlAltKey(rune(r.buffer[1] + 'a' - 1)) } @@ -473,22 +478,136 @@ func (r *LightRenderer) escSequence(sz *int) Event { if r.buffer[3] == '~' { return Event{Delete, 0, nil} } + if len(r.buffer) == 7 && r.buffer[6] == '~' && r.buffer[4] == '1' { + switch r.buffer[5] { + case '0': + return Event{AltShiftDelete, 0, nil} + case '1': + return Event{AltDelete, 0, nil} + case '2': + return Event{AltShiftDelete, 0, nil} + case '3': + return Event{CtrlAltDelete, 0, nil} + case '4': + return Event{CtrlAltShiftDelete, 0, nil} + case '5': + return Event{CtrlAltDelete, 0, nil} + case '6': + return Event{CtrlAltShiftDelete, 0, nil} + } + } if len(r.buffer) == 6 && r.buffer[5] == '~' { *sz = 6 switch r.buffer[4] { - case '5': - return Event{CtrlDelete, 0, nil} case '2': return Event{ShiftDelete, 0, nil} + case '3': + return Event{AltDelete, 0, nil} + case '4': + return Event{AltShiftDelete, 0, nil} + case '5': + return Event{CtrlDelete, 0, nil} + case '6': + return Event{CtrlShiftDelete, 0, nil} + case '7': + return Event{CtrlAltDelete, 0, nil} + case '8': + return Event{CtrlAltShiftDelete, 0, nil} + case '9': + return Event{AltDelete, 0, nil} } } return Event{Invalid, 0, nil} case '4': return Event{End, 0, nil} case '5': - return Event{PageUp, 0, nil} + if r.buffer[3] == '~' { + return Event{PageUp, 0, nil} + } + if len(r.buffer) == 7 && r.buffer[6] == '~' && r.buffer[4] == '1' { + switch r.buffer[5] { + case '0': + return Event{AltShiftPageUp, 0, nil} + case '1': + return Event{AltPageUp, 0, nil} + case '2': + return Event{AltShiftPageUp, 0, nil} + case '3': + return Event{CtrlAltPageUp, 0, nil} + case '4': + return Event{CtrlAltShiftPageUp, 0, nil} + case '5': + return Event{CtrlAltPageUp, 0, nil} + case '6': + return Event{CtrlAltShiftPageUp, 0, nil} + } + } + if len(r.buffer) == 6 && r.buffer[5] == '~' { + *sz = 6 + switch r.buffer[4] { + case '2': + return Event{ShiftPageUp, 0, nil} + case '3': + return Event{AltPageUp, 0, nil} + case '4': + return Event{AltShiftPageUp, 0, nil} + case '5': + return Event{CtrlPageUp, 0, nil} + case '6': + return Event{CtrlShiftPageUp, 0, nil} + case '7': + return Event{CtrlAltPageUp, 0, nil} + case '8': + return Event{CtrlAltShiftPageUp, 0, nil} + case '9': + return Event{AltPageUp, 0, nil} + } + } + return Event{Invalid, 0, nil} case '6': - return Event{PageDown, 0, nil} + if r.buffer[3] == '~' { + return Event{PageDown, 0, nil} + } + if len(r.buffer) == 7 && r.buffer[6] == '~' && r.buffer[4] == '1' { + switch r.buffer[5] { + case '0': + return Event{AltShiftPageDown, 0, nil} + case '1': + return Event{AltPageDown, 0, nil} + case '2': + return Event{AltShiftPageDown, 0, nil} + case '3': + return Event{CtrlAltPageDown, 0, nil} + case '4': + return Event{CtrlAltShiftPageDown, 0, nil} + case '5': + return Event{CtrlAltPageDown, 0, nil} + case '6': + return Event{CtrlAltShiftPageDown, 0, nil} + } + } + if len(r.buffer) == 6 && r.buffer[5] == '~' { + *sz = 6 + switch r.buffer[4] { + case '2': + return Event{ShiftPageDown, 0, nil} + case '3': + return Event{AltPageDown, 0, nil} + case '4': + return Event{AltShiftPageDown, 0, nil} + case '5': + return Event{CtrlPageDown, 0, nil} + case '6': + return Event{CtrlShiftPageDown, 0, nil} + case '7': + return Event{CtrlAltPageDown, 0, nil} + case '8': + return Event{CtrlAltShiftPageDown, 0, nil} + case '9': + return Event{AltPageDown, 0, nil} + } + } + return Event{Invalid, 0, nil} case '7': return Event{Home, 0, nil} case '8': @@ -526,63 +645,172 @@ func (r *LightRenderer) escSequence(sz *int) Event { } *sz = 6 switch r.buffer[4] { - case '1', '2', '3', '4', '5': + case '1', '2', '3', '4', '5', '6', '7', '8', '9': // Kitty iTerm2 WezTerm // SHIFT-ARROW "\e[1;2D" // ALT-SHIFT-ARROW "\e[1;4D" "\e[1;10D" "\e[1;4D" // CTRL-SHIFT-ARROW "\e[1;6D" N/A // CMD-SHIFT-ARROW "\e[1;10D" N/A N/A ("\e[1;2D") - alt := r.buffer[4] == '3' + ctrl := bytes.IndexByte([]byte{'5', '6', '7', '8'}, r.buffer[4]) >= 0 + alt := bytes.IndexByte([]byte{'3', '4', '7', '8'}, r.buffer[4]) >= 0 + shift := bytes.IndexByte([]byte{'2', '4', '6', '8'}, r.buffer[4]) >= 0 char := r.buffer[5] - altShift := false - if r.buffer[4] == '1' && r.buffer[5] == '0' { - altShift = true - if len(r.buffer) < 7 { - return Event{Invalid, 0, nil} - } - *sz = 7 - char = r.buffer[6] - } else if r.buffer[4] == '4' { - altShift = true + if r.buffer[4] == '9' { + ctrl = false + alt = true + shift = false if len(r.buffer) < 6 { return Event{Invalid, 0, nil} } *sz = 6 char = r.buffer[5] + } else if r.buffer[4] == '1' && bytes.IndexByte([]byte{'0', '1', '2', '3', '4', '5', '6'}, r.buffer[5]) >= 0 { + ctrl = bytes.IndexByte([]byte{'3', '4', '5', '6'}, r.buffer[5]) >= 0 + alt = true + shift = bytes.IndexByte([]byte{'0', '2', '4', '6'}, r.buffer[5]) >= 0 + if len(r.buffer) < 7 { + return Event{Invalid, 0, nil} + } + *sz = 7 + char = r.buffer[6] } + ctrlShift := ctrl && shift + ctrlAlt := ctrl && alt + altShift := alt && shift + ctrlAltShift := ctrl && alt && shift switch char { case 'A': - if alt { - return Event{AltUp, 0, nil} + if ctrlAltShift { + return Event{CtrlAltShiftUp, 0, nil} + } + if ctrlAlt { + return Event{CtrlAltUp, 0, nil} + } + if ctrlShift { + return Event{CtrlShiftUp, 0, nil} } if altShift { return Event{AltShiftUp, 0, nil} } - return Event{ShiftUp, 0, nil} - case 'B': + if ctrl { + return Event{CtrlUp, 0, nil} + } if alt { - return Event{AltDown, 0, nil} + return Event{AltUp, 0, nil} + } + if shift { + return Event{ShiftUp, 0, nil} + } + case 'B': + if ctrlAltShift { + return Event{CtrlAltShiftDown, 0, nil} + } + if ctrlAlt { + return Event{CtrlAltDown, 0, nil} + } + if ctrlShift { + return Event{CtrlShiftDown, 0, nil} } if altShift { return Event{AltShiftDown, 0, nil} } - return Event{ShiftDown, 0, nil} - case 'C': + if ctrl { + return Event{CtrlDown, 0, nil} + } if alt { - return Event{AltRight, 0, nil} + return Event{AltDown, 0, nil} + } + if shift { + return Event{ShiftDown, 0, nil} + } + case 'C': + if ctrlAltShift { + return Event{CtrlAltShiftRight, 0, nil} + } + if ctrlAlt { + return Event{CtrlAltRight, 0, nil} + } + if ctrlShift { + return Event{CtrlShiftRight, 0, nil} } if altShift { return Event{AltShiftRight, 0, nil} } - return Event{ShiftRight, 0, nil} - case 'D': + if ctrl { + return Event{CtrlRight, 0, nil} + } + if shift { + return Event{ShiftRight, 0, nil} + } if alt { - return Event{AltLeft, 0, nil} + return Event{AltRight, 0, nil} + } + case 'D': + if ctrlAltShift { + return Event{CtrlAltShiftLeft, 0, nil} + } + if ctrlAlt { + return Event{CtrlAltLeft, 0, nil} + } + if ctrlShift { + return Event{CtrlShiftLeft, 0, nil} } if altShift { return Event{AltShiftLeft, 0, nil} } - return Event{ShiftLeft, 0, nil} + if ctrl { + return Event{CtrlLeft, 0, nil} + } + if alt { + return Event{AltLeft, 0, nil} + } + if shift { + return Event{ShiftLeft, 0, nil} + } + case 'H': + if ctrlAltShift { + return Event{CtrlAltShiftHome, 0, nil} + } + if ctrlAlt { + return Event{CtrlAltHome, 0, nil} + } + if ctrlShift { + return Event{CtrlShiftHome, 0, nil} + } + if altShift { + return Event{AltShiftHome, 0, nil} + } + if ctrl { + return Event{CtrlHome, 0, nil} + } + if alt { + return Event{AltHome, 0, nil} + } + if shift { + return Event{ShiftHome, 0, nil} + } + case 'F': + if ctrlAltShift { + return Event{CtrlAltShiftEnd, 0, nil} + } + if ctrlAlt { + return Event{CtrlAltEnd, 0, nil} + } + if ctrlShift { + return Event{CtrlShiftEnd, 0, nil} + } + if altShift { + return Event{AltShiftEnd, 0, nil} + } + if ctrl { + return Event{CtrlEnd, 0, nil} + } + if alt { + return Event{AltEnd, 0, nil} + } + if shift { + return Event{ShiftEnd, 0, nil} + } } } // r.buffer[4] } // r.buffer[3] diff --git a/src/tui/light_test.go b/src/tui/light_test.go new file mode 100644 index 00000000..717a01d0 --- /dev/null +++ b/src/tui/light_test.go @@ -0,0 +1,335 @@ +package tui + +import ( + "fmt" + "os" + "testing" + "unicode" +) + +func TestLightRenderer(t *testing.T) { + tty_file, _ := os.Open("") + renderer, _ := NewLightRenderer( + "", tty_file, &ColorTheme{}, true, false, 0, false, true, + func(h int) int { return h }) + + light_renderer := renderer.(*LightRenderer) + + assertCharSequence := func(sequence string, name string) { + bytes := []byte(sequence) + light_renderer.buffer = bytes + event := light_renderer.GetChar() + if event.KeyName() != name { + t.Errorf( + "sequence: %q | %v | '%s' (%s) != %s", + string(bytes), bytes, + event.KeyName(), event.Type.String(), name) + } + } + + assertEscSequence := func(sequence string, name string) { + bytes := []byte(sequence) + light_renderer.buffer = bytes + + sz := 1 + event := light_renderer.escSequence(&sz) + if fmt.Sprintf("!%s", event.Type.String()) == name { + // this is fine + } else if event.KeyName() != name { + t.Errorf( + "sequence: %q | %v | '%s' (%s) != %s", + string(bytes), bytes, + event.KeyName(), event.Type.String(), name) + } + } + + // invalid + assertEscSequence("\x1b[<", "!Invalid") + assertEscSequence("\x1b[1;1R", "!Invalid") + assertEscSequence("\x1b[", "!Invalid") + assertEscSequence("\x1b[1", "!Invalid") + assertEscSequence("\x1b[3;3~1", "!Invalid") + assertEscSequence("\x1b[13", "!Invalid") + assertEscSequence("\x1b[1;3", "!Invalid") + assertEscSequence("\x1b[1;10", "!Invalid") + assertEscSequence("\x1b[220~", "!Invalid") + assertEscSequence("\x1b[5;30~", "!Invalid") + assertEscSequence("\x1b[6;30~", "!Invalid") + + // general + for r := 'a'; r < 'z'; r++ { + lower_r := fmt.Sprintf("%c", r) + upper_r := fmt.Sprintf("%c", unicode.ToUpper(r)) + assertCharSequence(lower_r, lower_r) + assertCharSequence(upper_r, upper_r) + } + + assertCharSequence("\x01", "ctrl-a") + assertCharSequence("\x02", "ctrl-b") + assertCharSequence("\x03", "ctrl-c") + assertCharSequence("\x04", "ctrl-d") + assertCharSequence("\x05", "ctrl-e") + assertCharSequence("\x06", "ctrl-f") + assertCharSequence("\x07", "ctrl-g") + // ctrl-h is the same as ctrl-backspace + // ctrl-i is the same as tab + assertCharSequence("\n", "ctrl-j") + assertCharSequence("\x0b", "ctrl-k") + assertCharSequence("\x0c", "ctrl-l") + assertCharSequence("\r", "enter") // enter + assertCharSequence("\x0e", "ctrl-n") + assertCharSequence("\x0f", "ctrl-o") + assertCharSequence("\x10", "ctrl-p") + assertCharSequence("\x11", "ctrl-q") + assertCharSequence("\x12", "ctrl-r") + assertCharSequence("\x13", "ctrl-s") + assertCharSequence("\x14", "ctrl-t") + assertCharSequence("\x15", "ctrl-u") + assertCharSequence("\x16", "ctrl-v") + assertCharSequence("\x17", "ctrl-w") + assertCharSequence("\x18", "ctrl-x") + assertCharSequence("\x19", "ctrl-y") + assertCharSequence("\x1a", "ctrl-z") + + assertCharSequence("\x00", "ctrl-space") + assertCharSequence("\x1c", "ctrl-\\") + assertCharSequence("\x1d", "ctrl-]") + assertCharSequence("\x1e", "ctrl-^") + assertCharSequence("\x1f", "ctrl-/") + + assertEscSequence("\x1ba", "alt-a") + assertEscSequence("\x1bb", "alt-b") + assertEscSequence("\x1bc", "alt-c") + assertEscSequence("\x1bd", "alt-d") + assertEscSequence("\x1be", "alt-e") + assertEscSequence("\x1bf", "alt-f") + assertEscSequence("\x1bg", "alt-g") + assertEscSequence("\x1bh", "alt-h") + assertEscSequence("\x1bi", "alt-i") + assertEscSequence("\x1bj", "alt-j") + assertEscSequence("\x1bk", "alt-k") + assertEscSequence("\x1bl", "alt-l") + assertEscSequence("\x1bm", "alt-m") + assertEscSequence("\x1bn", "alt-n") + assertEscSequence("\x1bo", "alt-o") + assertEscSequence("\x1bp", "alt-p") + assertEscSequence("\x1bq", "alt-q") + assertEscSequence("\x1br", "alt-r") + assertEscSequence("\x1bs", "alt-s") + assertEscSequence("\x1bt", "alt-t") + assertEscSequence("\x1bu", "alt-u") + assertEscSequence("\x1bv", "alt-v") + assertEscSequence("\x1bw", "alt-w") + assertEscSequence("\x1bx", "alt-x") + assertEscSequence("\x1by", "alt-y") + assertEscSequence("\x1bz", "alt-z") + + assertEscSequence("\x1bOP", "f1") + assertEscSequence("\x1bOQ", "f2") + assertEscSequence("\x1bOR", "f3") + assertEscSequence("\x1bOS", "f4") + assertEscSequence("\x1b[15~", "f5") + assertEscSequence("\x1b[17~", "f6") + assertEscSequence("\x1b[18~", "f7") + assertEscSequence("\x1b[19~", "f8") + assertEscSequence("\x1b[20~", "f9") + assertEscSequence("\x1b[21~", "f10") + assertEscSequence("\x1b[23~", "f11") + assertEscSequence("\x1b[24~", "f12") + + assertEscSequence("\x1b", "esc") + assertCharSequence("\t", "tab") + assertEscSequence("\x1b[Z", "shift-tab") + + assertCharSequence("\x7f", "backspace") + assertEscSequence("\x1b\x7f", "alt-backspace") + assertCharSequence("\b", "ctrl-backspace") + assertEscSequence("\x1b\b", "ctrl-alt-backspace") + + assertEscSequence("\x1b[A", "up") + assertEscSequence("\x1b[B", "down") + assertEscSequence("\x1b[C", "right") + assertEscSequence("\x1b[D", "left") + assertEscSequence("\x1b[H", "home") + assertEscSequence("\x1b[F", "end") + assertEscSequence("\x1b[2~", "insert") + assertEscSequence("\x1b[3~", "delete") + assertEscSequence("\x1b[5~", "page-up") + assertEscSequence("\x1b[6~", "page-down") + assertEscSequence("\x1b[7~", "home") + assertEscSequence("\x1b[8~", "end") + + assertEscSequence("\x1b[1;2A", "shift-up") + assertEscSequence("\x1b[1;2B", "shift-down") + assertEscSequence("\x1b[1;2C", "shift-right") + assertEscSequence("\x1b[1;2D", "shift-left") + assertEscSequence("\x1b[1;2H", "shift-home") + assertEscSequence("\x1b[1;2F", "shift-end") + assertEscSequence("\x1b[3;2~", "shift-delete") + assertEscSequence("\x1b[5;2~", "shift-page-up") + assertEscSequence("\x1b[6;2~", "shift-page-down") + + assertEscSequence("\x1b\x1b", "esc") + assertEscSequence("\x1b\x1b[A", "alt-up") + assertEscSequence("\x1b\x1b[B", "alt-down") + assertEscSequence("\x1b\x1b[C", "alt-right") + assertEscSequence("\x1b\x1b[D", "alt-left") + + assertEscSequence("\x1b[1;3A", "alt-up") + assertEscSequence("\x1b[1;3B", "alt-down") + assertEscSequence("\x1b[1;3C", "alt-right") + assertEscSequence("\x1b[1;3D", "alt-left") + assertEscSequence("\x1b[1;3H", "alt-home") + assertEscSequence("\x1b[1;3F", "alt-end") + assertEscSequence("\x1b[3;3~", "alt-delete") + assertEscSequence("\x1b[5;3~", "alt-page-up") + assertEscSequence("\x1b[6;3~", "alt-page-down") + + assertEscSequence("\x1b[1;4A", "alt-shift-up") + assertEscSequence("\x1b[1;4B", "alt-shift-down") + assertEscSequence("\x1b[1;4C", "alt-shift-right") + assertEscSequence("\x1b[1;4D", "alt-shift-left") + assertEscSequence("\x1b[1;4H", "alt-shift-home") + assertEscSequence("\x1b[1;4F", "alt-shift-end") + assertEscSequence("\x1b[3;4~", "alt-shift-delete") + assertEscSequence("\x1b[5;4~", "alt-shift-page-up") + assertEscSequence("\x1b[6;4~", "alt-shift-page-down") + + assertEscSequence("\x1b[1;5A", "ctrl-up") + assertEscSequence("\x1b[1;5B", "ctrl-down") + assertEscSequence("\x1b[1;5C", "ctrl-right") + assertEscSequence("\x1b[1;5D", "ctrl-left") + assertEscSequence("\x1b[1;5H", "ctrl-home") + assertEscSequence("\x1b[1;5F", "ctrl-end") + assertEscSequence("\x1b[3;5~", "ctrl-delete") + assertEscSequence("\x1b[5;5~", "ctrl-page-up") + assertEscSequence("\x1b[6;5~", "ctrl-page-down") + + assertEscSequence("\x1b[1;7A", "ctrl-alt-up") + assertEscSequence("\x1b[1;7B", "ctrl-alt-down") + assertEscSequence("\x1b[1;7C", "ctrl-alt-right") + assertEscSequence("\x1b[1;7D", "ctrl-alt-left") + assertEscSequence("\x1b[1;7H", "ctrl-alt-home") + assertEscSequence("\x1b[1;7F", "ctrl-alt-end") + assertEscSequence("\x1b[3;7~", "ctrl-alt-delete") + assertEscSequence("\x1b[5;7~", "ctrl-alt-page-up") + assertEscSequence("\x1b[6;7~", "ctrl-alt-page-down") + + assertEscSequence("\x1b[1;6A", "ctrl-shift-up") + assertEscSequence("\x1b[1;6B", "ctrl-shift-down") + assertEscSequence("\x1b[1;6C", "ctrl-shift-right") + assertEscSequence("\x1b[1;6D", "ctrl-shift-left") + assertEscSequence("\x1b[1;6H", "ctrl-shift-home") + assertEscSequence("\x1b[1;6F", "ctrl-shift-end") + assertEscSequence("\x1b[3;6~", "ctrl-shift-delete") + assertEscSequence("\x1b[5;6~", "ctrl-shift-page-up") + assertEscSequence("\x1b[6;6~", "ctrl-shift-page-down") + + assertEscSequence("\x1b[1;8A", "ctrl-alt-shift-up") + assertEscSequence("\x1b[1;8B", "ctrl-alt-shift-down") + assertEscSequence("\x1b[1;8C", "ctrl-alt-shift-right") + assertEscSequence("\x1b[1;8D", "ctrl-alt-shift-left") + assertEscSequence("\x1b[1;8H", "ctrl-alt-shift-home") + assertEscSequence("\x1b[1;8F", "ctrl-alt-shift-end") + assertEscSequence("\x1b[3;8~", "ctrl-alt-shift-delete") + assertEscSequence("\x1b[5;8~", "ctrl-alt-shift-page-up") + assertEscSequence("\x1b[6;8~", "ctrl-alt-shift-page-down") + + // xterm meta & mac + assertEscSequence("\x1b[1;9A", "alt-up") + assertEscSequence("\x1b[1;9B", "alt-down") + assertEscSequence("\x1b[1;9C", "alt-right") + assertEscSequence("\x1b[1;9D", "alt-left") + assertEscSequence("\x1b[1;9H", "alt-home") + assertEscSequence("\x1b[1;9F", "alt-end") + assertEscSequence("\x1b[3;9~", "alt-delete") + assertEscSequence("\x1b[5;9~", "alt-page-up") + assertEscSequence("\x1b[6;9~", "alt-page-down") + + assertEscSequence("\x1b[1;10A", "alt-shift-up") + assertEscSequence("\x1b[1;10B", "alt-shift-down") + assertEscSequence("\x1b[1;10C", "alt-shift-right") + assertEscSequence("\x1b[1;10D", "alt-shift-left") + assertEscSequence("\x1b[1;10H", "alt-shift-home") + assertEscSequence("\x1b[1;10F", "alt-shift-end") + assertEscSequence("\x1b[3;10~", "alt-shift-delete") + assertEscSequence("\x1b[5;10~", "alt-shift-page-up") + assertEscSequence("\x1b[6;10~", "alt-shift-page-down") + + assertEscSequence("\x1b[1;11A", "alt-up") + assertEscSequence("\x1b[1;11B", "alt-down") + assertEscSequence("\x1b[1;11C", "alt-right") + assertEscSequence("\x1b[1;11D", "alt-left") + assertEscSequence("\x1b[1;11H", "alt-home") + assertEscSequence("\x1b[1;11F", "alt-end") + assertEscSequence("\x1b[3;11~", "alt-delete") + assertEscSequence("\x1b[5;11~", "alt-page-up") + assertEscSequence("\x1b[6;11~", "alt-page-down") + + assertEscSequence("\x1b[1;12A", "alt-shift-up") + assertEscSequence("\x1b[1;12B", "alt-shift-down") + assertEscSequence("\x1b[1;12C", "alt-shift-right") + assertEscSequence("\x1b[1;12D", "alt-shift-left") + assertEscSequence("\x1b[1;12H", "alt-shift-home") + assertEscSequence("\x1b[1;12F", "alt-shift-end") + assertEscSequence("\x1b[3;12~", "alt-shift-delete") + assertEscSequence("\x1b[5;12~", "alt-shift-page-up") + assertEscSequence("\x1b[6;12~", "alt-shift-page-down") + + assertEscSequence("\x1b[1;13A", "ctrl-alt-up") + assertEscSequence("\x1b[1;13B", "ctrl-alt-down") + assertEscSequence("\x1b[1;13C", "ctrl-alt-right") + assertEscSequence("\x1b[1;13D", "ctrl-alt-left") + assertEscSequence("\x1b[1;13H", "ctrl-alt-home") + assertEscSequence("\x1b[1;13F", "ctrl-alt-end") + assertEscSequence("\x1b[3;13~", "ctrl-alt-delete") + assertEscSequence("\x1b[5;13~", "ctrl-alt-page-up") + assertEscSequence("\x1b[6;13~", "ctrl-alt-page-down") + + assertEscSequence("\x1b[1;14A", "ctrl-alt-shift-up") + assertEscSequence("\x1b[1;14B", "ctrl-alt-shift-down") + assertEscSequence("\x1b[1;14C", "ctrl-alt-shift-right") + assertEscSequence("\x1b[1;14D", "ctrl-alt-shift-left") + assertEscSequence("\x1b[1;14H", "ctrl-alt-shift-home") + assertEscSequence("\x1b[1;14F", "ctrl-alt-shift-end") + assertEscSequence("\x1b[3;14~", "ctrl-alt-shift-delete") + assertEscSequence("\x1b[5;14~", "ctrl-alt-shift-page-up") + assertEscSequence("\x1b[6;14~", "ctrl-alt-shift-page-down") + + assertEscSequence("\x1b[1;15A", "ctrl-alt-up") + assertEscSequence("\x1b[1;15B", "ctrl-alt-down") + assertEscSequence("\x1b[1;15C", "ctrl-alt-right") + assertEscSequence("\x1b[1;15D", "ctrl-alt-left") + assertEscSequence("\x1b[1;15H", "ctrl-alt-home") + assertEscSequence("\x1b[1;15F", "ctrl-alt-end") + assertEscSequence("\x1b[3;15~", "ctrl-alt-delete") + assertEscSequence("\x1b[5;15~", "ctrl-alt-page-up") + assertEscSequence("\x1b[6;15~", "ctrl-alt-page-down") + + assertEscSequence("\x1b[1;16A", "ctrl-alt-shift-up") + assertEscSequence("\x1b[1;16B", "ctrl-alt-shift-down") + assertEscSequence("\x1b[1;16C", "ctrl-alt-shift-right") + assertEscSequence("\x1b[1;16D", "ctrl-alt-shift-left") + assertEscSequence("\x1b[1;16H", "ctrl-alt-shift-home") + assertEscSequence("\x1b[1;16F", "ctrl-alt-shift-end") + assertEscSequence("\x1b[3;16~", "ctrl-alt-shift-delete") + assertEscSequence("\x1b[5;16~", "ctrl-alt-shift-page-up") + assertEscSequence("\x1b[6;16~", "ctrl-alt-shift-page-down") + + // tmux & emacs + assertEscSequence("\x1bOA", "up") + assertEscSequence("\x1bOB", "down") + assertEscSequence("\x1bOC", "right") + assertEscSequence("\x1bOD", "left") + assertEscSequence("\x1bOH", "home") + assertEscSequence("\x1bOF", "end") + + // rrvt + assertEscSequence("\x1b[1~", "home") + assertEscSequence("\x1b[4~", "end") + assertEscSequence("\x1b[11~", "f1") + assertEscSequence("\x1b[12~", "f2") + assertEscSequence("\x1b[13~", "f3") + assertEscSequence("\x1b[14~", "f4") + +} diff --git a/src/tui/tcell.go b/src/tui/tcell.go index 0f80882e..3bf28797 100644 --- a/src/tui/tcell.go +++ b/src/tui/tcell.go @@ -354,6 +354,8 @@ func (r *FullscreenRenderer) GetChar() Event { shift := (mods & tcell.ModShift) > 0 ctrlAlt := ctrl && alt altShift := alt && shift + ctrlShift := ctrl && shift + ctrlAltShift := ctrl && alt && shift keyfn := func(r rune) Event { if alt { @@ -380,8 +382,11 @@ func (r *FullscreenRenderer) GetChar() Event { case tcell.KeyCtrlH: switch ev.Rune() { case 0: + if ctrlAlt { + return Event{CtrlAltBackspace, 0, nil} + } if ctrl { - return Event{Backspace, 0, nil} + return Event{CtrlBackspace, 0, nil} } case rune(tcell.KeyCtrlH): switch { @@ -442,6 +447,9 @@ func (r *FullscreenRenderer) GetChar() Event { return Event{CtrlSlash, 0, nil} // section 3: (Alt)+Backspace2 case tcell.KeyBackspace2: + if ctrl { + return Event{CtrlBackspace, 0, nil} + } if alt { return Event{AltBackspace, 0, nil} } @@ -449,9 +457,21 @@ func (r *FullscreenRenderer) GetChar() Event { // section 4: (Alt+Shift)+Key(Up|Down|Left|Right) case tcell.KeyUp: + if ctrlAltShift { + return Event{CtrlAltShiftUp, 0, nil} + } + if ctrlAlt { + return Event{CtrlAltUp, 0, nil} + } + if ctrlShift { + return Event{CtrlShiftUp, 0, nil} + } if altShift { return Event{AltShiftUp, 0, nil} } + if ctrl { + return Event{CtrlUp, 0, nil} + } if shift { return Event{ShiftUp, 0, nil} } @@ -460,9 +480,21 @@ func (r *FullscreenRenderer) GetChar() Event { } return Event{Up, 0, nil} case tcell.KeyDown: + if ctrlAltShift { + return Event{CtrlAltShiftDown, 0, nil} + } + if ctrlAlt { + return Event{CtrlAltDown, 0, nil} + } + if ctrlShift { + return Event{CtrlShiftDown, 0, nil} + } if altShift { return Event{AltShiftDown, 0, nil} } + if ctrl { + return Event{CtrlDown, 0, nil} + } if shift { return Event{ShiftDown, 0, nil} } @@ -471,9 +503,21 @@ func (r *FullscreenRenderer) GetChar() Event { } return Event{Down, 0, nil} case tcell.KeyLeft: + if ctrlAltShift { + return Event{CtrlAltShiftLeft, 0, nil} + } + if ctrlAlt { + return Event{CtrlAltLeft, 0, nil} + } + if ctrlShift { + return Event{CtrlShiftLeft, 0, nil} + } if altShift { return Event{AltShiftLeft, 0, nil} } + if ctrl { + return Event{CtrlLeft, 0, nil} + } if shift { return Event{ShiftLeft, 0, nil} } @@ -482,9 +526,21 @@ func (r *FullscreenRenderer) GetChar() Event { } return Event{Left, 0, nil} case tcell.KeyRight: + if ctrlAltShift { + return Event{CtrlAltShiftRight, 0, nil} + } + if ctrlAlt { + return Event{CtrlAltRight, 0, nil} + } + if ctrlShift { + return Event{CtrlShiftRight, 0, nil} + } if altShift { return Event{AltShiftRight, 0, nil} } + if ctrl { + return Event{CtrlRight, 0, nil} + } if shift { return Event{ShiftRight, 0, nil} } @@ -497,20 +553,119 @@ func (r *FullscreenRenderer) GetChar() Event { case tcell.KeyInsert: return Event{Insert, 0, nil} case tcell.KeyHome: + if ctrlAltShift { + return Event{CtrlAltShiftHome, 0, nil} + } + if ctrlAlt { + return Event{CtrlAltHome, 0, nil} + } + if ctrlShift { + return Event{CtrlShiftHome, 0, nil} + } + if altShift { + return Event{AltShiftHome, 0, nil} + } + if ctrl { + return Event{CtrlHome, 0, nil} + } + if shift { + return Event{ShiftHome, 0, nil} + } + if alt { + return Event{AltHome, 0, nil} + } return Event{Home, 0, nil} case tcell.KeyDelete: + if ctrlAltShift { + return Event{CtrlAltShiftDelete, 0, nil} + } + if ctrlAlt { + return Event{CtrlAltDelete, 0, nil} + } + if ctrlShift { + return Event{CtrlShiftDelete, 0, nil} + } + if altShift { + return Event{AltShiftDelete, 0, nil} + } if ctrl { return Event{CtrlDelete, 0, nil} } + if alt { + return Event{AltDelete, 0, nil} + } if shift { return Event{ShiftDelete, 0, nil} } return Event{Delete, 0, nil} case tcell.KeyEnd: + if ctrlAltShift { + return Event{CtrlAltShiftEnd, 0, nil} + } + if ctrlAlt { + return Event{CtrlAltEnd, 0, nil} + } + if ctrlShift { + return Event{CtrlShiftEnd, 0, nil} + } + if altShift { + return Event{AltShiftEnd, 0, nil} + } + if ctrl { + return Event{CtrlEnd, 0, nil} + } + if shift { + return Event{ShiftEnd, 0, nil} + } + if alt { + return Event{AltEnd, 0, nil} + } return Event{End, 0, nil} case tcell.KeyPgUp: + if ctrlAltShift { + return Event{CtrlAltShiftPageUp, 0, nil} + } + if ctrlAlt { + return Event{CtrlAltPageUp, 0, nil} + } + if ctrlShift { + return Event{CtrlShiftPageUp, 0, nil} + } + if altShift { + return Event{AltShiftPageUp, 0, nil} + } + if ctrl { + return Event{CtrlPageUp, 0, nil} + } + if shift { + return Event{ShiftPageUp, 0, nil} + } + if alt { + return Event{AltPageUp, 0, nil} + } return Event{PageUp, 0, nil} case tcell.KeyPgDn: + if ctrlAltShift { + return Event{CtrlAltShiftPageDown, 0, nil} + } + if ctrlAlt { + return Event{CtrlAltPageDown, 0, nil} + } + if ctrlShift { + return Event{CtrlShiftPageDown, 0, nil} + } + if altShift { + return Event{AltShiftPageDown, 0, nil} + } + if ctrl { + return Event{CtrlPageDown, 0, nil} + } + if shift { + return Event{ShiftPageDown, 0, nil} + } + if alt { + return Event{AltPageDown, 0, nil} + } return Event{PageDown, 0, nil} case tcell.KeyBacktab: return Event{ShiftTab, 0, nil} diff --git a/src/tui/tcell_test.go b/src/tui/tcell_test.go index 8efd0ad8..c1e025cc 100644 --- a/src/tui/tcell_test.go +++ b/src/tui/tcell_test.go @@ -107,18 +107,20 @@ func TestGetCharEventKey(t *testing.T) { {giveKey{tcell.KeyBackspace2, 0, tcell.ModAlt}, wantKey{AltBackspace, 0, nil}}, // fabricated {giveKey{tcell.KeyDEL, 0, tcell.ModNone}, wantKey{Backspace, 0, nil}}, // fabricated, unhandled {giveKey{tcell.KeyDelete, 0, tcell.ModNone}, wantKey{Delete, 0, nil}}, - {giveKey{tcell.KeyDelete, 0, tcell.ModAlt}, wantKey{Delete, 0, nil}}, + {giveKey{tcell.KeyDelete, 0, tcell.ModAlt}, wantKey{AltDelete, 0, nil}}, + {giveKey{tcell.KeyBackspace, 0, tcell.ModCtrl}, wantKey{CtrlBackspace, 0, nil}}, + {giveKey{tcell.KeyBackspace, 0, tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAltBackspace, 0, nil}}, {giveKey{tcell.KeyBackspace, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled {giveKey{tcell.KeyBS, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled {giveKey{tcell.KeyCtrlH, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled {giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModNone}, wantKey{Backspace, 0, nil}}, // actual "Backspace" keystroke {giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModAlt}, wantKey{AltBackspace, 0, nil}}, // actual "Alt+Backspace" keystroke - {giveKey{tcell.KeyDEL, rune(tcell.KeyDEL), tcell.ModCtrl}, wantKey{Backspace, 0, nil}}, // actual "Ctrl+Backspace" keystroke + {giveKey{tcell.KeyDEL, rune(tcell.KeyDEL), tcell.ModCtrl}, wantKey{CtrlBackspace, 0, nil}}, // actual "Ctrl+Backspace" keystroke {giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModShift}, wantKey{Backspace, 0, nil}}, // actual "Shift+Backspace" keystroke - {giveKey{tcell.KeyCtrlH, 0, tcell.ModCtrl | tcell.ModAlt}, wantKey{Backspace, 0, nil}}, // actual "Ctrl+Alt+Backspace" keystroke - {giveKey{tcell.KeyCtrlH, 0, tcell.ModCtrl | tcell.ModShift}, wantKey{Backspace, 0, nil}}, // actual "Ctrl+Shift+Backspace" keystroke + {giveKey{tcell.KeyCtrlH, 0, tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAltBackspace, 0, nil}}, // actual "Ctrl+Alt+Backspace" keystroke + {giveKey{tcell.KeyCtrlH, 0, tcell.ModCtrl | tcell.ModShift}, wantKey{CtrlBackspace, 0, nil}}, // actual "Ctrl+Shift+Backspace" keystroke {giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModShift | tcell.ModAlt}, wantKey{AltBackspace, 0, nil}}, // actual "Shift+Alt+Backspace" keystroke - {giveKey{tcell.KeyCtrlH, 0, tcell.ModCtrl | tcell.ModAlt | tcell.ModShift}, wantKey{Backspace, 0, nil}}, // actual "Ctrl+Shift+Alt+Backspace" keystroke + {giveKey{tcell.KeyCtrlH, 0, tcell.ModCtrl | tcell.ModAlt | tcell.ModShift}, wantKey{CtrlAltBackspace, 0, nil}}, // actual "Ctrl+Shift+Alt+Backspace" keystroke {giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModCtrl}, wantKey{CtrlH, 0, nil}}, // actual "Ctrl+H" keystroke {giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAlt, 'h', nil}}, // fabricated "Ctrl+Alt+H" keystroke {giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModCtrl | tcell.ModShift}, wantKey{CtrlH, 0, nil}}, // actual "Ctrl+Shift+H" keystroke @@ -126,9 +128,41 @@ func TestGetCharEventKey(t *testing.T) { // section 4: (Alt+Shift)+Key(Up|Down|Left|Right) {giveKey{tcell.KeyUp, 0, tcell.ModNone}, wantKey{Up, 0, nil}}, - {giveKey{tcell.KeyDown, 0, tcell.ModAlt}, wantKey{AltDown, 0, nil}}, + {giveKey{tcell.KeyDown, 0, tcell.ModNone}, wantKey{Down, 0, nil}}, + {giveKey{tcell.KeyLeft, 0, tcell.ModNone}, wantKey{Left, 0, nil}}, + {giveKey{tcell.KeyRight, 0, tcell.ModNone}, wantKey{Right, 0, nil}}, + {giveKey{tcell.KeyUp, 0, tcell.ModNone}, wantKey{Up, 0, nil}}, + {giveKey{tcell.KeyDown, 0, tcell.ModNone}, wantKey{Down, 0, nil}}, + {giveKey{tcell.KeyRight, 0, tcell.ModNone}, wantKey{Right, 0, nil}}, + {giveKey{tcell.KeyLeft, 0, tcell.ModNone}, wantKey{Left, 0, nil}}, + {giveKey{tcell.KeyUp, 0, tcell.ModCtrl}, wantKey{CtrlUp, 0, nil}}, + {giveKey{tcell.KeyDown, 0, tcell.ModCtrl}, wantKey{CtrlDown, 0, nil}}, + {giveKey{tcell.KeyRight, 0, tcell.ModCtrl}, wantKey{CtrlRight, 0, nil}}, + {giveKey{tcell.KeyLeft, 0, tcell.ModCtrl}, wantKey{CtrlLeft, 0, nil}}, + {giveKey{tcell.KeyUp, 0, tcell.ModShift}, wantKey{ShiftUp, 0, nil}}, + {giveKey{tcell.KeyDown, 0, tcell.ModShift}, wantKey{ShiftDown, 0, nil}}, + {giveKey{tcell.KeyRight, 0, tcell.ModShift}, wantKey{ShiftRight, 0, nil}}, {giveKey{tcell.KeyLeft, 0, tcell.ModShift}, wantKey{ShiftLeft, 0, nil}}, + {giveKey{tcell.KeyUp, 0, tcell.ModAlt}, wantKey{AltUp, 0, nil}}, + {giveKey{tcell.KeyDown, 0, tcell.ModAlt}, wantKey{AltDown, 0, nil}}, + {giveKey{tcell.KeyRight, 0, tcell.ModAlt}, wantKey{AltRight, 0, nil}}, + {giveKey{tcell.KeyLeft, 0, tcell.ModAlt}, wantKey{AltLeft, 0, nil}}, + {giveKey{tcell.KeyUp, 0, tcell.ModCtrl | tcell.ModShift}, wantKey{CtrlShiftUp, 0, nil}}, + {giveKey{tcell.KeyDown, 0, tcell.ModCtrl | tcell.ModShift}, wantKey{CtrlShiftDown, 0, nil}}, + {giveKey{tcell.KeyRight, 0, tcell.ModCtrl | tcell.ModShift}, wantKey{CtrlShiftRight, 0, nil}}, + {giveKey{tcell.KeyLeft, 0, tcell.ModCtrl | tcell.ModShift}, wantKey{CtrlShiftLeft, 0, nil}}, + {giveKey{tcell.KeyUp, 0, tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAltUp, 0, nil}}, + {giveKey{tcell.KeyDown, 0, tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAltDown, 0, nil}}, + {giveKey{tcell.KeyRight, 0, tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAltRight, 0, nil}}, + {giveKey{tcell.KeyLeft, 0, tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAltLeft, 0, nil}}, + {giveKey{tcell.KeyUp, 0, tcell.ModShift | tcell.ModAlt}, wantKey{AltShiftUp, 0, nil}}, + {giveKey{tcell.KeyDown, 0, tcell.ModShift | tcell.ModAlt}, wantKey{AltShiftDown, 0, nil}}, {giveKey{tcell.KeyRight, 0, tcell.ModShift | tcell.ModAlt}, wantKey{AltShiftRight, 0, nil}}, + {giveKey{tcell.KeyLeft, 0, tcell.ModShift | tcell.ModAlt}, wantKey{AltShiftLeft, 0, nil}}, + {giveKey{tcell.KeyUp, 0, tcell.ModCtrl | tcell.ModShift | tcell.ModAlt}, wantKey{CtrlAltShiftUp, 0, nil}}, + {giveKey{tcell.KeyDown, 0, tcell.ModCtrl | tcell.ModShift | tcell.ModAlt}, wantKey{CtrlAltShiftDown, 0, nil}}, + {giveKey{tcell.KeyRight, 0, tcell.ModCtrl | tcell.ModShift | tcell.ModAlt}, wantKey{CtrlAltShiftRight, 0, nil}}, + {giveKey{tcell.KeyLeft, 0, tcell.ModCtrl | tcell.ModShift | tcell.ModAlt}, wantKey{CtrlAltShiftLeft, 0, nil}}, {giveKey{tcell.KeyUpLeft, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled {giveKey{tcell.KeyUpRight, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled {giveKey{tcell.KeyDownLeft, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled @@ -137,6 +171,46 @@ func TestGetCharEventKey(t *testing.T) { // section 5: (Insert|Home|Delete|End|PgUp|PgDn|BackTab|F1-F12) {giveKey{tcell.KeyInsert, 0, tcell.ModNone}, wantKey{Insert, 0, nil}}, {giveKey{tcell.KeyF1, 0, tcell.ModNone}, wantKey{F1, 0, nil}}, + {giveKey{tcell.KeyHome, 0, tcell.ModNone}, wantKey{Home, 0, nil}}, + {giveKey{tcell.KeyEnd, 0, tcell.ModNone}, wantKey{End, 0, nil}}, + {giveKey{tcell.KeyDelete, 0, tcell.ModNone}, wantKey{Delete, 0, nil}}, + {giveKey{tcell.KeyPgUp, 0, tcell.ModNone}, wantKey{PageUp, 0, nil}}, + {giveKey{tcell.KeyPgDn, 0, tcell.ModNone}, wantKey{PageDown, 0, nil}}, + {giveKey{tcell.KeyHome, 0, tcell.ModCtrl}, wantKey{CtrlHome, 0, nil}}, + {giveKey{tcell.KeyEnd, 0, tcell.ModCtrl}, wantKey{CtrlEnd, 0, nil}}, + {giveKey{tcell.KeyDelete, 0, tcell.ModCtrl}, wantKey{CtrlDelete, 0, nil}}, + {giveKey{tcell.KeyPgUp, 0, tcell.ModCtrl}, wantKey{CtrlPageUp, 0, nil}}, + {giveKey{tcell.KeyPgDn, 0, tcell.ModCtrl}, wantKey{CtrlPageDown, 0, nil}}, + {giveKey{tcell.KeyHome, 0, tcell.ModShift}, wantKey{ShiftHome, 0, nil}}, + {giveKey{tcell.KeyEnd, 0, tcell.ModShift}, wantKey{ShiftEnd, 0, nil}}, + {giveKey{tcell.KeyDelete, 0, tcell.ModShift}, wantKey{ShiftDelete, 0, nil}}, + {giveKey{tcell.KeyPgUp, 0, tcell.ModShift}, wantKey{ShiftPageUp, 0, nil}}, + {giveKey{tcell.KeyPgDn, 0, tcell.ModShift}, wantKey{ShiftPageDown, 0, nil}}, + {giveKey{tcell.KeyHome, 0, tcell.ModAlt}, wantKey{AltHome, 0, nil}}, + {giveKey{tcell.KeyEnd, 0, tcell.ModAlt}, wantKey{AltEnd, 0, nil}}, + {giveKey{tcell.KeyDelete, 0, tcell.ModAlt}, wantKey{AltDelete, 0, nil}}, + {giveKey{tcell.KeyPgUp, 0, tcell.ModAlt}, wantKey{AltPageUp, 0, nil}}, + {giveKey{tcell.KeyPgDn, 0, tcell.ModAlt}, wantKey{AltPageDown, 0, nil}}, + {giveKey{tcell.KeyHome, 0, tcell.ModCtrl | tcell.ModShift}, wantKey{CtrlShiftHome, 0, nil}}, + {giveKey{tcell.KeyEnd, 0, tcell.ModCtrl | tcell.ModShift}, wantKey{CtrlShiftEnd, 0, nil}}, + {giveKey{tcell.KeyDelete, 0, tcell.ModCtrl | tcell.ModShift}, wantKey{CtrlShiftDelete, 0, nil}}, + {giveKey{tcell.KeyPgUp, 0, tcell.ModCtrl | tcell.ModShift}, wantKey{CtrlShiftPageUp, 0, nil}}, + {giveKey{tcell.KeyPgDn, 0, tcell.ModCtrl | tcell.ModShift}, wantKey{CtrlShiftPageDown, 0, nil}}, + {giveKey{tcell.KeyHome, 0, tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAltHome, 0, nil}}, + {giveKey{tcell.KeyEnd, 0, tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAltEnd, 0, nil}}, + {giveKey{tcell.KeyDelete, 0, tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAltDelete, 0, nil}}, + {giveKey{tcell.KeyPgUp, 0, tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAltPageUp, 0, nil}}, + {giveKey{tcell.KeyPgDn, 0, tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAltPageDown, 0, nil}}, + {giveKey{tcell.KeyHome, 0, tcell.ModShift | tcell.ModAlt}, wantKey{AltShiftHome, 0, nil}}, + {giveKey{tcell.KeyEnd, 0, tcell.ModShift | tcell.ModAlt}, wantKey{AltShiftEnd, 0, nil}}, + {giveKey{tcell.KeyDelete, 0, tcell.ModShift | tcell.ModAlt}, wantKey{AltShiftDelete, 0, nil}}, + {giveKey{tcell.KeyPgUp, 0, tcell.ModShift | tcell.ModAlt}, wantKey{AltShiftPageUp, 0, nil}}, + {giveKey{tcell.KeyPgDn, 0, tcell.ModShift | tcell.ModAlt}, wantKey{AltShiftPageDown, 0, nil}}, + {giveKey{tcell.KeyHome, 0, tcell.ModCtrl | tcell.ModShift | tcell.ModAlt}, wantKey{CtrlAltShiftHome, 0, nil}}, + {giveKey{tcell.KeyEnd, 0, tcell.ModCtrl | tcell.ModShift | tcell.ModAlt}, wantKey{CtrlAltShiftEnd, 0, nil}}, + {giveKey{tcell.KeyDelete, 0, tcell.ModCtrl | tcell.ModShift | tcell.ModAlt}, wantKey{CtrlAltShiftDelete, 0, nil}}, + {giveKey{tcell.KeyPgUp, 0, tcell.ModCtrl | tcell.ModShift | tcell.ModAlt}, wantKey{CtrlAltShiftPageUp, 0, nil}}, + {giveKey{tcell.KeyPgDn, 0, tcell.ModCtrl | tcell.ModShift | tcell.ModAlt}, wantKey{CtrlAltShiftPageDown, 0, nil}}, // section 6: (Ctrl+Alt)+'rune' {giveKey{tcell.KeyRune, 'a', tcell.ModNone}, wantKey{Rune, 'a', nil}}, {giveKey{tcell.KeyRune, 'a', tcell.ModCtrl}, wantKey{Rune, 'a', nil}}, // fabricated @@ -198,6 +272,10 @@ func TestGetCharEventKey(t *testing.T) { initialResizeAsInvalid = false gotEvent = r.GetChar() } + if gotEvent.Type == Resize { + t.Logf("Resize swallowed") + gotEvent = r.GetChar() + } t.Logf("wantEvent = %T{Type: %v, Char: %q (%[3]v)}\n", test.wantKey, test.wantKey.Type, test.wantKey.Char) t.Logf("gotEvent = %T{Type: %v, Char: %q (%[3]v)}\n", gotEvent, gotEvent.Type, gotEvent.Char) diff --git a/src/tui/tui.go b/src/tui/tui.go index 7617d922..92154533 100644 --- a/src/tui/tui.go +++ b/src/tui/tui.go @@ -44,7 +44,6 @@ const ( CtrlZ Esc CtrlSpace - CtrlDelete // https://apple.stackexchange.com/questions/24261/how-do-i-send-c-that-is-control-slash-to-the-terminal CtrlBackSlash @@ -72,6 +71,10 @@ const ( ShiftLeft ShiftRight ShiftDelete + ShiftHome + ShiftEnd + ShiftPageUp + ShiftPageDown F1 F2 @@ -92,15 +95,67 @@ const ( AltDown AltLeft AltRight + AltDelete + AltHome + AltEnd + AltPageUp + AltPageDown AltShiftUp AltShiftDown AltShiftLeft AltShiftRight + AltShiftDelete + AltShiftHome + AltShiftEnd + AltShiftPageUp + AltShiftPageDown + + CtrlUp + CtrlDown + CtrlLeft + CtrlRight + CtrlHome + CtrlEnd + CtrlBackspace + CtrlDelete + CtrlPageUp + CtrlPageDown Alt CtrlAlt + CtrlAltUp + CtrlAltDown + CtrlAltLeft + CtrlAltRight + CtrlAltHome + CtrlAltEnd + CtrlAltBackspace + CtrlAltDelete + CtrlAltPageUp + CtrlAltPageDown + + CtrlShiftUp + CtrlShiftDown + CtrlShiftLeft + CtrlShiftRight + CtrlShiftHome + CtrlShiftEnd + CtrlShiftDelete + CtrlShiftPageUp + CtrlShiftPageDown + + CtrlAltShiftUp + CtrlAltShiftDown + CtrlAltShiftLeft + CtrlAltShiftRight + CtrlAltShiftHome + CtrlAltShiftEnd + CtrlAltShiftDelete + CtrlAltShiftPageUp + CtrlAltShiftPageDown + Invalid Fatal BracketedPasteBegin