diff --git a/kittens/broadcast/main.py b/kittens/broadcast/main.py index 6f13b2db3..e9b7947f5 100644 --- a/kittens/broadcast/main.py +++ b/kittens/broadcast/main.py @@ -9,7 +9,7 @@ from typing import Any, Dict, List, Optional, Tuple from kitty.cli import parse_args from kitty.cli_stub import BroadcastCLIOptions -from kitty.key_encoding import RELEASE, key_defs as K +from kitty.key_encoding import RELEASE, encode_key_event, key_defs as K from kitty.rc.base import MATCH_TAB_OPTION, MATCH_WINDOW_OPTION from kitty.remote_control import create_basic_command, encode_send from kitty.typing import KeyEventType @@ -48,12 +48,17 @@ class Broadcast(Handler): if key_event.key is K['TAB']: self.write_broadcast_text('\t') self.write('\t') + return elif key_event.key is K['BACKSPACE']: self.write_broadcast_text('\177') self.write('\x08\x1b[X') + return elif key_event.key is K['ENTER']: self.write_broadcast_text('\r') self.print('') + return + ek = encode_key_event(key_event) + self.write_broadcast_data('kitty-key:' + ek) def write_broadcast_text(self, text: str) -> None: self.write_broadcast_data('base64:' + standard_b64encode(text.encode('utf-8')).decode('ascii')) diff --git a/kittens/tui/loop.py b/kittens/tui/loop.py index dff048504..2f339791c 100644 --- a/kittens/tui/loop.py +++ b/kittens/tui/loop.py @@ -302,7 +302,7 @@ class Loop: def _on_apc(self, apc: str) -> None: if apc.startswith('K'): try: - k = decode_key_event(apc) + k = decode_key_event(apc[1:]) except Exception: pass else: diff --git a/kitty/key_encoding.py b/kitty/key_encoding.py index e7e072349..7c7eb7283 100644 --- a/kitty/key_encoding.py +++ b/kitty/key_encoding.py @@ -417,6 +417,10 @@ def symbolic_name(glfw_name: str) -> str: return glfw_name[9:].replace('_', ' ') +def glfw_key_name(symbolic_name: str) -> str: + return 'GLFW_KEY_' + symbolic_name.replace(' ', '_') + + def update_encoding() -> None: import re import subprocess @@ -492,9 +496,9 @@ del key_name, enc def decode_key_event(text: str) -> KeyEvent: - typ = type_map[text[1]] - mods = mod_map[text[2]] - key = key_rmap[text[3:5]] + typ = type_map[text[0]] + mods = mod_map[text[1]] + key = key_rmap[text[2:4]] return KeyEvent(typ, mods, key) @@ -503,3 +507,32 @@ def encode_key_event(key_event: KeyEvent) -> str: mods = rmod_map[key_event.mods] key = ENCODING[key_event.key.replace('_', ' ')] return typ + mods + key + + +class WindowSystemKeyEvent(NamedTuple): + code: int + mods: int + action: int + + +def decode_key_event_as_window_system_key(text: str) -> Optional[WindowSystemKeyEvent]: + k = decode_key_event(text) + glfw_name = glfw_key_name(k.key) + glfw_code = getattr(defines, glfw_name, None) + if glfw_code is None: + return None + action = defines.GLFW_PRESS + if k.type is RELEASE: + action = defines.GLFW_RELEASE + elif k.type is REPEAT: + action = defines.GLFW_REPEAT + mods = 0 + if k.mods & CTRL: + mods |= defines.GLFW_MOD_CONTROL + if k.mods & ALT: + mods |= defines.GLFW_MOD_ALT + if k.mods & SUPER: + mods |= defines.GLFW_MOD_SUPER + if k.mods & SHIFT: + mods |= defines.GLFW_MOD_SHIFT + return WindowSystemKeyEvent(glfw_code, mods, action) diff --git a/kitty/rc/send_text.py b/kitty/rc/send_text.py index fe2fa9dcc..8149de50e 100644 --- a/kitty/rc/send_text.py +++ b/kitty/rc/send_text.py @@ -8,6 +8,10 @@ import sys from typing import TYPE_CHECKING, Dict, Generator, List, Optional from kitty.config import parse_send_text_bytes +from kitty.key_encoding import ( + WindowSystemKeyEvent, decode_key_event_as_window_system_key +) +from kitty.keys import interpret_key_event from .base import ( MATCH_TAB_OPTION, MATCH_WINDOW_OPTION, ArgsType, Boss, MatchError, @@ -142,13 +146,20 @@ Do not send text to the active window, even if it is one of the matched windows. data = q.encode('utf-8') elif encoding == 'base64': data = base64.standard_b64decode(q) + elif encoding == 'kitty-key': + data = decode_key_event_as_window_system_key(q) else: raise TypeError(f'Invalid encoding for send-text data: {encoding}') exclude_active = payload_get('exclude_active') for window in windows: if window is not None: if not exclude_active or window is not boss.active_window: - window.write_to_child(data) + if isinstance(data, WindowSystemKeyEvent): + kdata = interpret_key_event(data.code, 0, data.mods, window, data.action) + if kdata: + window.write_to_child(kdata) + else: + window.write_to_child(data) send_text = SendText()