c++ - 如何在 OSX 上为 ncurses 提供鼠标支持?

标签 c++ macos ncurses

我目前已编译并运行 this tutorial 中的示例。在OSX上,发现无法捕获鼠标事件。

我稍微修改了它以使其更容易调试。看起来 wgetch 永远不会返回 KEY_MOUSE ,而只是在我单击时返回一些任意字符。我也相当确定这不是终端设置问题,因为 Vim 在同一终端中捕获鼠标点击没有问题。

我怀疑这个例子已经过时了。

有人知道使用 ncurses 捕获鼠标的现代方法吗?

下面是我修改后的代码版本,以供引用。

此外,我还使用 g++ -std=c++17 -ocurses_playcurses_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;
    }
}

最佳答案

我成功了!我不确定哪个特定的调整是重要的调整(我改变了大约十几个东西),而且我还有一堆我没有删除的仪器。

希望这足以让您继续前进。

/*
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;
        }
}

关于c++ - 如何在 OSX 上为 ncurses 提供鼠标支持?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72826242/

相关文章:

c++ - 如果我在管理 C++ 对象内存的 Objective C 中混合 C++ 代码,ARC 会处理它吗?

c++ - 如何在 Visual C++ 中有条件地包含一个不存在的文件?

macos - PS1 env 无法在新 Mac Catalina 上解析

c++ - 无法将 ncurses 表单与窗口相关联

c++ - 如何在数的质因数分解中找到质因数的重数?

c# - 从 C# 调用托管 C++ 时出现编译错误

macos - 组合 GUI 和命令行 OS X 应用程序

ios - 在 MacOS/IOS SDK 上强制 SSLv3 连接

c - Ncurses 鼠标滚轮向上滚动

c - 将 ncurses 窗口保持在前台