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

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-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.