Skip to content

Instantly share code, notes, and snippets.

@christianparpart
Last active January 21, 2024 20:24
Show Gist options
  • Save christianparpart/bf82bc3a8ad7f3abeee3ada41c3178a9 to your computer and use it in GitHub Desktop.
Save christianparpart/bf82bc3a8ad7f3abeee3ada41c3178a9 to your computer and use it in GitHub Desktop.
Terminal Spec: Passive Mouse Tracking

Passive Mouse Tracking

Motivation

While mouse event tracking is already possible in various modes and encodings, this feature seems most used by alt-screen applications however.

The reason why primary screen applications (such as your shell) usually don't make use of the mouse, is the design problem, that whenever the application is requesting mouse tracking events, the user cannot use the mouse to select text on the screen anymore.

With this VT extension, a new mode is introduced to inform the terminal that the user may still use the mouse to select text, but still have mouse events being reported to the application to allow passive tracking of mouse events.

This can then be used by shells to still act on mouse click events to reposition the cursor or mouse-hover events over commands to enable the possibility for the shell to create tooltips.

What this specification is Not

This spec is NOT trying to revolutionize mouse protocol support in the terminal nor trying to handle every little corner case that may or may not arise in the usage scenarios.

We however attempt to address a current need in a way that this specification is easily understood, easily implementable on both sides, and most importantly, helpful to users.

Semantics

The semantics of mouse reporting are not altered.

The application only receives mouse tracking events for the main page area.

Passive mouse tracking mode will ONLY work in conjunction with SGR transport mode (?1006). Using it with any other transport mode (e.g. X10, UTF-8, or URXVT) will be ignored.

The SGR mouse events received by the application will contain an additional parameter to the end indicating if this event has also been handled by the user interface (terminal frontend) or not.

While mode ?2029 is active mode ?1007 has no effect (i.e. wheel events are not translated to arrow keys).

Feature and mode detection.

Use DECRQM to detect if the mode is supported and if so, its current state. Passive mouse tracking is considered supported if and only if the reply contains state value 1 (set) or value 2 (reset).

Enabling Passive Mouse Tracking

Sending CSI ? 2029 h to the terminal will enable passive mouse tracking. This will implicitly activate DEC mode ?1006 (SGR) as well as ?1002 (Button click event tracking).

In case mouse move events are desired as well, the application is free to send CSI ? 2029 ; 1003 h in one go.

Syntax of the events being received

Since only SGR encoding is supported for passive mouse tracking, the syntax looks equivalent to this, except that an additional parameter is added to indicate whether or not the user interface (terminal) has handled this event as well.

Mouse Press (and move) Syntax: CSI ? <ButtonAndModifierMask> ; <Column> ; <Line> ; <HandledFlag> M

Mouse Release Syntax: CSI ? <ButtonAndModifierMask> ; <Column> ; <Line> ; <HandledFlag> m

Whereas <ButtonAndModifierMask, Column, <Line> are equivalent to how it is handled already. <HandledFlag> is either 1 or greater to indicate that the user interface has handled this event as well, or value 0 to indicate that the user interface has not handled this event.

Disabling Passive Mouse Tracking

Sending CSI ? 2029 l will disable passive mouse tracking and also have any mouse event mode as well as mouse event encoding mode disabled. It is therefore sufficient to simply send this single VT sequence to have it all cleared.

Disabling other mouse modes

When disabling other mouse modes (events as well as encoding) should alo disable passive mouse tracking implicitly in order to best avoid leaking passive mouse tracking into another application by accident.

Implementation Notes

Mouse Coordinates

While alt-screen application do not have the problem, it must be ensured for primary screen applications with scrollback lines available, that the mouse coordinates are mapped to the correct cell position. With top-left being (1, 1), when the viewport of the user interface is scrolled up by 5 lines, that grid cell must still be reported as (1, 1) as the connected terminal application does not have the notion of viewport or would be even able to reference these.

Fear of leaking mouse events into another application.

Applications like the shell (e.g. Bash, ZSH, Fish) are likely to frequently execute child processes, with having the PTY handles inherited. In case of fear that some mouse events might leak into the next application, the application may do the following:

  1. Disable mouse protocol (CSI ?2029 l)
  2. Discard any pending input from stdin that may have be read without waiting.
  3. Execute the child process.

Alternatively a very conservative way:

  1. Disable mouse protocol (CSI ?2929 l)
  2. Request DA1
  3. Consume and discard any input until DA1's response has been received.
  4. Execute child process.

Adoption state

Support Terminal/Tookit/App Notes
n/a xterm.js
n/a Windows Terminal
Contour see: contour-terminal/contour#882
n/a mintty
n/a notcurses
n/a foot
n/a Wezterm
n/a VTE / gnome-terminal
n/a iTerm2
n/a Kitty
n/a Alacritty
n/a Konsole
n/a st
@jerch
Copy link

jerch commented Nov 19, 2022

@christianparpart I'd have a few questions regard its technical implications here, maybe you answer that with some hints on how you plan to implement this.

First mouse tracking works on the normal buffer as fine as on the alternate buffer (take the the "fine" with a grain of salt - it is the same sh*t as over there due to awkward protocols/encodings). Imho the fact that mostly alt buffer apps use it comes from the idea to fully control that screen state, while that assumption normally cannot be made on the normal buffer with scrollback (as there is other output as well). So here I cannot quite follow your reasoning with the text selection & clipboard semantics.

On the tech level - we have several mouse actions that can be tracked:

  • button down only (X10)
  • button down|up incl. wheel button (VT200)
  • button down|up|wheel with drag (move on down)
  • all above - thus always reporting move in any button state + down|up|wheel button actions

Now the question is - how to make mouse reports working on scrollbuffer while still maintaining its other mouse sensitive semantics? To list these other mouse sensitive semantics on the normal buffer:

  • wheel action: buffer scrolling itself
  • wheel action: arrow up|down if in alternateScroll mode
  • point & select text (down + drag events)
  • point & double click for single word selection

On a first glance it should be possible to just keep everything working as it currently is, but also send the requested tracking info to app side on top. This would be the simplest approach and prolly easiest to implement on TE side (and appside has to be aware of incoming mouse reports anyway).

But on a second look I am not sure anymore, if for example a scroll action in the scroll buffer should be reported to app side (prolly a shell) - it has no means to act upon this. So I am not sure whether reporting wheel actions makes any sense in a "passive tracking mode". But the same argument can be applied to the DRAG event - if the user points & highlights anything far up in the scrollbuffer - whats the deal here for app side, beside "sniffing" on what the user does with its mousey (might that even raise security concerns)?

At this point imho a passive mouse tracking mode has very limited use cases for the scrollbuffer, if any at all. I still like the idea, but for a very different purpose - on the alternate buffer. Here a passive mode would enable to use all the normal mouse semantics along with the overloads from app side, e.g. a user can still point & select text while the app underneath keeps working as before.

These are just some early thoughts from my side on this, most likely I've overlooked edge cases, where it will show benefits, or would make mouse interaction with the terminal alot easier. Glad to hear about those.

@christianparpart
Copy link
Author

@jerch after our little private conversation I have now updated the draft spec accordingly. The Semantics section should precisely define your concern with respect to scrollback lines and when the user has changed to viewport to see parts or all of it.

The mouse wheel operations are no problem, because either the user should then configure the terminal to not use the wheel or the app to not use the weel but other keys.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment