如何构建支持超过 223 列鼠标输入的 Curses 程序

How to Build Curses Program That Supports More Than 223 Columns of Mouse Input

我正在尝试让一个 curses 程序在我的终端上跨显示器工作。但是,x 坐标不能移动超过第 223 列,而是循环。在源代码中,这似乎是由于它们被定义为 8 位,并且位置值仅在前 32 个值之后开始(即 x = raw_x - ' ')。

这是来自 https://gist.github.com/sylt/93d3f7b77e7f3a881603 的示例程序,演示了使用 libncurses5 编译时的问题。在其中,如果您的光标移动到 window 右侧超过 233 列,则 x 值将循环回到 0 - ' ',即 -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("3[?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("3[?1003l\n"); // Disable mouse movement events, as l = low

  endwin();

  return 0;
}

出于好奇,您可以使用 gcc file.c -lcurses

构建它

我该如何解决这个问题?我可以在全屏模式下使用 vim,tmux 鼠标交互也可以。这些都依赖于 ncurses,因此必须以某种方式修复它。我花了几个小时尝试阅读他们的来源,并尝试尝试我认为可行的样本。我也尝试了几种 printf() 终端模式,但 none 似乎启用了这种模式。我怎样才能让我的鼠标事件保持超过 8 位,从而让列字段保持大于 232 的值?

这是一个依赖于终端的特性(不是 ncurses 本身的限制)。 1980 年代后期的原始 xterm 协议将每个纵坐标编码为一个字节,为控制字符保留前 32 个。这给出 256 - 32 = 223.

xterm 在 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" 中使用该功能引入了一项实验性功能。

2014 中添加了 ncurses 中的描述。 ncurses 6 于 2015 年发布,并且仍然支持(通过编译时选项)ncurses 5 的 ABI 5。如果您的 "ncurses5" 至少与 2014 年的更改一样新,则该库支持 SGR 1006 而无需更改。

不将这些部分之一作为默认设置的原因 "xterm" 是各种 xterm 模仿器之间的可移植性很差(就像它们的文档一样),这只会增加错误报告。但是,如果您碰巧使用支持 SGR 1006 功能的终端之一(例如 xterm...),则 ncurses 库支持该功能。