I am trying to catch mouse scroll events in the terminal for my text editor. I have a couple questions.

Firstly, how can alternate scroll mode be enabled? Am I interpreting it correctly that when the alternate buffer is specified via \x1b[?1049h then scrolls are sent as <key-up> and <key-down>?

Specifically, I'm unable to understand this:

However if Alternate Scroll mode is set, then cursor up/down controls are sent when the terminal is displaying the Alternate Screen Buffer. The initial state of Alternate Scroll mode is set using the alternateScroll resource.

I am able to catch the scroll actions in the form \x1b[MCbCxCy in the below program, but I am not aware of an Alternate Scroll mode.

My second question is that for the above where are Cx and Cy coming from? It seems completely non-deterministic in my terminal. Here is a sample program you can copy paste to see this:

#include <termios.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>

#define ENABLE_ALT_SCREEN "\x1b[?1049h"
#define DISABLE_ALT_SCREEN "\x1b[?1049l"

#define ENABLE_MOUSE_TRACKING "\x1b[?1000h"
#define DISABLE_MOUSE_TRACKING "\x1b[?1000l"

struct termios orig_termios;

disable_raw_mode (void)
  tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios);

enable_raw_mode (void)
  tcgetattr(STDIN_FILENO, &orig_termios);

  struct termios raw = orig_termios;
  raw.c_iflag &= ~(BRKINT | INPCK | PARMRK | INLCR | IGNCR | ISTRIP | ICRNL | IXON);
  //  raw.c_oflag &= ~(OPOST);
  raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
  raw.c_cflag &= ~(CSIZE | PARENB);
  raw.c_cflag |= (CS8);

  tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw);

main (void)
  char c;
  while ( read(STDIN_FILENO,  &c, 1) == 1 && c != 'q')
      if (iscntrl(c))
        printf("%d\n", c);
        printf("%d ('%c')\n", c, c);

  return 0;

My terminal is xterm-256color.

  • 1
    Cx and Cy are single raw bytes representing the coordinates. Please do not use the legacy "1000" mouse mode without extensions in newly written apps, as sending raw bytes breaks after row or column 223, in fact, breaks the UTF-8-validness of the stream (potentially causing subtle problems here and there) after 95 rows or columns. Please enable the "1006" extension as well (as in "\x1b[?1006h") in addition to enabling the "1000" mouse reporting mode, this way you'll receive the coordinates as decimal numbers.
    – egmont
    Jul 31 at 20:13
  • The weirdness comes from the randomness of the raw bytes @egmont. You can see the program prints them in decimal form. Is there a preferred mouse mode to "1000" that can capture scroll events for my application? Jul 31 at 20:58
  • Again: the "randomness" are the x and y coordinates of the scroll event.
    – egmont
    Aug 1 at 9:16
  • 1
    I don't know what vim or nano do, you should check their source. I cannot comment on the randomness, if the terminal sends random values then mouse support shouldn't work in any of the apps. I don't have access to Terminal.app. Try with other terminals, such as iTerm2, see if the numbers are random there. I've tried with gnome-terminal, clicking on the same position produces the same numbers, as expected.
    – egmont
    Aug 3 at 21:52
  • 1
    The Cx and Cy raw byte values are 32 more than the coordinate, so at column 224 you'd get an overflow, but already at a value of 96 you'd get invalid UTF-8, you'll face serious problems if you have a charset converting layer such as luit. Also, the 223 column limit is reasonably very easy to hit. Just go with the 1006 extension if you want no trouble.
    – egmont
    Aug 3 at 21:52

1 Answer 1


The quote is from the xterm manpage, which refers to private mode 1007:

Ps = 1 0 0 7 ⇒ Enable Alternate Scroll Mode, xterm.
This corresponds to the alternateScroll resource.

For example

printf '\033[?1007h'

Other terminals may/may not support the control sequence (check their documentation).

  • I am not noticing any difference from this. Jul 31 at 21:05
  • With 1049 + 1007, it does not work as documented. Aug 1 at 19:11

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .