[Bug]: macOS — Option-composed non-ASCII letters (ç, ñ, å, ø) are swallowed in kitty-protocol TUIs even with "Option as Alt" disabled
- Dominant language
- TypeScript
- Stars
- 71.3k
- Forks
- 4.7k
- Avg merge
- 14h 54m
- Merged PRs (30d)
- 520
Description
## Problem
On macOS, `Option+C` (→ `ç`) does not reach a TUI that has negotiated the kitty keyboard
protocol. Instead of the composed character, the pane sends the physical chord `alt+c`
encoded as `CSI 99;3u`, and the character is lost entirely.
This happens **even though the pane is configured with Option explicitly NOT acting as
Alt** (`terminalMacOptionAsAlt: "false"`, Settings → Terminal → macOS keyboard). That
setting is the user stating "Option composes characters here", so a composed character
should be delivered verbatim.
It affects every letter macOS composes with Option outside ASCII: `ç ñ å ø œ æ ¡ ¿ …`
For pt-BR / es / da / no / sv users, `ç` is a plain letter typed dozens of times a day,
so a kitty-protocol agent pane is effectively unusable for writing prose.
No pane setting avoids it: none of the four `macOptionAsAlt` values
(`true` / `false` / `left` / `right`) reaches a code path that sends the character, and
switching the macOS input source between `U.S.` and `U.S. International – PC` does not
change the Option+C path either.
What *does* work under the very same kitty flags is the dead-key route on
`U.S. International – PC` (`'` then `c`, no Option held), which never enters this policy.
That isolates the defect precisely to the Option keydown path — the pane, the encoder and
the PTY all deliver `ç` fine.
## Environment
- Orca 1.4.199, macOS 26.5 (arm64)
- macOS input source: `U.S.` (also reproduced on `U.S. International – PC`)
- Settings → Terminal → macOS keyboard: Option is **not** Alt (`terminalMacOptionAsAlt = "false"`)
- Affected TUI: Claude Code 2.1.269 (enables the kitty keyboard protocol)
- **Not** affected: Codex, Grok — neither negotiates the protocol, and Orca already
force-disables kitty for `tuiAgent === 'grok'`
## Reproduce (no agent needed)
In any Orca terminal pane, with `terminalMacOptionAsAlt = "false"`:
```sh
printf '\033[5u'; cat -v # flags 5 = exactly what Claude Code sends
# now press Option+C
```
| kitty flags | bytes received on Option+C |
| --- | --- |
| protocol off | `ç` :white_check_mark: |
| `CSI > 1 u` | `ç` :white_check_mark: |
| `CSI > 5 u` | `^[[99;3u` :x: — character lost |
| `CSI > 29 u` | `^[[99;3;231u` :white_check_mark: (survives only as associated text) |
Same pane, same `CSI > 5 u`, but typing `ç` as `'`+`c` on `U.S. International – PC`
(no Option): `ç` arrives correctly.
Injecting `ç` as text with no Alt modifier works under any flag set, so the pane and the
PTY are fine — only the Option keydown path is.
## Root cause
`src/renderer/src/components/terminal-pane/terminal-option-shortcut-policy.ts`
`resolveTerminalOptionShortcutAction` guards the "send the composed text" branch with
`isLayoutComposedAsciiCharacter`, which accepts only code points `0x21…0x7e`:
```ts
// Why ASCII-only: the protocol says a text-producing key sends its text, but #8031 needs Option
// hotkeys to still reach kitty TUIs. ASCII splits the two — layouts hide `@ $ # [ ] { } \ |` behind
// Option with no other way to type them, while the glyphs on TUI-bound keys (π, ƒ, ∫) never are.
```
`ç` is U+00E7, so it fails the guard, falls through to `encodeTerminalOptionKittyEvent`,
and is emitted as the `alt+c` chord instead of as text.
That ASCII line was drawn in #14743 (fixing #14024, `@` / `$` on the Turkish layout). It
separates symbols from TUI glyphs correctly, but puts **accented letters on the wrong
side**: `ç`, `ñ`, `å` are letters the layout composes — not `π` / `ƒ` / `∫` glyphs that
happen to sit on TUI-bound keys.
## Suggested fix
When `canSendComposedText` is true — i.e. the user configured `macOptionAsAlt` so that
this Option side does **not** act as Alt — send the composed character regardless of its
code point. The user has already declared Option's role; the ASCII heuristic is only
needed where that role is ambiguous. Users who want Option to reach kitty TUIs as a
modifier (the #8031 case) set `macOptionAsAlt: "true"`, which this leaves untouched.
If a narrower change is preferred, at minimum widen the guard to Unicode letters whose
NFD decomposition starts with the key's unmodified base character (`ç` → `c`, `ñ` → `n`,
`å` → `a`), which keeps `π` / `ƒ` / `∫` on the chord path.
## Why it surfaced now
Claude Code ≤ 2.1.268 enabled the kitty protocol only for an allowlist of terminals
(`iTerm.app`, `kitty`, `WezTerm`, `ghostty`, `tmux`, `windows-terminal`, `WarpTerminal`)
— Orca was not in it, so the protocol stayed off and `ç` worked. 2.1.269 added a
`CSI ? u` probe; Orca answers it, so Claude Code now enables `CSI > 5 u` and the latent
bug became reachable. This also explains the "Not affected: Claude" note in #14024 back
in August.
Contributor guide
Research direction
Start with `src/renderer/src/components/terminal-pane/terminal-option-shortcut-policy.ts` and read `resolveTerminalOptionShortcutAction`, especially the composed-text guard and the kitty-event fallback. Check for tests covering this policy and the existing Option-as-Alt behavior. Reproduce with kitty flags 5 and Option+C; done means the composed character reaches the TUI when Option is configured not to act as Alt, while the Alt-modifier behavior remains available when configured as Alt.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- devtools
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100