From 701f40b5c8e88fc216d6636f43b2b360bda72dbf Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 17 Sep 2026 14:22:59 +0530 Subject: [PATCH] fix #10490 --- docs/changelog.rst | 4 ++++ docs/mapping.rst | 2 ++ kitty/keys.py | 3 +++ kitty/options/utils.py | 2 +- kitty_tests/keys.py | 7 +++++++ 5 files changed, 17 insertions(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 07400a527..dac6061e5 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -344,6 +344,10 @@ Detailed list of changes - :doc:`Multiple cursors protocol `: Fix hiding the main cursor with DECTCEM also hiding the extra cursors (:iss:`10489`) +- Add a new ``passthrough_and_end`` value for the ``--on-unknown`` option of + ``map``, that passes the unknown key through to the program and also exits + the custom keyboard mode (:iss:`10490`) + 0.48.2 [2026-07-30] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/mapping.rst b/docs/mapping.rst index 9c30ace8e..e9df3116d 100644 --- a/docs/mapping.rst +++ b/docs/mapping.rst @@ -415,6 +415,8 @@ below:: map --new-mode XXX --on-unknown end ... # Pass unknown keys to the program running in the active window map --new-mode XXX --on-unknown passthrough ... + # Pass unknown keys to the program and exit the keyboard mode + map --new-mode XXX --on-unknown passthrough_and_end ... When a key matches an action in a custom keyboard mode, the action is performed and the custom keyboard mode remains in effect. If you would rather have the diff --git a/kitty/keys.py b/kitty/keys.py index 17717f89e..c8c7e6574 100644 --- a/kitty/keys.py +++ b/kitty/keys.py @@ -242,6 +242,9 @@ class Mappings: return True if mode.on_unknown == 'passthrough': return False + if mode.on_unknown == 'passthrough_and_end': + self.pop_keyboard_mode() + return False if not self.pop_keyboard_mode(): self.ring_bell() return True diff --git a/kitty/options/utils.py b/kitty/options/utils.py index da7c5ae8c..2a49ce105 100644 --- a/kitty/options/utils.py +++ b/kitty/options/utils.py @@ -1414,7 +1414,7 @@ class LiteralField(Generic[T]): obj.__dict__[self._name] = value -OnUnknown = Literal['beep', 'end', 'ignore', 'passthrough'] +OnUnknown = Literal['beep', 'end', 'ignore', 'passthrough', 'passthrough_and_end'] OnAction = Literal['keep', 'end'] diff --git a/kitty_tests/keys.py b/kitty_tests/keys.py index ce08edf26..570108632 100644 --- a/kitty_tests/keys.py +++ b/kitty_tests/keys.py @@ -666,6 +666,13 @@ class TestKeys(BaseTest): self.ae(tm('x'), [True]) af(tm.keyboard_mode_stack) + # passthrough_and_end: unknown key exits the mode and is passed through + tm = TM('map --new-mode mw --on-unknown passthrough_and_end kitty_mod+f7', 'map --mode mw left neighboring_window left') + self.ae(tm('ctrl+shift+f7'), [True]) + self.ae(tm.actions, ['push_keyboard_mode mw']) + self.ae(tm('x'), [False]) + af(tm.keyboard_mode_stack) + # modal mapping with --on-action=end must restore OS keyboard processing tm = TM('map --new-mode mw --on-action end m', 'map --mode mw a new_window') self.ae(tm('m', 'a'), [True, True])