# Cursor Coupling Modes (DECHCCM, DECVCCM, DECPCCM)

> Choose whether the window follows the cursor around a page larger than the screen.

- **Sequence:** `CSI ? 60 h`
- **DEC STD 070:** [§5.5 Set/Reset Horizontal Cursor Coupling Mode, p. 5-85](https://archive.org/details/bitsavers_decstandar0VideoSystemsReferenceManualDec91_74264381/page/n339/mode/1up)

In DEC's windowing extension, the screen is a window onto a page of display
memory that can be wider, taller, or one of several pages. These three modes
decide whether the window follows the cursor when it moves out of view:

| Mode | Name | Set (coupled) | DEC STD 070 default |
| --- | --- | --- | --- |
| `60` | DECHCCM, horizontal | the page moves sideways in the window to keep the cursor visible | reset |
| `61` | DECVCCM, vertical | the page moves up or down in the window | set |
| `64` | DECPCCM, page | the window switches to the cursor's page | set |

DECVCCM is on [p. 5-86](https://archive.org/details/bitsavers_decstandar0VideoSystemsReferenceManualDec91_74264381/page/n340/mode/1up) and DECPCCM on
[p. 5-87](https://archive.org/details/bitsavers_decstandar0VideoSystemsReferenceManualDec91_74264381/page/n341/mode/1up), both in §5.5, Windowing Extension, at levels 3
and 4. The VT510 manual has
[DECVCCM](https://vt100.net/docs/vt510-rm/DECVCCM.html) and
[DECPCCM](https://vt100.net/docs/vt510-rm/DECPCCM.html), but no page for
DECHCCM.

A terminal whose page is the size of its screen has nothing to couple. xterm
recognizes all three modes and ignores them
([`charproc.c`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/charproc.c#L8012-L8045)); [DECRQM](https://control-codes.page/csi/decrqm/index.html.md) reports each
as permanently reset, `4`, at level 3 and up, and xterm is a VT420 by default
([`do_dec_rqm`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/misc.c#L5783-L5803)). esctest2 expects DECHCCM to be
permanently reset, and DECVCCM and DECPCCM to be changeable, listing xterm as
not supporting those two; the cases follow xterm.

libghostty-vt does not have the modes: none is in its table in `modes.zig`,
so DECRQM reports each as not recognized, `0`. Both cases are known
differences.

## Validation

### DECHCCM-1: All three permanently reset

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

Input, one step per line:

```text
\e[?60$p\e[?61$p\e[?64$p
```

Expected screen:

```text
|_____|
reply \e[?60;4$y\e[?61;4$y\e[?64;4$y
```

### DECHCCM-2: Even after they are set

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

Input, one step per line:

```text
\e[?60h\e[?61h\e[?64h
\e[?60$p\e[?61$p\e[?64$p
```

Expected screen:

```text
|_____|
reply \e[?60;4$y\e[?61;4$y\e[?64;4$y
```

---

This is the Markdown version of <https://control-codes.page/modes/dechccm/>. 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>.
