# Mouse Tracking (?9, ?1000 to ?1003, ?1005 to ?1007, ?1015, ?1016)

> Ask the terminal to report mouse buttons and movement, and choose how the reports are encoded.

- **Sequence:** `CSI ? 1000 h`
- **xterm:** [Mouse Tracking](https://invisible-island.net/xterm/ctlseqs/ctlseqs.html)

These modes ask the terminal to send the program a report when the mouse is
used over it, instead of using the mouse itself for selecting text. They are
xterm's, in DEC's private space. Two groups of them work together: one
chooses *which* events are reported, the other *how* a report is encoded.

| Mode | Reports |
| --- | --- |
| `9` | a button press only (X10 compatibility) |
| `1000` | presses and releases |
| `1001` | presses and releases, with highlight tracking |
| `1002` | presses, releases, and movement while a button is down |
| `1003` | presses, releases, and all movement |

| Mode | Encoding |
| --- | --- |
| *none* | `CSI M` and three bytes: the button and the coordinates, each plus 32; coordinates beyond 223 cannot be sent |
| `1005` | the same, with the coordinates in UTF-8 |
| `1006` | SGR: `CSI < b ; x ; y M` for a press, `m` for a release, in decimal |
| `1015` | urxvt: `CSI b ; x ; y M`, in decimal |
| `1016` | SGR, with the coordinates in pixels rather than cells |

Mode `1007`, *alternate scroll*, has the mouse wheel send cursor up and
down keys while the [alternate screen](https://control-codes.page/modes/altscreen/index.html.md) is showing and the
wheel is not being reported
([`AlternateScroll`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/scrollbar.c#L755-L783)); [focus events](https://control-codes.page/modes/focus/index.html.md),
`1004`, have their own page.

The reports go to the program, so a case cannot see them; what it can see is
what DECRQM says. The cases follow xterm, which keeps one value for each
group, not a flag per mode
([`dpmodes`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/charproc.c#L7807-L7849),
[`really_set_mousemode`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/charproc.c#L7432-L7439)):

- Setting one event mode replaces the one before it, and DECRQM reports
  only the latest as set. Resetting *any* of them turns tracking off.
- Setting one encoding replaces the one before it too, but resetting an
  encoding takes effect only if it is the one in use: xterm's comment says
  "a reset is only effective against the matching mode".
- Alternate scroll is off unless the `alternateScroll` resource turns it on
  ([`charproc.c`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/charproc.c#L422)).
- [RIS](https://control-codes.page/esc/ris/index.html.md) turns tracking and the encoding off; DECSTR does not
  ([`ReallyReset`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/charproc.c#L14432-L14443)).

libghostty-vt tracks the events the same way, with one value, but DECRQM
answers from a separate flag for each mode, so it reports a replaced mode as
still set. Resetting any encoding goes back to the default encoding even if
another is in use, which DECRQM does not show either: in that case it still
reports the other as set. It does not know mode `1001`, and it starts with
alternate scroll on. The cases those touch are known differences.

## Validation

### MOUSE-1: Off to begin with

Input, one step per line:

```text
\e[?1000$p
\e[?1002$p
\e[?1003$p
\e[?1006$p
```

Expected screen:

```text
|____|
reply \e[?1000;2$y\e[?1002;2$y\e[?1003;2$y\e[?1006;2$y
```

### MOUSE-2: Set and reset

Input, one step per line:

```text
\e[?1002h
\e[?1002$p
\e[?1002l
\e[?1002$p
```

Expected screen:

```text
|____|
reply \e[?1002;1$y\e[?1002;2$y
```

### MOUSE-3: One event mode at a time

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

Input, one step per line:

```text
\e[?1000h
\e[?1002h  # replaces 1000
\e[?1000$p
\e[?1002$p
```

Expected screen:

```text
|____|
reply \e[?1000;2$y\e[?1002;1$y
```

### MOUSE-4: X10 replaces the others too

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

Input, one step per line:

```text
\e[?1003h
\e[?9h
\e[?9$p
\e[?1003$p
```

Expected screen:

```text
|____|
reply \e[?9;1$y\e[?1003;2$y
```

### MOUSE-5: Resetting any event mode turns tracking off

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

Input, one step per line:

```text
\e[?1002h
\e[?1000l  # not the one that was set
\e[?1002$p
```

Expected screen:

```text
|____|
reply \e[?1002;2$y
```

### MOUSE-6: Highlight tracking

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

Input, one step per line:

```text
\e[?1001h
\e[?1001$p
```

Expected screen:

```text
|____|
reply \e[?1001;1$y
```

### MOUSE-7: One encoding at a time

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

Input, one step per line:

```text
\e[?1006h
\e[?1015h  # replaces 1006
\e[?1006$p
\e[?1015$p
```

Expected screen:

```text
|____|
reply \e[?1006;2$y\e[?1015;1$y
```

### MOUSE-8: Resetting another encoding leaves this one

Input, one step per line:

```text
\e[?1006h
\e[?1015l
\e[?1006$p
```

Expected screen:

```text
|____|
reply \e[?1006;1$y
```

### MOUSE-9: UTF-8 and pixel encodings

Input, one step per line:

```text
\e[?1005h
\e[?1005$p
\e[?1016h
\e[?1016$p
```

Expected screen:

```text
|____|
reply \e[?1005;1$y\e[?1016;1$y
```

### MOUSE-10: Alternate scroll is off by default

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

Input, one step per line:

```text
\e[?1007$p
```

Expected screen:

```text
|____|
reply \e[?1007;2$y
```

### MOUSE-11: DECSTR leaves tracking on

Input, one step per line:

```text
\e[?1002h
\e[?1006h
\e[!p
\e[?1002$p
\e[?1006$p
```

Expected screen:

```text
|____|
reply \e[?1002;1$y\e[?1006;1$y
```

### MOUSE-12: RIS turns it off

Input, one step per line:

```text
\e[?1002h
\e[?1006h
\ec
\e[?1002$p
\e[?1006$p
```

Expected screen:

```text
|____|
reply \e[?1002;2$y\e[?1006;2$y
```

---

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