keys.py 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. #!/usr/bin/env python
  2. # License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
  3. from functools import partial
  4. import kitty.fast_data_types as defines
  5. from kitty.key_encoding import EventType, KeyEvent, decode_key_event, encode_key_event
  6. from kitty.keys import Mappings
  7. from . import BaseTest
  8. class TestKeys(BaseTest):
  9. def test_encode_key_event(self):
  10. enc = defines.encode_key_for_tty
  11. ae = self.assertEqual
  12. shift, alt, ctrl, super, hyper, meta = defines.GLFW_MOD_SHIFT, defines.GLFW_MOD_ALT, defines.GLFW_MOD_CONTROL, defines.GLFW_MOD_SUPER, defines.GLFW_MOD_HYPER, defines.GLFW_MOD_META # noqa
  13. num_lock, caps_lock = defines.GLFW_MOD_NUM_LOCK, defines.GLFW_MOD_CAPS_LOCK
  14. press, repeat, release = defines.GLFW_PRESS, defines.GLFW_REPEAT, defines.GLFW_RELEASE # noqa
  15. def csi(mods=0, num=1, action=1, shifted_key=0, alternate_key=0, text=None, trailer='u'):
  16. ans = '\033['
  17. if isinstance(num, str):
  18. num = ord(num)
  19. if num != 1 or mods or shifted_key or alternate_key or text:
  20. ans += f'{num}'
  21. if shifted_key or alternate_key:
  22. if isinstance(shifted_key, str):
  23. shifted_key = ord(shifted_key)
  24. ans += ':' + (f'{shifted_key}' if shifted_key else '')
  25. if alternate_key:
  26. if isinstance(alternate_key, str):
  27. alternate_key = ord(alternate_key)
  28. ans += f':{alternate_key}'
  29. if mods or action > 1 or text:
  30. m = 0
  31. if mods & shift:
  32. m |= 1
  33. if mods & alt:
  34. m |= 2
  35. if mods & ctrl:
  36. m |= 4
  37. if mods & super:
  38. m |= 8
  39. if mods & hyper:
  40. m |= 16
  41. if mods & meta:
  42. m |= 32
  43. if action > 1 or m:
  44. ans += f';{m+1}'
  45. if action > 1:
  46. ans += f':{action}'
  47. elif text:
  48. ans += ';'
  49. if text:
  50. ans += ';' + ':'.join(map(str, map(ord, text)))
  51. return ans + trailer
  52. def mods_test(key, plain=None, shift=None, ctrl=None, alt=None, calt=None, cshift=None, ashift=None, csi_num=None, trailer='u'):
  53. c = partial(csi, num=csi_num or key, trailer=trailer)
  54. e = partial(enc, key=key)
  55. def a(a, b):
  56. ae(a, b, f"{a.encode('ascii')} != {b.encode('ascii')}")
  57. def w(a, b):
  58. return c(b) if a is None else a
  59. a(e(), plain or c())
  60. a(e(mods=defines.GLFW_MOD_SHIFT), w(shift, defines.GLFW_MOD_SHIFT))
  61. a(e(mods=defines.GLFW_MOD_CONTROL), w(ctrl, defines.GLFW_MOD_CONTROL))
  62. a(e(mods=defines.GLFW_MOD_ALT | defines.GLFW_MOD_CONTROL), w(calt, defines.GLFW_MOD_ALT | defines.GLFW_MOD_CONTROL))
  63. a(e(mods=defines.GLFW_MOD_SHIFT | defines.GLFW_MOD_CONTROL), w(cshift, defines.GLFW_MOD_CONTROL | defines.GLFW_MOD_SHIFT))
  64. a(e(mods=defines.GLFW_MOD_SHIFT | defines.GLFW_MOD_ALT), w(ashift, defines.GLFW_MOD_ALT | defines.GLFW_MOD_SHIFT))
  65. def mkp(name, *a, **kw):
  66. for x in (f'GLFW_FKEY_{name}', f'GLFW_FKEY_KP_{name}'):
  67. k = getattr(defines, x)
  68. mods_test(k, *a, **kw)
  69. mkp('ENTER', '\x0d', alt='\033\x0d', ctrl='\x0d', shift='\x0d', ashift='\033\x0d', calt='\033\x0d', cshift='\x0d')
  70. mods_test(defines.GLFW_FKEY_ESCAPE, '\x1b', alt='\033\033', ctrl='\x1b', shift='\x1b', calt='\x1b\x1b', cshift='\x1b', ashift='\x1b\x1b')
  71. mods_test(defines.GLFW_FKEY_BACKSPACE, '\x7f', alt='\033\x7f', ctrl='\x08', shift='\x7f', ashift='\033\x7f', cshift='\x08', calt='\x1b\x08')
  72. mods_test(defines.GLFW_FKEY_TAB, '\t', alt='\033\t', shift='\x1b[Z', ctrl='\t', ashift='\x1b\x1b[Z', cshift='\x1b[Z', calt='\x1b\t')
  73. mkp('INSERT', csi_num=2, trailer='~')
  74. mkp('DELETE', csi_num=3, trailer='~')
  75. mkp('PAGE_UP', csi_num=5, trailer='~')
  76. mkp('PAGE_DOWN', csi_num=6, trailer='~')
  77. mkp('HOME', csi_num=1, trailer='H')
  78. mkp('END', csi_num=1, trailer='F')
  79. mods_test(defines.GLFW_FKEY_F1, '\x1bOP', csi_num=1, trailer='P')
  80. mods_test(defines.GLFW_FKEY_F2, '\x1bOQ', csi_num=1, trailer='Q')
  81. mods_test(defines.GLFW_FKEY_F3, '\x1bOR', csi_num=13, trailer='~')
  82. mods_test(defines.GLFW_FKEY_F4, '\x1bOS', csi_num=1, trailer='S')
  83. mods_test(defines.GLFW_FKEY_F5, csi_num=15, trailer='~')
  84. mods_test(defines.GLFW_FKEY_F6, csi_num=17, trailer='~')
  85. mods_test(defines.GLFW_FKEY_F7, csi_num=18, trailer='~')
  86. mods_test(defines.GLFW_FKEY_F8, csi_num=19, trailer='~')
  87. mods_test(defines.GLFW_FKEY_F9, csi_num=20, trailer='~')
  88. mods_test(defines.GLFW_FKEY_F10, csi_num=21, trailer='~')
  89. mods_test(defines.GLFW_FKEY_F11, csi_num=23, trailer='~')
  90. mods_test(defines.GLFW_FKEY_F12, csi_num=24, trailer='~')
  91. mkp('UP', csi_num=1, trailer='A')
  92. mkp('DOWN', csi_num=1, trailer='B')
  93. mkp('RIGHT', csi_num=1, trailer='C')
  94. mkp('LEFT', csi_num=1, trailer='D')
  95. # legacy key tests {{{
  96. # start legacy letter tests (auto generated by gen-key-constants.py do not edit)
  97. ae(enc(ord('`'), shifted_key=ord('~')), '`')
  98. ae(enc(ord('`'), shifted_key=ord('~'), mods=shift), '~')
  99. ae(enc(ord('`'), shifted_key=ord('~'), mods=alt), "\x1b" + '`')
  100. ae(enc(ord('`'), shifted_key=ord('~'), mods=shift | alt), "\x1b" + '~')
  101. ae(enc(ord('`'), shifted_key=ord('~'), mods=ctrl), '`')
  102. ae(enc(ord('`'), shifted_key=ord('~'), mods=ctrl | alt), "\x1b" + '`')
  103. ae(enc(ord('1'), shifted_key=ord('!')), '1')
  104. ae(enc(ord('1'), shifted_key=ord('!'), mods=shift), '!')
  105. ae(enc(ord('1'), shifted_key=ord('!'), mods=alt), "\x1b" + '1')
  106. ae(enc(ord('1'), shifted_key=ord('!'), mods=shift | alt), "\x1b" + '!')
  107. ae(enc(ord('1'), shifted_key=ord('!'), mods=ctrl), '1')
  108. ae(enc(ord('1'), shifted_key=ord('!'), mods=ctrl | alt), "\x1b" + '1')
  109. ae(enc(ord('2'), shifted_key=ord('@')), '2')
  110. ae(enc(ord('2'), shifted_key=ord('@'), mods=shift), '@')
  111. ae(enc(ord('2'), shifted_key=ord('@'), mods=alt), "\x1b" + '2')
  112. ae(enc(ord('2'), shifted_key=ord('@'), mods=shift | alt), "\x1b" + '@')
  113. ae(enc(ord('2'), shifted_key=ord('@'), mods=ctrl), '\x00')
  114. ae(enc(ord('2'), shifted_key=ord('@'), mods=ctrl | alt), "\x1b" + '\x00')
  115. ae(enc(ord('3'), shifted_key=ord('#')), '3')
  116. ae(enc(ord('3'), shifted_key=ord('#'), mods=shift), '#')
  117. ae(enc(ord('3'), shifted_key=ord('#'), mods=alt), "\x1b" + '3')
  118. ae(enc(ord('3'), shifted_key=ord('#'), mods=shift | alt), "\x1b" + '#')
  119. ae(enc(ord('3'), shifted_key=ord('#'), mods=ctrl), '\x1b')
  120. ae(enc(ord('3'), shifted_key=ord('#'), mods=ctrl | alt), "\x1b" + '\x1b')
  121. ae(enc(ord('4'), shifted_key=ord('$')), '4')
  122. ae(enc(ord('4'), shifted_key=ord('$'), mods=shift), '$')
  123. ae(enc(ord('4'), shifted_key=ord('$'), mods=alt), "\x1b" + '4')
  124. ae(enc(ord('4'), shifted_key=ord('$'), mods=shift | alt), "\x1b" + '$')
  125. ae(enc(ord('4'), shifted_key=ord('$'), mods=ctrl), '\x1c')
  126. ae(enc(ord('4'), shifted_key=ord('$'), mods=ctrl | alt), "\x1b" + '\x1c')
  127. ae(enc(ord('5'), shifted_key=ord('%')), '5')
  128. ae(enc(ord('5'), shifted_key=ord('%'), mods=shift), '%')
  129. ae(enc(ord('5'), shifted_key=ord('%'), mods=alt), "\x1b" + '5')
  130. ae(enc(ord('5'), shifted_key=ord('%'), mods=shift | alt), "\x1b" + '%')
  131. ae(enc(ord('5'), shifted_key=ord('%'), mods=ctrl), '\x1d')
  132. ae(enc(ord('5'), shifted_key=ord('%'), mods=ctrl | alt), "\x1b" + '\x1d')
  133. ae(enc(ord('6'), shifted_key=ord('^')), '6')
  134. ae(enc(ord('6'), shifted_key=ord('^'), mods=shift), '^')
  135. ae(enc(ord('6'), shifted_key=ord('^'), mods=alt), "\x1b" + '6')
  136. ae(enc(ord('6'), shifted_key=ord('^'), mods=shift | alt), "\x1b" + '^')
  137. ae(enc(ord('6'), shifted_key=ord('^'), mods=ctrl), '\x1e')
  138. ae(enc(ord('6'), shifted_key=ord('^'), mods=ctrl | alt), "\x1b" + '\x1e')
  139. ae(enc(ord('7'), shifted_key=ord('&')), '7')
  140. ae(enc(ord('7'), shifted_key=ord('&'), mods=shift), '&')
  141. ae(enc(ord('7'), shifted_key=ord('&'), mods=alt), "\x1b" + '7')
  142. ae(enc(ord('7'), shifted_key=ord('&'), mods=shift | alt), "\x1b" + '&')
  143. ae(enc(ord('7'), shifted_key=ord('&'), mods=ctrl), '\x1f')
  144. ae(enc(ord('7'), shifted_key=ord('&'), mods=ctrl | alt), "\x1b" + '\x1f')
  145. ae(enc(ord('8'), shifted_key=ord('*')), '8')
  146. ae(enc(ord('8'), shifted_key=ord('*'), mods=shift), '*')
  147. ae(enc(ord('8'), shifted_key=ord('*'), mods=alt), "\x1b" + '8')
  148. ae(enc(ord('8'), shifted_key=ord('*'), mods=shift | alt), "\x1b" + '*')
  149. ae(enc(ord('8'), shifted_key=ord('*'), mods=ctrl), '\x7f')
  150. ae(enc(ord('8'), shifted_key=ord('*'), mods=ctrl | alt), "\x1b" + '\x7f')
  151. ae(enc(ord('9'), shifted_key=ord('(')), '9')
  152. ae(enc(ord('9'), shifted_key=ord('('), mods=shift), '(')
  153. ae(enc(ord('9'), shifted_key=ord('('), mods=alt), "\x1b" + '9')
  154. ae(enc(ord('9'), shifted_key=ord('('), mods=shift | alt), "\x1b" + '(')
  155. ae(enc(ord('9'), shifted_key=ord('('), mods=ctrl), '9')
  156. ae(enc(ord('9'), shifted_key=ord('('), mods=ctrl | alt), "\x1b" + '9')
  157. ae(enc(ord('0'), shifted_key=ord(')')), '0')
  158. ae(enc(ord('0'), shifted_key=ord(')'), mods=shift), ')')
  159. ae(enc(ord('0'), shifted_key=ord(')'), mods=alt), "\x1b" + '0')
  160. ae(enc(ord('0'), shifted_key=ord(')'), mods=shift | alt), "\x1b" + ')')
  161. ae(enc(ord('0'), shifted_key=ord(')'), mods=ctrl), '0')
  162. ae(enc(ord('0'), shifted_key=ord(')'), mods=ctrl | alt), "\x1b" + '0')
  163. ae(enc(ord('-'), shifted_key=ord('_')), '-')
  164. ae(enc(ord('-'), shifted_key=ord('_'), mods=shift), '_')
  165. ae(enc(ord('-'), shifted_key=ord('_'), mods=alt), "\x1b" + '-')
  166. ae(enc(ord('-'), shifted_key=ord('_'), mods=shift | alt), "\x1b" + '_')
  167. ae(enc(ord('-'), shifted_key=ord('_'), mods=ctrl), '-')
  168. ae(enc(ord('-'), shifted_key=ord('_'), mods=ctrl | alt), "\x1b" + '-')
  169. ae(enc(ord('='), shifted_key=ord('+')), '=')
  170. ae(enc(ord('='), shifted_key=ord('+'), mods=shift), '+')
  171. ae(enc(ord('='), shifted_key=ord('+'), mods=alt), "\x1b" + '=')
  172. ae(enc(ord('='), shifted_key=ord('+'), mods=shift | alt), "\x1b" + '+')
  173. ae(enc(ord('='), shifted_key=ord('+'), mods=ctrl), '=')
  174. ae(enc(ord('='), shifted_key=ord('+'), mods=ctrl | alt), "\x1b" + '=')
  175. ae(enc(ord('['), shifted_key=ord('{')), '[')
  176. ae(enc(ord('['), shifted_key=ord('{'), mods=shift), '{')
  177. ae(enc(ord('['), shifted_key=ord('{'), mods=alt), "\x1b" + '[')
  178. ae(enc(ord('['), shifted_key=ord('{'), mods=shift | alt), "\x1b" + '{')
  179. ae(enc(ord('['), shifted_key=ord('{'), mods=ctrl), '\x1b')
  180. ae(enc(ord('['), shifted_key=ord('{'), mods=ctrl | alt), "\x1b" + '\x1b')
  181. ae(enc(ord(']'), shifted_key=ord('}')), ']')
  182. ae(enc(ord(']'), shifted_key=ord('}'), mods=shift), '}')
  183. ae(enc(ord(']'), shifted_key=ord('}'), mods=alt), "\x1b" + ']')
  184. ae(enc(ord(']'), shifted_key=ord('}'), mods=shift | alt), "\x1b" + '}')
  185. ae(enc(ord(']'), shifted_key=ord('}'), mods=ctrl), '\x1d')
  186. ae(enc(ord(']'), shifted_key=ord('}'), mods=ctrl | alt), "\x1b" + '\x1d')
  187. ae(enc(ord('\\'), shifted_key=ord('|')), '\\')
  188. ae(enc(ord('\\'), shifted_key=ord('|'), mods=shift), '|')
  189. ae(enc(ord('\\'), shifted_key=ord('|'), mods=alt), "\x1b" + '\\')
  190. ae(enc(ord('\\'), shifted_key=ord('|'), mods=shift | alt), "\x1b" + '|')
  191. ae(enc(ord('\\'), shifted_key=ord('|'), mods=ctrl), '\x1c')
  192. ae(enc(ord('\\'), shifted_key=ord('|'), mods=ctrl | alt), "\x1b" + '\x1c')
  193. ae(enc(ord(';'), shifted_key=ord(':')), ';')
  194. ae(enc(ord(';'), shifted_key=ord(':'), mods=shift), ':')
  195. ae(enc(ord(';'), shifted_key=ord(':'), mods=alt), "\x1b" + ';')
  196. ae(enc(ord(';'), shifted_key=ord(':'), mods=shift | alt), "\x1b" + ':')
  197. ae(enc(ord(';'), shifted_key=ord(':'), mods=ctrl), ';')
  198. ae(enc(ord(';'), shifted_key=ord(':'), mods=ctrl | alt), "\x1b" + ';')
  199. ae(enc(ord("'"), shifted_key=ord('"')), "'")
  200. ae(enc(ord("'"), shifted_key=ord('"'), mods=shift), '"')
  201. ae(enc(ord("'"), shifted_key=ord('"'), mods=alt), "\x1b" + "'")
  202. ae(enc(ord("'"), shifted_key=ord('"'), mods=shift | alt), "\x1b" + '"')
  203. ae(enc(ord("'"), shifted_key=ord('"'), mods=ctrl), "'")
  204. ae(enc(ord("'"), shifted_key=ord('"'), mods=ctrl | alt), "\x1b" + "'")
  205. ae(enc(ord(','), shifted_key=ord('<')), ',')
  206. ae(enc(ord(','), shifted_key=ord('<'), mods=shift), '<')
  207. ae(enc(ord(','), shifted_key=ord('<'), mods=alt), "\x1b" + ',')
  208. ae(enc(ord(','), shifted_key=ord('<'), mods=shift | alt), "\x1b" + '<')
  209. ae(enc(ord(','), shifted_key=ord('<'), mods=ctrl), ',')
  210. ae(enc(ord(','), shifted_key=ord('<'), mods=ctrl | alt), "\x1b" + ',')
  211. ae(enc(ord('.'), shifted_key=ord('>')), '.')
  212. ae(enc(ord('.'), shifted_key=ord('>'), mods=shift), '>')
  213. ae(enc(ord('.'), shifted_key=ord('>'), mods=alt), "\x1b" + '.')
  214. ae(enc(ord('.'), shifted_key=ord('>'), mods=shift | alt), "\x1b" + '>')
  215. ae(enc(ord('.'), shifted_key=ord('>'), mods=ctrl), '.')
  216. ae(enc(ord('.'), shifted_key=ord('>'), mods=ctrl | alt), "\x1b" + '.')
  217. ae(enc(ord('/'), shifted_key=ord('?')), '/')
  218. ae(enc(ord('/'), shifted_key=ord('?'), mods=shift), '?')
  219. ae(enc(ord('/'), shifted_key=ord('?'), mods=alt), "\x1b" + '/')
  220. ae(enc(ord('/'), shifted_key=ord('?'), mods=shift | alt), "\x1b" + '?')
  221. ae(enc(ord('/'), shifted_key=ord('?'), mods=ctrl), '\x1f')
  222. ae(enc(ord('/'), shifted_key=ord('?'), mods=ctrl | alt), "\x1b" + '\x1f')
  223. ae(enc(ord('a'), shifted_key=ord('A')), 'a')
  224. ae(enc(ord('a'), shifted_key=ord('A'), mods=shift), 'A')
  225. ae(enc(ord('a'), shifted_key=ord('A'), mods=alt), "\x1b" + 'a')
  226. ae(enc(ord('a'), shifted_key=ord('A'), mods=shift | alt), "\x1b" + 'A')
  227. ae(enc(ord('a'), shifted_key=ord('A'), mods=ctrl), '\x01')
  228. ae(enc(ord('a'), shifted_key=ord('A'), mods=ctrl | alt), "\x1b" + '\x01')
  229. ae(enc(ord('b'), shifted_key=ord('B')), 'b')
  230. ae(enc(ord('b'), shifted_key=ord('B'), mods=shift), 'B')
  231. ae(enc(ord('b'), shifted_key=ord('B'), mods=alt), "\x1b" + 'b')
  232. ae(enc(ord('b'), shifted_key=ord('B'), mods=shift | alt), "\x1b" + 'B')
  233. ae(enc(ord('b'), shifted_key=ord('B'), mods=ctrl), '\x02')
  234. ae(enc(ord('b'), shifted_key=ord('B'), mods=ctrl | alt), "\x1b" + '\x02')
  235. ae(enc(ord('c'), shifted_key=ord('C')), 'c')
  236. ae(enc(ord('c'), shifted_key=ord('C'), mods=shift), 'C')
  237. ae(enc(ord('c'), shifted_key=ord('C'), mods=alt), "\x1b" + 'c')
  238. ae(enc(ord('c'), shifted_key=ord('C'), mods=shift | alt), "\x1b" + 'C')
  239. ae(enc(ord('c'), shifted_key=ord('C'), mods=ctrl), '\x03')
  240. ae(enc(ord('c'), shifted_key=ord('C'), mods=ctrl | alt), "\x1b" + '\x03')
  241. ae(enc(ord('d'), shifted_key=ord('D')), 'd')
  242. ae(enc(ord('d'), shifted_key=ord('D'), mods=shift), 'D')
  243. ae(enc(ord('d'), shifted_key=ord('D'), mods=alt), "\x1b" + 'd')
  244. ae(enc(ord('d'), shifted_key=ord('D'), mods=shift | alt), "\x1b" + 'D')
  245. ae(enc(ord('d'), shifted_key=ord('D'), mods=ctrl), '\x04')
  246. ae(enc(ord('d'), shifted_key=ord('D'), mods=ctrl | alt), "\x1b" + '\x04')
  247. ae(enc(ord('e'), shifted_key=ord('E')), 'e')
  248. ae(enc(ord('e'), shifted_key=ord('E'), mods=shift), 'E')
  249. ae(enc(ord('e'), shifted_key=ord('E'), mods=alt), "\x1b" + 'e')
  250. ae(enc(ord('e'), shifted_key=ord('E'), mods=shift | alt), "\x1b" + 'E')
  251. ae(enc(ord('e'), shifted_key=ord('E'), mods=ctrl), '\x05')
  252. ae(enc(ord('e'), shifted_key=ord('E'), mods=ctrl | alt), "\x1b" + '\x05')
  253. ae(enc(ord('f'), shifted_key=ord('F')), 'f')
  254. ae(enc(ord('f'), shifted_key=ord('F'), mods=shift), 'F')
  255. ae(enc(ord('f'), shifted_key=ord('F'), mods=alt), "\x1b" + 'f')
  256. ae(enc(ord('f'), shifted_key=ord('F'), mods=shift | alt), "\x1b" + 'F')
  257. ae(enc(ord('f'), shifted_key=ord('F'), mods=ctrl), '\x06')
  258. ae(enc(ord('f'), shifted_key=ord('F'), mods=ctrl | alt), "\x1b" + '\x06')
  259. ae(enc(ord('g'), shifted_key=ord('G')), 'g')
  260. ae(enc(ord('g'), shifted_key=ord('G'), mods=shift), 'G')
  261. ae(enc(ord('g'), shifted_key=ord('G'), mods=alt), "\x1b" + 'g')
  262. ae(enc(ord('g'), shifted_key=ord('G'), mods=shift | alt), "\x1b" + 'G')
  263. ae(enc(ord('g'), shifted_key=ord('G'), mods=ctrl), '\x07')
  264. ae(enc(ord('g'), shifted_key=ord('G'), mods=ctrl | alt), "\x1b" + '\x07')
  265. ae(enc(ord('h'), shifted_key=ord('H')), 'h')
  266. ae(enc(ord('h'), shifted_key=ord('H'), mods=shift), 'H')
  267. ae(enc(ord('h'), shifted_key=ord('H'), mods=alt), "\x1b" + 'h')
  268. ae(enc(ord('h'), shifted_key=ord('H'), mods=shift | alt), "\x1b" + 'H')
  269. ae(enc(ord('h'), shifted_key=ord('H'), mods=ctrl), '\x08')
  270. ae(enc(ord('h'), shifted_key=ord('H'), mods=ctrl | alt), "\x1b" + '\x08')
  271. ae(enc(ord('i'), shifted_key=ord('I')), 'i')
  272. ae(enc(ord('i'), shifted_key=ord('I'), mods=shift), 'I')
  273. ae(enc(ord('i'), shifted_key=ord('I'), mods=alt), "\x1b" + 'i')
  274. ae(enc(ord('i'), shifted_key=ord('I'), mods=shift | alt), "\x1b" + 'I')
  275. ae(enc(ord('i'), shifted_key=ord('I'), mods=ctrl), '\t')
  276. ae(enc(ord('i'), shifted_key=ord('I'), mods=ctrl | alt), "\x1b" + '\t')
  277. ae(enc(ord('j'), shifted_key=ord('J')), 'j')
  278. ae(enc(ord('j'), shifted_key=ord('J'), mods=shift), 'J')
  279. ae(enc(ord('j'), shifted_key=ord('J'), mods=alt), "\x1b" + 'j')
  280. ae(enc(ord('j'), shifted_key=ord('J'), mods=shift | alt), "\x1b" + 'J')
  281. ae(enc(ord('j'), shifted_key=ord('J'), mods=ctrl), '\n')
  282. ae(enc(ord('j'), shifted_key=ord('J'), mods=ctrl | alt), "\x1b" + '\n')
  283. ae(enc(ord('k'), shifted_key=ord('K')), 'k')
  284. ae(enc(ord('k'), shifted_key=ord('K'), mods=shift), 'K')
  285. ae(enc(ord('k'), shifted_key=ord('K'), mods=alt), "\x1b" + 'k')
  286. ae(enc(ord('k'), shifted_key=ord('K'), mods=shift | alt), "\x1b" + 'K')
  287. ae(enc(ord('k'), shifted_key=ord('K'), mods=ctrl), '\x0b')
  288. ae(enc(ord('k'), shifted_key=ord('K'), mods=ctrl | alt), "\x1b" + '\x0b')
  289. ae(enc(ord('l'), shifted_key=ord('L')), 'l')
  290. ae(enc(ord('l'), shifted_key=ord('L'), mods=shift), 'L')
  291. ae(enc(ord('l'), shifted_key=ord('L'), mods=alt), "\x1b" + 'l')
  292. ae(enc(ord('l'), shifted_key=ord('L'), mods=shift | alt), "\x1b" + 'L')
  293. ae(enc(ord('l'), shifted_key=ord('L'), mods=ctrl), '\x0c')
  294. ae(enc(ord('l'), shifted_key=ord('L'), mods=ctrl | alt), "\x1b" + '\x0c')
  295. ae(enc(ord('m'), shifted_key=ord('M')), 'm')
  296. ae(enc(ord('m'), shifted_key=ord('M'), mods=shift), 'M')
  297. ae(enc(ord('m'), shifted_key=ord('M'), mods=alt), "\x1b" + 'm')
  298. ae(enc(ord('m'), shifted_key=ord('M'), mods=shift | alt), "\x1b" + 'M')
  299. ae(enc(ord('m'), shifted_key=ord('M'), mods=ctrl), '\r')
  300. ae(enc(ord('m'), shifted_key=ord('M'), mods=ctrl | alt), "\x1b" + '\r')
  301. ae(enc(ord('n'), shifted_key=ord('N')), 'n')
  302. ae(enc(ord('n'), shifted_key=ord('N'), mods=shift), 'N')
  303. ae(enc(ord('n'), shifted_key=ord('N'), mods=alt), "\x1b" + 'n')
  304. ae(enc(ord('n'), shifted_key=ord('N'), mods=shift | alt), "\x1b" + 'N')
  305. ae(enc(ord('n'), shifted_key=ord('N'), mods=ctrl), '\x0e')
  306. ae(enc(ord('n'), shifted_key=ord('N'), mods=ctrl | alt), "\x1b" + '\x0e')
  307. ae(enc(ord('o'), shifted_key=ord('O')), 'o')
  308. ae(enc(ord('o'), shifted_key=ord('O'), mods=shift), 'O')
  309. ae(enc(ord('o'), shifted_key=ord('O'), mods=alt), "\x1b" + 'o')
  310. ae(enc(ord('o'), shifted_key=ord('O'), mods=shift | alt), "\x1b" + 'O')
  311. ae(enc(ord('o'), shifted_key=ord('O'), mods=ctrl), '\x0f')
  312. ae(enc(ord('o'), shifted_key=ord('O'), mods=ctrl | alt), "\x1b" + '\x0f')
  313. ae(enc(ord('p'), shifted_key=ord('P')), 'p')
  314. ae(enc(ord('p'), shifted_key=ord('P'), mods=shift), 'P')
  315. ae(enc(ord('p'), shifted_key=ord('P'), mods=alt), "\x1b" + 'p')
  316. ae(enc(ord('p'), shifted_key=ord('P'), mods=shift | alt), "\x1b" + 'P')
  317. ae(enc(ord('p'), shifted_key=ord('P'), mods=ctrl), '\x10')
  318. ae(enc(ord('p'), shifted_key=ord('P'), mods=ctrl | alt), "\x1b" + '\x10')
  319. ae(enc(ord('q'), shifted_key=ord('Q')), 'q')
  320. ae(enc(ord('q'), shifted_key=ord('Q'), mods=shift), 'Q')
  321. ae(enc(ord('q'), shifted_key=ord('Q'), mods=alt), "\x1b" + 'q')
  322. ae(enc(ord('q'), shifted_key=ord('Q'), mods=shift | alt), "\x1b" + 'Q')
  323. ae(enc(ord('q'), shifted_key=ord('Q'), mods=ctrl), '\x11')
  324. ae(enc(ord('q'), shifted_key=ord('Q'), mods=ctrl | alt), "\x1b" + '\x11')
  325. ae(enc(ord('r'), shifted_key=ord('R')), 'r')
  326. ae(enc(ord('r'), shifted_key=ord('R'), mods=shift), 'R')
  327. ae(enc(ord('r'), shifted_key=ord('R'), mods=alt), "\x1b" + 'r')
  328. ae(enc(ord('r'), shifted_key=ord('R'), mods=shift | alt), "\x1b" + 'R')
  329. ae(enc(ord('r'), shifted_key=ord('R'), mods=ctrl), '\x12')
  330. ae(enc(ord('r'), shifted_key=ord('R'), mods=ctrl | alt), "\x1b" + '\x12')
  331. ae(enc(ord('s'), shifted_key=ord('S')), 's')
  332. ae(enc(ord('s'), shifted_key=ord('S'), mods=shift), 'S')
  333. ae(enc(ord('s'), shifted_key=ord('S'), mods=alt), "\x1b" + 's')
  334. ae(enc(ord('s'), shifted_key=ord('S'), mods=shift | alt), "\x1b" + 'S')
  335. ae(enc(ord('s'), shifted_key=ord('S'), mods=ctrl), '\x13')
  336. ae(enc(ord('s'), shifted_key=ord('S'), mods=ctrl | alt), "\x1b" + '\x13')
  337. ae(enc(ord('t'), shifted_key=ord('T')), 't')
  338. ae(enc(ord('t'), shifted_key=ord('T'), mods=shift), 'T')
  339. ae(enc(ord('t'), shifted_key=ord('T'), mods=alt), "\x1b" + 't')
  340. ae(enc(ord('t'), shifted_key=ord('T'), mods=shift | alt), "\x1b" + 'T')
  341. ae(enc(ord('t'), shifted_key=ord('T'), mods=ctrl), '\x14')
  342. ae(enc(ord('t'), shifted_key=ord('T'), mods=ctrl | alt), "\x1b" + '\x14')
  343. ae(enc(ord('u'), shifted_key=ord('U')), 'u')
  344. ae(enc(ord('u'), shifted_key=ord('U'), mods=shift), 'U')
  345. ae(enc(ord('u'), shifted_key=ord('U'), mods=alt), "\x1b" + 'u')
  346. ae(enc(ord('u'), shifted_key=ord('U'), mods=shift | alt), "\x1b" + 'U')
  347. ae(enc(ord('u'), shifted_key=ord('U'), mods=ctrl), '\x15')
  348. ae(enc(ord('u'), shifted_key=ord('U'), mods=ctrl | alt), "\x1b" + '\x15')
  349. ae(enc(ord('v'), shifted_key=ord('V')), 'v')
  350. ae(enc(ord('v'), shifted_key=ord('V'), mods=shift), 'V')
  351. ae(enc(ord('v'), shifted_key=ord('V'), mods=alt), "\x1b" + 'v')
  352. ae(enc(ord('v'), shifted_key=ord('V'), mods=shift | alt), "\x1b" + 'V')
  353. ae(enc(ord('v'), shifted_key=ord('V'), mods=ctrl), '\x16')
  354. ae(enc(ord('v'), shifted_key=ord('V'), mods=ctrl | alt), "\x1b" + '\x16')
  355. ae(enc(ord('w'), shifted_key=ord('W')), 'w')
  356. ae(enc(ord('w'), shifted_key=ord('W'), mods=shift), 'W')
  357. ae(enc(ord('w'), shifted_key=ord('W'), mods=alt), "\x1b" + 'w')
  358. ae(enc(ord('w'), shifted_key=ord('W'), mods=shift | alt), "\x1b" + 'W')
  359. ae(enc(ord('w'), shifted_key=ord('W'), mods=ctrl), '\x17')
  360. ae(enc(ord('w'), shifted_key=ord('W'), mods=ctrl | alt), "\x1b" + '\x17')
  361. ae(enc(ord('x'), shifted_key=ord('X')), 'x')
  362. ae(enc(ord('x'), shifted_key=ord('X'), mods=shift), 'X')
  363. ae(enc(ord('x'), shifted_key=ord('X'), mods=alt), "\x1b" + 'x')
  364. ae(enc(ord('x'), shifted_key=ord('X'), mods=shift | alt), "\x1b" + 'X')
  365. ae(enc(ord('x'), shifted_key=ord('X'), mods=ctrl), '\x18')
  366. ae(enc(ord('x'), shifted_key=ord('X'), mods=ctrl | alt), "\x1b" + '\x18')
  367. ae(enc(ord('y'), shifted_key=ord('Y')), 'y')
  368. ae(enc(ord('y'), shifted_key=ord('Y'), mods=shift), 'Y')
  369. ae(enc(ord('y'), shifted_key=ord('Y'), mods=alt), "\x1b" + 'y')
  370. ae(enc(ord('y'), shifted_key=ord('Y'), mods=shift | alt), "\x1b" + 'Y')
  371. ae(enc(ord('y'), shifted_key=ord('Y'), mods=ctrl), '\x19')
  372. ae(enc(ord('y'), shifted_key=ord('Y'), mods=ctrl | alt), "\x1b" + '\x19')
  373. ae(enc(ord('z'), shifted_key=ord('Z')), 'z')
  374. ae(enc(ord('z'), shifted_key=ord('Z'), mods=shift), 'Z')
  375. ae(enc(ord('z'), shifted_key=ord('Z'), mods=alt), "\x1b" + 'z')
  376. ae(enc(ord('z'), shifted_key=ord('Z'), mods=shift | alt), "\x1b" + 'Z')
  377. ae(enc(ord('z'), shifted_key=ord('Z'), mods=ctrl), '\x1a')
  378. ae(enc(ord('z'), shifted_key=ord('Z'), mods=ctrl | alt), "\x1b" + '\x1a')
  379. # end legacy letter tests
  380. # }}}
  381. ae(enc(key=ord(':'), shifted_key=ord('/'), mods=shift | alt), '\x1b/')
  382. for key in '~!@#$%^&*()_+{}|:"<>?':
  383. ae(enc(key=ord(key), mods=alt), '\x1b' + key)
  384. ae(enc(key=ord(' ')), ' ')
  385. ae(enc(key=ord(' '), mods=ctrl | num_lock | caps_lock), '\0')
  386. ae(enc(key=ord(' '), mods=ctrl), '\0')
  387. ae(enc(key=ord(' '), mods=alt), '\x1b ')
  388. ae(enc(key=ord(' '), mods=shift), ' ')
  389. ae(enc(key=ord(' '), mods=ctrl | alt), '\x1b\0')
  390. ae(enc(key=ord(' '), mods=ctrl | shift), '\0')
  391. ae(enc(key=ord(' '), mods=alt | shift), '\x1b ')
  392. ae(enc(key=ord('i'), mods=ctrl | shift), csi(ctrl | shift, ord('i')))
  393. ae(enc(key=defines.GLFW_FKEY_LEFT_SHIFT), '')
  394. ae(enc(key=defines.GLFW_FKEY_CAPS_LOCK), '')
  395. q = partial(enc, key=ord('a'))
  396. ae(q(), 'a')
  397. ae(q(text='a'), 'a')
  398. ae(q(action=repeat), 'a')
  399. ae(q(action=release), '')
  400. # test disambiguate
  401. dq = partial(enc, key_encoding_flags=0b1)
  402. ae(dq(ord('a')), 'a')
  403. ae(dq(defines.GLFW_FKEY_ESCAPE), csi(num=27))
  404. ae(dq(defines.GLFW_FKEY_ENTER), '\r')
  405. ae(dq(defines.GLFW_FKEY_ENTER, mods=shift), csi(shift, 13))
  406. ae(dq(defines.GLFW_FKEY_TAB), '\t')
  407. ae(dq(defines.GLFW_FKEY_BACKSPACE), '\x7f')
  408. ae(dq(defines.GLFW_FKEY_TAB, mods=shift), csi(shift, 9))
  409. for mods in (ctrl, alt, ctrl | shift, alt | shift):
  410. ae(dq(ord('a'), mods=mods), csi(mods, ord('a')))
  411. ae(dq(ord(' '), mods=ctrl), csi(ctrl, ord(' ')))
  412. for k in (defines.GLFW_FKEY_KP_PAGE_UP, defines.GLFW_FKEY_KP_0):
  413. ae(dq(k), csi(num=k))
  414. ae(dq(k, mods=ctrl), csi(ctrl, num=k))
  415. ae(dq(defines.GLFW_FKEY_UP), '\x1b[A')
  416. ae(dq(defines.GLFW_FKEY_UP, mods=ctrl), csi(ctrl, 1, trailer='A'))
  417. # test event type reporting
  418. tq = partial(enc, key_encoding_flags=0b10)
  419. ae(tq(ord('a')), 'a')
  420. ae(tq(ord('a'), action=defines.GLFW_REPEAT), csi(num='a', action=2))
  421. ae(tq(ord('a'), action=defines.GLFW_RELEASE), csi(num='a', action=3))
  422. ae(tq(ord('a'), action=defines.GLFW_RELEASE, mods=shift), csi(shift, num='a', action=3))
  423. tq = partial(enc, key_encoding_flags=0b11)
  424. ae(tq(defines.GLFW_FKEY_BACKSPACE), '\x7f')
  425. ae(tq(defines.GLFW_FKEY_BACKSPACE, action=release), '')
  426. # test alternate key reporting
  427. aq = partial(enc, key_encoding_flags=0b100)
  428. ae(aq(ord('a')), 'a')
  429. ae(aq(ord('a'), shifted_key=ord('A')), 'a')
  430. ae(aq(ord('a'), mods=shift, shifted_key=ord('A')), csi(shift, 'a', shifted_key='A'))
  431. ae(aq(ord('a'), alternate_key=ord('A')), csi(num='a', alternate_key='A'))
  432. ae(aq(ord('a'), mods=shift, shifted_key=ord('A'), alternate_key=ord('b')), csi(shift, 'a', shifted_key='A', alternate_key='b'))
  433. # test report all keys
  434. kq = partial(enc, key_encoding_flags=0b1000)
  435. ae(kq(ord('a')), csi(num='a'))
  436. ae(kq(ord('a'), action=defines.GLFW_REPEAT), csi(num='a'))
  437. ae(kq(ord('a'), mods=ctrl), csi(ctrl, num='a'))
  438. ae(kq(defines.GLFW_FKEY_UP), '\x1b[A')
  439. ae(kq(defines.GLFW_FKEY_LEFT_SHIFT), csi(num=defines.GLFW_FKEY_LEFT_SHIFT))
  440. ae(kq(defines.GLFW_FKEY_ENTER), '\x1b[13u')
  441. ae(kq(defines.GLFW_FKEY_TAB), '\x1b[9u')
  442. ae(kq(defines.GLFW_FKEY_BACKSPACE), '\x1b[127u')
  443. # test embed text
  444. eq = partial(enc, key_encoding_flags=0b11000)
  445. ae(eq(ord('a'), text='a'), csi(num='a', text='a'))
  446. ae(eq(ord('a'), mods=shift, text='A'), csi(shift, num='a', text='A'))
  447. ae(eq(ord('a'), mods=shift, text='AB'), csi(shift, num='a', text='AB'))
  448. # test roundtripping via KeyEvent
  449. for mods in range(64):
  450. for action in EventType:
  451. for key in ('ENTER', 'a', 'TAB', 'F3'):
  452. for shifted_key in ('', 'X'):
  453. for alternate_key in ('', 'Y'):
  454. for text in ('', 'moose'):
  455. ev = KeyEvent(
  456. type=action, mods=mods, key=key, text=text, shifted_key=shifted_key, alternate_key=alternate_key,
  457. shift=bool(mods & 1), alt=bool(mods & 2), ctrl=bool(mods & 4), super=bool(mods & 8),
  458. hyper=bool(mods & 16), meta=bool(mods & 32)
  459. )
  460. ec = encode_key_event(ev)
  461. q = decode_key_event(ec[2:-1], ec[-1])
  462. self.ae(ev, q)
  463. def test_encode_mouse_event(self):
  464. NORMAL_PROTOCOL, UTF8_PROTOCOL, SGR_PROTOCOL, URXVT_PROTOCOL = range(4)
  465. L, M, R = 1, 2, 3
  466. protocol = SGR_PROTOCOL
  467. def enc(button=L, action=defines.PRESS, mods=0, x=1, y=1):
  468. return defines.test_encode_mouse(x, y, protocol, button, action, mods)
  469. self.ae(enc(), '<0;1;1M')
  470. self.ae(enc(action=defines.RELEASE), '<0;1;1m')
  471. self.ae(enc(action=defines.MOVE, button=0), '<35;1;1M')
  472. self.ae(enc(action=defines.DRAG), '<32;1;1M')
  473. self.ae(enc(R), '<2;1;1M')
  474. self.ae(enc(R, action=defines.RELEASE), '<2;1;1m')
  475. self.ae(enc(R, action=defines.DRAG), '<34;1;1M')
  476. self.ae(enc(M), '<1;1;1M')
  477. self.ae(enc(M, action=defines.RELEASE), '<1;1;1m')
  478. self.ae(enc(M, action=defines.DRAG), '<33;1;1M')
  479. self.ae(enc(x=1234, y=5678), '<0;1234;5678M')
  480. self.ae(enc(mods=defines.GLFW_MOD_SHIFT), '<4;1;1M')
  481. self.ae(enc(mods=defines.GLFW_MOD_ALT), '<8;1;1M')
  482. self.ae(enc(mods=defines.GLFW_MOD_CONTROL), '<16;1;1M')
  483. def test_mapping(self):
  484. from kitty.config import load_config
  485. from kitty.options.utils import parse_shortcut
  486. af = self.assertFalse
  487. class Window:
  488. def __init__(self, id=1):
  489. self.key_seqs = []
  490. self.id = id
  491. def send_key_sequence(self, *s):
  492. self.key_seqs.extend(s)
  493. class TM(Mappings):
  494. def __init__(self, *lines, active_window = Window()):
  495. self.active_window = active_window
  496. self.windows = [active_window]
  497. bad_lines = []
  498. self.options = load_config(overrides=lines, accumulate_bad_lines=bad_lines)
  499. af(bad_lines)
  500. self.ignore_os_keyboard_processing = False
  501. super().__init__()
  502. def get_active_window(self):
  503. return self.active_window
  504. def match_windows(self, expr: str):
  505. for w in self.windows:
  506. if str(w.id) == expr:
  507. yield w
  508. def show_error(self, title: str, msg: str) -> None:
  509. pass
  510. def ring_bell(self) -> None:
  511. pass
  512. def debug_print(self, *args, end: str = '\n') -> None:
  513. pass
  514. def combine(self, action_definition: str) -> bool:
  515. self.actions.append(action_definition)
  516. if action_definition.startswith('push_keyboard_mode '):
  517. self.push_keyboard_mode(action_definition.partition(' ')[2])
  518. elif action_definition == 'pop_keyboard_mode':
  519. self.pop_keyboard_mode()
  520. return bool(action_definition)
  521. def set_ignore_os_keyboard_processing(self, on: bool) -> None:
  522. self.ignore_os_keyboard_processing = on
  523. def set_cocoa_global_shortcuts(self, opts):
  524. return {}
  525. def get_options(self):
  526. return self.options
  527. def __call__(self, *keys: str):
  528. self.actions = []
  529. self.active_window.key_seqs = []
  530. consumed = []
  531. for key in keys:
  532. sk = parse_shortcut(key)
  533. ev = defines.KeyEvent(sk.key, 0, 0, sk.mods)
  534. consumed.append(self.dispatch_possible_special_key(ev))
  535. return consumed
  536. tm = TM('map ctrl+a new_window_with_cwd')
  537. self.ae(tm('ctrl+a'), [True])
  538. self.ae(tm.actions, ['new_window_with_cwd'])
  539. tm = TM('map ctrl+f>2 set_font_size 20')
  540. self.ae(tm('ctrl+f', '2'), [True, True])
  541. self.ae(tm.actions, ['set_font_size 20'])
  542. af(tm.active_window.key_seqs)
  543. # unmatched multi key mapping should send all keys to child
  544. self.ae(tm('ctrl+f', '1'), [True, False])
  545. af(tm.actions)
  546. self.ae(len(tm.active_window.key_seqs), 1) # ctrl+f should have been sent to the window
  547. # multi-key mapping that is unmapped should send all keys to child
  548. tm = TM('map kitty_mod+p>f')
  549. self.ae(tm('ctrl+shift+p', 'f'), [True, False])
  550. self.ae(len(tm.active_window.key_seqs), 1)
  551. # unmap
  552. tm = TM('map kitty_mod+enter')
  553. self.ae(tm('ctrl+shift+enter'), [False])
  554. # single key mapping overrides previous all multi-key mappings with same prefix
  555. tm = TM('map kitty_mod+p new_window')
  556. self.ae(tm('ctrl+shift+p', 'f'), [True, False])
  557. self.ae(tm.actions, ['new_window'])
  558. # multi-key mapping overrides previous single key mapping with same prefix
  559. tm = TM('map kitty_mod+s>p new_window')
  560. self.ae(tm('ctrl+shift+s', 'p'), [True, True])
  561. self.ae(tm.actions, ['new_window'])
  562. # mix of single and multi-key mappings with same prefix
  563. tm = TM('map alt+p>1 multi1', 'map alt+p single1', 'map alt+p>2 multi2')
  564. self.ae(tm('alt+p', '2'), [True, True])
  565. self.ae(tm.actions, ['multi2'])
  566. self.ae(tm('alt+p', '1'), [True, False])
  567. af(tm.actions)
  568. self.ae(len(tm.active_window.key_seqs), 1)
  569. # a single multi-key mapping should not prematurely match
  570. tm = TM('map alt+1>2>3 new_window')
  571. self.ae(tm('alt+1', '2'), [True, True])
  572. af(tm.actions)
  573. tm = TM('map alt+1>2>3 new_window')
  574. self.ae(tm('alt+1', '2', '3'), [True, True, True])
  575. self.ae(tm.actions, ['new_window'])
  576. # changing a multi key mapping
  577. tm = TM('map kitty_mod+p>f new_window')
  578. self.ae(tm('ctrl+shift+p', 'f'), [True, True])
  579. self.ae(tm.actions, ['new_window'])
  580. # different behavior with focus selection
  581. tm = TM('map --when-focus-on 2 kitty_mod+t')
  582. tm.windows.append(Window(2))
  583. self.ae(tm('ctrl+shift+t'), [True])
  584. tm.active_window = tm.windows[1]
  585. self.ae(tm('ctrl+shift+t'), [False])
  586. # modal mappings
  587. tm = TM('map --new-mode mw --on-unknown end kitty_mod+f7', 'map --mode mw left neighboring_window left', 'map --mode mw right neighboring_window right')
  588. self.ae(tm('ctrl+shift+f7'), [True])
  589. self.ae(tm.actions, ['push_keyboard_mode mw'])
  590. self.ae(tm('right'), [True])
  591. self.ae(tm.actions, ['neighboring_window right'])
  592. self.ae(tm('left'), [True])
  593. self.ae(tm.actions, ['neighboring_window left'])
  594. self.ae(tm('x'), [True])
  595. af(tm.keyboard_mode_stack)
  596. # modal mapping with --on-action=end must restore OS keyboard processing
  597. tm = TM('map --new-mode mw --on-action end m', 'map --mode mw a new_window')
  598. self.ae(tm('m', 'a'), [True, True])
  599. self.ae(tm.actions, ['push_keyboard_mode mw', 'new_window'])
  600. af(tm.ignore_os_keyboard_processing)