[BUG] Kitty keyboard protocol: Ctrl shortcuts fail on non-Latin keyboard layouts (e.g. Russian/Cyrillic)
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
When using Claude Code in kitty terminal with a non-Latin keyboard layout (Russian/Cyrillic), all Ctrl-based readline shortcuts stop working: Ctrl+A, Ctrl+E, Ctrl+U, Ctrl+K, Ctrl+W, Ctrl+B, Ctrl+F.
The shortcuts work fine on the English layout in the same terminal session.
Root Cause
The kitty keyboard protocol reports key events as CSI sequences with the Unicode codepoint of the current layout's character. On English layout, Ctrl+A sends CSI 97;5u (97 = 'a'). On Russian layout, the same physical key sends CSI 1092;5u (1092 = 'ф'). Claude Code matches keybindings against the primary key codepoint and doesn't recognize 'ф' as 'a'.
The kitty keyboard protocol has a mechanism for this — the "report alternate keys" enhancement flag (bit 0b1000), which makes the terminal report both the layout-specific key and the base (US layout) key. Claude Code should either:
- Request the alternate keys flag and use the base layout key for keybinding matching, or
- Map Ctrl + non-Latin codepoints to their physical-key equivalents internally.
This is different from #32087 (Ghostty/fixterms) — kitty terminal correctly implements the protocol, the issue is purely in how Claude Code consumes it.
What Should Happen?
Ctrl+A/E/U/K/W/B/F should work identically on any keyboard layout, as they do in every readline-based application and in legacy terminal mode (where Ctrl+key always produces a layout-independent control code like \x01).
Workaround
Adding explicit kitty mappings that send raw control codes for Russian Ctrl combinations:
# in kitty.conf
map ctrl+ф send_text all \x01 # Ctrl+A
map ctrl+у send_text all \x05 # Ctrl+E
map ctrl+ц send_text all \x17 # Ctrl+W
map ctrl+г send_text all \x15 # Ctrl+U
map ctrl+л send_text all \x0b # Ctrl+K
map ctrl+и send_text all \x02 # Ctrl+B
map ctrl+а send_text all \x06 # Ctrl+F
This works but is a per-user, per-layout hack. The proper fix should be in Claude Code's keyboard protocol handling.
Error Messages/Logs
No errors — keys are silently ignored.
Steps to Reproduce
- Open kitty terminal on macOS
- Switch to a non-Latin keyboard layout (e.g. Russian)
- Launch Claude Code
- Type some text in the input field
- Press Ctrl+A — cursor does not move to beginning of line
- Switch to English layout — Ctrl+A works
Claude Model
Opus
Is this a regression?
Unknown — may have started when kitty keyboard protocol support was added (v2.1.0+)
Claude Code Version
2.2.16
Platform
Anthropic API
Operating System
macOS (Darwin 25.3.0)
Terminal/Shell
kitty 0.41.1 / bash
Additional Information
Related issues: #32087, #17400, #18221, #11997
7 Comments
Found 2 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
This is not a duplicate. Both suggested issues (#27859, #19704) are about non-Latin layouts in legacy terminals (Terminal.app, iTerm) that don't use the kitty keyboard protocol. My issue is specifically about the kitty keyboard protocol CSI encoding — kitty sends
CSI 1092;5u(Unicode 'ф') instead ofCSI 97;5u('a') for Ctrl+A on Russian layout, and Claude Code doesn't handle this.The fix requires either requesting the alternate-keys enhancement flag (bit
0b1000) or mapping non-Latin codepoints to their physical-key equivalents — neither of which is addressed by the closed issues.Both #27859 and #19704 are closed, yet the problem persists on Claude Code 2.2.16 with kitty 0.41.1.
+1 — Same issue with Korean (Hangul) IME on macOS.
All Ctrl+key shortcuts (Ctrl+C, Ctrl+A, Ctrl+L, Ctrl+E, etc.) are silently ignored when the Korean input source is active. Switching to English immediately restores them.
Unlike this issue which is Kitty-specific, the Korean IME case reproduces across all terminals — Terminal.app, iTerm2, and cmux (Ghostty/libghostty-based). This suggests the root cause may not be limited to the Kitty keyboard protocol, but a broader issue in Claude Code's input handling for non-Latin input sources.
See #40291 for the full reproduction steps and environment details.
---
Workaround (임시 해결책)
Karabiner-Elements를 이용해 OS 레벨에서 Ctrl+키 입력 시 영문으로 전환 → 단축키 전송 → 한글 복원하는 방식입니다.
근본적인 해결은 아니지만, Claude Code에서 수정될 때까지 사용할 수 있습니다.
소스: https://github.com/pereng11/karabiner-korean-shortcuts
Same issue on Ghostty (macOS)
Reproduces on Ghostty 1.x with Russian (ЙЦУКЕН) layout. Specifically:
This confirms @pereng11's observation that the bug is not limited to kitty keyboard protocol — it's a broader issue in Claude Code's input layer. Ghostty uses a different protocol (fixterms/CSI u), yet the same root cause applies: the TUI matches keybindings by the Unicode codepoint of the current layout instead of the physical key position.
Suggested fix
Claude Code should normalize Ctrl+key combinations to their US-QWERTY physical equivalents before matching keybindings. A mapping table for common layouts (Cyrillic ЙЦУКЕН, Korean, etc.) would cover the majority of cases:
Alternatively, if the terminal supports it (kitty protocol bit
0b1000, or CSI u withbase-layout-key), use the reported base/alternate key directly.Environment
Closing for now — inactive for too long. Please open a new issue if this is still relevant.
Proposed fix with diff, vitest spec, and a zero-dep Node reproduction:
https://github.com/vetermanve/claude-code-non-latin-ctrl-keys
Same root cause as #36549. Three files, all backwards-compatible:
ink/termio/csi.ts— request Kitty progressive flag bit 2 in addition to bit 0:ENABLE_KITTY_KEYBOARD = csi('>5u') // was '>1u'
This is the alternate-keys flag @Flamefork pointed at in #36549.
ink/parse-keypress.ts— extend CSI_U_RE to capture the optional base-layout-key group from the kitty CSI u syntax (keycode[:shifted:base-layout-key][;modifier...] u).ink/parse-keypress.ts(CSI u branch) — when ctrl or super is held and the terminal provided a base-layout-key, route the matcher by that physical (US) key position. Plain typing (no ctrl/super) keeps the raw codepoint so non-Latin text input is untouched.Why this rather than a per-layout transliteration table (oviron's comment in #36549): the terminal already knows which physical key was pressed under any layout — Cyrillic, Greek, Arabic, Hebrew, Armenian, Georgian, Korean Hangul IME, etc. — and the Kitty spec mandates
reporting it via the alternate-keys flag. One code path covers every script, no per-layout maps to maintain.
Terminals that don't implement bit 2 keep emitting the short CSI u form, which the extended regex parses identically — fully backward compatible.
Links:
Reproduction output (broken parser vs fixed parser, side by side):
ctrl+c (RU layout, kitty alt-keys) broken: null fixed: name='c', ctrl=true pass
ctrl+e (RU layout, kitty alt-keys) broken: null fixed: name='e', ctrl=true pass
ctrl+v (GR layout, kitty alt-keys) broken: null fixed: name='v', ctrl=true pass
shift+Б (text typing) broken: null fixed: shift=true, name != 'b' pass
legacy kitty (no alt-keys) broken: name='c', ctrl=true fixed: name='c', ctrl=true pass
shift+enter broken: name='return' fixed: name='return' pass
Confirmed against claude-code 2.1.142 and npm @anthropic-ai/claude-code 2.1.150 / 2.1.152.
Happy to open a PR. Could a maintainer reopen #36549 and tag this for the input layer team?
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.