?9, ?1000 to ?1003, ?1005 to ?1007, ?1015, ?1016 Mouse Tracking
Ask the terminal to report mouse buttons and movement, and choose how the reports are encoded.
?1000 Mouse Tracking
CSI ? 1000 h/l
?9 X10 Mouse
CSI ? 9 h/l
?1001 Highlight Mouse Tracking
CSI ? 1001 h/l
?1002 Button-Event Mouse Tracking
CSI ? 1002 h/l
?1003 Any-Event Mouse Tracking
CSI ? 1003 h/l
?1005 UTF-8 Mouse Encoding
CSI ? 1005 h/l
?1006 SGR Mouse Encoding
CSI ? 1006 h/l
?1007 Alternate Scroll
CSI ? 1007 h/l
?1015 urxvt Mouse Encoding
CSI ? 1015 h/l
?1016 SGR Pixel Mouse Encoding
CSI ? 1016 h/l
- 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.
| 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 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
alternateScrollresource 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.
Support
| Terminal | Version | Support | Notes |
|---|---|---|---|
| VT220 | manual, 2nd ed., 1984 | No | not in the manual |
| VT510 | manual, 1st ed., 1993 | No | not in the manual; not in Table 5-6 |
| xterm | patch 412, xterm-411a | Yes | alternate scroll is off unless the alternateScroll resource is set |
| libghostty-vt | 0f171f6 | Partly | no mode 1001; DECRQM answers each mode’s own flag; alternate scroll on by default (MOUSE-3 to MOUSE-7, MOUSE-10) |
| kitty | 0.49.1, run in a VM | Partly | fails MOUSE-6 of the 5 cases that show it working |
| foot | 1.28.0, run in a VM | Partly | fails MOUSE-6, MOUSE-9 of the 5 cases that show it working |
| xterm.js headless | 6.0.0, run as a library | Partly | fails MOUSE-6, MOUSE-9 of the 5 cases that show it working |
| alacritty_terminal | 0.26.0, run as a library | Partly | fails MOUSE-6, MOUSE-9 of the 5 cases that show it working |
| ConEmu | build 230724, its documentation | Partly | lists 9, 1000, 1002, 1003, 1005, 1006 and 1015; not 1001, 1007 or 1016; ANSI escape codes |
| rxvt-unicode | 9.31, run in a VM | Partly | fails MOUSE-6, MOUSE-9, MOUSE-12 of the 5 cases that show it working |
| VTE | 0.84.1, run as a library | Partly | fails MOUSE-9 of the 5 cases that show it working |
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