diff --git a/key_encoding.asciidoc b/key_encoding.asciidoc index 9bf4d5df9..7fb440f71 100644 --- a/key_encoding.asciidoc +++ b/key_encoding.asciidoc @@ -3,126 +3,126 @@ See link:protocol-extensions.asciidoc#keyboard-handling[Keyboard Handling protocol extension] |=== -| Name | Number +| Name | Encoded representation -| 0 | 48 -| 1 | 49 -| 2 | 50 -| 3 | 51 -| 4 | 52 -| 5 | 53 -| 6 | 54 -| 7 | 55 -| 8 | 56 -| 9 | 57 -| A | 65 -| APOSTROPHE | 39 -| B | 66 -| BACKSLASH | 92 -| BACKSPACE | 259 -| C | 67 -| CAPS LOCK | 280 -| COMMA | 44 -| D | 68 -| DELETE | 261 -| DOWN | 264 -| E | 69 -| END | 269 -| ENTER | 257 -| EQUAL | 61 -| ESCAPE | 256 -| F | 70 -| F1 | 290 -| F10 | 299 -| F11 | 300 -| F12 | 301 -| F13 | 302 -| F14 | 303 -| F15 | 304 -| F16 | 305 -| F17 | 306 -| F18 | 307 -| F19 | 308 -| F2 | 291 -| F20 | 309 -| F21 | 310 -| F22 | 311 -| F23 | 312 -| F24 | 313 -| F25 | 314 -| F3 | 292 -| F4 | 293 -| F5 | 294 -| F6 | 295 -| F7 | 296 -| F8 | 297 -| F9 | 298 -| G | 71 -| GRAVE ACCENT | 96 -| H | 72 -| HOME | 268 -| I | 73 -| INSERT | 260 -| J | 74 -| K | 75 -| KP 0 | 320 -| KP 1 | 321 -| KP 2 | 322 -| KP 3 | 323 -| KP 4 | 324 -| KP 5 | 325 -| KP 6 | 326 -| KP 7 | 327 -| KP 8 | 328 -| KP 9 | 329 -| KP ADD | 334 -| KP DECIMAL | 330 -| KP DIVIDE | 331 -| KP ENTER | 335 -| KP EQUAL | 336 -| KP MULTIPLY | 332 -| KP SUBTRACT | 333 -| L | 76 -| LEFT | 263 -| LEFT ALT | 342 -| LEFT BRACKET | 91 -| LEFT CONTROL | 341 -| LEFT SHIFT | 340 -| LEFT SUPER | 343 -| M | 77 -| MINUS | 45 -| N | 78 -| NUM LOCK | 282 -| O | 79 -| P | 80 -| PAGE DOWN | 267 -| PAGE UP | 266 -| PAUSE | 284 -| PERIOD | 46 -| PRINT SCREEN | 283 -| Q | 81 -| R | 82 -| RIGHT | 262 -| RIGHT ALT | 346 -| RIGHT BRACKET | 93 -| RIGHT CONTROL | 345 -| RIGHT SHIFT | 344 -| RIGHT SUPER | 347 -| S | 83 -| SCROLL LOCK | 281 -| SEMICOLON | 59 -| SLASH | 47 -| SPACE | 32 -| T | 84 -| TAB | 258 -| U | 85 -| UP | 265 -| V | 86 -| W | 87 -| WORLD 1 | 161 -| WORLD 2 | 162 -| X | 88 -| Y | 89 -| Z | 90 +| 0 | `BM` +| 1 | `BN` +| 2 | `BO` +| 3 | `BP` +| 4 | `BQ` +| 5 | `BR` +| 6 | `BS` +| 7 | `BT` +| 8 | `BU` +| 9 | `BV` +| A | `Bd` +| APOSTROPHE | `BD` +| B | `Be` +| BACKSLASH | `CU` +| BACKSPACE | `HH` +| C | `Bf` +| CAPS LOCK | `Hc` +| COMMA | `BI` +| D | `Bg` +| DELETE | `HJ` +| DOWN | `HM` +| E | `Bh` +| END | `HR` +| ENTER | `HF` +| EQUAL | `BZ` +| ESCAPE | `HE` +| F | `Bi` +| F1 | `IC` +| F10 | `IL` +| F11 | `IM` +| F12 | `IN` +| F13 | `IO` +| F14 | `IP` +| F15 | `IQ` +| F16 | `IR` +| F17 | `IS` +| F18 | `IT` +| F19 | `IU` +| F2 | `ID` +| F20 | `IV` +| F21 | `IW` +| F22 | `IX` +| F23 | `IY` +| F24 | `IZ` +| F25 | `Ia` +| F3 | `IE` +| F4 | `IF` +| F5 | `IG` +| F6 | `IH` +| F7 | `II` +| F8 | `IJ` +| F9 | `IK` +| G | `Bj` +| GRAVE ACCENT | `CY` +| H | `CA` +| HOME | `HQ` +| I | `CB` +| INSERT | `HI` +| J | `CC` +| K | `CD` +| KP 0 | `Ig` +| KP 1 | `Ih` +| KP 2 | `Ii` +| KP 3 | `Ij` +| KP 4 | `JA` +| KP 5 | `JB` +| KP 6 | `JC` +| KP 7 | `JD` +| KP 8 | `JE` +| KP 9 | `JF` +| KP ADD | `JK` +| KP DECIMAL | `JG` +| KP DIVIDE | `JH` +| KP ENTER | `JL` +| KP EQUAL | `JM` +| KP MULTIPLY | `JI` +| KP SUBTRACT | `JJ` +| L | `CE` +| LEFT | `HL` +| LEFT ALT | `JS` +| LEFT BRACKET | `CT` +| LEFT CONTROL | `JR` +| LEFT SHIFT | `JQ` +| LEFT SUPER | `JT` +| M | `CF` +| MINUS | `BJ` +| N | `CG` +| NUM LOCK | `He` +| O | `CH` +| P | `CI` +| PAGE DOWN | `HP` +| PAGE UP | `HO` +| PAUSE | `Hg` +| PERIOD | `BK` +| PRINT SCREEN | `Hf` +| Q | `CJ` +| R | `CK` +| RIGHT | `HK` +| RIGHT ALT | `JW` +| RIGHT BRACKET | `CV` +| RIGHT CONTROL | `JV` +| RIGHT SHIFT | `JU` +| RIGHT SUPER | `JX` +| S | `CL` +| SCROLL LOCK | `Hd` +| SEMICOLON | `BX` +| SLASH | `BL` +| SPACE | `g` +| T | `CM` +| TAB | `HG` +| U | `CN` +| UP | `HN` +| V | `CO` +| W | `CP` +| WORLD 1 | `ER` +| WORLD 2 | `ES` +| X | `CQ` +| Y | `CR` +| Z | `CS` |=== diff --git a/kitty/boss.py b/kitty/boss.py index a5a65ee89..e8f6ed202 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -259,6 +259,7 @@ class Boss(Thread): is_key_pressed[key] = action == GLFW_PRESS self.start_cursor_blink() self.cursor_blink_zero_time = monotonic() + func = None if action == GLFW_PRESS or action == GLFW_REPEAT: func = get_shortcut(self.opts.keymap, mods, key, scancode) if func is not None: @@ -267,24 +268,24 @@ class Boss(Thread): passthrough = f() if not passthrough: return - tab = self.active_tab - if tab is None: - return - window = self.active_window - if window is not None: - yield window - if func is not None: - f = getattr(tab, func, getattr(window, func, None)) - if f is not None: - passthrough = f() - if not passthrough: - return - if window.screen.auto_repeat_enabled or action == GLFW_PRESS: - if window.char_grid.scrolled_by and key not in MODIFIER_KEYS: - window.scroll_end() - data = interpret_key_event(key, scancode, mods, window) - if data: - window.write_to_child(data) + tab = self.active_tab + if tab is None: + return + window = self.active_window + if window is None: + return + yield window + if func is not None: + f = getattr(tab, func, getattr(window, func, None)) + if f is not None: + passthrough = f() + if not passthrough: + return + if window.char_grid.scrolled_by and key not in MODIFIER_KEYS: + window.scroll_end() + data = interpret_key_event(key, scancode, mods, window, action) + if data: + window.write_to_child(data) @callback def on_focus(self, window, focused): diff --git a/kitty/keys.py b/kitty/keys.py index c999a8cfd..75783f163 100644 --- a/kitty/keys.py +++ b/kitty/keys.py @@ -2,7 +2,9 @@ # vim:fileencoding=utf-8 # License: GPL v3 Copyright: 2016, Kovid Goyal -import kitty.fast_data_types as defines +import string + +from . import fast_data_types as defines from .terminfo import key_as_bytes smkx_key_map = { @@ -80,22 +82,60 @@ def get_localized_key(key, scancode): return valid_localized_key_names.get((name or '').upper(), key) -def interpret_key_event(key, scancode, mods, window): +action_map = {defines.GLFW_PRESS: b'p', defines.GLFW_RELEASE: b'r', defines.GLFW_REPEAT: b't'} + + +def base64_encode(integer, chars=string.ascii_uppercase + string.ascii_lowercase + string.digits + '+/'): + ans = '' + while integer > 0: + integer, remainder = divmod(integer, 36) + ans = chars[remainder] + ans + return ans + + +def key_extended_map(): + ans = {} + for k in dir(defines): + if k.startswith('GLFW_KEY_'): + val = getattr(defines, k) + if val < defines.GLFW_KEY_LAST and val != defines.GLFW_KEY_UNKNOWN: + ans[k[9:]] = base64_encode(val) + return ans + + +key_extended_map = key_extended_map() + + +def extended_key_event(key, scancode, mods, action): + if key >= defines.GLFW_KEY_LAST or key == defines.GLFW_KEY_UNKNOWN or ( + # Shifted printable key should be handled by interpret_text_event() + mods == defines.GLFW_MOD_SHIFT and 32 <= key <= 126): + return b'' + if mods == 0 and key in (defines.GLFW_KEY_BACKSPACE, defines.GLFW_KEY_ENTER): + return smkx_key_map[key] + return '\033_K{}{:x}:{}\033\\'.format(action_map[action], mods, key_extended_map[key]).encode('ascii') + + +def interpret_key_event(key, scancode, mods, window, action): + screen = window.screen + if screen.extended_keyboard: + return extended_key_event(key, scancode, mods, action) data = bytearray() - key = get_localized_key(key, scancode) - if mods == defines.GLFW_MOD_CONTROL and key in control_codes: - # Map Ctrl-key to ascii control code - data.extend(control_codes[key]) - elif mods == defines.GLFW_MOD_ALT and key in alt_codes: - # Map Alt+key to Esc-key - data.extend(alt_codes[key]) - else: - key_map = get_key_map(window.screen) - x = key_map.get(key) - if x is not None: - if mods == defines.GLFW_MOD_SHIFT: - x = SHIFTED_KEYS.get(key, x) - data.extend(x) + if action == defines.GLFW_PRESS or (action == defines.GLFW_REPEAT and screen.auto_repeat_enabled): + key = get_localized_key(key, scancode) + if mods == defines.GLFW_MOD_CONTROL and key in control_codes: + # Map Ctrl-key to ascii control code + data.extend(control_codes[key]) + elif mods == defines.GLFW_MOD_ALT and key in alt_codes: + # Map Alt+key to Esc-key + data.extend(alt_codes[key]) + else: + key_map = get_key_map(screen) + x = key_map.get(key) + if x is not None: + if mods == defines.GLFW_MOD_SHIFT: + x = SHIFTED_KEYS.get(key, x) + data.extend(x) return bytes(data) @@ -109,13 +149,3 @@ def interpret_text_event(codepoint, mods): def get_shortcut(keymap, mods, key, scancode): key = get_localized_key(key, scancode) return keymap.get((mods & 0b1111, key)) - - -def key_integer_map(): - ans = {} - for k in dir(defines): - if k.startswith('GLFW_KEY_'): - val = getattr(defines, k) - if val < defines.GLFW_KEY_LAST and val != defines.GLFW_KEY_UNKNOWN: - ans[k[9:]] = val - return ans diff --git a/preprocess-readme.py b/preprocess-readme.py index 0ce3f6673..52b528ae2 100755 --- a/preprocess-readme.py +++ b/preprocess-readme.py @@ -37,15 +37,15 @@ if raw != nraw: raw = subprocess.check_output([ 'kitty', '-c', - 'from kitty.keys import *; import json; print(json.dumps(key_integer_map()))' + 'from kitty.keys import *; import json; print(json.dumps(key_extended_map))' ]).decode('utf-8') key_map = json.loads(raw) lines = [ 'See link:protocol-extensions.asciidoc#keyboard-handling[Keyboard Handling protocol extension]', - '', '|===', '| Name | Number', '' + '', '|===', '| Name | Encoded representation', '' ] for k in sorted(key_map): - lines.append('| {:15s} | {}'.format(k.replace('_', ' '), key_map[k])) + lines.append('| {:15s} | `{}`'.format(k.replace('_', ' '), key_map[k])) lines += ['', '|==='] with open('key_encoding.asciidoc', 'w') as f: print('= Key encoding for extended keyboard protocol\n', file=f) diff --git a/protocol-extensions.asciidoc b/protocol-extensions.asciidoc index 96c7bae4c..61504f1fe 100644 --- a/protocol-extensions.asciidoc +++ b/protocol-extensions.asciidoc @@ -365,15 +365,18 @@ The escape sequence encodes the following properties: _K:\ ``` -Where `` is one of `p` -- press, `r` -- release and `t` -- repeat. -Modifiers is zero or more of `c` -- Control, `a` -- Alt, `s` -- Shift and `m` -- Meta. -`` is a number corresponding to the key pressed. The key name to number mapping -is defined in link:key_encoding.asciidoc[this table]. +Where `` is one of `p` -- press, `r` -- release and `t` -- repeat. +Modifiers is a bitmask represented as a single hexadecimal digit in lower case. +Shift -- `0x1`, Control -- `0x2`, Alt -- `0x4` and Super -- `0x8`. `` is +a number (in lowercase hexadecimal) corresponding to the key pressed. The key name to +number mapping is defined in link:key_encoding.asciidoc[this table]. For example: ``` -_Kpca:88\ +_Kp6:58\ is ++x (press) +_Krf:10a\ is ++++PageUp (release) ``` -Is the key press event `++x`. +There is a `:` between the modifiers and the key-press so that in the future +more modifiers can be added, if needed.