4.4 KiB
Kitty Keyboard Protocol Specification
Metadata
| Field | Value |
|---|---|
| Institute | Molodetz Institute — Research & Retrieval Division |
| Subject | tui-framework-design |
| Document type | Source Dossier |
| Tier | 1 |
| Source title | Comprehensive keyboard handling in terminals - kitty |
| Source URL | https://sw.kovidgoyal.net/kitty/keyboard-protocol/ |
| Source publisher / author | Kovid Goyal / kitty project |
| Source type | standard |
| Source date (published) | Unknown — not stated |
| Date researched | 2026-10-10 |
| Researched by | tai (agent), model: Muse Spark, on behalf of retoor |
| Research method | direct page fetch |
| Confidence | High |
| Status | Active |
Summary
The authoritative specification of the kitty keyboard protocol: CSI unicode-key-code:alternate-key ; mods:event-type ; text-as-codepoints u key encoding, the five progressive-enhancement flags, the push/pop/query mechanism, the modifier bitmask, the functional key code table, and the support-detection procedure. Read to settle exactly which bytes enable bare-modifier key reporting and what a Shift press looks like on the wire.
Key findings
- Key event form:
CSI unicode-key-code:alternate-key ; mods:event-type u, plus optional;text-as-codepointstail (only with flag 16). Text keys use the codepoint as the number (shift+a is key97, mods shift). - Progressive-enhancement flags: 1 disambiguate escape codes, 2 report event types, 4 alternate keys, 8 all keys as escape codes, 16 associated text. Enable with
CSI flags ; mode u(mode 1 set-all default, 2 set-bits, 3 clear-bits); stack discipline viaCSI > flags upush (default 0) andCSI < number upop (default 1); query viaCSI ? u, replyCSI ? flags u. - Bare modifier press events are reported only with flag 8 (all keys as escape codes); without it there is no way to observe a lone Shift press at all. Flag 8 also converts every text key to escape-code form (no plain UTF-8 bytes) and implies disambiguation.
- Event types (needs flag 2) are a
:typesubfield on the modifier parameter: 1 press (default when absent), 2 repeat, 3 release. Without flag 2, repeats arrive indistinguishable from presses. - Modifier mask is
1 + bitswith shift=1, alt=2, ctrl=4, super=8, hyper=16, meta=32, caps_lock=64, num_lock=128; absent field defaults to 1 (no modifiers). For modifier-key events the mask reflects state including the current event, so a bare left-Shift press isCSI 57441 ; 2 uand its release isCSI 57441 ; 1 : 3 u. - Functional codes: ESCAPE
27u, ENTER13u, TAB9u, BACKSPACE127u, arrows1A/1B/1C/1D, LEFT_SHIFT57441u, RIGHT_SHIFT57447u, LEFT_CTRL57442u, F1-F12 keep legacy~/letter forms. - Main and alternate screens maintain independent keyboard-mode stacks, so pushing flags after entering the alternate screen never leaks into the shell's mode.
- Recommended detection: send the
CSI ? uquery followed by a primary-device-attributes request; a DA1 reply with no kitty reply means unsupported. Partial implementations are detected by set-then-query.
Pros / strengths
- It is the normative document: exact byte sequences, flag semantics, event-type encoding, and the full functional table in one place, with rationale notes (e.g. why Enter/Tab/Backspace keep legacy bytes under flag 1).
- Explicitly covers graceful degradation (unsupported terminals ignore the push) and the alternate-screen stack split, which is exactly what a fullscreen TUI needs.
Cons / limitations / caveats
- Dense single page (navigation-heavy HTML); the functional table mixes
uand legacy~/letter forms, so a reader must track which form applies under which flags. - The spec permits partial implementations while discouraging them, so set-then-query is the only honest capability check; a push-and-hope client must still parse legacy input as fallback.
Relevance to tai
Directly load-bearing for double-Shift detection in the TUI demo: it proves bare Shift is unobservable without flag 8, fixes the push sequence (CSI > 10 u for flags 8+2, pop with CSI < u), the press encoding (57441;2u), and the repeat/release filtering rule (ignore :2/:3 for tap detection). Drove the decision to push best-effort with no query round-trip and to parse legacy and CSI-u input side by side, plus a double-Escape fallback for terminals without kitty support.
Changelog
| Date | Change |
|---|---|
| 2026-10-10 | Initial dossier created. |