From c03310b5e5d9ea870025fbf090ee703bd801ed74 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 31 Dec 2022 14:03:16 +0530 Subject: [PATCH] Cleanup previous PR --- docs/changelog.rst | 2 ++ kitty/boss.py | 29 ++++++++--------- kitty/fast_data_types.pyi | 5 +-- kitty/glfw.c | 27 ---------------- kitty/keys.c | 65 +++++++++++++++++++++++---------------- kitty/keys.h | 3 +- 6 files changed, 56 insertions(+), 75 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 19c5fb9c2..22129c406 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -79,6 +79,8 @@ Detailed list of changes - macOS: Allow to customize :sc:`Hide `, :sc:`Hide Others `, :sc:`Minimize `, and :sc:`Quit ` global menu shortcuts. Note that :opt:`clear_all_shortcuts` will remove these shortcuts now (:iss:`948`) +- When a multi-key sequence does not match any action, send all key events to the child program (:pull:`5841`) + 0.26.5 [2022-11-07] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/kitty/boss.py b/kitty/boss.py index 14809d7ea..0b2b2f693 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -40,7 +40,7 @@ from .fast_data_types import ( cocoa_minimize_os_window, cocoa_set_menubar_title, create_os_window, current_application_quit_request, current_focused_os_window_id, current_os_window, destroy_global_data, focus_os_window, get_boss, get_options, get_os_window_size, - glfw_is_modifier_key, global_font_size, last_focused_os_window_id, mark_os_window_for_close, + is_modifier_key, global_font_size, last_focused_os_window_id, mark_os_window_for_close, os_window_font_size, patch_global_colors, redirect_mouse_handling, ring_bell, run_with_activation_token, safe_pipe, send_data_to_peer, set_application_quit_request, set_background_image, set_boss, set_in_sequence_mode, @@ -1191,9 +1191,9 @@ class Boss: set_in_sequence_mode(False) return False - if len(self.current_sequence): + if self.current_sequence: self.current_sequence.append(ev) - if ev.action == GLFW_RELEASE or glfw_is_modifier_key(ev.key): + if ev.action == GLFW_RELEASE or is_modifier_key(ev.key): return True # For a press/repeat event that's not a modifier, try matching with # kitty bindings: @@ -1210,19 +1210,16 @@ class Boss: if remaining: self.pending_sequences = remaining return True - else: - matched_action = matched_action or self.default_pending_action - if matched_action is not None and matched_action != '': - self.clear_pending_sequences() - self.combine(matched_action) - return True - else: - w = self.active_window - if w is not None: - for ev in self.current_sequence: - w.write_to_child(w.encoded_key(ev)) - self.clear_pending_sequences() - return False + matched_action = matched_action or self.default_pending_action + if matched_action: + self.clear_pending_sequences() + self.combine(matched_action) + return True + w = self.active_window + if w is not None: + w.write_to_child(b''.join(w.encoded_key(ev) for ev in self.current_sequence)) + self.clear_pending_sequences() + return False def cancel_current_visual_select(self) -> None: if self.current_visual_select: diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index 07c150faa..104967531 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -313,10 +313,6 @@ def glfw_get_key_name(key: int, native_key: int) -> Optional[str]: pass -def glfw_is_modifier_key(key: int) -> bool: - pass - - StartupCtx = NewType('StartupCtx', int) Display = NewType('Display', int) @@ -1515,3 +1511,4 @@ def wrapped_kitten_names() -> List[str]: ... def expand_ansi_c_escapes(test: str) -> str: ... def update_tab_bar_edge_colors(os_window_id: int) -> bool: ... def mask_kitty_signals_process_wide() -> None: ... +def is_modifier_key(key: int) -> bool: ... diff --git a/kitty/glfw.c b/kitty/glfw.c index 96a6a90c1..2ec636917 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -1257,32 +1257,6 @@ glfw_get_key_name(PyObject UNUSED *self, PyObject *args) { } -bool -is_modifier_key(const uint32_t key) { - START_ALLOW_CASE_RANGE - switch (key) { - case GLFW_FKEY_LEFT_SHIFT ... GLFW_FKEY_ISO_LEVEL5_SHIFT: - case GLFW_FKEY_CAPS_LOCK: - case GLFW_FKEY_SCROLL_LOCK: - case GLFW_FKEY_NUM_LOCK: - return true; - default: - return false; - } - END_ALLOW_CASE_RANGE -} - - -static PyObject* -glfw_is_modifier_key(PyObject UNUSED *self, PyObject *args) { - uint32_t key; - if (!PyArg_ParseTuple(args, "I", &key)) return NULL; - PyObject *ans = is_modifier_key(key) ? Py_True : Py_False; - Py_INCREF(ans); - return ans; -} - - static PyObject* glfw_window_hint(PyObject UNUSED *self, PyObject *args) { int key, val; @@ -1789,7 +1763,6 @@ static PyMethodDef module_methods[] = { {"glfw_terminate", (PyCFunction)glfw_terminate, METH_NOARGS, ""}, {"glfw_get_physical_dpi", (PyCFunction)glfw_get_physical_dpi, METH_NOARGS, ""}, {"glfw_get_key_name", (PyCFunction)glfw_get_key_name, METH_VARARGS, ""}, - METHODB(glfw_is_modifier_key, METH_VARARGS), {"glfw_primary_monitor_size", (PyCFunction)primary_monitor_size, METH_NOARGS, ""}, {"glfw_primary_monitor_content_scale", (PyCFunction)primary_monitor_content_scale, METH_NOARGS, ""}, {NULL, NULL, 0, NULL} /* Sentinel */ diff --git a/kitty/keys.c b/kitty/keys.c index 5ff37d805..2e12075a2 100644 --- a/kitty/keys.c +++ b/kitty/keys.c @@ -30,6 +30,21 @@ new(PyTypeObject *type UNUSED, PyObject *args, PyObject *kw) { return convert_glfw_key_event_to_python(&ev); } +bool +is_modifier_key(const uint32_t key) { + START_ALLOW_CASE_RANGE + switch (key) { + case GLFW_FKEY_LEFT_SHIFT ... GLFW_FKEY_ISO_LEVEL5_SHIFT: + case GLFW_FKEY_CAPS_LOCK: + case GLFW_FKEY_SCROLL_LOCK: + case GLFW_FKEY_NUM_LOCK: + return true; + default: + return false; + } + END_ALLOW_CASE_RANGE +} + static void dealloc(PyKeyEvent* self) { Py_CLEAR(self->key); Py_CLEAR(self->shifted_key); Py_CLEAR(self->alternate_key); @@ -164,22 +179,20 @@ on_key_input(GLFWkeyevent *ev) { debug("invalid state, ignoring\n"); return; } - PyObject *ke = NULL; -#define create_key_event() { ke = convert_glfw_key_event_to_python(ev); if (!ke) { PyErr_Print(); return; } } + bool dispatch_ok = true, consumed = false; +#define dispatch_key_event(name) { \ + PyObject *ke = NULL, *ret = NULL; \ + ke = convert_glfw_key_event_to_python(ev); if (!ke) { PyErr_Print(); return; }; \ + ret = PyObject_CallMethod(global_state.boss, #name, "O", ke); Py_CLEAR(ke); \ + if (ret == NULL) { PyErr_Print(); dispatch_ok = false; } \ + else { consumed = ret == Py_True; Py_CLEAR(ret); } \ + w = window_for_window_id(active_window_id); \ +} if (global_state.in_sequence_mode) { debug("in sequence mode, handling as a potential shortcut\n"); - create_key_event(); - PyObject *ret = PyObject_CallMethod( - global_state.boss, "process_sequence", "O", ke); - Py_CLEAR(ke); - // the shortcut could have created a new window or closed the - // window, rendering the pointer no longer valid - w = window_for_window_id(active_window_id); - if (ret == NULL) { PyErr_Print(); } - else { - bool consumed = ret == Py_True; - Py_DECREF(ret); - if (consumed && action != GLFW_RELEASE && w) { + dispatch_key_event(process_sequence); + if (dispatch_ok) { + if (consumed && action != GLFW_RELEASE && w && !is_modifier_key(key)) { w->last_special_key_pressed = key; } } @@ -187,18 +200,9 @@ on_key_input(GLFWkeyevent *ev) { } if (action == GLFW_PRESS || action == GLFW_REPEAT) { - create_key_event(); w->last_special_key_pressed = 0; - PyObject *ret = PyObject_CallMethod(global_state.boss, "dispatch_possible_special_key", "O", ke); - Py_CLEAR(ke); - bool consumed = false; - // the shortcut could have created a new window or closed the - // window, rendering the pointer no longer valid - w = window_for_window_id(active_window_id); - if (ret == NULL) { PyErr_Print(); } - else { - consumed = ret == Py_True; - Py_DECREF(ret); + dispatch_key_event(dispatch_possible_special_key); + if (dispatch_ok) { if (consumed) { debug("handled as shortcut\n"); if (w) w->last_special_key_pressed = key; @@ -211,7 +215,7 @@ on_key_input(GLFWkeyevent *ev) { debug("ignoring release event for previous press that was handled as shortcut\n"); return; } -#undef create_key_event +#undef dispatch_key_event if (action == GLFW_REPEAT && !screen->modes.mDECARM) { debug("discarding repeat key event as DECARM is off\n"); return; @@ -293,9 +297,18 @@ pyencode_key_for_tty(PyObject *self UNUSED, PyObject *args, PyObject *kw) { return PyUnicode_FromStringAndSize(output, MAX(0, num)); } +static PyObject* +pyis_modifier_key(PyObject *self UNUSED, PyObject *a) { + unsigned long key = PyLong_AsUnsignedLong(a); + if (PyErr_Occurred()) return NULL; + if (is_modifier_key(key)) { Py_RETURN_TRUE; } + Py_RETURN_FALSE; +} + static PyMethodDef module_methods[] = { M(key_for_native_key_name, METH_VARARGS), M(encode_key_for_tty, METH_VARARGS | METH_KEYWORDS), + M(is_modifier_key, METH_O), {0} }; diff --git a/kitty/keys.h b/kitty/keys.h index 944dc4797..2f70ca6d6 100644 --- a/kitty/keys.h +++ b/kitty/keys.h @@ -18,6 +18,5 @@ int encode_glfw_key_event(const GLFWkeyevent *e, const bool cursor_key_mode, const unsigned flags, char *output); -// Defined in glfw.c -extern bool +bool is_modifier_key(const uint32_t key);