I'm trying to get a curses program working with my terminal spanning my monitor. However, the x coordinate can't move past the 223rd column, instead it loops around. In the source, this seems to be due to them being defined as 8-bits, and having the position values start only after the first 32 values (i.e. x = raw_x - ' ').
Here's an example program from https://gist.github.com/sylt/93d3f7b77e7f3a881603 that demonstrates the issue when compiled with libncurses5. In it, if your cursor moves more than 233 columns to the right of the window, the x value will loop back over to 0 - ' ', i.e. -32
#include <curses.h>
#include <stdio.h>
int main()
{
initscr();
cbreak();
noecho();
// Enables keypad mode. This makes (at least for me) mouse events getting
// reported as KEY_MOUSE, instead as of random letters.
keypad(stdscr, TRUE);
// Don't mask any mouse events
mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL);
printf("\033[?1003h\n"); // Makes the terminal report mouse movement events
for (;;) {
int c = wgetch(stdscr);
// Exit the program on new line fed
if (c == '\n')
break;
char buffer[512];
size_t max_size = sizeof(buffer);
if (c == ERR) {
snprintf(buffer, max_size, "Nothing happened.");
}
else if (c == KEY_MOUSE) {
MEVENT event;
if (getmouse(&event) == OK) {
snprintf(buffer, max_size, "Mouse at row=%d, column=%d bstate=0x%08lx",
event.y, event.x, event.bstate);
}
else {
snprintf(buffer, max_size, "Got bad mouse event.");
}
}
else {
snprintf(buffer, max_size, "Pressed key %d (%s)", c, keyname(c));
}
move(0, 0);
insertln();
addstr(buffer);
clrtoeol();
move(0, 0);
}
printf("\033[?1003l\n"); // Disable mouse movement events, as l = low
endwin();
return 0;
}
for the curious, you can build this with gcc file.c -lcurses
How do I workaround this? I can use vim in full-screen mode mode, and tmux mouse interactions also work. These both depend on ncurses, so it must be fixed somehow. I tried reading their source for hours and attempting samples of what I thought would work. I've also tried several printf() terminal modes, but none seem to enable this mode. How can I get my mouse event to hold more than 8 bits, and thus let the columns field hold values larger than 232?
That's a terminal-dependent feature (not an ncurses limitation as such). The original xterm protocol dating from the late 1980s encodes each ordinate in a byte, reserving the first 32 for control characters. That gives 256 - 32 = 223.
xterm introduced an experimental feature in 2010 to extend the range. There is an ncurses terminal description "xterm-1005" which uses that. Some criticized that, and xterm introduced an different feature in 2012. Again, there is a "xterm-1006" using that feature.
The descriptions in ncurses were added in 2014. ncurses 6 was released in 2015, and still supports (by compile-time options) the ABI 5 for ncurses 5. If your "ncurses5" is at least as new as the changes in 2014, the library supports SGR 1006 without change.
The reason for not making one of those part of the default "xterm" is that portability across the various xterm imitators is poor (as is their documentation), and that would only increase bug reports. But if you happen to be using one of the terminals (such as xterm...) which support the SGR 1006 feature, that's supported in the ncurses library.