^[control-codes live in libghostty-vt

Private modes

?1000 Mouse Tracking

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

CSI ? 1000 h
xterm
Mouse Tracking

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.

ModeReports
9a button press only (X10 compatibility)
1000presses and releases
1001presses and releases, with highlight tracking
1002presses, releases, and movement while a button is down
1003presses, releases, and all movement
ModeEncoding
noneCSI M and three bytes: the button and the coordinates, each plus 32; coordinates beyond 223 cannot be sent
1005the same, with the coordinates in UTF-8
1006SGR: CSI < b ; x ; y M for a press, m for a release, in decimal
1015urxvt: CSI b ; x ; y M, in decimal
1016SGR, 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 is showing and the wheel is not being reported (AlternateScroll); focus events, 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, really_set_mousemode):

  • 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).
  • RIS turns tracking and the encoding off; DECSTR does not (ReallyReset).

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

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

MOUSE-2: Set and reset

\e[?1002h
\e[?1002$p
\e[?1002l
\e[?1002$p
|____|
reply \e[?1002;1$y\e[?1002;2$y

MOUSE-3: One event mode at a time

\e[?1000h
\e[?1002h  # replaces 1000
\e[?1000$p
\e[?1002$p
|____|
reply \e[?1000;2$y\e[?1002;1$y

MOUSE-4: X10 replaces the others too

\e[?1003h
\e[?9h
\e[?9$p
\e[?1003$p
|____|
reply \e[?9;1$y\e[?1003;2$y

MOUSE-5: Resetting any event mode turns tracking off

\e[?1002h
\e[?1000l  # not the one that was set
\e[?1002$p
|____|
reply \e[?1002;2$y

MOUSE-6: Highlight tracking

\e[?1001h
\e[?1001$p
|____|
reply \e[?1001;1$y

MOUSE-7: One encoding at a time

\e[?1006h
\e[?1015h  # replaces 1006
\e[?1006$p
\e[?1015$p
|____|
reply \e[?1006;2$y\e[?1015;1$y

MOUSE-8: Resetting another encoding leaves this one

\e[?1006h
\e[?1015l
\e[?1006$p
|____|
reply \e[?1006;1$y

MOUSE-9: UTF-8 and pixel encodings

\e[?1005h
\e[?1005$p
\e[?1016h
\e[?1016$p
|____|
reply \e[?1005;1$y\e[?1016;1$y

MOUSE-10: Alternate scroll is off by default

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

MOUSE-11: DECSTR leaves tracking on

\e[?1002h
\e[?1006h
\e[!p
\e[?1002$p
\e[?1006$p
|____|
reply \e[?1002;1$y\e[?1006;1$y

MOUSE-12: RIS turns it off

\e[?1002h
\e[?1006h
\ec
\e[?1002$p
\e[?1006$p
|____|
reply \e[?1002;2$y\e[?1006;2$y