DECARM — Auto-repeat keys mode (CSI ? 8 h / l)
Toggle whether the terminal repeats key bytes while a key is held down — a TUI-relevant knob for games and editors where holding j should NOT spam the buffer.
Byte forms
Every common string-literal form so you can paste-and-search either direction.
\x1b[?8h (repeat) \x1b[?8l (no repeat)\033[?8h / \033[?8l\e[?8h / \e[?8lESC [ ? 8 h / ESC [ ? 8 l1b 5b 3f 38 68 / 6cDescription
Auto-Repeat Mode. When set (\x1b[?8h, the default in nearly every terminal), holding down a key after the OS-defined repeat delay (typically 250 ms) causes the terminal to inject repeated key bytes at the OS-defined repeat rate (typically 30/sec) — the standard typewriter-style behaviour. When reset (\x1b[?8l), the terminal sends exactly one byte per physical keypress regardless of how long the key is held — so a roguelike that interprets j as 'move down once' won't see the player skipping across the map when they hold the key. The OS-defined delay/rate isn't tunable via DECARM (use xset r rate on X11, defaults write -g KeyRepeat on macOS, accessibility panel on Windows); DECARM only flips on/off. Critical for TUI games (curses-based roguelikes like nethack, brogue), action editors that interpret modal-style single-keystroke commands, and applications that want every keystroke debounced into a discrete event. Almost-universal support — only Linux console partial (depends on framebuffer driver). Restore to ?8h on exit, always — leaving auto-repeat off pollutes the user's shell session.
Spec citation: DEC VT100 (DECARM) / xterm-ctlseqs
Parameters
Examples
printf '\033[?8l' # turn OFF auto-repeat for the duration of this TUI\ntrap 'printf "\\033[?8h"' EXIT # restore on any exit\n# … game loop …import sys, atexit\nsys.stdout.write('\x1b[?8l') # roguelike: one move per keypress\natexit.register(lambda: sys.stdout.write('\x1b[?8h'))fmt.Print("\x1b[?8l")\ndefer fmt.Print("\x1b[?8h") // always restoreprocess.stdout.write('\x1b[?8l')\nprocess.on('exit', () => process.stdout.write('\x1b[?8h'))printf("\x1b[?8l");\natexit_set_restore("\x1b[?8h"); /* paired restore is non-optional */Used in
Real-world tools that emit this sequence — anchors the bytes to commands you've already used.
- vim long-press repeat suppressionVim sets `\x1b[?8l` on entering insert mode IF `:set ttimeoutlen=0` is configured, to prevent terminal-side key-repeat from outpacing the editor's per-key normal-mode commands — `:verbose set ttimeoutlen?` to inspect, trace with `script` to see the emit
- less paging with held arrow keyOn terminals where the OS *doesn't* generate key repeat (some terminal multiplexers in pre-3.2 tmux config), `less` relies on DECARM `\x1b[?8h` (default) for scroll-by-line repeat when the user holds `j` or `↓` — disable with `tmux: set -g repeat-time 0` and observe scrolling stop after one keypress
- terminfo `decarm` capabilityListed as the `km` boolean cap ("has metakey" — DECARM is implied for DEC-family terminals); `infocmp xterm | grep -E 'km|decarm'` shows the bit. Application code reads via `tigetflag("km")` to decide whether to install per-key debouncing
- GNU readline `quoted-insert` (Ctrl-V / Ctrl-Q)Held `Ctrl-V` to insert literal control bytes relies on DECARM `?8h` for repetition under terminals where the OS layer doesn't auto-repeat modified keys (some Wayland compositors with modifier-debounce on) — `bind -P | grep quoted-insert` shows the binding, trace with `READLINE_DEBUG=1`
- htop refresh-rate vs key-repeat interactionhtop's `Setup → Display options → Update interval` interacts with DECARM in the held-arrow scroll-process-list case: with `?8h` (default) and 1.5 s refresh, holding `↓` over a long list scrolls smoothly because terminal key-repeat outpaces the redraw; with `?8l` it pauses after each keypress until the redraw catches up — visible by toggling `setterm -repeat off`/`on` between sessions
Frequently asked
Short answers to the questions developers actually search for this sequence.
- What does DECARM
\x1b[?8h/\x1b[?8lactually control? - DECARM (Auto-Repeat Mode) controls whether the *terminal* generates repeated keystrokes when a key is held down — distinct from any OS-level key-repeat the windowing system also applies. On a hardware DEC VT220 / VT320 this was the only way to get held-key repetition; on modern emulators it's largely vestigial because the OS already handles key-repeat at the input-method layer (xkb, IBus, IMK on macOS, the Windows kernel). Today
?8his the default on every terminal in the support matrix;?8l(disable) is supported by xterm, kitty, foot, gnome-terminal, konsole — and is a no-op on Windows Terminal, ConPTY, alacritty (which delegates fully to the OS). Use case is dead — modern TUI authors disable the OS key-repeat globally via XKB or AppKit per-key rules instead of relying on DECARM. - Should I emit
\x1b[?8lto disable repeat for my editor's modal keymap? - No —
\x1b[?8ldoesn't reach the OS key-repeat layer, so a held key still floods your stdin with repeated bytes on every terminal that delegates repeat to the OS (Windows Terminal, ConPTY, alacritty, kitty under Wayland withenable_key_repeat = yes). The bytes that arrive look identical whether DECARM is on or off because the repeat is generated *outside* the terminal. The right pattern is application-side: timestamp incoming bytes and ignore duplicates within a debounce window, OR use the kitty keyboard protocol\x1b[>1u(which DOES report key-down vs key-up vs key-repeat as separate events with progressive enhancement flags). For Vim / Helix / Kakoune-style modal editing, the kitty protocol is the supported answer.
Terminal support
- xterm
- yes
- Linux console (fbcon)
- partial
- macOS Terminal.app
- yes
- iTerm2
- yes
- Windows Terminal
- yes
- cmd.exe / ConPTY
- partial
- kitty
- yes
- alacritty
- yes
- WezTerm
- yes
- Ghostty
- yes
- GNOME Terminal
- yes
- Konsole
- yes
- tmux
- yes
- GNU screen
- yes
| xterm | Linux console (fbcon) | macOS Terminal.app | iTerm2 | Windows Terminal | cmd.exe / ConPTY | kitty | alacritty | WezTerm | Ghostty | GNOME Terminal | Konsole | tmux | GNU screen |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| yes | partial | yes | yes | yes | partial | yes | yes | yes | yes | yes | yes | yes | yes |