Files
orca/src/main
Brennan BensonandBrennan Benson da2c692d31 fix(terminal): forward Option hotkeys to kitty-keyboard TUIs on compose layouts (#8031)
* fix(terminal): forward Option hotkeys to kitty-keyboard TUIs on compose layouts

On macOS layouts where Option composes characters (ABC and all non-US, the
effective default), pressing Option+P in a TUI that negotiated the kitty
keyboard protocol made xterm's kitty encoder report the composed codepoint
(alt+pi, CSI 960;3u) instead of the physical key (alt+p, CSI 112;3u). No TUI
binds the composed form, so agent hotkeys like OMP's Alt+P / Alt+M neither
fired nor typed anything.

Fix: mirror each pane's application-negotiated kitty flags with a scan-based
tracker fed only from PTY output (immune to Orca's defensive renderer-side
kitty resets on Ctrl+C interrupts and reattach), and have the terminal
shortcut policy encode Option chords as kitty CSI-u from the physical key
when the pane's app opted in. Dead keys stay exempt so Option composition
still works, and panes without kitty negotiation (shells) are unchanged.
Alt+Arrow / Alt+Backspace now defer to xterm's native kitty encoding in
kitty panes instead of the legacy readline translations.

The daemon's headless emulator tracks the same flags and re-arms them via
the snapshot rehydrate preamble (CSI = flags ; 1 u), so the behavior
survives window reloads and reattaches; PTY exit and cold restore reset the
mirror.

Validated byte-for-byte against a real omp 16.3.15 in a pty: the policy's
emitted CSI-u opens the temporary-model selector (Alt+P) and agent hub
(Alt+A), identical to the legacy ESC-prefixed forms it parses.

* fix(terminal): harden kitty Option-chord mirror for soft resets, replay redelivery, and non-QWERTY layouts

Three review findings on the kitty keyboard mirror, each verified against a
live omp 16.3.15 pty session using the real production modules:

- DECSTR: xterm's soft reset (CSI ! p) clears its kitty flags and stacks for
  both screens without switching buffers; the tracker now mirrors that, so a
  soft-resetting TUI stops receiving kitty-encoded Option chords.

- Replay redelivery: relay reconnects can redeliver the retained replay
  window, and each scan of the app's one-time CSI > u push grew the mirrored
  stack while the renderer's post-replay reset drained xterm's copy. The
  TUI's single exit pop (omp emits a bare CSI < u on quit) then landed on a
  stale frame, leaving Option+B/F/D kitty-encoded in a plain shell. Replay
  paths now scan with scanReplay(), which applies pushes as idempotent sets
  so redelivery cannot grow the stack; the live-output funnel and the
  daemon's once-per-byte emulator keep full stack semantics.

- Layout-correct base keys: kitty CSI-u reports must carry the key's
  unshifted codepoint in the active layout, but the encoder resolved it from
  a US-QWERTY physical-code table — on Dvorak/Colemak/AZERTY-class layouts
  (exactly the population whose effective Option-as-Alt default activates
  this path) the wrong key's chord fired, e.g. Colemak Option+P sent alt+r.
  A new keyboard-layout module caches Chromium's KeyboardLayoutMap (fetched
  at terminal setup and on focus-in, like the option-as-alt probe) and the
  policy resolves through it before the US fallback. Verified live: the
  layout-resolved bytes open omp's model selector; the US-table bytes do not.

* fix(terminal): reset kitty mirror on fresh spawn to cover replaced-PTY late exits

The exit handler resets the per-pane kitty keyboard mirror, but a late exit
from a replaced PTY takes the stale-transport early return and skips it —
so a restart-in-place could leak the old TUI's kitty flags into the fresh
shell, kitty-encoding Option chords the shell cannot parse. A fresh spawn
is by definition a new process with kitty state at zero, so startFreshSpawn
now resets the reused tracker itself, alongside the other per-pane mode
state it already clears. Reattach paths are untouched, so a live TUI's
mirrored flags still survive reconnects.

---------

Co-authored-by: Brennan Benson <brennanbenson@Brennans-MacBook-Pro.local>
2026-07-10 13:45:33 -07:00
..
2026-07-09 21:54:22 -07:00
2026-05-30 02:46:28 -07:00
2026-05-30 13:09:17 -07:00