跳到主要内容
ansicode

DECARM — 按键自动重复模式(CSI ? 8 h / l)

切换终端在按住按键时是否重复发送字节 —— 对游戏与编辑器很重要,按住 j 不应狂刷缓冲。

字节形式

涵盖所有常见的字符串字面量写法,方便正反查找。

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

说明

Auto-Repeat 模式。设置(\x1b[?8h,几乎所有终端的默认)时,按键超过 OS 定义的延迟(典型 250 ms)后保持按下会让终端按 OS 定义的速率(典型每秒 30 次)注入重复字节 —— 即标准打字机风格行为。重置(\x1b[?8l)时,无论按键保持多久,每次物理按键都只发一个字节 —— 这样把 j 解作「下移一格」的 roguelike 在玩家按住按键时不会跨地图狂奔。OS 延迟 / 速率不能通过 DECARM 调整(X11 用 xset r rate、macOS 用 defaults write -g KeyRepeat、Windows 用辅助功能面板);DECARM 只切开 / 关。对 TUI 游戏(基于 curses 的 roguelike 如 nethack、brogue)、解释单键命令的模式化编辑器、以及希望每次击键都防抖为离散事件的应用至关重要。支持几乎一致 —— 仅 Linux console 偏 partial(取决于 framebuffer 驱动)。退出时务必恢复 ?8h —— 关着 auto-repeat 退出会污染用户 shell 会话。

规范出处: DEC VT100 (DECARM) / xterm-ctlseqs

参数

示例

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 */

在哪里用到

实际会发出该序列的工具——把抽象字节锚定到你已经用过的命令上。

  • vim long-press repeat suppressionVim 进入插入模式时若配置 `:set ttimeoutlen=0` 会发 `\x1b[?8l`,防止终端侧按键重复超过编辑器按键级别的常规模式命令 —— `:verbose set ttimeoutlen?` 检查,用 `script` 跟踪可见发送
  • less paging with held arrow key在 OS *不*生成按键重复的终端上(pre-3.2 tmux 配置中的某些复用器),`less` 依赖 DECARM `\x1b[?8h`(默认)让用户按住 `j` 或 `↓` 时按行滚动重复 —— `tmux: set -g repeat-time 0` 关闭后观察按一次后停止滚动
  • terminfo `decarm` capability作为 `km` 布尔能力(「有 meta 键」—— 对 DEC 系终端隐含 DECARM)列出;`infocmp xterm | grep -E 'km|decarm'` 显示该位。应用代码通过 `tigetflag("km")` 读取来决定是否安装按键去抖
  • GNU readline `quoted-insert` (Ctrl-V / Ctrl-Q)按住 `Ctrl-V` 插入字面控制字节,在 OS 层不为修饰键自动重复的终端(某些带 modifier-debounce 的 Wayland 合成器)依赖 DECARM `?8h` 重复 —— `bind -P | grep quoted-insert` 显示绑定,用 `READLINE_DEBUG=1` 跟踪
  • htop refresh-rate vs key-repeat interactionhtop 的「Setup → Display options → Update interval」在「按住箭头滚动进程列表」场景与 DECARM 交互:`?8h`(默认)配 1.5 s 刷新时,按住 `↓` 滚动长列表平滑,因为终端按键重复超过重绘;`?8l` 则每次按键后暂停直到重绘追上 —— 在会话间切换 `setterm -repeat off`/`on` 可见

常见问题

针对这条序列,开发者真正会去搜索的问题的简短回答。

DECARM \x1b[?8h / \x1b[?8l 到底控制什么?
DECARM(Auto-Repeat Mode)控制*终端*是否在按键按住时生成重复按键 —— 不同于窗口系统应用的任何 OS 级按键重复。在硬件 DEC VT220 / VT320 上这是按住键得重复的唯一方法;在现代模拟器上基本是 vestigial,因为 OS 已在输入法层(xkb、IBus、macOS 上的 IMK、Windows 内核)处理按键重复。今天 ?8h 是支持矩阵中每个终端的默认值;?8l(关闭)xterm、kitty、foot、gnome-terminal、konsole 支持 —— Windows Terminal、ConPTY、alacritty(完全委托给 OS)上是空操作。用例已死 —— 现代 TUI 作者通过 XKB 或 AppKit 按键规则全局禁用 OS 按键重复,而不依赖 DECARM。
我的编辑器模态键映射应不应该发 \x1b[?8l 关闭重复?
不要 —— \x1b[?8l 触不到 OS 按键重复层,所以任何把重复委托给 OS 的终端上(Windows Terminal、ConPTY、alacritty、Wayland 下设 enable_key_repeat = yes 的 kitty),按住键仍会向你的 stdin 涌入重复字节。到达的字节无论 DECARM 开关都一样,因为重复是在终端*之外*生成的。正确模式在应用侧:给收到的字节打时间戳并在去抖窗口内忽略重复,或用 kitty keyboard protocol \x1b[>1u(它*会*把 key-down vs key-up vs key-repeat 作为带渐进增强标志的独立事件上报)。对 Vim / Helix / Kakoune 风格模态编辑,kitty 协议是受支持的答案。

终端支持

xterm
支持
Linux console (fbcon)
部分
macOS Terminal.app
支持
iTerm2
支持
Windows Terminal
支持
cmd.exe / ConPTY
部分
kitty
支持
alacritty
支持
WezTerm
支持
Ghostty
支持
GNOME Terminal
支持
Konsole
支持
tmux
支持
GNU screen
支持

相关序列