# Fix: special characters not input on non‑US keyboard layouts - #13
Open
visitorise wants to merge 1 commit into
Open
# Fix: special characters not input on non‑US keyboard layouts#13visitorise wants to merge 1 commit into
visitorise wants to merge 1 commit into
Conversation
Remove REPORT_ALL_KEYS_AS_ESCAPE_CODES from Kitty keyboard protocol enhancement flags. On non-US layouts, special character keys that interact with layout-specific modifiers (JIS Kana/Kanji, Alt-Gr, etc.) were encoded as CSI-u escape sequences with unexpected modifier bits, causing crossterm to fail decoding them as KeyCode::Char(..). Keeping DISAMBIGUATE_ESCAPE_CODES and REPORT_EVENT_TYPES ensures ESC/Ctrl-C disambiguation and key event type reporting remain functional. Numeric keypad input is unaffected as it uses a separate scancode path.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fix: special characters not input on non‑US keyboard layouts
1. Symptoms
On non‑US keyboard layouts (e.g. JIS, German, French, Nordic), the following special characters cannot be typed on the main keyboard area:
=,~,|,`,{,},+,*These characters work correctly when typed on the numeric keypad, and standard ASCII letters (
a–z,0–9) are unaffected. The issue manifests in Ghostty and other terminals that fully support the Kitty keyboard protocol.2. Root Cause
The Kitty keyboard protocol's Report all keys as escape codes progressive enhancement (flag
0b1000, value8) instructs the terminal to encode every keystroke — including plain text-producing keys — as CSI‑u escape sequences instead of raw UTF‑8 bytes.On non‑US keyboard layouts, special character keys occupy physical positions that differ from the US layout and may interact with layout‑specific modifier keys defined by
xkb(e.g. Kana / Kanji on JIS, Alt‑Gr on D and Y, Option on Mac). When the terminal wraps these keystrokes in CSI‑u sequences (CSI 61 ; modifiers u), the OS‑level keyboard‑layout translation can attach unexpected modifier bits (e.g.SUPER,META). Crossterm then fails to decode the resulting escape sequence back intoKeyCode::Char(…), causing the character to be silently dropped.The numeric keypad uses distinct hardware scancodes that bypass this code path, which is why those keys are unaffected.
3. Fix
Remove
REPORT_ALL_KEYS_AS_ESCAPE_CODESfrom thePushKeyboardEnhancementFlagsinvocation while keeping the other two flags.Two files changed:
src/main.rs— main event loop terminal setupsrc/remote/mod.rs— remote TUI terminal mode guardBefore:
After:
4. Impact Analysis
4.1 Why this is safe
The
DISAMBIGUATE_ESCAPE_CODESandREPORT_EVENT_TYPESflags are retained, so all of the following continue to work:Ctrl+Cambiguity. TheDISAMBIGUATE_ESCAPE_CODESflag alone is sufficient to distinguish a loneEscapepress from the start of an escape sequence, and to receiveCtrl+Cas a CSI‑u sequence instead of a kernelSIGINT.REPORT_EVENT_TYPESflag continues to deliverPress,Repeat, and — for non‑text‑producing keys —Releaseevents.handle_keysguard atapp.rs:3035returns early onKeyEventKind::Release. After this change, plain-text keys including Enter no longer produceReleaseevents at all (per the Kitty spec: "Enter, Tab and Backspace keys will not have release events unless Report all keys as escape codes is also set"). The guard becomes a permanent no‑op for Enter, which is strictly safer: a spurious Enter Release can never reach a freshly‑opened dialog.4.2 What gets better after the change
Currently, the only defence against a spurious Enter key‑release submitting a
freshly‑opened dialog (
app.rs:3035) is a runtime check(
if key.kind == KeyEventKind::Release { return; }).After this change the Enter
Releaseevent is no longer reported at all onKitty‑protocol terminals, so the dialog can never receive it. This turns a
runtime guard into a structural guarantee, eliminating the class of timing bugs
where a pending Enter Release races ahead of a dialog opening.
Disabling
REPORT_ALL_KEYS_AS_ESCAPE_CODESrestores the legacy convention thatplain text keys are delivered as raw UTF‑8 bytes. This is the path every TUI,
shell, and editor has relied on for decades, including in terminals that do
not support the Kitty protocol. Users switching between Ghostty (Kitty),
macOS Terminal.app (legacy), and tmux will now experience identical input
semantics for text characters, reducing “works only in my terminal” issues.
REPORT_ALL_KEYS_AS_ESCAPE_CODEScauses the terminal to send CSI‑u sequencesfor every character, including modifier info that tui‑textarea does not use for
plain text insertion. Removing it eliminates this overhead for the dominant
text‑entry path, slightly reducing input latency on high‑frequency keystroke
streams.
4.3 Behaviour shift per terminal category
Fully‑capable terminals (Kitty, Ghostty, foot, Alacritty ≥0.13, iTerm2, Contour, Rio, VS Code terminal)
The terminal parser's implementation of CSI‑u escape sequences is no longer mandatory for all keys. The OS delivers special character keys as raw UTF‑8, which maps to the correct
KeyCode::Char(…)path.Terminals with partial keyboard protocol support (WezTerm when keyboard enhancement is enabled, tmux
extended-keys, Zellij)The
supports_keyboard_enhancement()query relies on the Kitty push/pop/query stack. Since these terminals either default to off or lack the stack, the query fails andkeyboard_enhancementisfalse. ThePushKeyboardEnhancementFlagscall is never issued — this change is invisible to them.Terminals that support
modifyOtherKeysbut not the Kitty stack (xterm)Same reasoning:
supports_keyboard_enhancement()returnsfalsebecauseCSI ? ugoes unanswered or the response is ambiguous. No flags are pushed, so the change is invisible.Unsupported terminals (macOS Terminal.app, PuTTY, GNOME Terminal, Konsole, mosh, GNU Screen)
keyboard_enhancementis alwaysfalse— the flags are never sent. Zero impact.4.4 Build verification
cargo checkpasses without warnings or errors.5. Testing
=,~,|,`,{,},+,*) were typed on a JIS keyboard layout and confirmed to insert correctly into the prompt./modelsand other slash‑command dialogs were exercised. Dialog open, navigation, selection, and close behave identically to before the change. No spurious Enter‑submit regressions were observed.