kitty/kitty/key_encoding.py
2020-10-12 23:03:07 +05:30

506 lines
9.7 KiB
Python
Generated

#!/usr/bin/env python3
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
import string
from typing import Dict, NamedTuple, Optional
from . import fast_data_types as defines
from .key_names import key_name_aliases
# ENCODING {{{
ENCODING = {
'0': 'G',
'1': 'H',
'2': 'I',
'3': 'J',
'4': 'K',
'5': 'L',
'6': 'M',
'7': 'N',
'8': 'O',
'9': 'P',
'A': 'S',
'APOSTROPHE': 'B',
'B': 'T',
'BACKSLASH': 't',
'BACKSPACE': '1',
'C': 'U',
'CAPS LOCK': ':',
'COMMA': 'C',
'D': 'V',
'DELETE': '3',
'DOWN': '6',
'E': 'W',
'END': '-',
'ENTER': 'z',
'EQUAL': 'R',
'ESCAPE': 'y',
'F': 'X',
'F1': '/',
'F10': ']',
'F11': '{',
'F12': '}',
'F13': '@',
'F14': '%',
'F15': '$',
'F16': '#',
'F17': 'BA',
'F18': 'BB',
'F19': 'BC',
'F2': '*',
'F20': 'BD',
'F21': 'BE',
'F22': 'BF',
'F23': 'BG',
'F24': 'BH',
'F25': 'BI',
'F3': '?',
'F4': '&',
'F5': '<',
'F6': '>',
'F7': '(',
'F8': ')',
'F9': '[',
'G': 'Y',
'GRAVE ACCENT': 'v',
'H': 'Z',
'HOME': '.',
'I': 'a',
'INSERT': '2',
'J': 'b',
'K': 'c',
'KP 0': 'BJ',
'KP 1': 'BK',
'KP 2': 'BL',
'KP 3': 'BM',
'KP 4': 'BN',
'KP 5': 'BO',
'KP 6': 'BP',
'KP 7': 'BQ',
'KP 8': 'BR',
'KP 9': 'BS',
'KP ADD': 'BX',
'KP DECIMAL': 'BT',
'KP DIVIDE': 'BU',
'KP ENTER': 'BY',
'KP EQUAL': 'BZ',
'KP MULTIPLY': 'BV',
'KP SUBTRACT': 'BW',
'L': 'd',
'LEFT': '5',
'LEFT ALT': 'Bc',
'LEFT BRACKET': 's',
'LEFT CONTROL': 'Bb',
'LEFT SHIFT': 'Ba',
'LEFT SUPER': 'Bd',
'M': 'e',
'MINUS': 'D',
'N': 'f',
'NUM LOCK': '=',
'O': 'g',
'P': 'h',
'PAGE DOWN': '9',
'PAGE UP': '8',
'PAUSE': '!',
'PERIOD': 'E',
'PRINT SCREEN': '^',
'Q': 'i',
'R': 'j',
'RIGHT': '4',
'RIGHT ALT': 'Bg',
'RIGHT BRACKET': 'u',
'RIGHT CONTROL': 'Bf',
'RIGHT SHIFT': 'Be',
'RIGHT SUPER': 'Bh',
'S': 'k',
'SCROLL LOCK': '+',
'SEMICOLON': 'Q',
'SLASH': 'F',
'SPACE': 'A',
'T': 'l',
'TAB': '0',
'U': 'm',
'UP': '7',
'V': 'n',
'W': 'o',
'WORLD 1': 'w',
'WORLD 2': 'x',
'X': 'p',
'Y': 'q',
'Z': 'r',
'PLUS': 'Bi',
'UNDERSCORE': 'Bj',
'MENU': 'Bk',
'EXCLAM': 'Bl',
'DOUBLE QUOTE': 'Bm',
'NUMBER SIGN': 'Bn',
'DOLLAR': 'Bo',
'AMPERSAND': 'Bp',
'PARENTHESIS LEFT': 'Bq',
'PARENTHESIS RIGHT': 'Br',
'COLON': 'Bs',
'LESS': 'Bt',
'GREATER': 'Bu',
'AT': 'Bv',
'PARAGRAPH': 'Bw',
'MASCULINE': 'Bx',
'A GRAVE': 'By',
'A DIAERESIS': 'Bz',
'A RING': 'B0',
'AE': 'B1',
'C CEDILLA': 'B2',
'E GRAVE': 'B3',
'E ACUTE': 'B4',
'I GRAVE': 'B5',
'N TILDE': 'B6',
'O GRAVE': 'B7',
'O DIAERESIS': 'B8',
'O SLASH': 'B9',
'U GRAVE': 'B.',
'U DIAERESIS': 'B-',
'S SHARP': 'B:',
'CYRILLIC A': 'B+',
'CYRILLIC BE': 'B=',
'CYRILLIC VE': 'B^',
'CYRILLIC GHE': 'B!',
'CYRILLIC DE': 'B/',
'CYRILLIC IE': 'B*',
'CYRILLIC ZHE': 'B?',
'CYRILLIC ZE': 'B&',
'CYRILLIC I': 'B<',
'CYRILLIC SHORT I': 'B>',
'CYRILLIC KA': 'B(',
'CYRILLIC EL': 'B)',
'CYRILLIC EM': 'B[',
'CYRILLIC EN': 'B]',
'CYRILLIC O': 'B{',
'CYRILLIC PE': 'B}',
'CYRILLIC ER': 'B@',
'CYRILLIC ES': 'B%',
'CYRILLIC TE': 'B$',
'CYRILLIC U': 'B#',
'CYRILLIC EF': 'CA',
'CYRILLIC HA': 'CB',
'CYRILLIC TSE': 'CC',
'CYRILLIC CHE': 'CD',
'CYRILLIC SHA': 'CE',
'CYRILLIC SHCHA': 'CF',
'CYRILLIC HARD SIGN': 'CG',
'CYRILLIC YERU': 'CH',
'CYRILLIC SOFT SIGN': 'CI',
'CYRILLIC E': 'CJ',
'CYRILLIC YU': 'CK',
'CYRILLIC YA': 'CL',
'CYRILLIC IO': 'CM',
'CIRCUMFLEX': 'CN'
}
KEY_MAP = {
32: 'A',
33: 'Bl',
34: 'Bm',
35: 'Bn',
36: 'Bo',
38: 'Bp',
39: 'B',
40: 'Bq',
41: 'Br',
43: 'Bi',
44: 'C',
45: 'D',
46: 'E',
47: 'F',
48: 'G',
49: 'H',
50: 'I',
51: 'J',
52: 'K',
53: 'L',
54: 'M',
55: 'N',
56: 'O',
57: 'P',
58: 'Bs',
59: 'Q',
60: 'Bt',
61: 'R',
62: 'Bu',
64: 'Bv',
65: 'S',
66: 'T',
67: 'U',
68: 'V',
69: 'W',
70: 'X',
71: 'Y',
72: 'Z',
73: 'a',
74: 'b',
75: 'c',
76: 'd',
77: 'e',
78: 'f',
79: 'g',
80: 'h',
81: 'i',
82: 'j',
83: 'k',
84: 'l',
85: 'm',
86: 'n',
87: 'o',
88: 'p',
89: 'q',
90: 'r',
91: 's',
92: 't',
93: 'u',
94: 'CN',
95: 'Bj',
96: 'v',
161: 'w',
162: 'x',
167: 'Bw',
186: 'Bx',
192: 'By',
196: 'Bz',
197: 'B0',
198: 'B1',
199: 'B2',
200: 'B3',
201: 'B4',
204: 'B5',
209: 'B6',
210: 'B7',
214: 'B8',
216: 'B9',
217: 'B.',
220: 'B-',
222: 'B:',
223: 'B+',
224: 'B=',
225: 'B^',
226: 'B!',
227: 'B/',
228: 'B*',
229: 'B?',
230: 'B&',
231: 'B<',
232: 'B>',
233: 'B(',
234: 'B)',
235: 'B[',
236: 'B]',
237: 'B{',
238: 'B}',
239: 'B@',
240: 'B%',
241: 'B$',
242: 'B#',
243: 'CA',
244: 'CB',
245: 'CC',
246: 'CD',
247: 'CE',
248: 'CF',
249: 'CG',
250: 'CH',
251: 'CI',
252: 'CJ',
253: 'CK',
254: 'CL',
255: 'CM',
256: 'y',
257: 'z',
258: '0',
259: '1',
260: '2',
261: '3',
262: '4',
263: '5',
264: '6',
265: '7',
266: '8',
267: '9',
268: '.',
269: '-',
280: ':',
281: '+',
282: '=',
283: '^',
284: '!',
290: '/',
291: '*',
292: '?',
293: '&',
294: '<',
295: '>',
296: '(',
297: ')',
298: '[',
299: ']',
300: '{',
301: '}',
302: '@',
303: '%',
304: '$',
305: '#',
306: 'BA',
307: 'BB',
308: 'BC',
309: 'BD',
310: 'BE',
311: 'BF',
312: 'BG',
313: 'BH',
314: 'BI',
320: 'BJ',
321: 'BK',
322: 'BL',
323: 'BM',
324: 'BN',
325: 'BO',
326: 'BP',
327: 'BQ',
328: 'BR',
329: 'BS',
330: 'BT',
331: 'BU',
332: 'BV',
333: 'BW',
334: 'BX',
335: 'BY',
336: 'BZ',
340: 'Ba',
341: 'Bb',
342: 'Bc',
343: 'Bd',
344: 'Be',
345: 'Bf',
346: 'Bg',
347: 'Bh',
348: 'Bk'
}
# END_ENCODING }}}
text_keys = (
string.ascii_uppercase + string.ascii_lowercase + string.digits +
'`~!@#$%^&*()_-+=[{]}\\|<,>./?;:\'" '
'ÄäÖöÜüß§ºàåæçèéìñòøùабвгдежзийклмнопрстуфхцчшщъыьэюяё'
)
def text_match(key: str) -> Optional[str]:
if key.upper() == 'SPACE':
return ' '
if key not in text_keys:
return None
return key
def encode(
integer: int,
chars: str = string.ascii_uppercase + string.ascii_lowercase + string.digits +
'.-:+=^!/*?&<>()[]{}@%$#'
) -> str:
ans = ''
d = len(chars)
while True:
integer, remainder = divmod(integer, d)
ans = chars[remainder] + ans
if integer == 0:
break
return ans
def symbolic_name(glfw_name: str) -> str:
return glfw_name[9:].replace('_', ' ')
def update_encoding() -> None:
import re
import subprocess
keys = {a for a in dir(defines) if a.startswith('GLFW_KEY_')}
ans = ENCODING
key_map = {}
i = len(ans)
for k in sorted(keys, key=lambda k: int(getattr(defines, k))):
if k in ('GLFW_KEY_LAST', 'GLFW_KEY_LAST_PRINTABLE'):
continue
val = getattr(defines, k)
name = symbolic_name(k)
if val <= defines.GLFW_KEY_LAST and val != defines.GLFW_KEY_UNKNOWN:
if name not in ans:
ans[name] = encode(i)
i += 1
key_map[val] = ans[name]
with open(__file__, 'r+') as f:
raw = f.read()
nraw = re.sub(
r'^ENCODING = {.+^# END_ENCODING',
'ENCODING = {!r}\nKEY_MAP={!r}\n# END_ENCODING'.format(
ans, key_map
),
raw,
flags=re.MULTILINE | re.DOTALL
)
if raw == nraw:
raise SystemExit('Failed to replace ENCODING dict')
f.seek(0), f.truncate()
f.write(nraw)
subprocess.check_call(['yapf', '-i', __file__])
class KeyEvent(NamedTuple):
type: int
mods: int
key: str
PRESS: int = 1
REPEAT: int = 2
RELEASE: int = 4
SHIFT, ALT, CTRL, SUPER = 1, 2, 4, 8
type_map = {'p': PRESS, 't': REPEAT, 'r': RELEASE}
rtype_map = {v: k for k, v in type_map.items()}
mod_map = {c: i for i, c in enumerate('ABCDEFGHIJKLMNOP')}
rmod_map = {v: k for k, v in mod_map.items()}
key_rmap = {}
key_defs: Dict[str, str] = {}
config_key_map = {}
config_mod_map = {
'SHIFT': SHIFT,
'ALT': ALT,
'OPTION': ALT,
'': ALT,
'': SUPER,
'CMD': SUPER,
'SUPER': SUPER,
'CTRL': CTRL,
'CONTROL': CTRL
}
for key_name, enc in ENCODING.items():
key_name = key_name.replace(' ', '_')
key_defs[key_name] = config_key_map[key_name] = key_name
key_rmap[enc] = key_name
config_key_map.update({k: key_defs[v] for k, v in key_name_aliases.items() if v in key_defs})
enter_key = KeyEvent(PRESS, 0, key_defs['ENTER'])
backspace_key = KeyEvent(PRESS, 0, key_defs['BACKSPACE'])
globals().update(key_defs)
del key_name, enc
def decode_key_event(text: str) -> KeyEvent:
typ = type_map[text[1]]
mods = mod_map[text[2]]
key = key_rmap[text[3:5]]
return KeyEvent(typ, mods, key)
def encode_key_event(key_event: KeyEvent) -> str:
typ = rtype_map[key_event.type]
mods = rmod_map[key_event.mods]
key = ENCODING[key_event.key.replace('_', ' ')]
return typ + mods + key