Skip to main content
ansicode

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[\x1b[?8h (repeat) \x1b[?8l (no repeat)
\\033[\033[?8h / \033[?8l
\\e[\e[?8h / \e[?8l
ESC [ESC [ ? 8 h / ESC [ ? 8 l
hex1b 5b 3f 38 68 / 6c

Description

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

bash
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 …
python
import sys, atexit\nsys.stdout.write('\x1b[?8l')   # roguelike: one move per keypress\natexit.register(lambda: sys.stdout.write('\x1b[?8h'))
go
fmt.Print("\x1b[?8l")\ndefer fmt.Print("\x1b[?8h")   // always restore
javascript
process.stdout.write('\x1b[?8l')\nprocess.on('exit', () => process.stdout.write('\x1b[?8h'))
c
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[?8l actually 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 ?8h is 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[?8l to disable repeat for my editor's modal keymap?
No — \x1b[?8l doesn'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 with enable_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

Related sequences