# Keys

DUET's keys follow Impulse Tracker: the F-row and `Ctrl`/`Alt` chords
carry the commands, and the letter rows stay free for the piano. This
page is the whole reference. The same pages are in the app: `?` (or
`F1`) opens the help popup, drawn from the key layout in use, so a
layout you change documents itself.

Two tables below are generated by `tools/docgen.py` from the tree and
the binary; `python3 tools/docgen.py --check` says whether they are
current.

## Keys that are always the same

These are not part of the layout and cannot be rebound.

| key | does |
|---|---|
| `ARROWS` | move the cursor: field to field on the grid, row to row in a list, item to item on a page |
| `PGUP` `PGDN` `HOME` `END` | jump on the grid and in lists |
| `ESC` | leave the thing you are in (a popup, an editor, a marked block); on a work page with nothing to leave, `ESC` twice quits |
| `Ctrl+C` | quit at once, from anywhere |
| the letter rows | in JAM, a piano: `Z S X D C V ...` is the lower octave, `Q 2 W 3 E R ...` the upper one (`SPACE` switches EDIT and JAM) |
| `` ` `` `1` `~` `.` | on a note field: note off, note cut, note fade, clear |
| `0`–`9` `A`–`F` | type into a hex field |
| `SHIFT+ARROWS` | nudge the value under the cursor; on a note, transpose it |

## Commands and their default keys

Every command DUET has, with the keys the built-in layout gives it.
The `action` column is the name a key layout file uses (see *Your own
layout* below). A key belongs to one action: binding it elsewhere
takes it away.

<!-- docgen:keys-actions -->
### Transport

| action | default keys | what it does |
|---|---|---|
| `play_start` | `f5` `ctrl+f5` | play from start |
| `play_resume` | `f7` `ctrl+f6` | resume / SONG: play from the selected order |
| `play_pattern` | `f6` | play pattern (loops) |
| `stop` | `f8` | stop (position kept) |
| `rewind` | `ctrl+r` | stop + rewind |
| `jam_all_off` | `enter` | all jam notes off |

### Screens and pages

| action | default keys | what it does |
|---|---|---|
| `screen_next` | `tab` | to the PATTERN page; standing on it, flip to INSTRUMENTS |
| `screen_prev` | `shift+tab` | to the INSTRUMENTS page; standing on it, flip to PATTERN |
| `screen_up` | `ctrl+up` | the previous screen in the list (PROJECT, SONG, PATTERN, INSTRUMENTS, MIXER, VISUALIZER) |
| `screen_down` | `ctrl+down` | the next screen in the list |
| `screen_left` | — | same as screen_up (unbound by default) |
| `screen_right` | — | same as screen_down (unbound by default) |
| `page_pattern` | `f2` | go to the PATTERN editor |
| `page_rack` | `f4` | to the INSTRUMENTS page, rotating its lists I## > P## > S## > W## > I## |
| `page_song` | `f11` | go to the ORDER LIST |
| `page_project` | `f12` | go to the PROJECT page |
| `help` | `?` `/` `f1` | the key help popup (these pages, in the app) |
| `quit` | `q` | quit |

### How the grid looks

| action | default keys | what it does |
|---|---|---|
| `grid_cycle` | `ctrl+v` | co-play grid: IT > UNITY > POLY > SWM |
| `split_toggle` | `ctrl+t` | SPLIT: pin the SID columns to the right edge |
| `col_view` | `ctrl+w` | channel width: FULL > NOTE+INS > NOTE |
| `follow_toggle` | `ctrl+f` | follow on/off |
| `pulse_toggle` | `f3` | the grid's note pulse: seven looks, then off |

### Patterns

| action | default keys | what it does |
|---|---|---|
| `pattern_next` | `+` `=` | next pattern |
| `pattern_prev` | `-` `_` | prev pattern |
| `pattern_hop_next` | `ctrl+=` `ctrl++` | next pattern, PATTERN HOP patterns at a time (the hop is set on the PROJECT page) |
| `pattern_hop_prev` | `ctrl+-` `ctrl+_` | previous pattern, PATTERN HOP patterns at a time |
| `goto_pattern` | `ctrl+g` | GO TO a pattern: type its number |
| `pattern_length` | `l` `ctrl+f2` | pattern length (rows) |

### Jamming

| action | default keys | what it does |
|---|---|---|
| `jam_toggle` | `space` | EDIT <-> JAM on the pattern and instruments pages (in JAM the letter rows are a piano) |
| `octave_down` | `[` `{` | octave down |
| `octave_up` | `]` `}` | octave up |
| `ins_prev` | `;` `<` | prev instrument |
| `ins_next` | `'` `>` | next instrument |
| `osc_toggle` | `alt+o` | the scope panel on/off |

### Files and the project

| action | default keys | what it does |
|---|---|---|
| `open_file` | `o` `f9` `ctrl+o` | open file dialog |
| `open_instrument` | `i` `ctrl+f4` | load instrument |
| `project_save` | `f10` `ctrl+s` | save project (.zon+.it) |
| `project_new` | `ctrl+n` | new project (asks twice) |
| `export_audio` | `ctrl+e` `shift+f10` | EXPORT AUDIO (wav) |
| `export_sample` | `ctrl+b` | pattern page: bounce the marked block; elsewhere: the selected P## sample as a .wav |
| `reload_keys` | `ctrl+k` | re-read the key layout file |

### Undo

| action | default keys | what it does |
|---|---|---|
| `undo` | `ctrl+z` | undo (this target) |
| `redo` | `ctrl+y` | redo (this target) |
| `undo_list` | `ctrl+u` | undo history popup |

### Mute and solo

| action | default keys | what it does |
|---|---|---|
| `chan_mute` | `ctrl+m` `alt+f9` | MUTE the cursor's column (an IT channel, a SID voice, a synth slot or a SID-Wizard track) |
| `chan_solo` | `alt+f10` | SOLO the cursor's column |
| `chan_mute_1` | `alt+f1` | MUTE channel 1 |
| `chan_mute_2` | `alt+f2` | MUTE channel 2 |
| `chan_mute_3` | `alt+f3` | MUTE channel 3 |
| `chan_mute_4` | `alt+f4` | MUTE channel 4 |
| `chan_mute_5` | `alt+f5` | MUTE channel 5 |
| `chan_mute_6` | `alt+f6` | MUTE channel 6 |
| `chan_mute_7` | `alt+f7` | MUTE channel 7 |
| `chan_mute_8` | `alt+f8` | MUTE channel 8 |

### Zones and IT channels

| action | default keys | what it does |
|---|---|---|
| `zone_prev` | `alt+left` | jump to the previous zone of the page (the grid's IT / SYN / SID blocks; the console's sections) |
| `zone_next` | `alt+right` | jump to the next zone |
| `it_chans_more` | `alt+up` | IT CHANNELS +1 |
| `it_chans_less` | `alt+down` | IT CHANNELS -1 |

### The mark and the block

| action | default keys | what it does |
|---|---|---|
| `mark_begin` | `alt+b` | mark from here |
| `mark_end` | `alt+e` | end the block here |
| `mark_ladder` | `alt+d` | grow the mark: beat > bar > the rest of the column > the channel > the whole side |
| `mark_column` | `alt+l` | mark the whole channel; again, the whole side |
| `mark_clear` | `alt+u` | unmark (ESC does it too) |
| `block_copy` | `alt+c` | copy the block |
| `block_cut` | `alt+z` | cut the block |
| `block_paste` | `alt+p` | paste at the cursor |
| `block_mix` | `alt+m` | paste, but only into empty fields |
| `block_translate` | `alt+shift+p` | paste onto another kind of column with the effects translated into its language |
| `block_semi_up` | `alt+q` | block +1 semitone |
| `block_semi_down` | `alt+a` | block -1 semitone |
| `block_oct_up` | `alt+shift+q` | block +1 octave |
| `block_oct_down` | `alt+shift+a` | block -1 octave |
| `block_set_ins` | `alt+s` | set every note in the block to the current instrument |
| `pattern_ops` | `ctrl+p` | the block command list (interpolate, reverse, roll, ...); with no block it marks the whole side first |

### Sync markers

| action | default keys | what it does |
|---|---|---|
| `marker_set` | `alt+g` | the SYNC MARKER popup on the cursor's cell: a value a host program receives when the row plays; saved in the project (see [the pattern editor](pattern-editor.md)) |

### The system clipboard

| action | default keys | what it does |
|---|---|---|
| `sysclip_menu` | `alt+shift+x` `alt+x` | the SYSTEM CLIPBOARD list: COPY, CUT, PASTE, MIX PASTE and TRANSLATE PASTE through the operating system's clipboard, as text OpenMPT and another DUET read (see [the system clipboard](system-clipboard.md)); with no block it marks the whole side first |
| `sysclip_copy` | `alt+shift+c` | copy the block to the system clipboard (the ALT+C clipboard is untouched) |
| `sysclip_cut` | `alt+shift+z` | cut the block to the system clipboard |
| `sysclip_paste` | `alt+shift+v` | paste the system clipboard at the cursor - the fields it carries, on the columns it has |
| `sysclip_mix` | `alt+shift+m` | paste the system clipboard, but only into empty fields |
| `sysclip_translate` | `alt+shift+t` | paste the system clipboard onto another kind of column with the effects translated |
<!-- /docgen -->

## The pages' keys

The in-app help, page by page, as the built-in layout prints it
(`duet --dump-help`). GLOBAL holds everything that is true on every
page; the others are the pages of the screen list (`Ctrl+UP/DOWN`).

<!-- docgen:keys-help -->
### GLOBAL

```text
   TRANSPORT                          SCREENS
   F5 ^F5   play from start           TAB      PATTERN / flip
   F7 ^F6   resume / SONG: play from  SHIFT+TAB  INSTRUMENTS/flip
   F6       play pattern (loops)      F2       go to the PATTERN editor
   F8       stop (position kept)      F4       INSTRUMENTS: next list
   ^R       stop + rewind             F11      go to the ORDER LIST
   ENTER    all notes off             F12      go to the PROJECT page
                                      ^UP/DN   up and down this list
   FILES
   O F9 ^O  open file dialog            PROJECT
   I ^F4    load instrument             SONG │ SWM SONG
   F10 ^S   save project (.zon+.it)     PATTERN │ INSTRUMENTS
   ^N       new project (asks twice)    THE MIXER │ MIXER FX
   ^E SHIFT+F10  EXPORT AUDIO (wav)     VISUALIZER
   ^B       bounce block / P## wav
   after ^S SAVE REPORT: patterns     UNDO (the thing you are on)
            nothing plays, kept       ^Z       undo (this target)
            ENTER x2 = CLEAR ALL      ^Y       redo (this target)
                                      ^U       undo history popup
   ^K       reload key file           ENTER    in ^U: travel to line
   Q        quit
            (and ESC: press twice)    IN THE FILE DIALOG
                                      SPACE play · S-UP/DN oct
```

### PROJ

```text
   THE PROJECT PAGE
   ARROWS   move focus
   ENTER    edit a field, or run a button (ESC reverts text)
   SHIFT+.. LT/RT nudge 1, UP/DN nudge 10 - switches walk too
   digits   type into SPEED / TEMPO / IT CHANNELS / CH-HOP
            the line under the fields says what the focused one does

   FILE OPERATIONS
   OPEN     any supported file - it REPLACES this session
   NEW      a fresh duet    NEW IT  a bare Impulse song
   NEW SWM.. a SID tune: pick .swm / .sws / .swt / .swq
   +CO-PLAY add the other half; once paired it DROPS it again
   EXPORT   WAV renders audio (^E) - SID writes the SID columns
            out as a real SID-Wizard module

   WHAT SAVE WRITES  (the badge top-right says which)
   [DUET]   the .zon project + its .it song (+ a changed .swm)
   [IT]     the .it, and only it
   [SWM]    the module, and only it
   [CO]     the project, both halves saved with it
            SAVE AS picks a new name; the first save always asks

   SETUP  (one row per SID chip)
   SHIFT+.. LT/RT walks a chip off > 8580 > 6581 > off
            on its PAN: LT/RT nudge 5, UP/DN jump a whole stop
            a chip that is ON adds three SID columns to the grid

   QUALITY  (the SIDS header row) + the CPU %
   SHIFT+.. LT/RT walks FAST > INTERP > RESAMPLE
            how reSID turns the chip's 1 MHz into 48 kHz:
            FAST costs a quarter of INTERP and aliases;
            RESAMPLE band-limits it away for 16% more than
            INTERP. One knob, every chip.
            CPU % (top right) is what PLAYBACK costs: the audio
            callback's share of its own budget - 100% drops out.
```

### SONG

```text
   ORDER LIST                         CHANNELS
   UP/DN    walk the list             0-9      VOL or PAN, 0-64
   LT/RT    cross to the CHANNELS     L M R    hard left/centre/right
   0-F      type the pattern number   S        surround
   +  -     the +++ / --- marks       ENTER    on MUTE: silence it
   SH+ARR   count it up/down (1 / 10)
   n        another of THIS pattern   the table shows the columns
   INS      ... and so do INS and     the grid draws - as long as
   SH+BKSP  SHIFT+BACKSPACE           the song is wide, no more.
   N        a NEW section: the unused
            pattern, or a fresh one   SID rows: SHIFT+arrows or
   DEL BKSP drop this position        L/M/R place the chip. Its
   ENTER    edit that order's pattern type is on the PROJECT page.
   F7       play the song FROM HERE
                                      SWM SONG (TAB)
   the strip is what PLAYS in each    0-9      edit the entry's number
   pattern: PCM ice, SID amber.       t v s    transpose / vol / tempo
   a dim PAT number is a repeat.      j u      jump (a ROW) / subtune
                                      +  -     the rule / the END
                                      n N DEL  repeat / new / drop
                                      INS      repeat too (SH+BKSP)
                                      ENTER    open ptn / follow jump
                                               ... or LIST the kinds
                                      SH+ENTER the WHOLE ROW on the grid
                                      ^P       that list, from any cell
                                      SH+ARR   count up/down (1 / 10)
                                      UP       at the top: SUBTUNE
                                      SH+LT/RT ... pick one (F5 plays it)
                                      N        there: a NEW subtune
                                      RIGHT    past tracks: TEMPO pane
                                               ... the FX $12/$15 grooves
                                      ENTER    on TEMPO: funktempo on/off

                                      the keys are the glyphs
                                      the cells show; jumps
                                      read as row numbers.

                                      EVERY TRACK ENDS in an END
                                      or a JUMP, as SID-Wizard's
                                      own do. That row takes only
                                      the other one; anything else
                                      you place lands ABOVE it,
                                      and DEL keeps it. Below a
                                      shorter track, typing adds
                                      a row at its own end.
```

### PATTERN

```text
   PATTERN                            EDIT (the keyboard types)
   ARROWS   field to field, PGUP/HOME SPACE    EDIT <-> JAM
   ^LT/RT   hop N channels: CH-HOP    PIANO    z/q rows enter notes
   ALT+RIGHT  jump to the NEXT zone   ` 1 ~ .  note off/cut/fade/clear
            IT / SYNTH / SID blocks   0-F      type into the field (hex)
   ALT+UP   IT CHANNELS +1            LETTERS  IT fx; hex on SID
   ALT+DOWN  IT CHANNELS -1           ENTER    the FX PICKER: VOL, FX,
                                               and its value
   + =      next pattern              ENTER    on an INS number: jump
   - _      prev pattern                       to it - on an empty or
   ^= ^+    next, PATTERN HOP                  $40+ one, the INS-FX
   ^- ^_    prev, PATTERN HOP                  list (SW columns only)
   ^G       GO TO pattern (type it)   in JAM: arrows step channels
   L ^F2    pattern length (rows)
   ^M ALT+F9  MUTE this column        TRANSPOSE (SHIFT+..)
   ALT+F10  SOLO this column          LT/RT    semitone -/+
   ALT+F1-8 MUTE channels 1-8         UP/DN    octave +/-
   the HOP is P-HOP on the            empty note: last note lands
   PROJECT page; +/- auto-repeat.     on a vbX cell: LT/RT dials
   EVERY pattern number exists        the vibrato amplitude
   from load: '+' and ^G just
   walk out to an empty one.          A BLOCK (the BLOCK page)
                                      ALT+B    mark from here
   VIEW                               ALT+D    beat>bar>rest>ch>side
   ^V       grid IT>UNITY>POLY>SWM    ^P       the command list
   ^T       SPLIT: pin SID columns    the whole vocabulary is one
   ^W       channel width (3 looks)   page over: mark something and
   ^F       follow on/off             '?' lands on it.
   F3       grid pulse (7 looks)
                                      SYNC MARKER (a project fact)
   JAM INSTRUMENT                     ALT+G    sync marker at the cu
   ; <      prev instrument           a value a host program gets
   ' >      next instrument           when the row plays; DEL clears
   ALT+O    the scope panel on/off
   the scope shows what the           SW COLUMNS (.swm)
   keyboard plays; ESC closes         +  -     THIS column's phrase
                                      F6       loop the combination
                                      the column IS the pattern;
                                      the header shows its number.
```

### BLOCK

```text
   THE MARK (a block)                 ON THE BLOCK
   ALT+B    mark from here            ^P       the command list
   ALT+D    beat>bar>rest>ch>side       ^P lists them all, with their
   ALT+L    the whole channel           keys; no block = the whole
   ALT+E    end the block here          side, marked so you see it.
   ALT+U    unmark (ESC too)          ALT+C    copy the block
   MARKING = still following the      ALT+Z    cut the block
   cursor; ENTER holds it, then       ALT+P    paste at the cursor
   the cursor walks off freely.       ALT+M    paste into gaps only
   A block stays on ONE side of       ALT+SHIFT+P  TRANSLATE PASTE
   the IT/SID seam.                   ALT+S    block: set instrument
                                        paste onto another kind of
   ON A SID-WIZARD GRID                 column and the effects come
   Every verb here works on the         too, in its own language.
   SW tracks too. A column IS a       ALT+SHIFT+X system clipboard
   phrase, so a verb runs ONCE          out to another DUET/OpenMPT
   per phrase however many            ALT+SHIFT+C copy out
   tracks show it, and each           ALT+SHIFT+Z cut out
   column stops at its own            ALT+SHIFT+V paste in
   length. A block DOES cross to      ALT+SHIFT+M ... into gaps
   a song's columns - the note        ALT+SHIFT+T ... translated
   lands converted, and TRANSLATE     ALT+Q/A  semitone +/-
   PASTE carries the effects.         +SHIFT   ... an octave
                                      SHIFT+.. arrows do both too
                                      DEL      clear the block
                                      ^P only  interpolate, reverse, roll
                                      paste lands on the FIELDS it
                                      was cut from: the cursor gives
                                      the row and the channel only.

                                      ROWS (with no block)
                                      DEL BKSP delete row, pull up
                                      INS      insert row, push down
                                      SH+BKSP  ... the same insert
                                      ALT+ them the whole row, one side
```

### INS

```text
   THE INSTRUMENT LIST                THE SWI EDITOR  (S## W##)
   UP/DOWN  pick a slot: I## .. K##   arrows   params, then tables
   ZSXDCV.. jam it - lower octave     0-9 A-F  type hex
   Q2W3ER.. ... upper octave          ENTER    toggle / add a row
   [ {      octave down               INS      add a row too, and so
   ] }      octave up                 SH+BKSP  does SHIFT+BACKSPACE
   SH+SPACE all notes off             SH+arrow nudge the value
   ^D       COPY the highlighted      BKSP DEL delete the row
   BKSP     CLEAR it (nothing moves)  g        gate-off marker
   DEL      CLEAR + wipe its notes    F10 ^S   save the project
   TAB      next list (I P S W D K)
   F4       ... and it never leaves   THE SAMPLE EDITOR  (P##)
   END      the list's buttons, below arrows   name/tuning/loop/vib
                                      digits   type; ENTER switches
   THE LIST'S BUTTONS  (below it)     z        snap a zero crossing
   IMPORT   parts -> next free slot   SH+arrow nudge (C5: a semitone)
   +I##     new I##: pick its sample  ^B       bounce block / P## wav
   EXPAND   show 10 more slots        a sample lives in the .it -
   SHRINK   ... only the ones in use  the PROJECT save writes it
   a DIM button is at its limit
                                      THE I## EDITOR
   THE SLOT'S BUTTONS  (detail pane)  UP+strip GENERAL MAP VOL PAN PITCH
   CLEAR    blank it, nothing moves   MAP: a   spread it to every key
   CLR+NOTES ... and wipe its cells
   LOAD     a file INTO this slot     ITS ENVELOPES (VOL/PAN/PITCH)
   SAVE     .swi / .wav out of it     UP/DOWN  walk nodes  L/R: tick|val
                                      SH+arrow DRAG the node, 2D
   IMPORT  (.swm ins / .it sample)    ENTER    +node (midpoint)
   UP/DOWN  walk that module's parts  BKSP     -node
   SPACE    audition it where it lies s S l L  sustain/loop band on node
   [ ]      the audition octave       e c f    on/off carry filter
   SH+UP/DN (same, the dialog's)
   c        +CHORDS: bring the chord  THE D## EDITOR (DUST)
   ENTER    take it (list stays up)   UP+strip VOICE TABLES MOD MACRO
   only instruments that ARP a        arrows   4 tables, one tab
   chord ($7F) bring one along;       UP       row 00 up: the CLOCK
   a SAMPLE brings all of itself      f        follow the playhead
                                      ENTER    MOD: pick source/dest
                                      MOD foot base|held|mod|final, live
                                      MACRO    SFx/Zxx + the vol column
                                      armed in SETUP (PROJECT)

                                      IN EVERY EDITOR
                                      RIGHT    or ENTER: step in
                                      ESC      back to the list
                                      LEFT     ... off the 1st field
                                      SPACE    JAM on/off (piano)
                                      [ ]      its octave
                                      ALT+O    the scope panel on/off

                                      ... or the [OSC] button in
                                      the slot's own button row;
                                      the line under the fields
                                      reads the value back to you
```

### MIXER

```text
   THE MIXER (a studio console)       SEND FX (TAB from the mixer)
   LT/RT    walk strips, any zone     TAB      strips, sends, the units
   ^LT/RT   hop CH-HOP strips at once A B C D  one send per unit, 0-100
   ALT+LEFT  jump to the PREV zone    +/-      nudge 1, SH+UP/DN 10
   ALT+RIGHT  jump to the NEXT zone   ENTER    a send off, and back
            CHANNELS/CHIPS/SYNTHS/OUT a        this send on EVERY strip
   UP/DN    walk the strip's rows     0        send off / knob to default
   +/-      fine nudge, SH+UP/DN big  ENTER b  on a unit: its BYPASS
            hold a nudge to SWEEP     m s      mute / solo this strip
   ENTER b  bypass (a nudge ARMS it)  s        a unit: all RETURNS alone
   0        0 dB / flat / defaults
   m s      mute/solo this strip (^M) EVERY UNIT HAS A RETURN STRIP: its
                                      own bar, LEVEL, MUTE, SOLO and EQ.
   CH strips are the song's own       BYPASS stops the unit; MUTE drops
   VOL/PAN 0-64; the dB knobs are     what comes back and lets it ring.
   the .zon's. EQ: 120 Hz shelf,
   1.2 kHz, 8 kHz shelf, +-12 dB.     DELAY: echo. TIME counts ROWS, so
   DYN is the master chain: EQ >      it follows the song's tempo; MODE
   fader > COMP > LIMITER, its GR     PING bounces it left to right.
   bars hanging. Every stage is BORN  REVERB: SPACE picks ROOM/PLATE/HALL
   BYPASSED: untouched is identical.  - DECAY how long, DAMP how dark.
   DUST strips (one per armed         CHORUS: 2-4 sweeping copies; heavy
   slot) carry their own PAN here.    FDBK flanges. DRIVE: distortion,
                                      CRUSH is the C64 one. DUCK bows a

                                      return under the dry mix.
                                      A send taps the strip AFTER its own
                                      fader, pan and EQ; the returns land
                                      in the mix before the MASTER chain.
```

### VIZ

```text
   VISUALIZER
   LT/RT    cycle VU BARS / SPECTRUM / SCOPE / PLASMA
   UP/DN    bar style NORMAL / SCANLINES / GAP
            (on VU BARS + SPECTRUM)

   DUO + COPPER are parked (--viz reaches them)
```
<!-- /docgen -->

## Your own layout

A layout is a small `.zon` file that binds actions to keys over the
built-in default. Load one with `--keys file.zon`, or put it at
`~/.config/duet/keys.zon` and it loads on its own; `Ctrl+K` re-reads
it while DUET runs. Two are shipped in `docs/keymaps/`:

- `impulse.zon` — the built-in layout written out in full, to copy
  from. Loading it changes nothing.
- `sidwizard.zon` — SID-Wizard's transport on `F1`–`F4`.

The file is a struct: a `.name`, then one field per action you want to
change. Actions you leave out keep their defaults.

```zig
.{
    .name = "mine",
    .play_start = "f1",        // one key
    .help = "?,/,f1",          // alternatives, comma-separated
    .page_rack = "none",       // unbind
}
```

A key is spelled:

- a single printable character: `q`, `;`, `+` (case matters: `L` and
  `l` are two keys);
- `space`, `tab`, `shift+tab`, `enter`;
- `f1` … `f12`, and their `alt+`, `ctrl+` and `shift+` forms;
- `ctrl+up` `ctrl+down` `ctrl+left` `ctrl+right`, and the same four
  with `alt+`;
- `ctrl+` a printable character (`ctrl+s`, `ctrl+=`), except `c`, `h`,
  `i` and `j`, which the terminal keeps;
- `alt+` a printable character, and `alt+shift+` a letter;
- `none`.

Some of these only exist on a terminal that speaks the kitty keyboard
protocol (the window build always does): a modified F-key, `Ctrl` with
punctuation, `Ctrl+M` (a legacy terminal sends it as `ENTER`), every
`Alt` chord, `Shift+SPACE`. On a legacy terminal such a key never
arrives as itself, which is why everything bound to one has another
road — a plain key, or a button on a page;
[troubleshooting](troubleshooting.md) lists them. The protocol reports
a shifted key as its base key — `?` arrives as `/`, `+` as `=` — so
bind both.

A file that fails to parse at start-up is reported on the terminal
(`does not parse`, `names a key that does not exist`, `no such file`)
and the built-in layout is used; on `Ctrl+K` the status line says
`KEYS: the file does not parse - the old layout is kept` and the
layout in use stays. Fix the file and press `Ctrl+K` again.
