简体   繁体   English

如何使鼠标支持适用于 OSX 上的 ncurses?

[英]How can I make mouse support work for ncurses on OSX?

I have currently compiled and run the example from this tutorial on OSX, and found that it does not work to capture the mouse event.我目前已在 OSX 上编译并运行本教程中的示例,发现捕获鼠标事件不起作用。

I modified it slightly to make it easier to debug.我稍微修改了一下,使它更容易调试。 It looks like wgetch is never returning KEY_MOUSE and instead is just returning some arbitrary character when I click.看起来 wgetch 永远不会返回KEY_MOUSE ,而是在我单击时返回一些任意字符。 I'm also fairly sure it is not a terminal setting issue because Vim has no problem capturing mouse clicks in the exact same terminal.我也相当确定这不是终端设置问题,因为 Vim 在完全相同的终端中捕获鼠标点击没有问题。

I suspect the example is simply out of date.我怀疑这个例子已经过时了。

Does anyone know the modern way to use ncurses to capture the mouse?有谁知道使用 ncurses 捕获鼠标的现代方法?

Below is my modified version of the code, for context.下面是我修改后的代码版本,用于上下文。

Also, I compiled with g++ -std=c++17 -o curses_play curses_play.cc -lncurses .另外,我用g++ -std=c++17 -o curses_play curses_play.cc -lncurses

#include <ncurses.h>
#include <string.h>
#include <stdio.h>

#define WIDTH 30
#define HEIGHT 10

int startx = 0;
int starty = 0;

char *choices[] = {   "Choice 1",
  "Choice 2",
  "Choice 3",
  "Choice 4",
  "Exit",
};

int n_choices = sizeof(choices) / sizeof(char *);

void print_menu(WINDOW *menu_win, int highlight);
void report_choice(int mouse_x, int mouse_y, int *p_choice);

int main()
{ int c, choice = 0;
  WINDOW *menu_win;
  MEVENT event;

  /* Initialize curses */
  initscr();
  clear();
  noecho();
  cbreak(); //Line buffering disabled. pass on everything

  /* Try to put the window in the middle of screen */
  startx = (80 - WIDTH) / 2;
  starty = (24 - HEIGHT) / 2;

  attron(A_REVERSE);
  mvprintw(23, 1, "Click on Exit to quit (Works best in a virtual console)");
  refresh();
  attroff(A_REVERSE);

  /* Print the menu for the first time */
  menu_win = newwin(HEIGHT, WIDTH, starty, startx);
  print_menu(menu_win, 1);
  /* Get all the mouse events */
  mousemask(ALL_MOUSE_EVENTS  | REPORT_MOUSE_POSITION, NULL);

  while(1)
  { c = wgetch(menu_win);
    switch(c)
    { case KEY_MOUSE:
      mvprintw(24, 0, "Found mouse!");
      if(getmouse(&event) == OK)
      { /* When the user clicks left mouse button */
        if(event.bstate & BUTTON1_PRESSED)
        { report_choice(event.x + 1, event.y + 1, &choice);
          if(choice == -1) //Exit chosen
            goto end;
          mvprintw(22, 1, "Choice made is : %d String Chosen is \"%10s\"", choice, choices[choice - 1]);
          refresh();
        }
      }
      print_menu(menu_win, choice);
      break;
      default:
      mvprintw(24, 0, "Charcter pressed is = %3d Hopefully it can be printed as '%c'", c, c);
      refresh();
      break;
    }
  }
end:
  endwin();
  return 0;
}


void print_menu(WINDOW *menu_win, int highlight)
{
  int x, y, i;

  x = 2;
  y = 2;
  box(menu_win, 0, 0);
  for(i = 0; i < n_choices; ++i)
  { if(highlight == i + 1)
    { wattron(menu_win, A_REVERSE);
      mvwprintw(menu_win, y, x, "%s", choices[i]);
      wattroff(menu_win, A_REVERSE);
    }
    else
      mvwprintw(menu_win, y, x, "%s", choices[i]);
    ++y;
  }
  wrefresh(menu_win);
}

/* Report the choice according to mouse position */
void report_choice(int mouse_x, int mouse_y, int *p_choice)
{ int i,j, choice;

  i = startx + 2;
  j = starty + 3;

  for(choice = 0; choice < n_choices; ++choice)
    if(mouse_y == j + choice && mouse_x >= i && mouse_x <= i + strlen(choices[choice]))
    { if(choice == n_choices - 1)
      *p_choice = -1;
      else
        *p_choice = choice + 1;
      break;
    }
}

I got it working, I'm not sure which particular tweak was the important tweak (there's about a dozen-or-so things I changed).我让它工作了,我不确定哪个特定的调整是重要的调整(我改变了大约十几个东西)。 and I also have a bunch of instrumentation which I did not strip out我也有一堆我没有去掉的仪器

Hopefully this is sufficient to get you going.希望这足以让你继续前进。

/*
brew install ncurses
clang++ -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded -Wno-c99-compat -Wno-poison-system-directories -pedantic -fsanitize=undefined,null -std=c++17 -cxx-isystem /usr/local/include -o Merlin2011 Merlin2011.cpp -lncurses
./Merlin2011
*/
#include <ncurses.h>
#include <clocale>
#include <cstring>

#define WIDTH 30
#define HEIGHT 10

static int startx = 0;
static int starty = 0;

static char const* choices[] = {
    "Choice 1", "Choice 2", "Choice 3", "Choice 4", "Exit",
};

static int n_choices = sizeof(choices) / sizeof(char*);

static void print_menu(WINDOW* menu_win, int highlight);
static void report_choice(int mouse_x, int mouse_y, int* p_choice);

static
char sane(int c) {
    if (c > ' ' && c <= '~')
        return static_cast<char>(c);
    return ' ';
}

int main() {
    int choice = 0;
    WINDOW* menu_win;

    setlocale(LC_ALL, "");

    /* Initialize curses */
    initscr();
    clear();
    noecho();
    cbreak();  // Line buffering disabled. pass on everything
    keypad(stdscr, TRUE);
    halfdelay(1);

    /* Try to put the window in the middle of screen */
    startx = (80 - WIDTH) / 2;
    starty = (24 - HEIGHT) / 2;

    attron(A_REVERSE);
    mvprintw(23, 1, "Click on Exit to quit (Works best in a virtual console)");
    refresh();
    attroff(A_REVERSE);

    /* Print the menu for the first time */
    menu_win = newwin(HEIGHT, WIDTH, starty, startx);
    scrollok(menu_win, TRUE);
    keypad(menu_win, TRUE);
    print_menu(menu_win, 1);
    /* Get all the mouse events */
    //auto mm_success = mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, nullptr);
    /* Get just just the click event. */
    mmask_t mousemask_setting = NCURSES_BUTTON_CLICKED;
    auto mm_success = mousemask(mousemask_setting, nullptr);

    if (!mm_success) {
        mvprintw(22, 1, "FAIL: mousemask");
    } else if (mm_success == mousemask_setting) {
        mvprintw(22, 1, "SUCCESS: mousemask");
    } else {
        mvprintw(22, 1, "Partial success: mousemask %x of %x", mm_success, mousemask_setting);
    }
    refresh();

    bool loop{ true };

    while (loop) {
        auto c = wgetch(menu_win);

        switch (c) {
            case KEY_MOUSE: {
                MEVENT event;
                mvprintw(20, 1, "Found mouse!");
                if (getmouse(&event) == OK) { /* When the user clicks left mouse button */
                    mvprintw(20, 1, "Found mouse! %3d %3d %d", event.x, event.y, event.bstate);
                    //if (event.bstate & BUTTON1_PRESSED) { ... }
                    if (event.bstate & NCURSES_BUTTON_CLICKED) {
                        mvprintw(20, 1, "Found mouse! %3d %3d MOUSE_CLICK", event.x, event.y);
                        report_choice(event.x + 1, event.y + 1, &choice);
                        if (choice == -1) { // Exit chosen
                            loop = false;
                            break;
                        }
                        mvprintw(22, 1, "Choice made is : %d String Chosen is \"%10s\"", choice, choices[choice - 1]);
                        refresh();
                    }
                }
                print_menu(menu_win, choice);
            } break;

            case ERR: {
                static int count = 0;
                ++count;
                mvprintw(21, 0, "Nothing happened (%d).", count);
                refresh();
            } break;

            default: {
                static int i = 0;
                mvprintw(24+i, 0, "Key pressed is = %3d '%c'", c, sane(c));
                if (++i == 30)
                    i = 0;
                mvprintw(24+i, 0, "-------------------------");
                refresh();
                if (c == 'q')
                    loop = false;
            } break;
        }
    }

    endwin();
}

void print_menu(WINDOW* menu_win, int highlight) {
    int x, y, i;

    x = 2;
    y = 2;
    box(menu_win, 0, 0);
    for (i = 0; i < n_choices; ++i) {
        if (highlight == i + 1) {
            wattron(menu_win, A_REVERSE);
            mvwprintw(menu_win, y, x, "%s", choices[i]);
            wattroff(menu_win, A_REVERSE);
        } else
            mvwprintw(menu_win, y, x, "%s", choices[i]);
        ++y;
    }
    wrefresh(menu_win);
}

/* Report the choice according to mouse position */
void report_choice(int mouse_x, int mouse_y, int* p_choice) {
    int i, j, choice;

    i = startx + 2;
    j = starty + 3;

    for (choice = 0; choice < n_choices; ++choice)
        if (mouse_y == j + choice && mouse_x >= i && mouse_x <= i + strlen(choices[choice])) {
            if (choice == n_choices - 1)
                *p_choice = -1;
            else
                *p_choice = choice + 1;
            break;
        }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM