From 74388b4183d0f7253221d62cbb7c48070e4c1fc9 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 3 Dec 2023 13:08:53 +0530 Subject: [PATCH] A simple action to remap key presses sent to programs running in kitty --- docs/changelog.rst | 3 +++ docs/faq.rst | 16 +++++----------- docs/mapping.rst | 19 ++++++------------- kitty/options/utils.py | 5 +++++ kitty/window.py | 30 ++++++++++++++++++++++++++++++ 5 files changed, 49 insertions(+), 24 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index e528d8332..8703a8ec8 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -48,6 +48,9 @@ Detailed list of changes - A new option :opt:`notify_on_cmd_finish` to show a desktop notification when a long running command finishes (:pull:`6817`) +- A new action :ac:`send_key` to simplify mapping key presses to other keys without needing :ac:`send_text` + + 0.31.0 [2023-11-08] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/faq.rst b/docs/faq.rst index e52490747..f4857f25f 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -389,20 +389,14 @@ How do I map key presses in kitty to different keys in the terminal program? This is accomplished by using ``map`` with :sc:`send_text ` in :file:`kitty.conf`. For example:: - map alt+s send_text normal,application \x13 + map alt+s send_key ctrl+s -This maps :kbd:`alt+s` to :kbd:`ctrl+s`. To figure out what bytes to use for -the :sc:`send_text ` you can use the ``show_key`` kitten. Run:: +This causes the program running in kitty to receive the :kbd:`ctrl+s` key when +you press the :kbd:`alt+s` key. To see this in action, run:: - kitten show_key + kitten show-key -m kitty -Then press the key you want to emulate. Note that this kitten will only show -keys that actually reach the terminal program, in particular, keys mapped to -actions in kitty will not be shown. To check those first map them to -:ac:`no_op`. You can also start a kitty instance without any shortcuts to -interfere:: - - kitty -o clear_all_shortcuts=yes kitten show_key +Which will print out what key events it receives. How do I open a new window or tab with the same working directory as the current window? diff --git a/docs/mapping.rst b/docs/mapping.rst index 5e601f386..addbed08e 100644 --- a/docs/mapping.rst +++ b/docs/mapping.rst @@ -215,23 +215,16 @@ also simulate pressing the enter key which is ``\r``. For example:: Now, if you press :kbd:`f1` when at shell prompt it will run the ``echo Hello, world!`` command. -To have one key press send another key press:: +To have one key press send another key press, use :ac:`send_key`:: - map alt+s send_text normal,application \x13 + map alt+s send_key ctrl+s -This maps :kbd:`alt+s` to :kbd:`ctrl+s`. To figure out what bytes to use for -the :sc:`send_text ` you can use the ``show_key`` kitten. Run:: +This causes the program running in kitty to receive the :kbd:`ctrl+s` key when +you press the :kbd:`alt+s` key. To see this in action, run:: - kitten show_key + kitten show-key -m kitty -Then press the key you want to emulate. Note that this kitten will only show -keys that actually reach the terminal program, in particular, keys mapped to -actions in kitty will not be shown. To check those first unmap them. -You can also start a kitty instance without any shortcuts to interfere: - -.. code-block:: sh - - kitty -o clear_all_shortcuts=yes kitten show_key +Which will print out what key events it receives. All mappable actions ------------------------ diff --git a/kitty/options/utils.py b/kitty/options/utils.py index f6ffbf81c..87eeafbc0 100644 --- a/kitty/options/utils.py +++ b/kitty/options/utils.py @@ -89,6 +89,11 @@ def send_text_parse(func: str, rest: str) -> FuncArgsType: return func, [mode, data] +@func_with_args('send_key') +def send_key(func: str, rest: str) -> FuncArgsType: + return func, rest.split() + + @func_with_args('run_kitten', 'run_simple_kitten', 'kitten') def kitten_parse(func: str, rest: str) -> FuncArgsType: if func == 'kitten': diff --git a/kitty/window.py b/kitty/window.py index 418dc4836..25ea26b51 100644 --- a/kitty/window.py +++ b/kitty/window.py @@ -46,6 +46,8 @@ from .fast_data_types import ( CURSOR_UNDERLINE, DCS, GLFW_MOD_CONTROL, + GLFW_PRESS, + GLFW_RELEASE, NO_CURSOR_SHAPE, OSC, SCROLL_FULL, @@ -871,6 +873,34 @@ class Window: self.write_to_child(text) return False + @ac( + 'misc', ''' + Send the specified keys to the active window. + Note that the key will be sent only if the current keyboard mode of the program running in the terminal supports it. + Both key press and key release are sent. First presses for all specified keys and then releases in reverse order. + To send a pattern of press and release for multiple keys use the :ac:`combine` action. For example:: + + map f1 send_key ctrl+x alt+y + map f1 combine : send_key ctrl+x : send_key ctrl+y + ''') + def send_key(self, *args: str) -> bool: + from .options.utils import parse_shortcut + km = get_options().kitty_mod + passthrough = True + events = [] + for human_key in args: + sk = parse_shortcut(human_key) + if sk.is_native: + raise ValueError(f'Native key codes not allowed in send_key: {human_key}') + sk = sk.resolve_kitty_mod(km) + events.append(KeyEvent(key=sk.key, mods=sk.mods, action=GLFW_PRESS)) + for ev in events + [KeyEvent(key=x.key, mods=x.mods, action=GLFW_RELEASE) for x in reversed(events)]: + enc = self.encoded_key(ev) + if enc: + self.write_to_child(enc) + passthrough = False + return passthrough + @ac('debug', 'Show a dump of the current lines in the scrollback + screen with their line attributes') def dump_lines_with_attrs(self) -> None: strings: List[str] = []