Terminal Mouse Support

This is a collection of notes about Unix terminal mouse support, collected from various documentation and reverse engineered from GPM’s and libgpm’s source code.

This is mostly interesting for historical purposes. I do not endorse using the technologies and protocols described below.

The Linux GPM daemon makes mouse support available on the Linux console.

I read some of GPM’s source code recently to understand the interaction between GPM, the kernel’s TTY driver and text-mode applications with mouse support. Documentation in that corner is sparse, so here is a writeup of how this works together.

GPM predates libinput

First of all, GPM is old and had to implement custom support for individual devices at the time. These days, the Consolation project is a GPM replacement based on libinput with a smaller and cleaner codebase.

Default mode of operation

Application Unix socket /dev/gpmctl GPM daemon devices drivers libGPM

In the default mode of operation, an appliation links to libgpm. libgpm has functions to enable and disable mouse mode, and a function Gpm_Getc() to replace fgetc(3). What is special about this function is that apart from keyboard input, this function also returns mouse events.

libgpm’s default mode is that clients connect to the GPM daemon through Unix Domain Sockets on /dev/gpmctl, and GPM ships mouse events through that channel. So far so good.

Using libgpm when the terminal is actually an xterm

libgpm also offers an additional mode of operation, which makes the library usable in xterm. (Whether this works in practice, I am not sure about it.) xterm uses a custom protocol for mouse support which is based on terminal escape codes rather than a Unix Domain Socket.

Application stdin stdout xterm TTY libGPM terminal escape sequences

The process is:

  1. Application: libgpm detects that this mode should be used by checking that $TERM starts with “xterm”. (I believe terminfo or termcap would have been a more appropriate mechanism, but this is what it does.)
  2. Application: libgpm enables “mouse reporting” mode by writing the escape sequence \033[?1000h to the TTY.
  3. XTerm: When a mouse button changes status, the xterm TTY device will now write an escape sequence with the current mouse status to the TTY’s input buffer. This takes the form of \033[Mbxy, where b is the button status and x and y are the 1-based mouse coordinates, measured in characters. All three parameters are 1 byte long and the encoded number for each is added to 0x20 (space).

Using GPM with xterm-supporting applications

The converse scenario is also supposed to work: Applications that are built for xterm are supposed to work on the Linux console through GPM’s xterm emulation.

Application stdin stdout Console TTY GPM daemon jiggle devices send mouse events through ioctl drivers

The flow of events is:

  1. Application: Runs on console and enables mouse reporting by writing \033[?1000h to the TTY
  2. User: Jiggles the mouse onto another character or presses a mouse button
  3. GPM: Receives the mouse event and calls ioctl(2) with TIOCLINUX/TIOCL_SETSEL/TIOCL_SELMOUSEREPORT.
  4. Linux kernel driver: Checks that terminal has mouse reporting enabled, then writes the mouse position as an escape sequence to the TTY input buffer. The escape sequence could for instance be \033[M !! for “mouse at top left corner, no buttons pressed”.
  5. Application: Reads from the TTY device and interprets that mouse escape sequence to react accordingly.

References about the Xterm mode

The best descriptions that I could find of this protocol are: