Add tests for key mapping
Also fix Alt+Special keys no generating correct codes
This commit is contained in:
parent
5525d4db49
commit
08f336769f
@ -7,7 +7,28 @@ from .terminfo import key_as_bytes
|
|||||||
from .utils import base64_encode
|
from .utils import base64_encode
|
||||||
from .key_encoding import KEY_MAP
|
from .key_encoding import KEY_MAP
|
||||||
|
|
||||||
smkx_key_map = {
|
|
||||||
|
def modify_key_bytes(keybytes, amt):
|
||||||
|
ans = bytearray(keybytes)
|
||||||
|
amt = str(amt).encode('ascii')
|
||||||
|
if ans[-1] == ord('~'):
|
||||||
|
return bytes(ans[:-1] + bytearray(b';' + amt + b'~'))
|
||||||
|
if ans[1] == ord('O'):
|
||||||
|
return bytes(ans[:1] + bytearray(b'[1;' + amt) + ans[-1:])
|
||||||
|
raise ValueError('Unknown key type')
|
||||||
|
|
||||||
|
|
||||||
|
def modify_complex_key(name, amt):
|
||||||
|
return modify_key_bytes(key_as_bytes(name), amt)
|
||||||
|
|
||||||
|
|
||||||
|
control_codes = {}
|
||||||
|
smkx_key_map = {}
|
||||||
|
alt_codes = {defines.GLFW_KEY_TAB: b'\033\t'}
|
||||||
|
shift_alt_codes = {defines.GLFW_KEY_TAB: key_as_bytes('kcbt')}
|
||||||
|
alt_mods = (defines.GLFW_MOD_ALT, defines.GLFW_MOD_SHIFT | defines.GLFW_MOD_ALT)
|
||||||
|
|
||||||
|
for kf, kn in {
|
||||||
defines.GLFW_KEY_UP: 'kcuu1',
|
defines.GLFW_KEY_UP: 'kcuu1',
|
||||||
defines.GLFW_KEY_DOWN: 'kcud1',
|
defines.GLFW_KEY_DOWN: 'kcud1',
|
||||||
defines.GLFW_KEY_LEFT: 'kcub1',
|
defines.GLFW_KEY_LEFT: 'kcub1',
|
||||||
@ -18,12 +39,19 @@ smkx_key_map = {
|
|||||||
defines.GLFW_KEY_DELETE: 'kdch1',
|
defines.GLFW_KEY_DELETE: 'kdch1',
|
||||||
defines.GLFW_KEY_PAGE_UP: 'kpp',
|
defines.GLFW_KEY_PAGE_UP: 'kpp',
|
||||||
defines.GLFW_KEY_PAGE_DOWN: 'knp',
|
defines.GLFW_KEY_PAGE_DOWN: 'knp',
|
||||||
}
|
}.items():
|
||||||
smkx_key_map = {k: key_as_bytes(v) for k, v in smkx_key_map.items()}
|
smkx_key_map[kf] = key_as_bytes(kn)
|
||||||
|
alt_codes[kf] = modify_complex_key(kn, 3)
|
||||||
|
shift_alt_codes[kf] = modify_complex_key(kn, 4)
|
||||||
|
control_codes[kf] = modify_complex_key(kn, 5)
|
||||||
for f in range(1, 13):
|
for f in range(1, 13):
|
||||||
kf = getattr(defines, 'GLFW_KEY_F{}'.format(f))
|
kf = getattr(defines, 'GLFW_KEY_F{}'.format(f))
|
||||||
smkx_key_map[kf] = key_as_bytes('kf{}'.format(f))
|
kn = 'kf{}'.format(f)
|
||||||
del f, kf
|
smkx_key_map[kf] = key_as_bytes(kn)
|
||||||
|
alt_codes[kf] = modify_complex_key(kn, 3)
|
||||||
|
shift_alt_codes[kf] = modify_complex_key(kn, 4)
|
||||||
|
control_codes[kf] = modify_complex_key(kn, 5)
|
||||||
|
del f, kf, kn
|
||||||
|
|
||||||
smkx_key_map[defines.GLFW_KEY_ESCAPE] = b'\033'
|
smkx_key_map[defines.GLFW_KEY_ESCAPE] = b'\033'
|
||||||
smkx_key_map[defines.GLFW_KEY_ENTER] = b'\r'
|
smkx_key_map[defines.GLFW_KEY_ENTER] = b'\r'
|
||||||
@ -39,28 +67,13 @@ SHIFTED_KEYS = {
|
|||||||
defines.GLFW_KEY_RIGHT: key_as_bytes('kRIT'),
|
defines.GLFW_KEY_RIGHT: key_as_bytes('kRIT'),
|
||||||
}
|
}
|
||||||
|
|
||||||
control_codes = {
|
control_codes.update({
|
||||||
k: (1 + i, )
|
k: (1 + i, )
|
||||||
for i, k in
|
for i, k in
|
||||||
enumerate(range(defines.GLFW_KEY_A, defines.GLFW_KEY_RIGHT_BRACKET + 1))
|
enumerate(range(defines.GLFW_KEY_A, defines.GLFW_KEY_RIGHT_BRACKET + 1))
|
||||||
}
|
})
|
||||||
|
|
||||||
|
|
||||||
def rkey(name, a, b):
|
|
||||||
return bytearray(key_as_bytes(name).replace(a, b))
|
|
||||||
|
|
||||||
|
|
||||||
control_codes[defines.GLFW_KEY_PAGE_UP] = rkey('kpp', b'~', b';5~')
|
|
||||||
control_codes[defines.GLFW_KEY_PAGE_DOWN] = rkey('knp', b'~', b';5~')
|
|
||||||
control_codes[defines.GLFW_KEY_DELETE] = rkey('kdch1', b'~', b';5~')
|
|
||||||
alt_codes = {
|
|
||||||
k: (0x1b, k)
|
|
||||||
for i, k in enumerate(
|
|
||||||
range(defines.GLFW_KEY_SPACE, defines.GLFW_KEY_RIGHT_BRACKET + 1)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
alt_mods = (defines.GLFW_MOD_ALT, defines.GLFW_MOD_SHIFT | defines.GLFW_MOD_ALT)
|
|
||||||
|
|
||||||
rmkx_key_map = smkx_key_map.copy()
|
rmkx_key_map = smkx_key_map.copy()
|
||||||
rmkx_key_map.update({
|
rmkx_key_map.update({
|
||||||
defines.GLFW_KEY_UP: b'\033[A',
|
defines.GLFW_KEY_UP: b'\033[A',
|
||||||
@ -70,9 +83,6 @@ rmkx_key_map.update({
|
|||||||
defines.GLFW_KEY_HOME: b'\033[H',
|
defines.GLFW_KEY_HOME: b'\033[H',
|
||||||
defines.GLFW_KEY_END: b'\033[F',
|
defines.GLFW_KEY_END: b'\033[F',
|
||||||
})
|
})
|
||||||
for sk in 'UP DOWN LEFT RIGHT HOME END'.split():
|
|
||||||
sk = getattr(defines, 'GLFW_KEY_' + sk)
|
|
||||||
control_codes[sk] = rmkx_key_map[sk].replace(b'[', b'[1;5')
|
|
||||||
|
|
||||||
cursor_key_mode_map = {True: smkx_key_map, False: rmkx_key_map}
|
cursor_key_mode_map = {True: smkx_key_map, False: rmkx_key_map}
|
||||||
|
|
||||||
@ -132,7 +142,7 @@ def extended_key_event(key, scancode, mods, action):
|
|||||||
).encode('ascii')
|
).encode('ascii')
|
||||||
|
|
||||||
|
|
||||||
def interpret_key_event(key, scancode, mods, window, action):
|
def interpret_key_event(key, scancode, mods, window, action, get_localized_key=get_localized_key):
|
||||||
screen = window.screen
|
screen = window.screen
|
||||||
key = get_localized_key(key, scancode)
|
key = get_localized_key(key, scancode)
|
||||||
if screen.extended_keyboard:
|
if screen.extended_keyboard:
|
||||||
@ -145,8 +155,8 @@ def interpret_key_event(key, scancode, mods, window, action):
|
|||||||
# Map Ctrl-key to ascii control code
|
# Map Ctrl-key to ascii control code
|
||||||
data.extend(control_codes[key])
|
data.extend(control_codes[key])
|
||||||
elif mods in alt_mods and key in alt_codes:
|
elif mods in alt_mods and key in alt_codes:
|
||||||
# Handled by interpret text event
|
# Printable keys handled by interpret_text_event()
|
||||||
pass
|
data.extend((alt_codes if mods == defines.GLFW_MOD_ALT else shift_alt_codes)[key])
|
||||||
else:
|
else:
|
||||||
key_map = get_key_map(screen)
|
key_map = get_key_map(screen)
|
||||||
x = key_map.get(key)
|
x = key_map.get(key)
|
||||||
|
|||||||
81
kitty_tests/keys.py
Normal file
81
kitty_tests/keys.py
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=utf-8
|
||||||
|
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
|
import kitty.fast_data_types as defines
|
||||||
|
from kitty.keys import (
|
||||||
|
interpret_key_event, modify_complex_key, modify_key_bytes, smkx_key_map
|
||||||
|
)
|
||||||
|
|
||||||
|
from . import BaseTest
|
||||||
|
|
||||||
|
|
||||||
|
class DummyWindow:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.screen = self
|
||||||
|
self.extended_keyboard = False
|
||||||
|
self.cursor_key_mode = True
|
||||||
|
|
||||||
|
|
||||||
|
class TestParser(BaseTest):
|
||||||
|
|
||||||
|
def test_modify_complex_key(self):
|
||||||
|
self.ae(modify_complex_key('kcuu1', 4), b'\033[1;4A')
|
||||||
|
self.ae(modify_complex_key('kcuu1', 3), b'\033[1;3A')
|
||||||
|
self.ae(modify_complex_key('kf5', 3), b'\033[15;3~')
|
||||||
|
self.assertRaises(ValueError, modify_complex_key, 'kri', 3)
|
||||||
|
|
||||||
|
def test_interpret_key_event(self):
|
||||||
|
# test rmkx/smkx
|
||||||
|
w = DummyWindow()
|
||||||
|
|
||||||
|
def k(expected, key, mods=0):
|
||||||
|
actual = interpret_key_event(
|
||||||
|
getattr(defines, 'GLFW_KEY_' + key),
|
||||||
|
0,
|
||||||
|
mods,
|
||||||
|
w,
|
||||||
|
defines.GLFW_PRESS,
|
||||||
|
get_localized_key=lambda k, s: k
|
||||||
|
)
|
||||||
|
self.ae(b'\033' + expected.encode('ascii'), actual)
|
||||||
|
|
||||||
|
for ckm, mch in {True: 'O', False: '['}.items():
|
||||||
|
w.cursor_key_mode = ckm
|
||||||
|
for name, ch in {
|
||||||
|
'UP': 'A',
|
||||||
|
'DOWN': 'B',
|
||||||
|
'RIGHT': 'C',
|
||||||
|
'LEFT': 'D',
|
||||||
|
'HOME': 'H',
|
||||||
|
'END': 'F',
|
||||||
|
}.items():
|
||||||
|
k(mch + ch, name)
|
||||||
|
w.cursor_key_mode = True
|
||||||
|
|
||||||
|
# test remaining special keys
|
||||||
|
for key, num in zip('INSERT DELETE PAGE_UP PAGE_DOWN'.split(), '2356'):
|
||||||
|
k('[' + num + '~', key)
|
||||||
|
for key, num in zip('1234', 'PQRS'):
|
||||||
|
k('O' + num, 'F' + key)
|
||||||
|
for key, num in zip(range(5, 13), (15, 17, 18, 19, 20, 21, 23, 24)):
|
||||||
|
k('[' + str(num) + '~', 'F{}'.format(key))
|
||||||
|
|
||||||
|
# test modifiers
|
||||||
|
SPECIAL_KEYS = 'UP DOWN RIGHT LEFT HOME END INSERT DELETE PAGE_UP PAGE_DOWN '
|
||||||
|
for i in range(1, 13):
|
||||||
|
SPECIAL_KEYS += 'F{} '.format(i)
|
||||||
|
SPECIAL_KEYS = SPECIAL_KEYS.strip().split()
|
||||||
|
for mods, num in zip(('CONTROL', 'ALT', 'SHIFT+ALT'), '534'):
|
||||||
|
fmods = 0
|
||||||
|
num = int(num)
|
||||||
|
for m in mods.split('+'):
|
||||||
|
fmods |= getattr(defines, 'GLFW_MOD_' + m)
|
||||||
|
km = partial(k, mods=fmods)
|
||||||
|
for key in SPECIAL_KEYS:
|
||||||
|
keycode = getattr(defines, 'GLFW_KEY_' + key)
|
||||||
|
base_key = smkx_key_map[keycode]
|
||||||
|
km(modify_key_bytes(base_key, num).decode('ascii')[1:], key)
|
||||||
Loading…
x
Reference in New Issue
Block a user