Files
tai/research/tui-framework-design/kovidgoyal-kitty-keyboard-protocol.md
T
2026-10-11 00:10:46 +02:00

56 lines
4.4 KiB
Markdown

# 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-codepoints` tail (only with flag 16). Text keys use the codepoint as the number (shift+a is key `97`, 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 via `CSI > flags u` push (default 0) and `CSI < number u` pop (default 1); query via `CSI ? u`, reply `CSI ? 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 `:type` subfield 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 + bits` with 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 is `CSI 57441 ; 2 u` and its release is `CSI 57441 ; 1 : 3 u`.
- Functional codes: ESCAPE `27u`, ENTER `13u`, TAB `9u`, BACKSPACE `127u`, arrows `1A/1B/1C/1D`, LEFT_SHIFT `57441u`, RIGHT_SHIFT `57447u`, LEFT_CTRL `57442u`, 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 ? u` query 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 `u` and 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. |