# DEC Device Status Reports (DECDSR)

> Private status requests: DEC's extended cursor position, printer, keyboard and macro space, and newer ones for dark or light colors and visibility.

- **Sequence:** `CSI ? Ps n`
- **DECXCPR**, Extended Cursor Position Report: `CSI ? Pl ; Pc ; Pp R`
- **DECMSR**, Macro Space Report: `CSI Pn * {`
- **DEC STD 070:** [§5.4.4 Extended Cursor Position Report, p. 5-55](https://archive.org/details/bitsavers_decstandar0VideoSystemsReferenceManualDec91_74264381/page/n309/mode/1up)
- **VT220:** [§4.17.2 Device Status Report (DSR)](https://vt100.net/docs/vt220-rm/chapter4.html#S4.17.2)
- **VT510:** [DSR—Device Status Reports](https://vt100.net/docs/vt510-rm/DSR.html)

With a `?` before the parameter, a [device status report](https://control-codes.page/csi/dsr/index.html.md) asks
one of DEC's own questions, or one of the few that newer terminals have
added in the same form. Each has its own answer:

| `Ps` | Asks for | Possible answers | xterm, as a VT420, answers |
| --- | --- | --- | --- |
| `5` | the operating status, in the private form | `CSI ? 0 n`, ready | `CSI ? 0 n` |
| `6` | the cursor position, with the page: DECXCPR | `CSI ? Pl ; Pc ; Pp R` | `CSI ? Pl ; Pc ; 1 R` |
| `15` | the printer's status | `CSI ? 10 n` ready, `11` not ready, `13` no printer, `18` busy, `19` assigned to the other session | `CSI ? 13 n`, no printer |
| `25` | whether the user-defined keys are locked | `CSI ? 20 n` unlocked, `21` locked | `CSI ? 20 n`, unlocked |
| `26` | the keyboard | `CSI ? 27 ; Pn ; Pst ; Ptyp n`: language, status and type | `CSI ? 27 ; 1 ; 0 ; 0 n`: North American, ready, an LK201 |
| `55` | the locator's status | `CSI ? 50 n` ready, `53` no locator | `CSI ? 53 n`, no locator |
| `56` | the locator's type | `CSI ? 57 ; 0 n` unknown, `57 ; 1` a mouse | `CSI ? 57 ; 0 n`, unknown |
| `62` | the space left for macros: DECMSR | `CSI Pn * {` | `CSI 0000 * {`, none |
| `63 ; Pid` | a checksum of the macros: DECCKSR | `DCS Pid ! ~ D…D ST` | `DCS Pid ! ~ 0000 ST` |
| `75` | the data integrity flag | `CSI ? 70 n` no errors, `71` an error, `73` no report since power-up | `CSI ? 70 n`, no errors |
| `85` | the multiple-session configuration | `CSI ? 83 n` not configured, among others | `CSI ? 83 n`, not configured |
| `996` | whether the colors are [dark or light](https://control-codes.page/modes/color-scheme/index.html.md) | `CSI ? 997 ; 1 n` dark, `997 ; 2` light | nothing |
| `998` | whether the view is [visible](https://control-codes.page/modes/visibility/index.html.md) | `CSI ? 999 ; 1 n` potentially visible, `999 ; 2` not visible | nothing |

`?996` is from Contour's
[Dark and Light Mode detection](https://github.com/contour-terminal/contour/blob/ab57ab3288c3dca5ff727311cb3f1401bac30549/docs/vt-extensions/color-palette-update-notifications.md),
and `?998` from
[Private Mode for Terminal Visibility Reports](https://rockorager.dev/misc/visibility-reports/);
each answer is sent unasked as well, while its private mode, `2031` or
`2033`, is set. The rest are DEC's. The possible answers are the VT510
manual's, for the locator xterm's
[control sequences](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/ctlseqs.ms#L2043-L2097),
and for multiple sessions only the one xterm sends.

Most answers take the same form, `CSI ? Ps n`, so a host reading one back
can tell from the number what it answers:

| Answer `Ps` | Answers | Means |
| --- | --- | --- |
| `0` | `?5` | ready |
| `10`, `11`, `13`, `18`, `19` | `?15` | the printer is ready, not ready, missing, busy, or assigned to the other session |
| `20`, `21` | `?25` | the user-defined keys are unlocked, or locked |
| `27` | `?26` | the keyboard: its language, status and type follow |
| `50`, `53` | `?55` | the locator is ready, or missing |
| `57` | `?56` | the locator: its type follows |
| `70`, `71`, `73` | `?75` | no errors, an error, or no report since power-up |
| `83` | `?85` | not configured for multiple sessions |
| `997` | `?996` | the colors: `1` dark or `2` light follows |
| `999` | `?998` | the view: `1` potentially visible or `2` not visible follows |

A terminal that receives one of these answers has not been asked anything,
and does not answer it.

These are the answers in xterm's
[`CASE_DSR`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/charproc.c#L4599-L4746),
from a default build, which is a VT420
([`DFT_DECID`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/ptyx.h#L398-L400)).
Each is gated on a terminal level: the printer, keyboard and user-defined
key reports need a VT220 or later, the locator reports a VT330, and DECMSR,
DECCKSR, data integrity and multiple sessions a VT420. The locator answers
depend on how xterm was built: with `--enable-dec-locator`, which is off by
default, it answers `CSI ? 50 n` (ready) and `CSI ? 57 ; 1 n` (a mouse)
instead. xterm also answers `CSI ? 5 n` with `CSI ? 0 n`, the operating
status in the private form.

**DECXCPR** is the cursor position report with the page number added.
DEC STD 070 makes it a level 3 and 4 function, and counts the line and
column from the margins in origin mode, as [CPR](https://control-codes.page/csi/dsr/index.html.md) does. Its
answer starts `CSI ?`; the VT510 manual's
[DECXCPR](https://vt100.net/docs/vt510-rm/DECXCPR.html) page leaves the `?`
out, but xterm sends it, and esctest2's `test_DECDSR_DECXCPR` expects it.
xterm, with one page, always reports page 1.

**DECMSR** reports the bytes free for macros, divided by 16
([DEC STD 070 §5.12.3, p. 5-185](https://archive.org/details/bitsavers_decstandar0VideoSystemsReferenceManualDec91_74264381/page/n439/mode/1up)).
xterm has no macros and reports none; it writes the number as four
hexadecimal digits, `0000`, where DEC STD 070 defines a plain number.

**DECCKSR** reports a checksum as four hexadecimal digits in a control
string labelled with the `Pid` the request gave
([DEC STD 070 §5.12.2, p. 5-181](https://archive.org/details/bitsavers_decstandar0VideoSystemsReferenceManualDec91_74264381/page/n435/mode/1up)).
The same report answers [DECRQCRA](https://vt100.net/docs/vt510-rm/DECRQCRA.html)'s
checksum of a rectangle. With no macros, xterm reports `0000`.

The VT510 manual describes the others on their own pages:
[printer port](https://vt100.net/docs/vt510-rm/DSR-PP.html),
[user-defined keys](https://vt100.net/docs/vt510-rm/DSR-UDK.html),
[keyboard](https://vt100.net/docs/vt510-rm/DSR-KBD.html),
[macro space](https://vt100.net/docs/vt510-rm/DSR-MSR.html),
[memory checksum](https://vt100.net/docs/vt510-rm/DECCKSR.html) and
[data integrity](https://vt100.net/docs/vt510-rm/DSR-DIR.html).

## Not in libghostty-vt

libghostty-vt answers only DECXCPR, `?6`, of DEC's requests, always with
page 1, as xterm does. Its DSR dispatch in `stream.zig` looks the request up
in a table, `entries` in `device_status.zig`, that has only the ANSI requests
`5` and `6`, DECXCPR, and two private ones of its own, `?996` (the
[color scheme](https://control-codes.page/modes/color-scheme/index.html.md)) and `?998` ([visibility](https://control-codes.page/modes/visibility/index.html.md)); any other request, and any with two parameters
such as `?63 ; Pid`, is logged as invalid and dropped. Every case below
that expects an answer to another request is therefore a known difference:
xterm, a VT420 by default, sends it.

## Support

| Terminal | Version | Support | Notes |
| --- | --- | --- | --- |
| VT220 | [manual](https://vt100.net/docs/vt220-rm/), 2nd ed., 1984 | Partly | printer, user-defined keys and keyboard only ([§4.17.2 Device Status Report (DSR)](https://vt100.net/docs/vt220-rm/chapter4.html#S4.17.2)) |
| VT510 | [manual](https://vt100.net/docs/vt510-rm/), 1st ed., 1993 | Partly | [DSR](https://vt100.net/docs/vt510-rm/DSR.html): no locator (`55`, `56`) or multiple-session (`85`) reports |
| xterm | patch 412, [xterm-411a](https://github.com/ThomasDickey/xterm-snapshots/tree/xterm-411a) | Yes | reports no locator unless built with `--enable-dec-locator` |
| libghostty-vt | [919dca5](https://github.com/ghostty-org/ghostty/tree/919dca5c848d43a489a4cb2e1feade016f0fa2db) | Partly | answers only DECXCPR, `?6`, of these, and its own `?996` and `?998` |
| kitty | 0.49.1, [run in a VM](https://git.jcollie.dev/jeff/control-codes/src/branch/main/emulators/results/kitty.json) | No | fails the 2 cases that show it working |
| foot | 1.28.0, [run in a VM](https://git.jcollie.dev/jeff/control-codes/src/branch/main/emulators/results/foot.json) | No | fails the 2 cases that show it working |
| pyte | 0.8.2, [run as a library](https://git.jcollie.dev/jeff/control-codes/src/branch/main/emulators/results/pyte.json) | No | fails the 2 cases that show it working |
| xterm.js headless | 6.0.0, [run as a library](https://git.jcollie.dev/jeff/control-codes/src/branch/main/emulators/results/xtermjs.json) | No | fails the 2 cases that show it working |
| alacritty_terminal | 0.26.0, [run as a library](https://git.jcollie.dev/jeff/control-codes/src/branch/main/emulators/results/alacritty.json) | No | fails the 2 cases that show it working |
| ConEmu | build 230724, its [documentation](https://conemu.github.io/en/AnsiEscapeCodes.html) | No | lists only `ESC [ 5 n` and `ESC [ 6 n`: [ANSI escape codes](https://conemu.github.io/en/AnsiEscapeCodes.html) |
| rxvt-unicode | 9.31, [run in a VM](https://git.jcollie.dev/jeff/control-codes/src/branch/main/emulators/results/urxvt.json) | No | fails the 2 cases that show it working |
| VTE | 0.84.1, [run as a library](https://git.jcollie.dev/jeff/control-codes/src/branch/main/emulators/results/vte.json) | Yes | passes the 2 cases that show it working |

## Validation

### DECDSR-1: Extended cursor position

Input, one step per line:

```text
\e[2;3H
\e[?6n
```

Expected screen:

```text
|_____|
|_____|
|_____|
reply \e[?2;3;1R
```

### DECDSR-2: Counted from the margins in origin mode

Input, one step per line:

```text
\e[?69h   # allow left and right margins
\e[2;5s   # margins at columns 2 and 5
\e[2;4r   # region is lines 2 to 4
\e[?6h    # origin mode
\e[2;2H   # line 3, column 3 of the screen
\e[?6n
```

Expected screen:

```text
|_____|
|_____|
|_____|
|_____|
cursor 3,3
reply \e[?2;2;1R
```

### DECDSR-3: Operating status, the private way

*A known difference: libghostty-vt does not pass this case.*

Input, one step per line:

```text
\e[?5n
```

Expected screen:

```text
|_____|
reply \e[?0n
```

### DECDSR-4: Printer, user-defined keys and keyboard

*A known difference: libghostty-vt does not pass this case.*

Input, one step per line:

```text
\e[?15n   # printer
\e[?25n   # user-defined keys
\e[?26n   # keyboard
```

Expected screen:

```text
|_____|
reply \e[?13n\e[?20n\e[?27;1;0;0n
```

### DECDSR-5: The locator

*A known difference: libghostty-vt does not pass this case.*

Input, one step per line:

```text
\e[?55n   # status
\e[?56n   # type
```

Expected screen:

```text
|_____|
reply \e[?53n\e[?57;0n
```

### DECDSR-6: Macro space

*A known difference: libghostty-vt does not pass this case.*

Input, one step per line:

```text
\e[?62n
```

Expected screen:

```text
|_____|
reply \e[0000*{
```

### DECDSR-7: Memory checksum

*A known difference: libghostty-vt does not pass this case.*

Input, one step per line:

```text
\e[?63;123n
```

Expected screen:

```text
|_____|
reply \eP123!~0000\e\\
```

### DECDSR-8: Data integrity and multiple sessions

*A known difference: libghostty-vt does not pass this case.*

Input, one step per line:

```text
\e[?75n   # data integrity
\e[?85n   # multiple sessions
```

Expected screen:

```text
|_____|
reply \e[?70n\e[?83n
```

### DECDSR-9: A request it does not know

Input, one step per line:

```text
\e[?99n
```

Expected screen:

```text
|_____|
reply none
```

---

This is the Markdown version of <https://control-codes.page/csi/decdsr/>. On that page every validation case runs live in libghostty-vt, the terminal emulation core of Ghostty, compiled to WebAssembly.

The validation cases are written in the notation described in <https://control-codes.page/notation/index.html.md>.
