From 8290b136e18d437890860e3cc2a11b57f4a0a3b2 Mon Sep 17 00:00:00 2001 From: Hunter Bown Date: Sun, 3 May 2026 05:45:52 -0500 Subject: [PATCH] feat(tui): push DISAMBIGUATE_ESCAPE_CODES on startup (#442) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Opt into the Kitty keyboard protocol's escape-code disambiguation so terminals that support it (Kitty, Ghostty, Alacritty 0.13+, WezTerm, recent Konsole / xterm) report unambiguous events for Option/Alt-modified keys, plain Esc, and multi-byte sequences. Push happens after `enable_raw_mode` and the alt-screen / mouse-capture / bracketed-paste setup so the order matches shutdown's reverse-order pop. Only the disambiguation tier is pushed — `REPORT_EVENT_TYPES` and the higher tiers emit release events that the existing key handlers would mis-route as duplicate presses. Pop on exit was already wired in main.rs (panic) and ui.rs (normal shutdown) per #443; the recent #443 follow-up extended that to the suspend paths so editor / shell-suspend children inherit a clean keyboard mode. The push + the four pops form a complete pair. Failure to push is logged at debug level and ignored — a quirky terminal can't block startup. On terminals without protocol support the escape sequence is silently discarded and behaviour is identical to today (iTerm2, Terminal.app, Windows 10 conhost). No new dependency; everything runs through crossterm's existing `PushKeyboardEnhancementFlags` command. --- CHANGELOG.md | 11 +++++++++++ crates/tui/src/tui/ui.rs | 25 +++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9347d15d..f3afe7b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -165,6 +165,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 the same hierarchy `App::new` uses (`.agents/skills` → `skills` → `~/.deepseek/skills`). Available in Plan and Agent/Yolo modes. +- **Kitty keyboard protocol opt-in** (#442) — pushes + `DISAMBIGUATE_ESCAPE_CODES` at startup so terminals that + support the protocol (Kitty, Ghostty, Alacritty 0.13+, + WezTerm, recent Konsole / xterm) report unambiguous events + for Option/Alt-modified keys, plain Esc, and multi-byte + sequences. Legacy terminals silently discard the escape and + see no change. Only the disambiguation tier is pushed — + release-event reporting was deliberately skipped because the + existing handlers would mis-route releases as duplicate + presses. The flags are popped on shutdown / panic / suspend + paths (#443). - **RLM tool family** (#512) — `rlm` tool cards map to `ToolFamily::Rlm` and render `rlm`, not `swarm`. Stale "swarm" wording cleaned out of docs / comments / tests. diff --git a/crates/tui/src/tui/ui.rs b/crates/tui/src/tui/ui.rs index eed3a6b3..2782229b 100644 --- a/crates/tui/src/tui/ui.rs +++ b/crates/tui/src/tui/ui.rs @@ -180,6 +180,31 @@ pub async fn run_tui(config: &Config, options: TuiOptions) -> Result<()> { if use_bracketed_paste { execute!(stdout, EnableBracketedPaste)?; } + // #442: opt into the Kitty keyboard protocol's escape-code + // disambiguation so terminals that support it (Kitty, Ghostty, + // Alacritty 0.13+, WezTerm, recent Konsole, recent xterm) report + // unambiguous events for Option/Alt-modified keys, plain Esc, and + // multi-byte sequences. Terminals that don't recognise the escape + // silently discard it; behaviour is identical to today on legacy + // terminals (iTerm2, Terminal.app, Windows 10 conhost). + // + // Only `DISAMBIGUATE_ESCAPE_CODES` is pushed — the higher tiers + // (`REPORT_EVENT_TYPES`, `REPORT_ALL_KEYS_AS_ESCAPE_CODES`) emit + // release events that the existing key handlers would mis-route + // as duplicate presses. Best-effort: failure to push is logged + // and ignored so a quirky terminal can't block startup. + if let Err(err) = execute!( + stdout, + crossterm::event::PushKeyboardEnhancementFlags( + crossterm::event::KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES + ) + ) { + tracing::debug!( + target: "kitty_keyboard", + ?err, + "PushKeyboardEnhancementFlags ignored (terminal lacks support)" + ); + } let backend = CrosstermBackend::new(stdout); let mut terminal = Terminal::new(backend)?; let event_broker = EventBroker::new();