From 6b2ffc774fa8105a4b0cd4378c9f140d5ea9f8ed Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 14 Jan 2021 04:26:03 +0530 Subject: [PATCH] Port shortcut and sequence matching code --- docs/keyboard-protocol.rst | 4 ++++ kitty/boss.py | 27 +++++++++++++-------------- kitty/conf/definition.py | 1 + kitty/config_data.py | 3 ++- kitty/keys.py | 19 ++++++++++--------- 5 files changed, 30 insertions(+), 24 deletions(-) diff --git a/docs/keyboard-protocol.rst b/docs/keyboard-protocol.rst index 259ce914e..8574ce98c 100644 --- a/docs/keyboard-protocol.rst +++ b/docs/keyboard-protocol.rst @@ -575,6 +575,10 @@ Note that the escape codes above of the form ``CSI 1 letter`` will omit the Bugs in fixterms ------------------- +The following is a list of errata in the `original fixterms proposal +`_ , corrected in this +specification. + * No way to disambiguate :kbd:`Esc` keypresses, other than using 8-bit controls which are undesirable for other reasons * Incorrectly claims special keys are sometimes encoded using ``CSI letter`` encodings when it diff --git a/kitty/boss.py b/kitty/boss.py index c9703d06e..7379fc60a 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -30,14 +30,14 @@ from .constants import ( ) from .fast_data_types import ( CLOSE_BEING_CONFIRMED, IMPERATIVE_CLOSE_REQUESTED, NO_CLOSE_REQUESTED, - ChildMonitor, add_timer, background_opacity_of, change_background_opacity, - change_os_window_state, cocoa_set_menubar_title, create_os_window, - current_application_quit_request, current_os_window, destroy_global_data, - focus_os_window, get_clipboard_string, global_font_size, - mark_os_window_for_close, os_window_font_size, patch_global_colors, - safe_pipe, set_application_quit_request, set_background_image, set_boss, - set_clipboard_string, set_in_sequence_mode, thread_write, - toggle_fullscreen, toggle_maximized + ChildMonitor, KeyEvent, add_timer, background_opacity_of, + change_background_opacity, change_os_window_state, cocoa_set_menubar_title, + create_os_window, current_application_quit_request, current_os_window, + destroy_global_data, focus_os_window, get_clipboard_string, + global_font_size, mark_os_window_for_close, os_window_font_size, + patch_global_colors, safe_pipe, set_application_quit_request, + set_background_image, set_boss, set_clipboard_string, set_in_sequence_mode, + thread_write, toggle_fullscreen, toggle_maximized ) from .keys import get_shortcut, shortcut_matches from .layout.base import set_layout_options @@ -663,20 +663,19 @@ class Boss: if t is not None: return t.active_window - def dispatch_special_key(self, key: int, native_key: int, action: int, mods: int) -> bool: + def dispatch_possible_special_key(self, ev: KeyEvent) -> bool: # Handles shortcuts, return True if the key was consumed - key_action = get_shortcut(self.keymap, mods, key, native_key) + key_action = get_shortcut(self.keymap, ev) if key_action is None: - sequences = get_shortcut(self.opts.sequence_map, mods, key, native_key) + sequences = get_shortcut(self.opts.sequence_map, ev) if sequences and not isinstance(sequences, KeyAction): self.pending_sequences = sequences set_in_sequence_mode(True) return True elif isinstance(key_action, KeyAction): - self.current_key_press_info = key, native_key, action, mods return self.dispatch_action(key_action) - def process_sequence(self, key: int, native_key: int, action: Any, mods: int) -> None: + def process_sequence(self, ev: KeyEvent) -> None: if not self.pending_sequences: set_in_sequence_mode(False) return @@ -684,7 +683,7 @@ class Boss: remaining = {} matched_action = None for seq, key_action in self.pending_sequences.items(): - if shortcut_matches(seq[0], mods, key, native_key): + if shortcut_matches(seq[0], ev): seq = seq[1:] if seq: remaining[seq] = key_action diff --git a/kitty/conf/definition.py b/kitty/conf/definition.py index a858e34ff..d1e3bcf5b 100644 --- a/kitty/conf/definition.py +++ b/kitty/conf/definition.py @@ -157,6 +157,7 @@ def remove_markup(text: str) -> str: return { 'layouts': 'https://sw.kovidgoyal.net/kitty/index.html#layouts', 'sessions': 'https://sw.kovidgoyal.net/kitty/index.html#sessions', + 'functional': 'https://sw.kovidgoyal.net/kitty/keyboard-protocol.html#functional-key-definitions', }[m.group(2)] return str(m.group(2)) diff --git a/kitty/config_data.py b/kitty/config_data.py index 64c7fb8c6..8a620b91f 100644 --- a/kitty/config_data.py +++ b/kitty/config_data.py @@ -135,7 +135,8 @@ as color16 to color255.''') _('Keyboard shortcuts'), _('''\ Keys are identified simply by their lowercase unicode characters. For example: -``a`` for the A key, ``[`` for the left square bracket key, etc. +``a`` for the A key, ``[`` for the left square bracket key, etc. For functional +keys, such as ``Enter or Escape`` the names are present at :ref:`functional`. For a list of modifier names, see: :link:`GLFW mods ` diff --git a/kitty/keys.py b/kitty/keys.py index 763b04a8e..7703594c3 100644 --- a/kitty/keys.py +++ b/kitty/keys.py @@ -4,8 +4,9 @@ from typing import Optional, Union -from .constants import SingleKey from .config import KeyAction, KeyMap, SequenceMap, SubSequenceMap +from .constants import SingleKey +from .fast_data_types import KeyEvent from .typing import ScreenType @@ -16,15 +17,15 @@ def keyboard_mode_name(screen: ScreenType) -> str: return 'application' if screen.cursor_key_mode else 'normal' -def get_shortcut(keymap: Union[KeyMap, SequenceMap], mods: int, key: int, native_key: int) -> Optional[Union[KeyAction, SubSequenceMap]]: - mods &= 0b1111 - ans = keymap.get(SingleKey(mods, False, key)) +def get_shortcut(keymap: Union[KeyMap, SequenceMap], ev: KeyEvent) -> Optional[Union[KeyAction, SubSequenceMap]]: + mods = ev.mods & 0b1111 + ans = keymap.get(SingleKey(mods, False, ev.key)) if ans is None: - ans = keymap.get(SingleKey(mods, True, native_key)) + ans = keymap.get(SingleKey(mods, True, ev.native_key)) return ans -def shortcut_matches(s: SingleKey, mods: int, key: int, native_key: int) -> bool: - mods &= 0b1111 - q = native_key if s[1] else key - return bool(s[0] & 0b1111 == mods & 0b1111 and s[2] == q) +def shortcut_matches(s: SingleKey, ev: KeyEvent) -> bool: + mods = ev.mods & 0b1111 + q = ev.native_key if s.is_native else ev.key + return bool(s.mods & 0b1111 == mods & 0b1111 and s.key == q)