diff --git a/prompt_toolkit/input/ansi_escape_sequences.py b/prompt_toolkit/input/ansi_escape_sequences.py index 2324de45b..f31541851 100644 --- a/prompt_toolkit/input/ansi_escape_sequences.py +++ b/prompt_toolkit/input/ansi_escape_sequences.py @@ -1,6 +1,14 @@ """ Mappings from VT100 (ANSI) escape sequences to the corresponding prompt_toolkit keys. + +We are not using the terminfo/termcap databases to detect the ANSI escape +sequences for the input. Instead, we recognize 99% of the most common +sequences. This works well, because in practice, every modern terminal is +mostly Xterm compatible. + +Some useful docs: +- Mintty: https://github.com/mintty/mintty/blob/master/wiki/Keycodes.md """ from typing import Dict, Tuple, Union @@ -11,9 +19,9 @@ "REVERSE_ANSI_SEQUENCES", ] - # Mapping of vt100 escape codes to Keys. ANSI_SEQUENCES: Dict[str, Union[Keys, Tuple[Keys, ...]]] = { + # Control keys. "\x00": Keys.ControlAt, # Control-At (Also for Ctrl-Space) "\x01": Keys.ControlA, # Control-A (home) "\x02": Keys.ControlB, # Control-B (emacs cursor left) @@ -55,25 +63,19 @@ # support it. (Most terminals send ControlH when backspace is pressed.) # See: http://www.ibb.net/~anne/keyboard.html "\x7f": Keys.ControlH, - "\x1b[A": Keys.Up, - "\x1b[B": Keys.Down, - "\x1b[C": Keys.Right, - "\x1b[D": Keys.Left, - "\x1b[H": Keys.Home, - "\x1bOH": Keys.Home, - "\x1b[F": Keys.End, - "\x1bOF": Keys.End, - "\x1b[3~": Keys.Delete, - "\x1b[3;2~": Keys.ShiftDelete, # xterm, gnome-terminal. - "\x1b[3;5~": Keys.ControlDelete, # xterm, gnome-terminal. + # -- + # Various "\x1b[1~": Keys.Home, # tmux + "\x1b[2~": Keys.Insert, + "\x1b[3~": Keys.Delete, "\x1b[4~": Keys.End, # tmux "\x1b[5~": Keys.PageUp, "\x1b[6~": Keys.PageDown, "\x1b[7~": Keys.Home, # xrvt "\x1b[8~": Keys.End, # xrvt "\x1b[Z": Keys.BackTab, # shift + tab - "\x1b[2~": Keys.Insert, + # -- + # Function keys. "\x1bOP": Keys.F1, "\x1bOQ": Keys.F2, "\x1bOR": Keys.F3, @@ -116,18 +118,75 @@ "\x1b[21;2~": Keys.F22, "\x1b[23;2~": Keys.F23, "\x1b[24;2~": Keys.F24, - "\x1b[1;5A": Keys.ControlUp, # Cursor Mode - "\x1b[1;5B": Keys.ControlDown, # Cursor Mode - "\x1b[1;5C": Keys.ControlRight, # Cursor Mode - "\x1b[1;5D": Keys.ControlLeft, # Cursor Mode - "\x1b[1;5H": Keys.ControlHome, - "\x1b[1;5F": Keys.ControlEnd, - "\x1b[1;2A": Keys.ShiftUp, - "\x1b[1;2B": Keys.ShiftDown, - "\x1b[1;2C": Keys.ShiftRight, - "\x1b[1;2D": Keys.ShiftLeft, - "\x1b[1;2H": Keys.ShiftHome, - "\x1b[1;2F": Keys.ShiftEnd, + # -- + # Control + function keys. + "\x1b[1;5P": Keys.ControlF1, + "\x1b[1;5Q": Keys.ControlF2, + # "\x1b[1;5R": Keys.ControlF3, # Conflicts with CPR response. + "\x1b[1;5S": Keys.ControlF4, + "\x1b[15;5~": Keys.ControlF5, + "\x1b[17;5~": Keys.ControlF6, + "\x1b[18;5~": Keys.ControlF7, + "\x1b[19;5~": Keys.ControlF8, + "\x1b[20;5~": Keys.ControlF9, + "\x1b[21;5~": Keys.ControlF10, + "\x1b[23;5~": Keys.ControlF11, + "\x1b[24;5~": Keys.ControlF12, + "\x1b[1;6P": Keys.ControlF13, + "\x1b[1;6Q": Keys.ControlF14, + # "\x1b[1;6R": Keys.ControlF15, # Conflicts with CPR response. + "\x1b[1;6S": Keys.ControlF16, + "\x1b[15;6~": Keys.ControlF17, + "\x1b[17;6~": Keys.ControlF18, + "\x1b[18;6~": Keys.ControlF19, + "\x1b[19;6~": Keys.ControlF20, + "\x1b[20;6~": Keys.ControlF21, + "\x1b[21;6~": Keys.ControlF22, + "\x1b[23;6~": Keys.ControlF23, + "\x1b[24;6~": Keys.ControlF24, + # -- + # Tmux (Win32 subsystem) sends the following scroll events. + "\x1b[62~": Keys.ScrollUp, + "\x1b[63~": Keys.ScrollDown, + "\x1b[200~": Keys.BracketedPaste, # Start of bracketed paste. + # -- + # Sequences generated by numpad 5. Not sure what it means. (It doesn't + # appear in 'infocmp'. Just ignore. + "\x1b[E": Keys.Ignore, # Xterm. + "\x1b[G": Keys.Ignore, # Linux console. + # -- + # Meta/control/escape + pageup/pagedown/insert/delete. + "\x1b[3;2~": Keys.ShiftDelete, # xterm, gnome-terminal. + "\x1b[5;2~": Keys.ShiftPageUp, + "\x1b[6;2~": Keys.ShiftPageDown, + "\x1b[2;3~": (Keys.Escape, Keys.Insert), + "\x1b[3;3~": (Keys.Escape, Keys.Delete), + "\x1b[5;3~": (Keys.Escape, Keys.PageUp), + "\x1b[6;3~": (Keys.Escape, Keys.PageDown), + "\x1b[2;4~": (Keys.Escape, Keys.ShiftInsert), + "\x1b[3;4~": (Keys.Escape, Keys.ShiftDelete), + "\x1b[5;4~": (Keys.Escape, Keys.ShiftPageUp), + "\x1b[6;4~": (Keys.Escape, Keys.ShiftPageDown), + "\x1b[3;5~": Keys.ControlDelete, # xterm, gnome-terminal. + "\x1b[5;5~": Keys.ControlPageUp, + "\x1b[6;5~": Keys.ControlPageDown, + "\x1b[3;6~": Keys.ShiftControlDelete, + "\x1b[5;6~": Keys.ShiftControlPageUp, + "\x1b[6;6~": Keys.ShiftControlPageDown, + "\x1b[2;7~": (Keys.Escape, Keys.ControlInsert), + "\x1b[5;7~": (Keys.Escape, Keys.ControlPageDown), + "\x1b[6;7~": (Keys.Escape, Keys.ControlPageDown), + "\x1b[2;8~": (Keys.Escape, Keys.ShiftControlInsert), + "\x1b[5;8~": (Keys.Escape, Keys.ShiftControlPageDown), + "\x1b[6;8~": (Keys.Escape, Keys.ShiftControlPageDown), + # -- + # Arrows. + "\x1b[A": Keys.Up, + "\x1b[B": Keys.Down, + "\x1b[C": Keys.Right, + "\x1b[D": Keys.Left, + "\x1b[H": Keys.Home, + "\x1b[F": Keys.End, # Tmux sends following keystrokes when control+arrow is pressed, but for # Emacs ansi-term sends the same sequences for normal arrow keys. Consider # it a normal arrow press, because that's more important. @@ -135,16 +194,15 @@ "\x1bOB": Keys.Down, "\x1bOC": Keys.Right, "\x1bOD": Keys.Left, - "\x1b[5A": Keys.ControlUp, - "\x1b[5B": Keys.ControlDown, - "\x1b[5C": Keys.ControlRight, - "\x1b[5D": Keys.ControlLeft, - "\x1bOc": Keys.ControlRight, # rxvt - "\x1bOd": Keys.ControlLeft, # rxvt - # Tmux (Win32 subsystem) sends the following scroll events. - "\x1b[62~": Keys.ScrollUp, - "\x1b[63~": Keys.ScrollDown, - "\x1b[200~": Keys.BracketedPaste, # Start of bracketed paste. + "\x1bOF": Keys.End, + "\x1bOH": Keys.Home, + # Shift + arrows. + "\x1b[1;2A": Keys.ShiftUp, + "\x1b[1;2B": Keys.ShiftDown, + "\x1b[1;2C": Keys.ShiftRight, + "\x1b[1;2D": Keys.ShiftLeft, + "\x1b[1;2F": Keys.ShiftEnd, + "\x1b[1;2H": Keys.ShiftHome, # Meta + arrow keys. Several terminals handle this differently. # The following sequences are for xterm and gnome-terminal. # (Iterm sends ESC followed by the normal arrow_up/down/left/right @@ -154,34 +212,104 @@ # pressing ESC (to go to Vi navigation mode), followed by just the # 'b' or 'f' key. These combinations are handled in # the input processor.) - "\x1b[1;3D": (Keys.Escape, Keys.Left), - "\x1b[1;3C": (Keys.Escape, Keys.Right), "\x1b[1;3A": (Keys.Escape, Keys.Up), "\x1b[1;3B": (Keys.Escape, Keys.Down), - # Option+arrow on (some?) Macs when using iTerm defaults - # (see issue #483) + "\x1b[1;3C": (Keys.Escape, Keys.Right), + "\x1b[1;3D": (Keys.Escape, Keys.Left), + "\x1b[1;3F": (Keys.Escape, Keys.End), + "\x1b[1;3H": (Keys.Escape, Keys.Home), + # Alt+shift+number. + "\x1b[1;4A": (Keys.Escape, Keys.ShiftDown), + "\x1b[1;4B": (Keys.Escape, Keys.ShiftUp), + "\x1b[1;4C": (Keys.Escape, Keys.ShiftRight), + "\x1b[1;4D": (Keys.Escape, Keys.ShiftLeft), + "\x1b[1;4F": (Keys.Escape, Keys.ShiftEnd), + "\x1b[1;4H": (Keys.Escape, Keys.ShiftHome), + # Control + arrows. + "\x1b[1;5A": Keys.ControlUp, # Cursor Mode + "\x1b[1;5B": Keys.ControlDown, # Cursor Mode + "\x1b[1;5C": Keys.ControlRight, # Cursor Mode + "\x1b[1;5D": Keys.ControlLeft, # Cursor Mode + "\x1b[1;5F": Keys.ControlEnd, + "\x1b[1;5H": Keys.ControlHome, + # Tmux sends following keystrokes when control+arrow is pressed, but for + # Emacs ansi-term sends the same sequences for normal arrow keys. Consider + # it a normal arrow press, because that's more important. + "\x1b[5A": Keys.ControlUp, + "\x1b[5B": Keys.ControlDown, + "\x1b[5C": Keys.ControlRight, + "\x1b[5D": Keys.ControlLeft, + "\x1bOc": Keys.ControlRight, # rxvt + "\x1bOd": Keys.ControlLeft, # rxvt + # Control + shift + arrows. + "\x1b[1;6A": Keys.ShiftControlDown, + "\x1b[1;6B": Keys.ShiftControlUp, + "\x1b[1;6C": Keys.ShiftControlRight, + "\x1b[1;6D": Keys.ShiftControlLeft, + "\x1b[1;6F": Keys.ShiftControlEnd, + "\x1b[1;6H": Keys.ShiftControlHome, + # Control + Meta + arrows. + "\x1b[1;7A": (Keys.Escape, Keys.ControlDown), + "\x1b[1;7B": (Keys.Escape, Keys.ControlUp), + "\x1b[1;7C": (Keys.Escape, Keys.ControlRight), + "\x1b[1;7D": (Keys.Escape, Keys.ControlLeft), + "\x1b[1;7F": (Keys.Escape, Keys.ControlEnd), + "\x1b[1;7H": (Keys.Escape, Keys.ControlHome), + # Meta + Shift + arrows. + "\x1b[1;8A": (Keys.Escape, Keys.ShiftControlDown), + "\x1b[1;8B": (Keys.Escape, Keys.ShiftControlUp), + "\x1b[1;8C": (Keys.Escape, Keys.ShiftControlRight), + "\x1b[1;8D": (Keys.Escape, Keys.ShiftControlLeft), + "\x1b[1;8F": (Keys.Escape, Keys.ShiftControlEnd), + "\x1b[1;8H": (Keys.Escape, Keys.ShiftControlHome), + # Meta + arrow on (some?) Macs when using iTerm defaults (see issue #483). "\x1b[1;9A": (Keys.Escape, Keys.Up), "\x1b[1;9B": (Keys.Escape, Keys.Down), "\x1b[1;9C": (Keys.Escape, Keys.Right), "\x1b[1;9D": (Keys.Escape, Keys.Left), - # Sequences generated by numpad 5. Not sure what it means. (It doesn't - # appear in 'infocmp'. Just ignore. - "\x1b[E": Keys.Ignore, # Xterm. - "\x1b[G": Keys.Ignore, # Linux console. - # Alt + home/end/page-up/page-down/insert. - "\x1b[1;3H": (Keys.Escape, Keys.Home), - "\x1b[1;3F": (Keys.Escape, Keys.End), - "\x1b[5;3~": (Keys.Escape, Keys.PageUp), - "\x1b[6;3~": (Keys.Escape, Keys.PageDown), - "\x1b[2;3~": (Keys.Escape, Keys.Insert), - "\x1b[3;3~": (Keys.Escape, Keys.Delete), - # Control+Shift in mintty/wsltty - "\x1b[1;6D": Keys.ShiftControlLeft, - "\x1b[1;6C": Keys.ShiftControlRight, - "\x1b[1;6B": Keys.ShiftControlUp, - "\x1b[1;6A": Keys.ShiftControlDown, - "\x1b[1;6H": Keys.ShiftControlHome, - "\x1b[1;6F": Keys.ShiftControlEnd, + # -- + # Control/shift/meta + number in mintty. + # (c-2 will actually send c-@ and c-6 will send c-^.) + "\x1b[1;5p": Keys.Control0, + "\x1b[1;5q": Keys.Control1, + "\x1b[1;5r": Keys.Control2, + "\x1b[1;5s": Keys.Control3, + "\x1b[1;5t": Keys.Control4, + "\x1b[1;5u": Keys.Control5, + "\x1b[1;5v": Keys.Control6, + "\x1b[1;5w": Keys.Control7, + "\x1b[1;5x": Keys.Control8, + "\x1b[1;5y": Keys.Control9, + "\x1b[1;6p": Keys.ShiftControl0, + "\x1b[1;6q": Keys.ShiftControl1, + "\x1b[1;6r": Keys.ShiftControl2, + "\x1b[1;6s": Keys.ShiftControl3, + "\x1b[1;6t": Keys.ShiftControl4, + "\x1b[1;6u": Keys.ShiftControl5, + "\x1b[1;6v": Keys.ShiftControl6, + "\x1b[1;6w": Keys.ShiftControl7, + "\x1b[1;6x": Keys.ShiftControl8, + "\x1b[1;6y": Keys.ShiftControl9, + "\x1b[1;7p": (Keys.Escape, Keys.Control0), + "\x1b[1;7q": (Keys.Escape, Keys.Control1), + "\x1b[1;7r": (Keys.Escape, Keys.Control2), + "\x1b[1;7s": (Keys.Escape, Keys.Control3), + "\x1b[1;7t": (Keys.Escape, Keys.Control4), + "\x1b[1;7u": (Keys.Escape, Keys.Control5), + "\x1b[1;7v": (Keys.Escape, Keys.Control6), + "\x1b[1;7w": (Keys.Escape, Keys.Control7), + "\x1b[1;7x": (Keys.Escape, Keys.Control8), + "\x1b[1;7y": (Keys.Escape, Keys.Control9), + "\x1b[1;8p": (Keys.Escape, Keys.ShiftControl0), + "\x1b[1;8q": (Keys.Escape, Keys.ShiftControl1), + "\x1b[1;8r": (Keys.Escape, Keys.ShiftControl2), + "\x1b[1;8s": (Keys.Escape, Keys.ShiftControl3), + "\x1b[1;8t": (Keys.Escape, Keys.ShiftControl4), + "\x1b[1;8u": (Keys.Escape, Keys.ShiftControl5), + "\x1b[1;8v": (Keys.Escape, Keys.ShiftControl6), + "\x1b[1;8w": (Keys.Escape, Keys.ShiftControl7), + "\x1b[1;8x": (Keys.Escape, Keys.ShiftControl8), + "\x1b[1;8y": (Keys.Escape, Keys.ShiftControl9), } diff --git a/prompt_toolkit/keys.py b/prompt_toolkit/keys.py index d72d30b75..254d0633a 100644 --- a/prompt_toolkit/keys.py +++ b/prompt_toolkit/keys.py @@ -49,11 +49,44 @@ class Keys(str, Enum): ControlY = "c-y" ControlZ = "c-z" + Control1 = "c-1" + Control2 = "c-2" + Control3 = "c-3" + Control4 = "c-4" + Control5 = "c-5" + Control6 = "c-6" + Control7 = "c-7" + Control8 = "c-8" + Control9 = "c-9" + Control0 = "c-0" + + ShiftControl1 = "s-c-1" + ShiftControl2 = "s-c-2" + ShiftControl3 = "s-c-3" + ShiftControl4 = "s-c-4" + ShiftControl5 = "s-c-5" + ShiftControl6 = "s-c-6" + ShiftControl7 = "s-c-7" + ShiftControl8 = "s-c-8" + ShiftControl9 = "s-c-9" + ShiftControl0 = "s-c-0" + ControlBackslash = "c-\\" ControlSquareClose = "c-]" ControlCircumflex = "c-^" ControlUnderscore = "c-_" + Left = "left" + Right = "right" + Up = "up" + Down = "down" + Home = "home" + End = "end" + Insert = "insert" + Delete = "delete" + PageUp = "pageup" + PageDown = "pagedown" + ControlLeft = "c-left" ControlRight = "c-right" ControlUp = "c-up" @@ -61,6 +94,20 @@ class Keys(str, Enum): ControlHome = "c-home" ControlEnd = "c-end" ControlInsert = "c-insert" + ControlDelete = "c-delete" + ControlPageUp = "c-pageup" + ControlPageDown = "c-pagedown" + + ShiftLeft = "s-left" + ShiftRight = "s-right" + ShiftUp = "s-up" + ShiftDown = "s-down" + ShiftHome = "s-home" + ShiftEnd = "s-end" + ShiftInsert = "s-insert" + ShiftDelete = "s-delete" + ShiftPageUp = "s-pageup" + ShiftPageDown = "s-pagedown" ShiftControlLeft = "s-c-left" ShiftControlRight = "s-c-right" @@ -68,29 +115,12 @@ class Keys(str, Enum): ShiftControlDown = "s-c-down" ShiftControlHome = "s-c-home" ShiftControlEnd = "s-c-end" + ShiftControlInsert = "s-c-insert" + ShiftControlDelete = "s-c-delete" + ShiftControlPageUp = "s-c-pageup" + ShiftControlPageDown = "s-c-pagedown" - Up = "up" - Down = "down" - Right = "right" - Left = "left" - - ShiftLeft = "s-left" - ShiftUp = "s-up" - ShiftDown = "s-down" - ShiftRight = "s-right" - ShiftDelete = "s-delete" BackTab = "s-tab" # shift + tab - ShiftHome = "s-home" - ShiftEnd = "s-end" - ShiftInsert = "s-insert" - - Home = "home" - End = "end" - Delete = "delete" - ControlDelete = "c-delete" - PageUp = "pageup" - PageDown = "pagedown" - Insert = "insert" F1 = "f1" F2 = "f2" @@ -117,6 +147,31 @@ class Keys(str, Enum): F23 = "f23" F24 = "f24" + ControlF1 = "c-f1" + ControlF2 = "c-f2" + ControlF3 = "c-f3" + ControlF4 = "c-f4" + ControlF5 = "c-f5" + ControlF6 = "c-f6" + ControlF7 = "c-f7" + ControlF8 = "c-f8" + ControlF9 = "c-f9" + ControlF10 = "c-f10" + ControlF11 = "c-f11" + ControlF12 = "c-f12" + ControlF13 = "c-f13" + ControlF14 = "c-f14" + ControlF15 = "c-f15" + ControlF16 = "c-f16" + ControlF17 = "c-f17" + ControlF18 = "c-f18" + ControlF19 = "c-f19" + ControlF20 = "c-f20" + ControlF21 = "c-f21" + ControlF22 = "c-f22" + ControlF23 = "c-f23" + ControlF24 = "c-f24" + # Matches any key. Any = ""