client: recognize kitty keyboard protocol encoding of detach key#71
client: recognize kitty keyboard protocol encoding of detach key#71mgabor3141 wants to merge 2 commits into
Conversation
|
Note on read boundaries: A reviewer pointed out that both this patch and the existing single-byte detach check assume the key event arrives as a complete, self-contained This is a pre-existing architectural limitation — the original If there's interest in making the input handling more robust across the board, both the legacy and CSI detach checks could benefit from a small ring buffer that scans across read boundaries. Happy to do that work in a follow-up if desired. |
e78e808 to
8059781
Compare
Modern terminals (kitty, wezterm, foot, ghostty) and shell/editor applications (fish, neovim, helix) increasingly use the kitty keyboard protocol, which encodes key presses as CSI u sequences instead of raw control bytes: Ctrl-\ legacy: 0x1C -> kitty protocol: ESC [ 92 ; <mod> u The modifier field encodes all active modifiers including lock keys: modifier = 1 + (shift:1|alt:2|ctrl:4|super:8|...|capslock:64|numlock:128) For example, Ctrl-\ with numlock on produces ESC[92;133u, not 0x1C. Since abduco only checked for the single-byte value, the detach key was silently ignored whenever the keyboard protocol was active — which is the default state at a fish shell prompt or inside neovim/helix. This adds a CSI u parser alongside the existing single-byte check in the client read loop. The parser: - Extracts the Unicode codepoint and verifies it matches the detach key - Extracts the modifier bitmask and checks that ctrl (bit 2) is set - Ignores other modifier bits (numlock, capslock, shift, etc.) - Handles the optional event type suffix (:1 press, :2 repeat, :3 release) - Works with any detach key configured via -e Closes martanne#66
Restrict the kitty keyboard protocol detach matcher to better mirror the legacy single-byte behavior: - Only match key press events (:1 or absent), not repeat (:2) or release (:3). In practice the press triggers detach before the release arrives, but this is more correct. - Reject if shift, alt, super, hyper, or meta are also held. The legacy byte for e.g. Ctrl-\ is distinct from Ctrl+Shift-\, so extra non-lock modifiers should not trigger detach. Lock keys (numlock, capslock) are still allowed since they do not affect key identity.
8059781 to
d6551eb
Compare
Problem
The detach key (default Ctrl-\) does not work when the kitty keyboard protocol is active. This affects an increasing number of terminal + application combinations:
Terminals: kitty, wezterm, foot, ghostty, rio
Applications that enable it: fish shell, neovim, helix, kakoune
When the protocol is active, Ctrl-\ is sent as a CSI u sequence (
ESC [ 92 ; <mod> u) instead of the raw byte0x1C. Sinceclient_mainloop()only checkspkt.u.msg[0] == KEY_DETACH(a single-byte comparison), the detach key is silently ignored.Reproducing
Subtle gotcha: numlock
The modifier field in the kitty protocol encodes all active modifiers including lock keys:
modifier = 1 + (shift:1 | alt:2 | ctrl:4 | super:8 | ... | capslock:64 | numlock:128).So Ctrl-\ with numlock on is
ESC[92;133u(notESC[92;5u). A simple string match against a fixed sequence won't work — the modifier must be parsed as a bitmask.Solution
Adds a small CSI u parser (
is_csi_detach()) alongside the existing single-byte check. It::1press,:2repeat,:3release)-eThe change is backward-compatible — the legacy single-byte check remains, so terminals not using the protocol are unaffected.
Closes #66