DECDMAC / DECINVM — 定义与调用宏(DCS Pn ; Pn ; Pn ! z ... ST / CSI Pn * z)
用数字句柄存储一段字节序列(DECDMAC),按需回放(DECINVM)—— DEC VT520 的终端内置宏录制器。
字节形式
涵盖所有常见的字符串字面量写法,方便正反查找。
\x1bP<Pid>;<Pdt>;<Penc>!z<MACRO-BODY>\x1b\\ (define) \x1b[<Pid>*z (invoke)\033P<Pid>;<Pdt>;<Penc>!z<body>\033\\ / \033[<Pid>*z\eP<Pid>;<Pdt>;<Penc>!z<body>\e\\ / \e[<Pid>*zESC P Pid ; Pdt ; Penc ! z BODY ESC \ / ESC [ Pid * z1b 50 ... 21 7a ... 1b 5c / 1b 5b ... 2a 7a说明
DEC VT520 / VT525 宏机制 —— 一对组合序列。**DECDMAC**(定义宏)是中间字节 `!`(0x21)、末字节 `z`(0x7a)的 DCS 帧,把体 `<MACRO-BODY>` 存于整数句柄 `Pid`(0–63)下。参数: - `Pid` —— 宏编号(0–63)。 - `Pdt`(delete-type)—— `0`(默认)只覆盖本宏;`1` 在写入前删除**所有**宏。 - `Penc`(encoding)—— `0`(默认)体为普通 7 / 8 位终端字节;`1` 体为十六进制编码(每两个十六进制 = 一字节)—— 十六进制形式让宏可安全包含 ESC、ST、`;` 等会提前终止 DCS 帧的解析敏感字节。 **DECINVM**(调用宏)是中间字节 `*`(0x2a)、末字节 `z` 的 CSI 序列 —— `\x1b[<Pid>*z` 回放该句柄下存储的全部字节,仿佛它们是刚通过线路到达(任何嵌入的 SGR、光标移动、OSC 等都以正常解析器状态执行)。 **用途**(历史):表单录入终端 —— 主机程序在会话开始时定义一组稳定的光标定位 + 框线宏,随后用短小的 DECINVM 调用驱动屏幕,而非在整页里重复发送沉重的 CSI 序列上千次。在慢串口上省字节(原始动机);同时让终端缓存光标定位工作。 **现代相关性**:基本为零。仅 xterm 以有意义的精度实现两者(`disallowedColors` / `allowMacro` 资源默认**关**,因远程进程定义后被调用的宏是一个小但真实的 shell 集成 / 剪贴板注入攻击面)。现代模拟器(alacritty / kitty / wezterm / ghostty / Windows Terminal)静默忽略两者。用途:VT520 忠实模拟器测试套件、表单终端保留工作、奇异演示。
规范出处: DEC VT520 RM (DECDMAC / DECINVM) / xterm-ctlseqs
参数
| Pid | 宏编号 0–63(定义与调用共享同一数字命名空间)。 |
| Pdt | DECDMAC 的删除类型:0 = 仅覆盖该槽,1 = 先删除所有宏。 |
| Penc | DECDMAC 体的编码:0 = 原始字节,1 = 十六进制编码(对 ESC / ST / `;` 安全)。 |
示例
# Define macro 1 = 'cursor-home + clear screen', then invoke twice.\nprintf '\033P1;0;0!z\033[H\033[2J\033\\\\'\nprintf '\033[1*z' # invoke — clears screen\nprintf '\033[1*z' # invoke again — still clearsimport sys\n# Hex-encoded body so the macro can contain ESC safely:\nbody_hex = '1b5b481b5b324a' # ESC[H ESC[2J\nsys.stdout.write(f'\x1bP2;0;1!z{body_hex}\x1b\\\\')\nsys.stdout.write('\x1b[2*z') # invoke macro 2// Define a 'red bold' SGR macro then invoke at every log line:\nfmt.Print("\x1bP3;0;0!z\x1b[1;31m\x1b\\\\")\nfor _, line := range lines { fmt.Print("\x1b[3*z" + line + "\x1b[0m\n") }// Wipe all macros and store a fresh one in slot 0:\nprocess.stdout.write('\x1bP0;1;0!zHELLO\x1b\\\\')\nprocess.stdout.write('\x1b[0*z') // prints HELLO/* Define macro 7 = SGR reset; invoke at end of every styled span. */\nprintf("\x1bP7;0;0!z\x1b[0m\x1b\\\\");\nfor (int i = 0; i < n; ++i) {\n print_colored(items[i]);\n printf("\x1b[7*z");\n}终端支持
- xterm
- 支持
- Linux console (fbcon)
- 不支持
- macOS Terminal.app
- 不支持
- iTerm2
- 不支持
- Windows Terminal
- 不支持
- cmd.exe / ConPTY
- 不支持
- kitty
- 不支持
- alacritty
- 不支持
- WezTerm
- 不支持
- Ghostty
- 不支持
- GNOME Terminal
- 不支持
- Konsole
- 不支持
- tmux
- 不支持
- GNU screen
- 不支持
| xterm | Linux console (fbcon) | macOS Terminal.app | iTerm2 | Windows Terminal | cmd.exe / ConPTY | kitty | alacritty | WezTerm | Ghostty | GNOME Terminal | Konsole | tmux | GNU screen |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 支持 | 不支持 | 不支持 | 不支持 | 不支持 | 不支持 | 不支持 | 不支持 | 不支持 | 不支持 | 不支持 | 不支持 | 不支持 | 不支持 |