termkey_spec.lua 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976
  1. local t = require('test.unit.testutil')
  2. local itp = t.gen_itp(it)
  3. local bit = require('bit')
  4. --- @alias TermKeyKey {utf8: string, type: integer, modifiers: integer, code: {codepoint: integer, sym: any, number: integer}}
  5. --- @class termkey
  6. --- @field TERMKEY_CANON_SPACESYMBOL integer
  7. --- @field TERMKEY_FLAG_SPACESYMBOL integer
  8. --- @field TERMKEY_FLAG_UTF8 integer
  9. --- @field TERMKEY_FORMAT_ALTISMETA integer
  10. --- @field TERMKEY_FORMAT_CARETCTRL integer
  11. --- @field TERMKEY_FORMAT_LONGMOD integer
  12. --- @field TERMKEY_FORMAT_LOWERMOD integer
  13. --- @field TERMKEY_FORMAT_LOWERSPACE integer
  14. --- @field TERMKEY_FORMAT_MOUSE_POS integer
  15. --- @field TERMKEY_FORMAT_SPACEMOD integer
  16. --- @field TERMKEY_FORMAT_WRAPBRACKET integer
  17. --- @field TERMKEY_KEYMOD_ALT integer
  18. --- @field TERMKEY_KEYMOD_CTRL integer
  19. --- @field TERMKEY_MOUSE_DRAG integer
  20. --- @field TERMKEY_MOUSE_PRESS integer
  21. --- @field TERMKEY_MOUSE_RELEASE integer
  22. --- @field TERMKEY_RES_AGAIN integer
  23. --- @field TERMKEY_RES_KEY integer
  24. --- @field TERMKEY_RES_NONE integer
  25. --- @field TERMKEY_SYM_DOWN integer
  26. --- @field TERMKEY_SYM_PAGEUP integer
  27. --- @field TERMKEY_SYM_SPACE integer
  28. --- @field TERMKEY_SYM_UNKNOWN integer
  29. --- @field TERMKEY_SYM_UP integer
  30. --- @field TERMKEY_TYPE_DCS integer
  31. --- @field TERMKEY_TYPE_FUNCTION integer
  32. --- @field TERMKEY_TYPE_KEYSYM integer
  33. --- @field TERMKEY_TYPE_MODEREPORT integer
  34. --- @field TERMKEY_TYPE_MOUSE integer
  35. --- @field TERMKEY_TYPE_OSC integer
  36. --- @field TERMKEY_TYPE_POSITION integer
  37. --- @field TERMKEY_TYPE_UNICODE integer
  38. --- @field TERMKEY_TYPE_UNKNOWN_CSI integer
  39. --- @field termkey_canonicalise fun(any, any):any
  40. --- @field termkey_destroy fun(any)
  41. --- @field termkey_get_buffer_remaining fun(any):integer
  42. --- @field termkey_get_buffer_size fun(any):integer
  43. --- @field termkey_get_canonflags fun(any):any
  44. --- @field termkey_get_keyname fun(any, any):any
  45. --- @field termkey_getkey fun(any, any):any
  46. --- @field termkey_getkey_force fun(any, any):any
  47. --- @field termkey_interpret_csi fun(any, any, any, any, any):any
  48. --- @field termkey_interpret_modereport fun(any, any, any, any, any):any
  49. --- @field termkey_interpret_mouse fun(any, any, TermKeyKey, integer, integer, integer):any
  50. --- @field termkey_interpret_position fun(any, any, any, any):any
  51. --- @field termkey_interpret_string fun(any, TermKeyKey, any):any
  52. --- @field termkey_lookup_keyname fun(any, any, any):any
  53. --- @field termkey_new_abstract fun(string, integer):any
  54. --- @field termkey_push_bytes fun(any, string, integer):integer
  55. --- @field termkey_set_buffer_size fun(any, integer):integer
  56. --- @field termkey_set_canonflags fun(any, any):any
  57. --- @field termkey_set_flags fun(any, integer)
  58. --- @field termkey_start fun(any):integer
  59. --- @field termkey_stop fun(any):integer
  60. --- @field termkey_strfkey fun(any, string, integer, any, any):integer
  61. local termkey = t.cimport(
  62. './src/nvim/tui/termkey/termkey.h',
  63. './src/nvim/tui/termkey/termkey-internal.h',
  64. './src/nvim/tui/termkey/termkey_defs.h',
  65. './src/nvim/tui/termkey/driver-csi.h'
  66. )
  67. describe('termkey', function()
  68. itp('01base', function()
  69. local tk = termkey.termkey_new_abstract('vt100', 0)
  70. t.neq(tk, nil)
  71. t.eq(termkey.termkey_get_buffer_size(tk), 256)
  72. t.eq(tk.is_started, 1) -- tk->is_started true after construction
  73. termkey.termkey_stop(tk)
  74. t.neq(tk.is_started, 1) -- tk->is_started false after termkey_stop()
  75. termkey.termkey_start(tk)
  76. t.eq(tk.is_started, 1) -- tk->is_started true after termkey_start()
  77. termkey.termkey_destroy(tk)
  78. end)
  79. itp('02getkey', function()
  80. local tk = termkey.termkey_new_abstract('vt100', 0)
  81. local key = t.ffi.new('TermKeyKey') ---@type TermKeyKey
  82. t.eq(termkey.termkey_get_buffer_remaining(tk), 256) -- buffer free initially 256
  83. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_NONE) -- getkey yields RES_NONE when empty
  84. t.eq(termkey.termkey_push_bytes(tk, 'h', 1), 1) -- push_bytes returns 1
  85. t.eq(termkey.termkey_get_buffer_remaining(tk), 255) -- buffer free 255 after push_bytes
  86. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY after h
  87. t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type after h
  88. t.eq(key.code.codepoint, string.byte('h')) -- key.code.codepoint after h
  89. t.eq(key.modifiers, 0) -- key.modifiers after h
  90. t.eq(t.ffi.string(key.utf8), 'h') -- key.utf8 after h
  91. t.eq(termkey.termkey_get_buffer_remaining(tk), 256) -- buffer free 256 after getkey
  92. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_NONE) -- getkey yields RES_NONE a second time
  93. termkey.termkey_push_bytes(tk, '\x01', 1)
  94. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY after C-a
  95. t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type after C-a
  96. t.eq(key.code.codepoint, string.byte('a')) -- key.code.codepoint after C-a
  97. t.eq(key.modifiers, termkey.TERMKEY_KEYMOD_CTRL) -- key.modifiers after C-a
  98. termkey.termkey_push_bytes(tk, '\033OA', 3)
  99. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY after Up
  100. -- is_int(key.type, TERMKEY_TYPE_KEYSYM, "key.type after Up");
  101. -- is_int(key.code.sym, TERMKEY_SYM_UP, "key.code.sym after Up");
  102. t.eq(key.modifiers, 0) -- key.modifiers after Up
  103. t.eq(termkey.termkey_push_bytes(tk, '\033O', 2), 2) -- push_bytes returns 2
  104. -- is_int(termkey_get_buffer_remaining(tk), 254, "buffer free 254 after partial write");
  105. -- is_int(termkey_getkey(tk, &key), TERMKEY_RES_AGAIN, "getkey yields RES_AGAIN after partial write");
  106. termkey.termkey_push_bytes(tk, 'C', 1)
  107. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY after Right completion
  108. -- is_int(key.type, TERMKEY_TYPE_KEYSYM, "key.type after Right");
  109. -- is_int(key.code.sym, TERMKEY_SYM_RIGHT, "key.code.sym after Right");
  110. -- is_int(key.modifiers, 0, "key.modifiers after Right");
  111. -- is_int(termkey_get_buffer_remaining(tk), 256, "buffer free 256 after completion");
  112. termkey.termkey_push_bytes(tk, '\033[27;5u', 7)
  113. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY after Ctrl-Escape
  114. -- is_int(key.type, TERMKEY_TYPE_KEYSYM, "key.type after Ctrl-Escape");
  115. -- is_int(key.code.sym, TERMKEY_SYM_ESCAPE, "key.code.sym after Ctrl-Escape");
  116. -- is_int(key.modifiers, TERMKEY_KEYMOD_CTRL, "key.modifiers after Ctrl-Escape");
  117. termkey.termkey_push_bytes(tk, '\0', 1)
  118. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY after Ctrl-Space
  119. t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type after Ctrl-Space
  120. -- t.eq(key.code.codepoint, string.byte(' ')) -- key.code.codepoint after Ctrl-Space
  121. -- is_int(key.modifiers, TERMKEY_KEYMOD_CTRL, "key.modifiers after Ctrl-Space");
  122. termkey.termkey_destroy(tk)
  123. end)
  124. itp('03utf8', function()
  125. local tk = termkey.termkey_new_abstract('vt100', termkey.TERMKEY_FLAG_UTF8)
  126. local key = t.ffi.new('TermKeyKey') ---@type TermKeyKey
  127. termkey.termkey_push_bytes(tk, 'a', 1)
  128. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY low ASCII
  129. t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type low ASCII
  130. t.eq(key.code.codepoint, string.byte('a')) -- key.code.codepoint low ASCII
  131. -- 2-byte UTF-8 range is U+0080 to U+07FF (0xDF 0xBF)
  132. -- However, we'd best avoid the C1 range, so we'll start at U+00A0 (0xC2 0xA0)
  133. termkey.termkey_push_bytes(tk, '\xC2\xA0', 2)
  134. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 2 low
  135. t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type UTF-8 2 low
  136. t.eq(key.code.codepoint, 0x00A0) -- key.code.codepoint UTF-8 2 low
  137. termkey.termkey_push_bytes(tk, '\xDF\xBF', 2)
  138. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 2 high
  139. t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type UTF-8 2 high
  140. t.eq(key.code.codepoint, 0x07FF) -- key.code.codepoint UTF-8 2 high
  141. -- 3-byte UTF-8 range is U+0800 (0xE0 0xA0 0x80) to U+FFFD (0xEF 0xBF 0xBD)
  142. termkey.termkey_push_bytes(tk, '\xE0\xA0\x80', 3)
  143. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 3 low
  144. t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type UTF-8 3 low
  145. t.eq(key.code.codepoint, 0x0800) -- key.code.codepoint UTF-8 3 low
  146. termkey.termkey_push_bytes(tk, '\xEF\xBF\xBD', 3)
  147. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 3 high
  148. t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type UTF-8 3 high
  149. t.eq(key.code.codepoint, 0xFFFD) -- key.code.codepoint UTF-8 3 high
  150. -- 4-byte UTF-8 range is U+10000 (0xF0 0x90 0x80 0x80) to U+10FFFF (0xF4 0x8F 0xBF 0xBF)
  151. termkey.termkey_push_bytes(tk, '\xF0\x90\x80\x80', 4)
  152. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 4 low
  153. t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type UTF-8 4 low
  154. t.eq(key.code.codepoint, 0x10000) -- key.code.codepoint UTF-8 4 low
  155. termkey.termkey_push_bytes(tk, '\xF4\x8F\xBF\xBF', 4)
  156. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 4 high
  157. t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type UTF-8 4 high
  158. t.eq(key.code.codepoint, 0x10FFFF) -- key.code.codepoint UTF-8 4 high
  159. -- Invalid continuations
  160. termkey.termkey_push_bytes(tk, '\xC2!', 2)
  161. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 2 invalid cont
  162. t.eq(key.code.codepoint, 0xFFFD) -- key.code.codepoint UTF-8 2 invalid cont
  163. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 2 invalid after
  164. t.eq(key.code.codepoint, string.byte('!')) -- key.code.codepoint UTF-8 2 invalid after
  165. termkey.termkey_push_bytes(tk, '\xE0!', 2)
  166. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 3 invalid cont
  167. t.eq(key.code.codepoint, 0xFFFD) -- key.code.codepoint UTF-8 3 invalid cont
  168. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 3 invalid after
  169. t.eq(key.code.codepoint, string.byte('!')) -- key.code.codepoint UTF-8 3 invalid after
  170. termkey.termkey_push_bytes(tk, '\xE0\xA0!', 3)
  171. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 3 invalid cont 2
  172. t.eq(key.code.codepoint, 0xFFFD) -- key.code.codepoint UTF-8 3 invalid cont 2
  173. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 3 invalid after
  174. t.eq(key.code.codepoint, string.byte('!')) -- key.code.codepoint UTF-8 3 invalid after
  175. termkey.termkey_push_bytes(tk, '\xF0!', 2)
  176. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 4 invalid cont
  177. t.eq(key.code.codepoint, 0xFFFD) -- key.code.codepoint UTF-8 4 invalid cont
  178. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 4 invalid after
  179. t.eq(key.code.codepoint, string.byte('!')) -- key.code.codepoint UTF-8 4 invalid after
  180. termkey.termkey_push_bytes(tk, '\xF0\x90!', 3)
  181. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 4 invalid cont 2
  182. t.eq(key.code.codepoint, 0xFFFD) -- key.code.codepoint UTF-8 4 invalid cont 2
  183. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 4 invalid after
  184. t.eq(key.code.codepoint, string.byte('!')) -- key.code.codepoint UTF-8 4 invalid after
  185. termkey.termkey_push_bytes(tk, '\xF0\x90\x80!', 4)
  186. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 4 invalid cont 3
  187. t.eq(key.code.codepoint, 0xFFFD) -- key.code.codepoint UTF-8 4 invalid cont 3
  188. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 4 invalid after
  189. t.eq(key.code.codepoint, string.byte('!')) -- key.code.codepoint UTF-8 4 invalid after
  190. -- Partials
  191. termkey.termkey_push_bytes(tk, '\xC2', 1)
  192. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_AGAIN) -- getkey yields RES_AGAIN UTF-8 2 partial
  193. termkey.termkey_push_bytes(tk, '\xA0', 1)
  194. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 2 partial
  195. t.eq(key.code.codepoint, 0x00A0) -- key.code.codepoint UTF-8 2 partial
  196. termkey.termkey_push_bytes(tk, '\xE0', 1)
  197. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_AGAIN) -- getkey yields RES_AGAIN UTF-8 3 partial
  198. termkey.termkey_push_bytes(tk, '\xA0', 1)
  199. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_AGAIN) -- getkey yields RES_AGAIN UTF-8 3 partial
  200. termkey.termkey_push_bytes(tk, '\x80', 1)
  201. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 3 partial
  202. t.eq(key.code.codepoint, 0x0800) -- key.code.codepoint UTF-8 3 partial
  203. termkey.termkey_push_bytes(tk, '\xF0', 1)
  204. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_AGAIN) -- getkey yields RES_AGAIN UTF-8 4 partial
  205. termkey.termkey_push_bytes(tk, '\x90', 1)
  206. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_AGAIN) -- getkey yields RES_AGAIN UTF-8 4 partial
  207. termkey.termkey_push_bytes(tk, '\x80', 1)
  208. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_AGAIN) -- getkey yields RES_AGAIN UTF-8 4 partial
  209. termkey.termkey_push_bytes(tk, '\x80', 1)
  210. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY UTF-8 4 partial
  211. t.eq(key.code.codepoint, 0x10000) -- key.code.codepoint UTF-8 4 partial
  212. termkey.termkey_destroy(tk)
  213. end)
  214. itp('04flags', function()
  215. local tk = termkey.termkey_new_abstract('vt100', 0)
  216. local key = t.ffi.new('TermKeyKey') ---@type TermKeyKey
  217. termkey.termkey_push_bytes(tk, ' ', 1)
  218. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY after space
  219. t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type after space
  220. t.eq(key.code.codepoint, string.byte(' ')) -- key.code.codepoint after space
  221. t.eq(key.modifiers, 0) -- key.modifiers after space
  222. termkey.termkey_set_flags(tk, termkey.TERMKEY_FLAG_SPACESYMBOL)
  223. termkey.termkey_push_bytes(tk, ' ', 1)
  224. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY after space
  225. t.eq(key.type, termkey.TERMKEY_TYPE_KEYSYM) -- key.type after space with FLAG_SPACESYMBOL
  226. t.eq(key.code.sym, termkey.TERMKEY_SYM_SPACE) -- key.code.sym after space with FLAG_SPACESYMBOL
  227. t.eq(key.modifiers, 0) -- key.modifiers after space with FLAG_SPACESYMBOL
  228. termkey.termkey_destroy(tk)
  229. end)
  230. itp('06buffer', function()
  231. local tk = termkey.termkey_new_abstract('vt100', 0)
  232. local key = t.ffi.new('TermKeyKey') ---@type TermKeyKey
  233. t.eq(termkey.termkey_get_buffer_remaining(tk), 256) -- buffer free initially 256
  234. t.eq(termkey.termkey_get_buffer_size(tk), 256) -- buffer size initially 256
  235. t.eq(termkey.termkey_push_bytes(tk, 'h', 1), 1) -- push_bytes returns 1
  236. t.eq(termkey.termkey_get_buffer_remaining(tk), 255) -- buffer free 255 after push_bytes
  237. t.eq(termkey.termkey_get_buffer_size(tk), 256) -- buffer size 256 after push_bytes
  238. t.eq(not not termkey.termkey_set_buffer_size(tk, 512), true) -- buffer set size OK
  239. t.eq(termkey.termkey_get_buffer_remaining(tk), 511) -- buffer free 511 after push_bytes
  240. t.eq(termkey.termkey_get_buffer_size(tk), 512) -- buffer size 512 after push_bytes
  241. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- buffered key still usable after resize
  242. termkey.termkey_destroy(tk)
  243. end)
  244. local function termkey_keyname2sym(tk, keyname)
  245. local sym = t.ffi.new('TermKeySym[1]')
  246. local endp = termkey.termkey_lookup_keyname(tk, keyname, sym)
  247. if endp == nil then
  248. return termkey.TERMKEY_SYM_UNKNOWN
  249. end
  250. return sym
  251. end
  252. itp('10keyname', function()
  253. local tk = termkey.termkey_new_abstract('vt100', 0)
  254. local sym = termkey_keyname2sym(tk, 'SomeUnknownKey')
  255. t.eq(sym, termkey.TERMKEY_SYM_UNKNOWN) -- keyname2sym SomeUnknownKey
  256. sym = termkey_keyname2sym(tk, 'Space')
  257. t.eq(sym[0], termkey.TERMKEY_SYM_SPACE) -- keyname2sym Space
  258. local _end = termkey.termkey_lookup_keyname(tk, 'Up', sym)
  259. t.neq(_end, nil) -- termkey_get_keyname Up returns non-NULL
  260. t.eq(t.ffi.string(_end), '') -- termkey_get_keyname Up return points at endofstring
  261. t.eq(sym[0], termkey.TERMKEY_SYM_UP) -- termkey_get_keyname Up yields Up symbol
  262. _end = termkey.termkey_lookup_keyname(tk, 'DownMore', sym)
  263. t.neq(_end, nil) -- termkey_get_keyname DownMore returns non-NULL
  264. t.eq(t.ffi.string(_end), 'More') -- termkey_get_keyname DownMore return points at More
  265. t.eq(sym[0], termkey.TERMKEY_SYM_DOWN) -- termkey_get_keyname DownMore yields Down symbol
  266. _end = termkey.termkey_lookup_keyname(tk, 'SomeUnknownKey', sym)
  267. t.eq(_end, nil) -- termkey_get_keyname SomeUnknownKey returns NULL
  268. t.eq(t.ffi.string(termkey.termkey_get_keyname(tk, termkey.TERMKEY_SYM_SPACE)), 'Space') -- "get_keyname SPACE");
  269. termkey.termkey_destroy(tk)
  270. end)
  271. itp('11strfkey', function()
  272. local tk = termkey.termkey_new_abstract('vt100', 0)
  273. ---@type TermKeyKey
  274. local key = t.ffi.new(
  275. 'TermKeyKey',
  276. { type = termkey.TERMKEY_TYPE_UNICODE, code = { codepoint = string.byte('A') } }
  277. )
  278. local buffer = t.ffi.new('char[16]')
  279. local len = termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, 0)
  280. t.eq(len, 1) -- length for unicode/A/0
  281. t.eq(t.ffi.string(buffer), 'A') -- buffer for unicode/A/0
  282. len = termkey.termkey_strfkey(
  283. tk,
  284. buffer,
  285. t.ffi.sizeof(buffer),
  286. key,
  287. termkey.TERMKEY_FORMAT_WRAPBRACKET
  288. )
  289. t.eq(len, 1) -- length for unicode/A/0 wrapbracket
  290. t.eq(t.ffi.string(buffer), 'A') -- buffer for unicode/A/0 wrapbracket
  291. ---@type TermKeyKey
  292. key = t.ffi.new('TermKeyKey', {
  293. type = termkey.TERMKEY_TYPE_UNICODE,
  294. code = { codepoint = string.byte('b') },
  295. modifiers = termkey.TERMKEY_KEYMOD_CTRL,
  296. })
  297. len = termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, 0)
  298. t.eq(len, 3) -- length for unicode/b/CTRL
  299. t.eq(t.ffi.string(buffer), 'C-b') -- buffer for unicode/b/CTRL
  300. len =
  301. termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, termkey.TERMKEY_FORMAT_LONGMOD)
  302. t.eq(len, 6) -- length for unicode/b/CTRL longmod
  303. t.eq(t.ffi.string(buffer), 'Ctrl-b') -- buffer for unicode/b/CTRL longmod
  304. len = termkey.termkey_strfkey(
  305. tk,
  306. buffer,
  307. t.ffi.sizeof(buffer),
  308. key,
  309. bit.bor(termkey.TERMKEY_FORMAT_LONGMOD, termkey.TERMKEY_FORMAT_SPACEMOD)
  310. )
  311. t.eq(len, 6) -- length for unicode/b/CTRL longmod|spacemod
  312. t.eq(t.ffi.string(buffer), 'Ctrl b') -- buffer for unicode/b/CTRL longmod|spacemod
  313. len = termkey.termkey_strfkey(
  314. tk,
  315. buffer,
  316. t.ffi.sizeof(buffer),
  317. key,
  318. bit.bor(termkey.TERMKEY_FORMAT_LONGMOD, termkey.TERMKEY_FORMAT_LOWERMOD)
  319. )
  320. t.eq(len, 6) -- length for unicode/b/CTRL longmod|lowermod
  321. t.eq(t.ffi.string(buffer), 'ctrl-b') -- buffer for unicode/b/CTRL longmod|lowermod
  322. len = termkey.termkey_strfkey(
  323. tk,
  324. buffer,
  325. t.ffi.sizeof(buffer),
  326. key,
  327. bit.bor(
  328. termkey.TERMKEY_FORMAT_LONGMOD,
  329. termkey.TERMKEY_FORMAT_SPACEMOD,
  330. termkey.TERMKEY_FORMAT_LOWERMOD
  331. )
  332. )
  333. t.eq(len, 6) -- length for unicode/b/CTRL longmod|spacemod|lowermode
  334. t.eq(t.ffi.string(buffer), 'ctrl b') -- buffer for unicode/b/CTRL longmod|spacemod|lowermode
  335. len = termkey.termkey_strfkey(
  336. tk,
  337. buffer,
  338. t.ffi.sizeof(buffer),
  339. key,
  340. termkey.TERMKEY_FORMAT_CARETCTRL
  341. )
  342. t.eq(len, 2) -- length for unicode/b/CTRL caretctrl
  343. t.eq(t.ffi.string(buffer), '^B') -- buffer for unicode/b/CTRL caretctrl
  344. len = termkey.termkey_strfkey(
  345. tk,
  346. buffer,
  347. t.ffi.sizeof(buffer),
  348. key,
  349. termkey.TERMKEY_FORMAT_WRAPBRACKET
  350. )
  351. t.eq(len, 5) -- length for unicode/b/CTRL wrapbracket
  352. t.eq(t.ffi.string(buffer), '<C-b>') -- buffer for unicode/b/CTRL wrapbracket
  353. ---@type TermKeyKey
  354. key = t.ffi.new('TermKeyKey', {
  355. type = termkey.TERMKEY_TYPE_UNICODE,
  356. code = { codepoint = string.byte('c') },
  357. modifiers = termkey.TERMKEY_KEYMOD_ALT,
  358. })
  359. len = termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, 0)
  360. t.eq(len, 3) -- length for unicode/c/ALT
  361. t.eq(t.ffi.string(buffer), 'A-c') -- buffer for unicode/c/ALT
  362. len =
  363. termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, termkey.TERMKEY_FORMAT_LONGMOD)
  364. t.eq(len, 5) -- length for unicode/c/ALT longmod
  365. t.eq(t.ffi.string(buffer), 'Alt-c') -- buffer for unicode/c/ALT longmod
  366. len = termkey.termkey_strfkey(
  367. tk,
  368. buffer,
  369. t.ffi.sizeof(buffer),
  370. key,
  371. termkey.TERMKEY_FORMAT_ALTISMETA
  372. )
  373. t.eq(len, 3) -- length for unicode/c/ALT altismeta
  374. t.eq(t.ffi.string(buffer), 'M-c') -- buffer for unicode/c/ALT altismeta
  375. len = termkey.termkey_strfkey(
  376. tk,
  377. buffer,
  378. t.ffi.sizeof(buffer),
  379. key,
  380. bit.bor(termkey.TERMKEY_FORMAT_LONGMOD, termkey.TERMKEY_FORMAT_ALTISMETA)
  381. )
  382. t.eq(len, 6) -- length for unicode/c/ALT longmod|altismeta
  383. t.eq(t.ffi.string(buffer), 'Meta-c') -- buffer for unicode/c/ALT longmod|altismeta
  384. ---@type TermKeyKey
  385. key = t.ffi.new(
  386. 'TermKeyKey',
  387. { type = termkey.TERMKEY_TYPE_KEYSYM, code = { sym = termkey.TERMKEY_SYM_UP } }
  388. )
  389. len = termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, 0)
  390. t.eq(len, 2) -- length for sym/Up/0
  391. t.eq(t.ffi.string(buffer), 'Up') -- buffer for sym/Up/0
  392. len = termkey.termkey_strfkey(
  393. tk,
  394. buffer,
  395. t.ffi.sizeof(buffer),
  396. key,
  397. termkey.TERMKEY_FORMAT_WRAPBRACKET
  398. )
  399. t.eq(len, 4) -- length for sym/Up/0 wrapbracket
  400. t.eq(t.ffi.string(buffer), '<Up>') -- buffer for sym/Up/0 wrapbracket
  401. ---@type TermKeyKey
  402. key = t.ffi.new(
  403. 'TermKeyKey',
  404. { type = termkey.TERMKEY_TYPE_KEYSYM, code = { sym = termkey.TERMKEY_SYM_PAGEUP } }
  405. )
  406. len = termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, 0)
  407. t.eq(len, 6) -- length for sym/PageUp/0
  408. t.eq(t.ffi.string(buffer), 'PageUp') -- buffer for sym/PageUp/0
  409. len = termkey.termkey_strfkey(
  410. tk,
  411. buffer,
  412. t.ffi.sizeof(buffer),
  413. key,
  414. termkey.TERMKEY_FORMAT_LOWERSPACE
  415. )
  416. t.eq(len, 7) -- length for sym/PageUp/0 lowerspace
  417. t.eq(t.ffi.string(buffer), 'page up') -- buffer for sym/PageUp/0 lowerspace
  418. -- If size of buffer is too small, strfkey should return something consistent
  419. len = termkey.termkey_strfkey(tk, buffer, 4, key, 0)
  420. t.eq(len, 6) -- length for sym/PageUp/0
  421. t.eq(t.ffi.string(buffer), 'Pag') -- buffer of len 4 for sym/PageUp/0
  422. len = termkey.termkey_strfkey(tk, buffer, 4, key, termkey.TERMKEY_FORMAT_LOWERSPACE)
  423. t.eq(len, 7) -- length for sym/PageUp/0 lowerspace
  424. t.eq(t.ffi.string(buffer), 'pag') -- buffer of len 4 for sym/PageUp/0 lowerspace
  425. key = t.ffi.new('TermKeyKey', { type = termkey.TERMKEY_TYPE_FUNCTION, code = { number = 5 } }) ---@type TermKeyKey
  426. len = termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, 0)
  427. t.eq(len, 2) -- length for func/5/0
  428. t.eq(t.ffi.string(buffer), 'F5') -- buffer for func/5/0
  429. len = termkey.termkey_strfkey(
  430. tk,
  431. buffer,
  432. t.ffi.sizeof(buffer),
  433. key,
  434. termkey.TERMKEY_FORMAT_WRAPBRACKET
  435. )
  436. t.eq(len, 4) -- length for func/5/0 wrapbracket
  437. t.eq(t.ffi.string(buffer), '<F5>') -- buffer for func/5/0 wrapbracket
  438. len = termkey.termkey_strfkey(
  439. tk,
  440. buffer,
  441. t.ffi.sizeof(buffer),
  442. key,
  443. termkey.TERMKEY_FORMAT_LOWERSPACE
  444. )
  445. t.eq(len, 2) -- length for func/5/0 lowerspace
  446. t.eq(t.ffi.string(buffer), 'f5') -- buffer for func/5/0 lowerspace
  447. termkey.termkey_destroy(tk)
  448. end)
  449. itp('13cmpkey', function()
  450. local function termkey_keycmp(tk, key1, key2)
  451. termkey.termkey_canonicalise(tk, key1)
  452. termkey.termkey_canonicalise(tk, key2)
  453. if key1.type ~= key2.type then
  454. return key1.type - key2.type
  455. end
  456. if key1.type == termkey.TERMKEY_TYPE_UNICODE then
  457. if key1.code.codepoint ~= key2.code.codepoint then
  458. return key1.code.codepoint - key2.code.codepoint
  459. end
  460. end
  461. return key1.modifiers - key2.modifiers
  462. end
  463. local tk = termkey.termkey_new_abstract('vt100', 0)
  464. ---@type TermKeyKey
  465. local key1 = t.ffi.new('TermKeyKey', {
  466. type = termkey.TERMKEY_TYPE_UNICODE,
  467. code = { codepoint = string.byte('A') },
  468. modifiers = 0,
  469. })
  470. ---@type TermKeyKey
  471. local key2 = t.ffi.new('TermKeyKey', {
  472. type = termkey.TERMKEY_TYPE_UNICODE,
  473. code = { codepoint = string.byte('A') },
  474. modifiers = 0,
  475. })
  476. t.eq(termkey_keycmp(tk, key1, key1), 0) -- cmpkey same structure
  477. t.eq(termkey_keycmp(tk, key1, key2), 0) -- cmpkey identical structure
  478. key2.modifiers = termkey.TERMKEY_KEYMOD_CTRL
  479. t.eq(termkey_keycmp(tk, key1, key2) < 0, true) -- cmpkey orders CTRL after nomod
  480. t.eq(termkey_keycmp(tk, key2, key1) > 0, true) -- cmpkey orders nomod before CTRL
  481. key2.code.codepoint = string.byte('B')
  482. key2.modifiers = 0
  483. t.eq(termkey_keycmp(tk, key1, key2) < 0, true) -- cmpkey orders 'B' after 'A'
  484. t.eq(termkey_keycmp(tk, key2, key1) > 0, true) -- cmpkey orders 'A' before 'B'
  485. key1.modifiers = termkey.TERMKEY_KEYMOD_CTRL
  486. t.eq(termkey_keycmp(tk, key1, key2) < 0, true) -- cmpkey orders nomod 'B' after CTRL 'A'
  487. t.eq(termkey_keycmp(tk, key2, key1) > 0, true) -- cmpkey orders CTRL 'A' before nomod 'B'
  488. key2.type = termkey.TERMKEY_TYPE_KEYSYM
  489. key2.code.sym = termkey.TERMKEY_SYM_UP
  490. t.eq(termkey_keycmp(tk, key1, key2) < 0, true) -- cmpkey orders KEYSYM after UNICODE
  491. t.eq(termkey_keycmp(tk, key2, key1) > 0, true) -- cmpkey orders UNICODE before KEYSYM
  492. key1.type = termkey.TERMKEY_TYPE_KEYSYM
  493. key1.code.sym = termkey.TERMKEY_SYM_SPACE
  494. key1.modifiers = 0
  495. key2.type = termkey.TERMKEY_TYPE_UNICODE
  496. key2.code.codepoint = string.byte(' ')
  497. key2.modifiers = 0
  498. t.eq(termkey_keycmp(tk, key1, key2), 0) -- cmpkey considers KEYSYM/SPACE and UNICODE/SP identical
  499. termkey.termkey_set_canonflags(
  500. tk,
  501. bit.bor(termkey.termkey_get_canonflags(tk), termkey.TERMKEY_CANON_SPACESYMBOL)
  502. )
  503. t.eq(termkey_keycmp(tk, key1, key2), 0) -- "cmpkey considers KEYSYM/SPACE and UNICODE/SP identical under SPACESYMBOL");
  504. termkey.termkey_destroy(tk)
  505. end)
  506. itp('30mouse', function()
  507. local tk = termkey.termkey_new_abstract('vt100', 0)
  508. local key = t.ffi.new('TermKeyKey', { type = -1 }) ---@type TermKeyKey
  509. local ev = t.ffi.new('TermKeyMouseEvent[1]')
  510. local button = t.ffi.new('int[1]')
  511. local line = t.ffi.new('int[1]')
  512. local col = t.ffi.new('int[1]')
  513. local buffer = t.ffi.new('char[32]')
  514. termkey.termkey_push_bytes(tk, '\x1b[M !!', 6)
  515. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for mouse press
  516. t.eq(key.type, termkey.TERMKEY_TYPE_MOUSE) -- key.type for mouse press
  517. t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY
  518. t.eq(ev[0], termkey.TERMKEY_MOUSE_PRESS) -- mouse event for press
  519. t.eq(button[0], 1) -- mouse button for press
  520. t.eq(line[0], 1) -- mouse line for press
  521. t.eq(col[0], 1) -- mouse column for press
  522. t.eq(key.modifiers, 0) -- modifiers for press
  523. local len = termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, 0)
  524. t.eq(len, 13) -- string length for press
  525. t.eq(t.ffi.string(buffer), 'MousePress(1)') -- string buffer for press
  526. len = termkey.termkey_strfkey(
  527. tk,
  528. buffer,
  529. t.ffi.sizeof(buffer),
  530. key,
  531. termkey.TERMKEY_FORMAT_MOUSE_POS
  532. )
  533. t.eq(len, 21) -- string length for press
  534. t.eq(t.ffi.string(buffer), 'MousePress(1) @ (1,1)') -- string buffer for press
  535. termkey.termkey_push_bytes(tk, '\x1b[M@"!', 6)
  536. termkey.termkey_getkey(tk, key)
  537. t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY
  538. t.eq(ev[0], termkey.TERMKEY_MOUSE_DRAG) -- mouse event for drag
  539. t.eq(button[0], 1) -- mouse button for drag
  540. t.eq(line[0], 1) -- mouse line for drag
  541. t.eq(col[0], 2) -- mouse column for drag
  542. t.eq(key.modifiers, 0) -- modifiers for press
  543. termkey.termkey_push_bytes(tk, '\x1b[M##!', 6)
  544. termkey.termkey_getkey(tk, key)
  545. t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY
  546. t.eq(ev[0], termkey.TERMKEY_MOUSE_RELEASE) -- mouse event for release
  547. t.eq(line[0], 1) -- mouse line for release
  548. t.eq(col[0], 3) -- mouse column for release
  549. t.eq(key.modifiers, 0) -- modifiers for press
  550. termkey.termkey_push_bytes(tk, '\x1b[M0++', 6)
  551. termkey.termkey_getkey(tk, key)
  552. t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY
  553. t.eq(ev[0], termkey.TERMKEY_MOUSE_PRESS) -- mouse event for Ctrl-press
  554. t.eq(button[0], 1) -- mouse button for Ctrl-press
  555. t.eq(line[0], 11) -- mouse line for Ctrl-press
  556. t.eq(col[0], 11) -- mouse column for Ctrl-press
  557. t.eq(key.modifiers, termkey.TERMKEY_KEYMOD_CTRL) -- modifiers for Ctrl-press
  558. len = termkey.termkey_strfkey(tk, buffer, t.ffi.sizeof(buffer), key, 0)
  559. t.eq(len, 15) -- string length for Ctrl-press
  560. t.eq(t.ffi.string(buffer), 'C-MousePress(1)') -- string buffer for Ctrl-press
  561. termkey.termkey_push_bytes(tk, '\x1b[M`!!', 6)
  562. termkey.termkey_getkey(tk, key)
  563. t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY
  564. t.eq(ev[0], termkey.TERMKEY_MOUSE_PRESS) -- mouse event for wheel down
  565. t.eq(button[0], 4) -- mouse button for wheel down
  566. termkey.termkey_push_bytes(tk, '\x1b[Mb!!', 6)
  567. termkey.termkey_getkey(tk, key)
  568. t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY
  569. t.eq(ev[0], termkey.TERMKEY_MOUSE_PRESS) -- mouse event for wheel left
  570. t.eq(button[0], 6) -- mouse button for wheel left
  571. -- rxvt protocol
  572. termkey.termkey_push_bytes(tk, '\x1b[0;20;20M', 10)
  573. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for mouse press rxvt protocol
  574. t.eq(key.type, termkey.TERMKEY_TYPE_MOUSE) -- key.type for mouse press rxvt protocol
  575. t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY
  576. t.eq(ev[0], termkey.TERMKEY_MOUSE_PRESS) -- mouse event for press rxvt protocol
  577. t.eq(button[0], 1) -- mouse button for press rxvt protocol
  578. t.eq(line[0], 20) -- mouse line for press rxvt protocol
  579. t.eq(col[0], 20) -- mouse column for press rxvt protocol
  580. t.eq(key.modifiers, 0) -- modifiers for press rxvt protocol
  581. termkey.termkey_push_bytes(tk, '\x1b[3;20;20M', 10)
  582. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for mouse release rxvt protocol
  583. t.eq(key.type, termkey.TERMKEY_TYPE_MOUSE) -- key.type for mouse release rxvt protocol
  584. t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY
  585. t.eq(ev[0], termkey.TERMKEY_MOUSE_RELEASE) -- mouse event for release rxvt protocol
  586. t.eq(line[0], 20) -- mouse line for release rxvt protocol
  587. t.eq(col[0], 20) -- mouse column for release rxvt protocol
  588. t.eq(key.modifiers, 0) -- modifiers for release rxvt protocol
  589. -- SGR protocol
  590. termkey.termkey_push_bytes(tk, '\x1b[<0;30;30M', 11)
  591. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for mouse press SGR encoding
  592. t.eq(key.type, termkey.TERMKEY_TYPE_MOUSE) -- key.type for mouse press SGR encoding
  593. t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY
  594. t.eq(ev[0], termkey.TERMKEY_MOUSE_PRESS) -- mouse event for press SGR
  595. t.eq(button[0], 1) -- mouse button for press SGR
  596. t.eq(line[0], 30) -- mouse line for press SGR
  597. t.eq(col[0], 30) -- mouse column for press SGR
  598. t.eq(key.modifiers, 0) -- modifiers for press SGR
  599. termkey.termkey_push_bytes(tk, '\x1b[<0;30;30m', 11)
  600. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for mouse release SGR encoding
  601. t.eq(key.type, termkey.TERMKEY_TYPE_MOUSE) -- key.type for mouse release SGR encoding
  602. t.eq(termkey.termkey_interpret_mouse(tk, key, ev, button, line, col), termkey.TERMKEY_RES_KEY) -- interpret_mouse yields RES_KEY
  603. t.eq(ev[0], termkey.TERMKEY_MOUSE_RELEASE) -- mouse event for release SGR
  604. termkey.termkey_push_bytes(tk, '\x1b[<0;500;300M', 13)
  605. termkey.termkey_getkey(tk, key)
  606. termkey.termkey_interpret_mouse(tk, key, ev, button, line, col)
  607. t.eq(line[0], 300) -- mouse line for press SGR wide
  608. t.eq(col[0], 500) -- mouse column for press SGR wide
  609. termkey.termkey_destroy(tk)
  610. end)
  611. itp('31position', function()
  612. local tk = termkey.termkey_new_abstract('vt100', 0)
  613. local key = t.ffi.new('TermKeyKey') ---@type TermKeyKey
  614. local line = t.ffi.new('int[1]')
  615. local col = t.ffi.new('int[1]')
  616. termkey.termkey_push_bytes(tk, '\x1b[?15;7R', 8)
  617. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for position report
  618. t.eq(key.type, termkey.TERMKEY_TYPE_POSITION) -- key.type for position report
  619. t.eq(termkey.termkey_interpret_position(tk, key, line, col), termkey.TERMKEY_RES_KEY) -- interpret_position yields RES_KEY
  620. t.eq(line[0], 15) -- line for position report
  621. t.eq(col[0], 7) -- column for position report
  622. -- A plain CSI R is likely to be <F3> though.
  623. -- This is tricky :/
  624. termkey.termkey_push_bytes(tk, '\x1b[R', 3)
  625. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for <F3>
  626. t.eq(key.type, termkey.TERMKEY_TYPE_FUNCTION) -- key.type for <F3>
  627. t.eq(key.code.number, 3) -- key.code.number for <F3>
  628. termkey.termkey_destroy(tk)
  629. end)
  630. itp('32modereport', function()
  631. local tk = termkey.termkey_new_abstract('vt100', 0)
  632. local key = t.ffi.new('TermKeyKey') ---@type TermKeyKey
  633. local initial = t.ffi.new('int[1]')
  634. local mode = t.ffi.new('int[1]')
  635. local value = t.ffi.new('int[1]')
  636. termkey.termkey_push_bytes(tk, '\x1b[?1;2$y', 8)
  637. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for mode report
  638. t.eq(key.type, termkey.TERMKEY_TYPE_MODEREPORT) -- key.type for mode report
  639. t.eq(
  640. termkey.termkey_interpret_modereport(tk, key, initial, mode, value),
  641. termkey.TERMKEY_RES_KEY
  642. ) -- interpret_modereoprt yields RES_KEY
  643. t.eq(initial[0], 63) -- initial indicator from mode report
  644. t.eq(mode[0], 1) -- mode number from mode report
  645. t.eq(value[0], 2) -- mode value from mode report
  646. termkey.termkey_push_bytes(tk, '\x1b[4;1$y', 7)
  647. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for mode report
  648. t.eq(key.type, termkey.TERMKEY_TYPE_MODEREPORT) -- key.type for mode report
  649. t.eq(
  650. termkey.termkey_interpret_modereport(tk, key, initial, mode, value),
  651. termkey.TERMKEY_RES_KEY
  652. ) -- interpret_modereoprt yields RES_KEY
  653. t.eq(initial[0], 0) -- initial indicator from mode report
  654. t.eq(mode[0], 4) -- mode number from mode report
  655. t.eq(value[0], 1) -- mode value from mode report
  656. termkey.termkey_destroy(tk)
  657. end)
  658. itp('38csi', function()
  659. local tk = termkey.termkey_new_abstract('vt100', 0)
  660. local key = t.ffi.new('TermKeyKey') ---@type TermKeyKey
  661. local args = t.ffi.new('TermKeyCsiParam[16]')
  662. local nargs = t.ffi.new('size_t[1]')
  663. local command = t.ffi.new('unsigned[1]')
  664. termkey.termkey_push_bytes(tk, '\x1b[5;25v', 7)
  665. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for CSI v
  666. t.eq(key.type, termkey.TERMKEY_TYPE_UNKNOWN_CSI) -- key.type for unknown CSI
  667. t.eq(termkey.termkey_interpret_csi(tk, key, args, nargs, command), termkey.TERMKEY_RES_KEY) -- interpret_csi yields RES_KEY
  668. t.eq(nargs[0], 2) -- nargs for unknown CSI
  669. -- t.eq(args[0], 5) -- args[0] for unknown CSI
  670. -- t.eq(args[1], 25) -- args[1] for unknown CSI
  671. t.eq(command[0], 118) -- command for unknown CSI
  672. termkey.termkey_push_bytes(tk, '\x1b[?w', 4)
  673. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for CSI ? w
  674. t.eq(key.type, termkey.TERMKEY_TYPE_UNKNOWN_CSI) -- key.type for unknown CSI
  675. t.eq(termkey.termkey_interpret_csi(tk, key, args, nargs, command), termkey.TERMKEY_RES_KEY) -- interpret_csi yields RES_KEY
  676. t.eq(command[0], bit.bor(bit.lshift(63, 8), 119)) -- command for unknown CSI
  677. termkey.termkey_push_bytes(tk, '\x1b[?$x', 5)
  678. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for CSI ? $x
  679. t.eq(key.type, termkey.TERMKEY_TYPE_UNKNOWN_CSI) -- key.type for unknown CSI
  680. t.eq(termkey.termkey_interpret_csi(tk, key, args, nargs, command), termkey.TERMKEY_RES_KEY) -- interpret_csi yields RES_KEY
  681. t.eq(command[0], bit.bor(bit.lshift(36, 16), bit.lshift(63, 8), 120)) -- command for unknown CSI
  682. termkey.termkey_destroy(tk)
  683. end)
  684. itp('39dcs', function()
  685. local tk = termkey.termkey_new_abstract('xterm', 0)
  686. local key = t.ffi.new('TermKeyKey') ---@type TermKeyKey
  687. -- 7bit DCS
  688. termkey.termkey_push_bytes(tk, '\x1bP1$r1 q\x1b\\', 10)
  689. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for DCS
  690. t.eq(key.type, termkey.TERMKEY_TYPE_DCS) -- key.type for DCS
  691. t.eq(key.modifiers, 0) -- key.modifiers for DCS
  692. local str = t.ffi.new('const char*[1]')
  693. t.eq(termkey.termkey_interpret_string(tk, key, str), termkey.TERMKEY_RES_KEY) -- termkey_interpret_string() gives string
  694. t.eq(t.ffi.string(str[0]), '1$r1 q') -- termkey_interpret_string() yields correct string
  695. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_NONE) -- getkey again yields RES_NONE
  696. -- 8bit DCS
  697. termkey.termkey_push_bytes(tk, '\x901$r2 q\x9c', 8)
  698. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for DCS
  699. t.eq(key.type, termkey.TERMKEY_TYPE_DCS) -- key.type for DCS
  700. t.eq(key.modifiers, 0) -- key.modifiers for DCS
  701. t.eq(termkey.termkey_interpret_string(tk, key, str), termkey.TERMKEY_RES_KEY) -- "termkey_interpret_string() gives string");
  702. t.eq(t.ffi.string(str[0]), '1$r2 q') -- "termkey_interpret_string() yields correct string");
  703. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_NONE) -- "getkey again yields RES_NONE");
  704. -- 7bit OSC
  705. termkey.termkey_push_bytes(tk, '\x1b]15;abc\x1b\\', 10)
  706. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_KEY) -- getkey yields RES_KEY for OSC
  707. t.eq(key.type, termkey.TERMKEY_TYPE_OSC) -- key.type for OSC
  708. t.eq(key.modifiers, 0) -- key.modifiers for OSC
  709. t.eq(termkey.termkey_interpret_string(tk, key, str), termkey.TERMKEY_RES_KEY) -- "termkey_interpret_string() gives string");
  710. t.eq(t.ffi.string(str[0]), '15;abc') -- "termkey_interpret_string() yields correct string");
  711. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_NONE) -- getkey again yields RES_NONE
  712. -- False alarm
  713. termkey.termkey_push_bytes(tk, '\x1bP', 2)
  714. t.eq(termkey.termkey_getkey(tk, key), termkey.TERMKEY_RES_AGAIN) -- getkey yields RES_AGAIN for false alarm
  715. t.eq(termkey.termkey_getkey_force(tk, key), termkey.TERMKEY_RES_KEY) -- getkey_force yields RES_KEY for false alarm
  716. t.eq(key.type, termkey.TERMKEY_TYPE_UNICODE) -- key.type for false alarm
  717. t.eq(key.code.codepoint, string.byte('P')) -- key.code.codepoint for false alarm
  718. t.eq(key.modifiers, termkey.TERMKEY_KEYMOD_ALT) -- key.modifiers for false alarm
  719. termkey.termkey_destroy(tk)
  720. end)
  721. end)