通过 DECRQSS 查询 DECSCUSR — 读取当前光标形状(`\x1bP$q q\x1b\\`)
光标形状参数的查询往返 —— 通过 DECRQSS 查询 DECSCUSR,终端回复当前 `Ps SP q` 设置。
字节形式
涵盖所有常见的字符串字面量写法,方便正反查找。
\x1bP$q q\x1b\\\033P$q q\033\\\eP$q q\e\\ESC P $ q SP q ESC \1b 50 24 71 20 71 1b 5c说明
DECSCUSR(`dec-cursor-shape`)定义的是*设置器* —— `\x1b[<Ps> SP q` 用于变更光标形状。它没有像 OSC 10 / 11 / 12 那样对称的 `?` 风格查询 opcode;**查询侧**是叠加在 DECRQSS(`dcs-decrqss`)之上的:向终端请求那个末字节为 `SP q` 的可设置函数,让终端回复当前状态。 **请求** —— `\x1bP$q q\x1b\\`。解析:DCS 帧(`\x1bP`)、中间字节 `$` + 末字节 `q`(DECRQSS opcode)、负载 `" q"`(唯一标识 DECSCUSR 设置器的字节 —— 其 `SP` 中间字节加 `q` 末字节)、以 ST(`\x1b\\`)结束。 **回复** —— 成功时为 `\x1bP1$r<Ps> q\x1b\\`,`<Ps>` 即当前参数(`0` 用户默认至 `6` 实心竖线 —— 完整表见 `dec-cursor-shape`)。前导 `1` 是 DECRQSS 的成功指示(`0` 表「请求无效」);`$r` 是其回复帧的中间字节+末字节。 **为何重要** —— 在模态弹层(fzf / atuin / tmux 中 neovim 的浮窗)周围保存与还原光标形状的 TUI 必须知道*原始*形状才能还原。没有此查询,只能盲目重置为 `0`(用户默认 —— 但会丢掉父程序的覆盖)或硬编码猜测。DECRQSS 的往返让弹层得以捕获并忠实回放。 **示例握手** —— bash 带超时:`printf '\x1bP$q q\x1b\\' > /dev/tty; IFS= read -r -d '\\' -t 0.1 reply < /dev/tty; echo "$reply" | grep -oE 'P1\\$r[0-9]+'` —— 光标为实心竖线时返回 `P1$r6`。 **注意** —— xterm / iTerm2 / Kitty / WezTerm / Ghostty / Alacritty / Konsole 会回复;Linux console / cmd.exe / macOS Terminal 不会。务必加约 100 ms 超时,缺失时回退到 `Ps = 0`(用户默认)。若光标形状从未显式设置过,部分模拟器会回 `\x1bP0$r\x1b\\`(DECRQSS「无效」)—— 同样按「用默认」处理。
规范出处: xterm-ctlseqs (DECRQSS + DECSCUSR)
参数
| payload | 被查询的设置器标识字节 —— 这里为 `" q"`(SP + q),即 DECSCUSR 的中间字节 + 末字节。 |
| reply Ps | 当前形状:0 = 用户默认、1 = 闪烁方块、2 = 实心方块、3 = 闪烁下划线、4 = 实心下划线、5 = 闪烁竖线、6 = 实心竖线。 |
示例
# Capture current cursor shape (raw + timeout).\nold=$(stty -g); stty -echo raw min 0 time 1\nprintf '\033P$q q\033\\\\' > /dev/tty\nIFS= read -r -d '\\\\' reply < /dev/tty\nstty "$old"\nshape=$(echo "$reply" | sed -nE 's/.*P1\\$r([0-9]+).*/\\1/p')\necho "current cursor: ${shape:-default}"import sys, termios, tty, re\ndef cursor_shape():\n fd = sys.stdin.fileno(); old = termios.tcgetattr(fd); tty.setraw(fd)\n try:\n sys.stdout.write('\x1bP$q q\x1b\\\\'); sys.stdout.flush()\n buf = b''\n while b'\\x1b\\\\' not in buf:\n buf += sys.stdin.buffer.read1(64)\n m = re.search(rb'P1\\$r(\\d+)', buf)\n return int(m.group(1)) if m else 0\n finally:\n termios.tcsetattr(fd, termios.TCSADRAIN, old)// Save shape -> open popup with bar cursor -> restore.\nshape := queryCursorShape() // via DECRQSS round-trip\nfmt.Print(\"\\x1b[6 q\") // bar for popup\ndefer fmt.Printf(\"\\x1b[%d q\", shape) // restore on exit// Query, then echo a description.\nprocess.stdin.setRawMode(true); process.stdin.resume();\nprocess.stdout.write('\\x1bP$q q\\x1b\\\\');\nlet buf = '';\nprocess.stdin.on('data', chunk => {\n buf += chunk.toString();\n if (!buf.includes('\\x1b\\\\')) return;\n process.stdin.setRawMode(false); process.stdin.pause();\n const m = buf.match(/P1\\$r(\\d+)/);\n const names = ['default','blink block','steady block','blink underline','steady underline','blink bar','steady bar'];\n console.log(names[m ? +m[1] : 0]);\n});/* Round-trip the cursor shape — minimal raw read. */\nprintf(\"\\x1bP$q q\\x1b\\\\\"); fflush(stdout);\nchar buf[64]; int n = read(0, buf, sizeof buf - 1);\nint shape = 0;\nif (n > 0) { buf[n] = 0; sscanf(strstr(buf, \"P1$r\"), \"P1$r%d\", &shape); }终端支持
- 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 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 支持 | 不支持 | 不支持 | 支持 | 部分 | 不支持 | 支持 | 支持 | 支持 | 支持 | 部分 | 支持 | 不支持 | 不支持 |
相关序列
在家族食谱中
DCS 食谱 · 3. 向终端提问 —— DECRQSS、terminfo cap、DECRQTSR、DECRQUPSS、光标样式