Summary
Implement the higher levels of the kitty keyboard protocol, building on the level-1 ("disambiguate escape codes") support added in 71e69e81.
Level 1 is intentionally isolated to crates/okena-terminal/src/input.rs (kitty_disambiguate_bytes) and the KittyKeyboardFlags plumbing, because it only rewrites keys that already bypass the GPUI text-input path. The remaining levels touch the delicate text-input dispatch and need their own focused effort + manual cross-platform verification.
Scope (what's still missing)
alacritty_terminal already tracks all of these flags in TermMode; okena only honors DISAMBIGUATE_ESC_CODES today. To implement:
Architectural considerations
This is the part that made us split it out (see discussion). It is an extension of an existing pattern, not a violation — but it lands in the most sensitive part of input:
- Mode-dependent text routing. When
REPORT_ALL_KEYS_AS_ESC is on, text keys must be intercepted at on_key_down and the InputHandler text path suppressed. The view already branches on terminal mode per keystroke (is_app_cursor_mode(), now kitty_keyboard_flags()), so this extends that — but it must be done carefully so normal typing never regresses when the flag is off.
- IME / dead keys / compose. Bypassing
InputHandler bypasses OS text composition. REPORT_ASSOCIATED_TEXT wants the composed character at key-down, which doesn't exist yet for IME. Even reference terminals have caveats here. This is the main correctness hazard and the reason manual cross-platform testing (macOS IME, Linux compose) is required.
- Key-release events.
REPORT_EVENT_TYPES needs key-up delivery to the terminal element.
- Flag-advertising asymmetry. alacritty answers the app's
CSI ? u query with whatever flags the app pushed, regardless of what okena actually encodes. With only level 1 implemented, an app that requested a higher level is told it's active but receives legacy bytes for the keys we don't yet encode. (Level 1 is never worse than the previous all-legacy behavior; this matters when implementing partial higher levels.) A clean fix would be to clamp the accepted flags to what okena can honor — which needs a sidecar that filters the kitty set/push CSI u sequences alacritty currently handles internally.
References
- Kitty keyboard protocol spec: https://sw.kovidgoyal.net/kitty/keyboard-protocol/
- alacritty's own encoder (
alacritty/src/input/keyboard.rs) is the closest reference, since okena consumes alacritty's TermMode flags.
- Level-1 implementation + plumbing to mirror: commit 71e69e81 (
crates/okena-terminal/src/input.rs, terminal/modes.rs).
Acceptance
- neovim / kitty's
kitty +kitten show_key -m kitty report correct codes across press/repeat/release.
- No regression to normal typing, IME, or dead-key/compose input when the protocol is off (the common case).
- Unit tests for the encoder cover each level's representative cases, alongside the existing level-1 tests in
input::tests.
🤖 Generated with Claude Code
Summary
Implement the higher levels of the kitty keyboard protocol, building on the level-1 ("disambiguate escape codes") support added in 71e69e81.
Level 1 is intentionally isolated to
crates/okena-terminal/src/input.rs(kitty_disambiguate_bytes) and theKittyKeyboardFlagsplumbing, because it only rewrites keys that already bypass the GPUI text-input path. The remaining levels touch the delicate text-input dispatch and need their own focused effort + manual cross-platform verification.Scope (what's still missing)
alacritty_terminalalready tracks all of these flags inTermMode; okena only honorsDISAMBIGUATE_ESC_CODEStoday. To implement:REPORT_ALL_KEYS_AS_ESC(0b1000) — every key, including plain printable characters, must be reported asCSI uand must not be delivered as text. Requires routing text away from GPUI'sInputHandlerwhen the flag is active.REPORT_ASSOCIATED_TEXT(0b10000) — include the produced text as codepoints in theCSI usequence (CSI key ; mods ; text u). Needs the resolved character at key-down time, which is not available for IME / dead-key / compose input.REPORT_EVENT_TYPES(0b10) — emit press / repeat / release event types (CSI key ; mods:event u). Requires wiring key-up events, which the current input dispatch does not handle.REPORT_ALTERNATE_KEYS(0b100) — include shifted / base-layout alternate key codes (CSI key:shifted:base ; mods u). Needs richer key info than okena's currentKeyEvent { key: String, key_char, modifiers }carries.KittyKeyboardFlags(currently a singledisambiguate_escape_codesfield) andTerminal::kitty_keyboard_flags()to expose all the flags.CSI u/ functional forms the protocol expects.Architectural considerations
This is the part that made us split it out (see discussion). It is an extension of an existing pattern, not a violation — but it lands in the most sensitive part of input:
REPORT_ALL_KEYS_AS_ESCis on, text keys must be intercepted aton_key_downand theInputHandlertext path suppressed. The view already branches on terminal mode per keystroke (is_app_cursor_mode(), nowkitty_keyboard_flags()), so this extends that — but it must be done carefully so normal typing never regresses when the flag is off.InputHandlerbypasses OS text composition.REPORT_ASSOCIATED_TEXTwants the composed character at key-down, which doesn't exist yet for IME. Even reference terminals have caveats here. This is the main correctness hazard and the reason manual cross-platform testing (macOS IME, Linux compose) is required.REPORT_EVENT_TYPESneeds key-up delivery to the terminal element.CSI ? uquery with whatever flags the app pushed, regardless of what okena actually encodes. With only level 1 implemented, an app that requested a higher level is told it's active but receives legacy bytes for the keys we don't yet encode. (Level 1 is never worse than the previous all-legacy behavior; this matters when implementing partial higher levels.) A clean fix would be to clamp the accepted flags to what okena can honor — which needs a sidecar that filters the kitty set/pushCSI usequences alacritty currently handles internally.References
alacritty/src/input/keyboard.rs) is the closest reference, since okena consumes alacritty'sTermModeflags.crates/okena-terminal/src/input.rs,terminal/modes.rs).Acceptance
kitty +kitten show_key -m kittyreport correct codes across press/repeat/release.input::tests.🤖 Generated with Claude Code