From 119e30627bc9bd1c84104b7ae3736fedaa12711f Mon Sep 17 00:00:00 2001 From: teknium1 <127238744+teknium1@users.noreply.github.com> Date: Fri, 18 Sep 2026 04:23:28 -0700 Subject: [PATCH] fix(cli): Super+ under modifyOtherKeys types the character Ghostty encodes Super+o as ESC[27;9;111~ (Super+Shift as modifier 10) once modifyOtherKeys=2 is pushed; the CLI has no Super bindings, so the sequence leaked as literal escape text (#114242). Map the tilde form for modifiers 9 and 10 over the printable range to chr(cp), the same produced-codepoint rule the Shift rows use and what the Ink TUI already does. --- hermes_cli/pt_input_extras.py | 6 +++++- tests/hermes_cli/test_modify_other_keys_aliases.py | 11 +++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/hermes_cli/pt_input_extras.py b/hermes_cli/pt_input_extras.py index 17d6daef49..71826ea3b9 100644 --- a/hermes_cli/pt_input_extras.py +++ b/hermes_cli/pt_input_extras.py @@ -252,8 +252,12 @@ def _modify_other_keys_aliases(ANSI_SEQUENCES: dict, Keys) -> dict[str, object]: # Existing entries (Shift+Enter \x1b[27;2;13~, Shift+Tab, Shift+Space) win via setdefault. # xterm/Ghostty only use this encoding for produced codepoints 0x40-0x7E (`IsControlInput`); # '!' '#' '$' still arrive as plain text, so the 33-63 rows are inert there but harmless. + # Super+ (modifier 9, Super+Shift 10) follows the same produced-codepoint rule: + # Ghostty sends Super+o as ESC[27;9;111~ (#114242). The CLI has no Super bindings, so type + # the character — what the terminal sends without modifyOtherKeys and what the Ink TUI does. for cp in range(33, 127): - _put(f"\x1b[27;2;{cp}~", chr(cp)) + for modifier in (2, 9, 10): + _put(f"\x1b[27;{modifier};{cp}~", chr(cp)) # The Esc KEY under Kitty disambiguate mode: ESC[27u (+ modifiers 1-16 incl. super 9+, and # lock twins of the modifier-less form, which is how a lone Esc arrives with a lock on). diff --git a/tests/hermes_cli/test_modify_other_keys_aliases.py b/tests/hermes_cli/test_modify_other_keys_aliases.py index c304f0730c..c54db220db 100644 --- a/tests/hermes_cli/test_modify_other_keys_aliases.py +++ b/tests/hermes_cli/test_modify_other_keys_aliases.py @@ -287,6 +287,17 @@ def test_modify_other_keys_shift_symbol_produces_char(cp): assert ANSI_SEQUENCES.get(f"\x1b[{cp};2u") is None +@pytest.mark.parametrize("seq, ch", [ + ("\x1b[27;9;111~", "o"), # Super+o (the #114242 report) + ("\x1b[27;10;79~", "O"), # Super+Shift+o +]) +def test_modify_other_keys_super_printable_produces_char(seq, ch): + """Ghostty encodes Super+ as ESC[27;9;~ under modifyOtherKeys=2; + the CLI has no Super bindings, so it must type the character (Ink TUI parity), + not leak the escape text (#114242).""" + assert _parse(seq) == [ch] + + def test_shift_symbol_data_normalized_in_buffer(): """End-to-end: Vt100Parser with install_keypress_data_normalization must deliver the character in KeyPress.data, not the raw escape."""