2021-01-09 08:44:37 +03:00
|
|
|
#!/usr/bin/env python
|
|
|
|
# vim:fileencoding=utf-8
|
|
|
|
# License: GPLv3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net>
|
|
|
|
|
2021-01-09 10:18:19 +03:00
|
|
|
from typing import Dict, List
|
|
|
|
|
|
|
|
|
2021-01-11 08:58:42 +03:00
|
|
|
functional_key_defs = '''# {{{
|
2021-01-09 10:18:19 +03:00
|
|
|
# kitty XKB macOS
|
|
|
|
escape Escape -
|
|
|
|
enter Return -
|
|
|
|
tab Tab -
|
2021-01-09 13:12:16 +03:00
|
|
|
backspace BackSpace -
|
2021-01-09 10:18:19 +03:00
|
|
|
insert Insert -
|
|
|
|
delete Delete -
|
|
|
|
left Left -
|
|
|
|
right Right -
|
|
|
|
up Up -
|
|
|
|
down Down -
|
|
|
|
page_up Page_Up -
|
|
|
|
page_down Page_Down -
|
|
|
|
home Home -
|
|
|
|
end End -
|
|
|
|
caps_lock Caps_Lock -
|
|
|
|
scroll_lock Scroll_Lock -
|
|
|
|
num_lock Num_Lock -
|
|
|
|
print_screen Print -
|
|
|
|
pause Pause -
|
|
|
|
menu Menu -
|
|
|
|
f1 F1 -
|
|
|
|
f2 F2 -
|
|
|
|
f3 F3 -
|
|
|
|
f4 F4 -
|
|
|
|
f5 F5 -
|
|
|
|
f6 F6 -
|
|
|
|
f7 F7 -
|
|
|
|
f8 F8 -
|
|
|
|
f9 F9 -
|
|
|
|
f10 F10 -
|
|
|
|
f11 F11 -
|
|
|
|
f12 F12 -
|
|
|
|
f13 F13 -
|
|
|
|
f14 F14 -
|
|
|
|
f15 F15 -
|
|
|
|
f16 F16 -
|
|
|
|
f17 F17 -
|
|
|
|
f18 F18 -
|
|
|
|
f19 F19 -
|
|
|
|
f20 F20 -
|
|
|
|
f21 F21 -
|
|
|
|
f22 F22 -
|
|
|
|
f23 F23 -
|
|
|
|
f24 F24 -
|
|
|
|
f25 F25 -
|
|
|
|
f26 F26 -
|
|
|
|
f27 F27 -
|
|
|
|
f28 F28 -
|
|
|
|
f29 F29 -
|
|
|
|
f30 F30 -
|
|
|
|
f31 F31 -
|
|
|
|
f32 F32 -
|
|
|
|
f33 F33 -
|
|
|
|
f34 F34 -
|
|
|
|
f35 F35 -
|
|
|
|
kp_0 KP_0 -
|
|
|
|
kp_1 KP_1 -
|
|
|
|
kp_2 KP_2 -
|
|
|
|
kp_3 KP_3 -
|
|
|
|
kp_4 KP_4 -
|
|
|
|
kp_5 KP_5 -
|
|
|
|
kp_6 KP_6 -
|
|
|
|
kp_7 KP_7 -
|
|
|
|
kp_8 KP_8 -
|
|
|
|
kp_9 KP_9 -
|
|
|
|
kp_decimal KP_Decimal -
|
|
|
|
kp_divide KP_Divide -
|
|
|
|
kp_multiply KP_Multiply -
|
|
|
|
kp_subtract KP_Subtract -
|
|
|
|
kp_add KP_Add -
|
|
|
|
kp_enter KP_Enter -
|
|
|
|
kp_equal KP_Equal -
|
2021-01-10 08:58:10 +03:00
|
|
|
kp_separator KP_Separator -
|
|
|
|
kp_left KP_Left -
|
|
|
|
kp_right KP_Right -
|
|
|
|
kp_up KP_Up -
|
|
|
|
kp_down KP_Down -
|
|
|
|
kp_page_up KP_Page_Up -
|
|
|
|
kp_page_down KP_Page_Down -
|
|
|
|
kp_home KP_Home -
|
|
|
|
kp_end KP_End -
|
|
|
|
kp_insert KP_Insert -
|
|
|
|
kp_delete KP_Delete -
|
2021-01-09 10:18:19 +03:00
|
|
|
left_shift Shift_L -
|
|
|
|
left_control Control_L -
|
|
|
|
left_alt Alt_L -
|
|
|
|
left_super Super_L -
|
|
|
|
right_shift Shift_R -
|
|
|
|
right_control Control_R -
|
|
|
|
right_alt Alt_R -
|
|
|
|
right_super Super_R -
|
|
|
|
media_play XF86AudioPlay -
|
|
|
|
media_pause XF86AudioPause -
|
|
|
|
media_play_pause - -
|
2021-01-09 13:12:16 +03:00
|
|
|
media_reverse - -
|
2021-01-09 10:18:19 +03:00
|
|
|
media_stop XF86AudioStop -
|
|
|
|
media_fast_forward XF86AudioForward -
|
|
|
|
media_rewind XF86AudioRewind -
|
|
|
|
media_track_next XF86AudioNext -
|
|
|
|
media_track_previous XF86AudioPrev -
|
|
|
|
media_record XF86AudioRecord -
|
|
|
|
lower_volume XF86AudioLowerVolume -
|
|
|
|
raise_volume XF86AudioRaiseVolume -
|
|
|
|
mute_volume XF86AudioMute -
|
2021-01-11 08:58:42 +03:00
|
|
|
''' # }}}
|
|
|
|
|
2021-01-11 19:28:54 +03:00
|
|
|
functional_encoding_overrides = {
|
|
|
|
'insert': 2, 'delete': 3, 'page_up': 5, 'page_down': 6,
|
2021-01-12 02:47:15 +03:00
|
|
|
'home': 7, 'end': 8, 'tab': 9, 'f1': 11, 'f2': 12, 'enter': 13, 'f4': 14,
|
2021-01-11 19:28:54 +03:00
|
|
|
'f5': 15, 'f6': 17, 'f7': 18, 'f8': 19, 'f9': 20, 'f10': 21,
|
2021-01-12 11:12:12 +03:00
|
|
|
'f11': 23, 'f12': 24, 'escape': 27, 'backspace': 127
|
2021-01-11 19:28:54 +03:00
|
|
|
}
|
|
|
|
different_trailer_functionals = {
|
|
|
|
'up': 'A', 'down': 'B', 'right': 'C', 'left': 'D', 'end': 'F', 'home': 'H',
|
2021-01-12 02:47:15 +03:00
|
|
|
'f1': 'P', 'f2': 'Q', 'f3': 'R', 'f4': 'S', 'enter': 'u', 'tab': 'u',
|
2021-01-12 11:12:12 +03:00
|
|
|
'backspace': 'u', 'escape': 'u'
|
2021-01-11 19:28:54 +03:00
|
|
|
}
|
2021-01-09 10:18:19 +03:00
|
|
|
functional_key_names: List[str] = []
|
|
|
|
name_to_code: Dict[str, int] = {}
|
2021-01-09 13:12:16 +03:00
|
|
|
name_to_xkb: Dict[str, str] = {}
|
2021-01-09 08:44:37 +03:00
|
|
|
start_code = 0xe000
|
2021-01-09 10:18:19 +03:00
|
|
|
for line in functional_key_defs.splitlines():
|
|
|
|
line = line.strip()
|
|
|
|
if not line or line.startswith('#'):
|
|
|
|
continue
|
|
|
|
parts = line.split()
|
|
|
|
name = parts[0]
|
|
|
|
functional_key_names.append(name)
|
|
|
|
name_to_code[name] = len(name_to_code) + start_code
|
2021-01-09 13:12:16 +03:00
|
|
|
if parts[1] != '-':
|
|
|
|
name_to_xkb[name] = parts[1]
|
2021-01-09 08:44:37 +03:00
|
|
|
last_code = start_code + len(functional_key_names) - 1
|
2021-01-09 10:18:19 +03:00
|
|
|
|
|
|
|
|
|
|
|
def patch_file(path: str, what: str, text: str, start_marker: str = '/* ', end_marker: str = ' */') -> None:
|
2021-01-12 04:37:37 +03:00
|
|
|
simple_start_q = f'{start_marker}start {what}{end_marker}'
|
2021-01-09 10:21:41 +03:00
|
|
|
start_q = f'{start_marker}start {what} (auto generated by gen-key-constants.py do not edit){end_marker}'
|
2021-01-09 10:18:19 +03:00
|
|
|
end_q = f'{start_marker}end {what}{end_marker}'
|
|
|
|
|
|
|
|
with open(path, 'r+') as f:
|
|
|
|
raw = f.read()
|
2021-01-11 08:58:42 +03:00
|
|
|
try:
|
|
|
|
start = raw.index(start_q)
|
|
|
|
except ValueError:
|
2021-01-12 04:37:37 +03:00
|
|
|
try:
|
|
|
|
start = raw.index(simple_start_q)
|
|
|
|
except ValueError:
|
|
|
|
raise SystemExit(f'Failed to find "{simple_start_q}" in {path}')
|
2021-01-11 08:58:42 +03:00
|
|
|
try:
|
|
|
|
end = raw.index(end_q)
|
|
|
|
except ValueError:
|
|
|
|
raise SystemExit(f'Failed to find "{end_q}" in {path}')
|
2021-01-09 10:18:19 +03:00
|
|
|
raw = raw[:start] + start_q + '\n' + text + '\n' + raw[end:]
|
|
|
|
f.seek(0)
|
|
|
|
f.truncate(0)
|
|
|
|
f.write(raw)
|
2021-01-09 08:44:37 +03:00
|
|
|
|
|
|
|
|
|
|
|
def generate_glfw_header() -> None:
|
|
|
|
lines = [
|
|
|
|
'typedef enum {',
|
2021-01-12 04:37:37 +03:00
|
|
|
f' GLFW_FKEY_FIRST = 0x{start_code:x}u,',
|
2021-01-09 08:44:37 +03:00
|
|
|
]
|
2021-01-12 12:33:53 +03:00
|
|
|
klines, pyi, names, knames = [], [], [], []
|
2021-01-09 08:44:37 +03:00
|
|
|
for name, code in name_to_code.items():
|
2021-01-12 04:37:37 +03:00
|
|
|
lines.append(f' GLFW_FKEY_{name.upper()} = 0x{code:x}u,')
|
|
|
|
klines.append(f' ADDC(GLFW_FKEY_{name.upper()});')
|
|
|
|
pyi.append(f'GLFW_FKEY_{name.upper()}: int')
|
|
|
|
names.append(f' case GLFW_FKEY_{name.upper()}: return "{name.upper()}";')
|
2021-01-12 12:33:53 +03:00
|
|
|
knames.append(f' case GLFW_FKEY_{name.upper()}: return PyUnicode_FromString("{name}");')
|
2021-01-12 04:37:37 +03:00
|
|
|
lines.append(f' GLFW_FKEY_LAST = 0x{last_code:x}u')
|
2021-01-09 08:44:37 +03:00
|
|
|
lines.append('} GLFWFunctionKey;')
|
2021-01-09 10:18:19 +03:00
|
|
|
patch_file('glfw/glfw3.h', 'functional key names', '\n'.join(lines))
|
2021-01-12 04:37:37 +03:00
|
|
|
patch_file('kitty/glfw.c', 'glfw functional keys', '\n'.join(klines))
|
2021-01-12 05:16:21 +03:00
|
|
|
patch_file('kitty/fast_data_types.pyi', 'glfw functional keys', '\n'.join(pyi), start_marker='# ', end_marker='')
|
2021-01-12 04:37:37 +03:00
|
|
|
patch_file('glfw/input.c', 'functional key names', '\n'.join(names))
|
2021-01-12 12:33:53 +03:00
|
|
|
patch_file('kitty/glfw.c', 'glfw functional key names', '\n'.join(knames))
|
2021-01-09 08:44:37 +03:00
|
|
|
|
|
|
|
|
2021-01-09 13:12:16 +03:00
|
|
|
def generate_xkb_mapping() -> None:
|
|
|
|
lines, rlines = [], []
|
|
|
|
for name, xkb in name_to_xkb.items():
|
|
|
|
lines.append(f' case XKB_KEY_{xkb}: return GLFW_FKEY_{name.upper()};')
|
|
|
|
rlines.append(f' case GLFW_FKEY_{name.upper()}: return XKB_KEY_{xkb};')
|
|
|
|
patch_file('glfw/xkb_glfw.c', 'xkb to glfw', '\n'.join(lines))
|
|
|
|
patch_file('glfw/xkb_glfw.c', 'glfw to xkb', '\n'.join(rlines))
|
|
|
|
|
|
|
|
|
2021-01-11 08:58:42 +03:00
|
|
|
def generate_functional_table() -> None:
|
|
|
|
lines = [
|
|
|
|
'',
|
|
|
|
'.. csv-table:: Functional key codes',
|
2021-01-11 19:28:54 +03:00
|
|
|
' :header: "Name", "CSI sequence"',
|
2021-01-11 08:58:42 +03:00
|
|
|
''
|
|
|
|
]
|
2021-01-12 02:47:15 +03:00
|
|
|
enc_lines = []
|
2021-01-11 08:58:42 +03:00
|
|
|
for name, code in name_to_code.items():
|
2021-01-11 19:28:54 +03:00
|
|
|
if name in functional_encoding_overrides or name in different_trailer_functionals:
|
|
|
|
code = oc = functional_encoding_overrides.get(name, code)
|
|
|
|
trailer = different_trailer_functionals.get(name, '~')
|
2021-01-12 02:47:15 +03:00
|
|
|
code = code if trailer in '~u' else 1
|
|
|
|
enc_lines.append((' ' * 8) + f"case GLFW_FKEY_{name.upper()}: S({code}, '{trailer}');")
|
2021-01-11 19:28:54 +03:00
|
|
|
if code == 1 and name not in ('up', 'down', 'left', 'right'):
|
|
|
|
trailer += f' or CSI {oc} ... ~'
|
|
|
|
else:
|
|
|
|
trailer = 'u'
|
|
|
|
name = f'"{name.upper()}",'.ljust(25)
|
|
|
|
lines.append(f' {name} "CSI {code} ... {trailer}"')
|
2021-01-11 08:58:42 +03:00
|
|
|
lines.append('')
|
|
|
|
patch_file('docs/keyboard-protocol.rst', 'functional key table', '\n'.join(lines), start_marker='.. ', end_marker='')
|
2021-01-12 02:47:15 +03:00
|
|
|
patch_file('kitty/key_encoding.c', 'special numbers', '\n'.join(enc_lines))
|
2021-01-11 08:58:42 +03:00
|
|
|
|
|
|
|
|
2021-01-09 08:44:37 +03:00
|
|
|
def main() -> None:
|
|
|
|
generate_glfw_header()
|
2021-01-09 13:12:16 +03:00
|
|
|
generate_xkb_mapping()
|
2021-01-11 08:58:42 +03:00
|
|
|
generate_functional_table()
|
2021-01-09 08:44:37 +03:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|