ansi_escape_sequences.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. """
  2. Mappings from VT100 (ANSI) escape sequences to the corresponding prompt_toolkit
  3. keys.
  4. We are not using the terminfo/termcap databases to detect the ANSI escape
  5. sequences for the input. Instead, we recognize 99% of the most common
  6. sequences. This works well, because in practice, every modern terminal is
  7. mostly Xterm compatible.
  8. Some useful docs:
  9. - Mintty: https://github.com/mintty/mintty/blob/master/wiki/Keycodes.md
  10. """
  11. from __future__ import annotations
  12. from ..keys import Keys
  13. __all__ = [
  14. "ANSI_SEQUENCES",
  15. "REVERSE_ANSI_SEQUENCES",
  16. ]
  17. # Mapping of vt100 escape codes to Keys.
  18. ANSI_SEQUENCES: dict[str, Keys | tuple[Keys, ...]] = {
  19. # Control keys.
  20. "\x00": Keys.ControlAt, # Control-At (Also for Ctrl-Space)
  21. "\x01": Keys.ControlA, # Control-A (home)
  22. "\x02": Keys.ControlB, # Control-B (emacs cursor left)
  23. "\x03": Keys.ControlC, # Control-C (interrupt)
  24. "\x04": Keys.ControlD, # Control-D (exit)
  25. "\x05": Keys.ControlE, # Control-E (end)
  26. "\x06": Keys.ControlF, # Control-F (cursor forward)
  27. "\x07": Keys.ControlG, # Control-G
  28. "\x08": Keys.ControlH, # Control-H (8) (Identical to '\b')
  29. "\x09": Keys.ControlI, # Control-I (9) (Identical to '\t')
  30. "\x0a": Keys.ControlJ, # Control-J (10) (Identical to '\n')
  31. "\x0b": Keys.ControlK, # Control-K (delete until end of line; vertical tab)
  32. "\x0c": Keys.ControlL, # Control-L (clear; form feed)
  33. "\x0d": Keys.ControlM, # Control-M (13) (Identical to '\r')
  34. "\x0e": Keys.ControlN, # Control-N (14) (history forward)
  35. "\x0f": Keys.ControlO, # Control-O (15)
  36. "\x10": Keys.ControlP, # Control-P (16) (history back)
  37. "\x11": Keys.ControlQ, # Control-Q
  38. "\x12": Keys.ControlR, # Control-R (18) (reverse search)
  39. "\x13": Keys.ControlS, # Control-S (19) (forward search)
  40. "\x14": Keys.ControlT, # Control-T
  41. "\x15": Keys.ControlU, # Control-U
  42. "\x16": Keys.ControlV, # Control-V
  43. "\x17": Keys.ControlW, # Control-W
  44. "\x18": Keys.ControlX, # Control-X
  45. "\x19": Keys.ControlY, # Control-Y (25)
  46. "\x1a": Keys.ControlZ, # Control-Z
  47. "\x1b": Keys.Escape, # Also Control-[
  48. "\x9b": Keys.ShiftEscape,
  49. "\x1c": Keys.ControlBackslash, # Both Control-\ (also Ctrl-| )
  50. "\x1d": Keys.ControlSquareClose, # Control-]
  51. "\x1e": Keys.ControlCircumflex, # Control-^
  52. "\x1f": Keys.ControlUnderscore, # Control-underscore (Also for Ctrl-hyphen.)
  53. # ASCII Delete (0x7f)
  54. # Vt220 (and Linux terminal) send this when pressing backspace. We map this
  55. # to ControlH, because that will make it easier to create key bindings that
  56. # work everywhere, with the trade-off that it's no longer possible to
  57. # handle backspace and control-h individually for the few terminals that
  58. # support it. (Most terminals send ControlH when backspace is pressed.)
  59. # See: http://www.ibb.net/~anne/keyboard.html
  60. "\x7f": Keys.ControlH,
  61. # --
  62. # Various
  63. "\x1b[1~": Keys.Home, # tmux
  64. "\x1b[2~": Keys.Insert,
  65. "\x1b[3~": Keys.Delete,
  66. "\x1b[4~": Keys.End, # tmux
  67. "\x1b[5~": Keys.PageUp,
  68. "\x1b[6~": Keys.PageDown,
  69. "\x1b[7~": Keys.Home, # xrvt
  70. "\x1b[8~": Keys.End, # xrvt
  71. "\x1b[Z": Keys.BackTab, # shift + tab
  72. "\x1b\x09": Keys.BackTab, # Linux console
  73. "\x1b[~": Keys.BackTab, # Windows console
  74. # --
  75. # Function keys.
  76. "\x1bOP": Keys.F1,
  77. "\x1bOQ": Keys.F2,
  78. "\x1bOR": Keys.F3,
  79. "\x1bOS": Keys.F4,
  80. "\x1b[[A": Keys.F1, # Linux console.
  81. "\x1b[[B": Keys.F2, # Linux console.
  82. "\x1b[[C": Keys.F3, # Linux console.
  83. "\x1b[[D": Keys.F4, # Linux console.
  84. "\x1b[[E": Keys.F5, # Linux console.
  85. "\x1b[11~": Keys.F1, # rxvt-unicode
  86. "\x1b[12~": Keys.F2, # rxvt-unicode
  87. "\x1b[13~": Keys.F3, # rxvt-unicode
  88. "\x1b[14~": Keys.F4, # rxvt-unicode
  89. "\x1b[15~": Keys.F5,
  90. "\x1b[17~": Keys.F6,
  91. "\x1b[18~": Keys.F7,
  92. "\x1b[19~": Keys.F8,
  93. "\x1b[20~": Keys.F9,
  94. "\x1b[21~": Keys.F10,
  95. "\x1b[23~": Keys.F11,
  96. "\x1b[24~": Keys.F12,
  97. "\x1b[25~": Keys.F13,
  98. "\x1b[26~": Keys.F14,
  99. "\x1b[28~": Keys.F15,
  100. "\x1b[29~": Keys.F16,
  101. "\x1b[31~": Keys.F17,
  102. "\x1b[32~": Keys.F18,
  103. "\x1b[33~": Keys.F19,
  104. "\x1b[34~": Keys.F20,
  105. # Xterm
  106. "\x1b[1;2P": Keys.F13,
  107. "\x1b[1;2Q": Keys.F14,
  108. # '\x1b[1;2R': Keys.F15, # Conflicts with CPR response.
  109. "\x1b[1;2S": Keys.F16,
  110. "\x1b[15;2~": Keys.F17,
  111. "\x1b[17;2~": Keys.F18,
  112. "\x1b[18;2~": Keys.F19,
  113. "\x1b[19;2~": Keys.F20,
  114. "\x1b[20;2~": Keys.F21,
  115. "\x1b[21;2~": Keys.F22,
  116. "\x1b[23;2~": Keys.F23,
  117. "\x1b[24;2~": Keys.F24,
  118. # --
  119. # CSI 27 disambiguated modified "other" keys (xterm)
  120. # Ref: https://invisible-island.net/xterm/modified-keys.html
  121. # These are currently unsupported, so just re-map some common ones to the
  122. # unmodified versions
  123. "\x1b[27;2;13~": Keys.ControlM, # Shift + Enter
  124. "\x1b[27;5;13~": Keys.ControlM, # Ctrl + Enter
  125. "\x1b[27;6;13~": Keys.ControlM, # Ctrl + Shift + Enter
  126. # --
  127. # Control + function keys.
  128. "\x1b[1;5P": Keys.ControlF1,
  129. "\x1b[1;5Q": Keys.ControlF2,
  130. # "\x1b[1;5R": Keys.ControlF3, # Conflicts with CPR response.
  131. "\x1b[1;5S": Keys.ControlF4,
  132. "\x1b[15;5~": Keys.ControlF5,
  133. "\x1b[17;5~": Keys.ControlF6,
  134. "\x1b[18;5~": Keys.ControlF7,
  135. "\x1b[19;5~": Keys.ControlF8,
  136. "\x1b[20;5~": Keys.ControlF9,
  137. "\x1b[21;5~": Keys.ControlF10,
  138. "\x1b[23;5~": Keys.ControlF11,
  139. "\x1b[24;5~": Keys.ControlF12,
  140. "\x1b[1;6P": Keys.ControlF13,
  141. "\x1b[1;6Q": Keys.ControlF14,
  142. # "\x1b[1;6R": Keys.ControlF15, # Conflicts with CPR response.
  143. "\x1b[1;6S": Keys.ControlF16,
  144. "\x1b[15;6~": Keys.ControlF17,
  145. "\x1b[17;6~": Keys.ControlF18,
  146. "\x1b[18;6~": Keys.ControlF19,
  147. "\x1b[19;6~": Keys.ControlF20,
  148. "\x1b[20;6~": Keys.ControlF21,
  149. "\x1b[21;6~": Keys.ControlF22,
  150. "\x1b[23;6~": Keys.ControlF23,
  151. "\x1b[24;6~": Keys.ControlF24,
  152. # --
  153. # Tmux (Win32 subsystem) sends the following scroll events.
  154. "\x1b[62~": Keys.ScrollUp,
  155. "\x1b[63~": Keys.ScrollDown,
  156. "\x1b[200~": Keys.BracketedPaste, # Start of bracketed paste.
  157. # --
  158. # Sequences generated by numpad 5. Not sure what it means. (It doesn't
  159. # appear in 'infocmp'. Just ignore.
  160. "\x1b[E": Keys.Ignore, # Xterm.
  161. "\x1b[G": Keys.Ignore, # Linux console.
  162. # --
  163. # Meta/control/escape + pageup/pagedown/insert/delete.
  164. "\x1b[3;2~": Keys.ShiftDelete, # xterm, gnome-terminal.
  165. "\x1b[5;2~": Keys.ShiftPageUp,
  166. "\x1b[6;2~": Keys.ShiftPageDown,
  167. "\x1b[2;3~": (Keys.Escape, Keys.Insert),
  168. "\x1b[3;3~": (Keys.Escape, Keys.Delete),
  169. "\x1b[5;3~": (Keys.Escape, Keys.PageUp),
  170. "\x1b[6;3~": (Keys.Escape, Keys.PageDown),
  171. "\x1b[2;4~": (Keys.Escape, Keys.ShiftInsert),
  172. "\x1b[3;4~": (Keys.Escape, Keys.ShiftDelete),
  173. "\x1b[5;4~": (Keys.Escape, Keys.ShiftPageUp),
  174. "\x1b[6;4~": (Keys.Escape, Keys.ShiftPageDown),
  175. "\x1b[3;5~": Keys.ControlDelete, # xterm, gnome-terminal.
  176. "\x1b[5;5~": Keys.ControlPageUp,
  177. "\x1b[6;5~": Keys.ControlPageDown,
  178. "\x1b[3;6~": Keys.ControlShiftDelete,
  179. "\x1b[5;6~": Keys.ControlShiftPageUp,
  180. "\x1b[6;6~": Keys.ControlShiftPageDown,
  181. "\x1b[2;7~": (Keys.Escape, Keys.ControlInsert),
  182. "\x1b[5;7~": (Keys.Escape, Keys.ControlPageDown),
  183. "\x1b[6;7~": (Keys.Escape, Keys.ControlPageDown),
  184. "\x1b[2;8~": (Keys.Escape, Keys.ControlShiftInsert),
  185. "\x1b[5;8~": (Keys.Escape, Keys.ControlShiftPageDown),
  186. "\x1b[6;8~": (Keys.Escape, Keys.ControlShiftPageDown),
  187. # --
  188. # Arrows.
  189. # (Normal cursor mode).
  190. "\x1b[A": Keys.Up,
  191. "\x1b[B": Keys.Down,
  192. "\x1b[C": Keys.Right,
  193. "\x1b[D": Keys.Left,
  194. "\x1b[H": Keys.Home,
  195. "\x1b[F": Keys.End,
  196. # Tmux sends following keystrokes when control+arrow is pressed, but for
  197. # Emacs ansi-term sends the same sequences for normal arrow keys. Consider
  198. # it a normal arrow press, because that's more important.
  199. # (Application cursor mode).
  200. "\x1bOA": Keys.Up,
  201. "\x1bOB": Keys.Down,
  202. "\x1bOC": Keys.Right,
  203. "\x1bOD": Keys.Left,
  204. "\x1bOF": Keys.End,
  205. "\x1bOH": Keys.Home,
  206. # Shift + arrows.
  207. "\x1b[1;2A": Keys.ShiftUp,
  208. "\x1b[1;2B": Keys.ShiftDown,
  209. "\x1b[1;2C": Keys.ShiftRight,
  210. "\x1b[1;2D": Keys.ShiftLeft,
  211. "\x1b[1;2F": Keys.ShiftEnd,
  212. "\x1b[1;2H": Keys.ShiftHome,
  213. # Meta + arrow keys. Several terminals handle this differently.
  214. # The following sequences are for xterm and gnome-terminal.
  215. # (Iterm sends ESC followed by the normal arrow_up/down/left/right
  216. # sequences, and the OSX Terminal sends ESCb and ESCf for "alt
  217. # arrow_left" and "alt arrow_right." We don't handle these
  218. # explicitly, in here, because would could not distinguish between
  219. # pressing ESC (to go to Vi navigation mode), followed by just the
  220. # 'b' or 'f' key. These combinations are handled in
  221. # the input processor.)
  222. "\x1b[1;3A": (Keys.Escape, Keys.Up),
  223. "\x1b[1;3B": (Keys.Escape, Keys.Down),
  224. "\x1b[1;3C": (Keys.Escape, Keys.Right),
  225. "\x1b[1;3D": (Keys.Escape, Keys.Left),
  226. "\x1b[1;3F": (Keys.Escape, Keys.End),
  227. "\x1b[1;3H": (Keys.Escape, Keys.Home),
  228. # Alt+shift+number.
  229. "\x1b[1;4A": (Keys.Escape, Keys.ShiftDown),
  230. "\x1b[1;4B": (Keys.Escape, Keys.ShiftUp),
  231. "\x1b[1;4C": (Keys.Escape, Keys.ShiftRight),
  232. "\x1b[1;4D": (Keys.Escape, Keys.ShiftLeft),
  233. "\x1b[1;4F": (Keys.Escape, Keys.ShiftEnd),
  234. "\x1b[1;4H": (Keys.Escape, Keys.ShiftHome),
  235. # Control + arrows.
  236. "\x1b[1;5A": Keys.ControlUp, # Cursor Mode
  237. "\x1b[1;5B": Keys.ControlDown, # Cursor Mode
  238. "\x1b[1;5C": Keys.ControlRight, # Cursor Mode
  239. "\x1b[1;5D": Keys.ControlLeft, # Cursor Mode
  240. "\x1b[1;5F": Keys.ControlEnd,
  241. "\x1b[1;5H": Keys.ControlHome,
  242. # Tmux sends following keystrokes when control+arrow is pressed, but for
  243. # Emacs ansi-term sends the same sequences for normal arrow keys. Consider
  244. # it a normal arrow press, because that's more important.
  245. "\x1b[5A": Keys.ControlUp,
  246. "\x1b[5B": Keys.ControlDown,
  247. "\x1b[5C": Keys.ControlRight,
  248. "\x1b[5D": Keys.ControlLeft,
  249. "\x1bOc": Keys.ControlRight, # rxvt
  250. "\x1bOd": Keys.ControlLeft, # rxvt
  251. # Control + shift + arrows.
  252. "\x1b[1;6A": Keys.ControlShiftDown,
  253. "\x1b[1;6B": Keys.ControlShiftUp,
  254. "\x1b[1;6C": Keys.ControlShiftRight,
  255. "\x1b[1;6D": Keys.ControlShiftLeft,
  256. "\x1b[1;6F": Keys.ControlShiftEnd,
  257. "\x1b[1;6H": Keys.ControlShiftHome,
  258. # Control + Meta + arrows.
  259. "\x1b[1;7A": (Keys.Escape, Keys.ControlDown),
  260. "\x1b[1;7B": (Keys.Escape, Keys.ControlUp),
  261. "\x1b[1;7C": (Keys.Escape, Keys.ControlRight),
  262. "\x1b[1;7D": (Keys.Escape, Keys.ControlLeft),
  263. "\x1b[1;7F": (Keys.Escape, Keys.ControlEnd),
  264. "\x1b[1;7H": (Keys.Escape, Keys.ControlHome),
  265. # Meta + Shift + arrows.
  266. "\x1b[1;8A": (Keys.Escape, Keys.ControlShiftDown),
  267. "\x1b[1;8B": (Keys.Escape, Keys.ControlShiftUp),
  268. "\x1b[1;8C": (Keys.Escape, Keys.ControlShiftRight),
  269. "\x1b[1;8D": (Keys.Escape, Keys.ControlShiftLeft),
  270. "\x1b[1;8F": (Keys.Escape, Keys.ControlShiftEnd),
  271. "\x1b[1;8H": (Keys.Escape, Keys.ControlShiftHome),
  272. # Meta + arrow on (some?) Macs when using iTerm defaults (see issue #483).
  273. "\x1b[1;9A": (Keys.Escape, Keys.Up),
  274. "\x1b[1;9B": (Keys.Escape, Keys.Down),
  275. "\x1b[1;9C": (Keys.Escape, Keys.Right),
  276. "\x1b[1;9D": (Keys.Escape, Keys.Left),
  277. # --
  278. # Control/shift/meta + number in mintty.
  279. # (c-2 will actually send c-@ and c-6 will send c-^.)
  280. "\x1b[1;5p": Keys.Control0,
  281. "\x1b[1;5q": Keys.Control1,
  282. "\x1b[1;5r": Keys.Control2,
  283. "\x1b[1;5s": Keys.Control3,
  284. "\x1b[1;5t": Keys.Control4,
  285. "\x1b[1;5u": Keys.Control5,
  286. "\x1b[1;5v": Keys.Control6,
  287. "\x1b[1;5w": Keys.Control7,
  288. "\x1b[1;5x": Keys.Control8,
  289. "\x1b[1;5y": Keys.Control9,
  290. "\x1b[1;6p": Keys.ControlShift0,
  291. "\x1b[1;6q": Keys.ControlShift1,
  292. "\x1b[1;6r": Keys.ControlShift2,
  293. "\x1b[1;6s": Keys.ControlShift3,
  294. "\x1b[1;6t": Keys.ControlShift4,
  295. "\x1b[1;6u": Keys.ControlShift5,
  296. "\x1b[1;6v": Keys.ControlShift6,
  297. "\x1b[1;6w": Keys.ControlShift7,
  298. "\x1b[1;6x": Keys.ControlShift8,
  299. "\x1b[1;6y": Keys.ControlShift9,
  300. "\x1b[1;7p": (Keys.Escape, Keys.Control0),
  301. "\x1b[1;7q": (Keys.Escape, Keys.Control1),
  302. "\x1b[1;7r": (Keys.Escape, Keys.Control2),
  303. "\x1b[1;7s": (Keys.Escape, Keys.Control3),
  304. "\x1b[1;7t": (Keys.Escape, Keys.Control4),
  305. "\x1b[1;7u": (Keys.Escape, Keys.Control5),
  306. "\x1b[1;7v": (Keys.Escape, Keys.Control6),
  307. "\x1b[1;7w": (Keys.Escape, Keys.Control7),
  308. "\x1b[1;7x": (Keys.Escape, Keys.Control8),
  309. "\x1b[1;7y": (Keys.Escape, Keys.Control9),
  310. "\x1b[1;8p": (Keys.Escape, Keys.ControlShift0),
  311. "\x1b[1;8q": (Keys.Escape, Keys.ControlShift1),
  312. "\x1b[1;8r": (Keys.Escape, Keys.ControlShift2),
  313. "\x1b[1;8s": (Keys.Escape, Keys.ControlShift3),
  314. "\x1b[1;8t": (Keys.Escape, Keys.ControlShift4),
  315. "\x1b[1;8u": (Keys.Escape, Keys.ControlShift5),
  316. "\x1b[1;8v": (Keys.Escape, Keys.ControlShift6),
  317. "\x1b[1;8w": (Keys.Escape, Keys.ControlShift7),
  318. "\x1b[1;8x": (Keys.Escape, Keys.ControlShift8),
  319. "\x1b[1;8y": (Keys.Escape, Keys.ControlShift9),
  320. }
  321. def _get_reverse_ansi_sequences() -> dict[Keys, str]:
  322. """
  323. Create a dictionary that maps prompt_toolkit keys back to the VT100 escape
  324. sequences.
  325. """
  326. result: dict[Keys, str] = {}
  327. for sequence, key in ANSI_SEQUENCES.items():
  328. if not isinstance(key, tuple):
  329. if key not in result:
  330. result[key] = sequence
  331. return result
  332. REVERSE_ANSI_SEQUENCES = _get_reverse_ansi_sequences()