# Fuzzball keyboard — v0.1 (implementable draft)
Subsystem letter: `k`. Framing, replies and errors: see [README](README.md).
## 1. One mode
There is exactly one mode: **structured key events**. While it is on, every key event
(press, repeat, release) is reported as one message; nothing is sent in legacy form.
While it is off, the terminal sends legacy (xterm/VT) bytes.
Enable / disable (per screen; the main and alternate screens are independent):
```
ESC P = F z k s ; on=1[,v=0][,id=<n>] ESC \ enable
ESC P = F z k s ; on=0[,id=<n>] ESC \ disable
ESC P = F z k q ; id=<n> ESC \ query
→ ESC P = F z k r ; id=<n>,ok=1,on=1 ESC \
```
The mode is also turned off by RIS and when the program's screen is left (e.g. leaving
the alternate screen restores the main screen's own state).
## 2. Event message
Sent by the terminal to the application:
```
| `t` | `p` press, `r` repeat, `u` release. |
| `code` | physical key, as the USB HID usage name from the W3C UI Events `code` list, e.g. `KeyA`, `Digit1`, `ArrowUp`, `ShiftLeft`, `Numpad7`. Layout independent. |
| `key` | logical key: a W3C UI Events `key` name for non-text keys (`Enter`, `Escape`, `F13`, `MediaPlayPause`…), or `U+XXXX` for the unmodified character the key produces on the current layout (e.g. `U+0061` for `a`, `U+0444` for `ф`). |
| `mods` | bitmask of held modifiers: 1 Shift, 2 Alt, 4 Ctrl, 8 Super, 16 Hyper, 32 Meta, 64 AltGr. Omitted when 0. |
| `locks` | 1 CapsLock, 2 NumLock, 4 ScrollLock. Omitted when 0. |
| `text` | UTF-8 text this event inserts, hex-encoded (so any character is safe on the wire). Omitted when none. Present for presses and repeats only. |
| `ime` | `start`, `update`, `commit`, `cancel` — composition state; see §3. |
Modifier keys themselves produce events (`code=ShiftLeft,key=Shift`), with `mods`
reflecting the state **after** the event.
Examples:
```
a ESC P = F z k e ; t=p,code=KeyA,key=U+0061,text=61 ESC \
Shift+a ESC P = F z k e ; t=p,code=KeyA,key=U+0061,mods=1,text=41 ESC \
release a ESC P = F z k e ; t=u,code=KeyA,key=U+0061 ESC \
Ctrl+c ESC P = F z k e ; t=p,code=KeyC,key=U+0063,mods=4 ESC \
Ctrl+ф (RU) ESC P = F z k e ; t=p,code=KeyA,key=U+0444,mods=4 ESC \
Enter ESC P = F z k e ; t=p,code=Enter,key=Enter,text=0d ESC \
Up (repeat) ESC P = F z k e ; t=r,code=ArrowUp,key=ArrowUp ESC \
Left Shift ESC P = F z k e ; t=p,code=ShiftLeft,key=Shift,mods=1 ESC \
```
Applications get both the physical key (for shortcuts that should not move with the
layout, e.g. games, vim's `hjkl` on Dvorak if desired) and the logical key (for shortcuts
by letter), without the terminal guessing which one is meant.
## 3. IME and composed text
Composition is reported separately from key presses so applications don't mistake
pre-edit keystrokes for input:
```
ESC P = F z k e ; t=p,ime=start ESC \
ESC P = F z k e ; t=p,ime=update,text=e3818b ESC \ pre-edit "か", not inserted
ESC P = F z k e ; t=p,ime=commit,text=e6bca2e5ad97 ESC \ insert "漢字"
ESC P = F z k e ; t=p,ime=cancel ESC \
```
Key events consumed by the IME are not reported. Dead keys behave like a one-character
composition (`start` … `commit`). Applications that don't care about pre-edit only act on
`commit`.
## 4. Paste
Pasted text is not keyboard input; it stays on bracketed paste (mode 2004) whether or not
this mode is on.
## 5. Capability keys
In the common capability reply: `k=1` (mode available), `k_ime=1` if IME events are
reported, `k_release=1` if the platform delivers release events (some remote setups
cannot).
## 6. Differences from the Kitty keyboard protocol
- No flag bits: one mode, always full information.
- Physical and logical keys are separate named fields instead of numeric code points
plus "alternate keys".
- Text is always explicit (hex), so control characters and non-BMP text are unambiguous.
- IME composition is part of the protocol.