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.
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. 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.
I suspect the example is simply out of date.
Does anyone know the modern way to use ncurses to capture the mouse?
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
.
#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 \"s\"", choice, choices[choice - 1]);
refresh();
}
}
print_menu(menu_win, choice);
break;
default:
mvprintw(24, 0, "Charcter pressed is = = 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;
}
}
CodePudding user response:
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! = = %d", event.x, event.y, event.bstate);
//if (event.bstate & BUTTON1_PRESSED) { ... }
if (event.bstate & NCURSES_BUTTON_CLICKED) {
mvprintw(20, 1, "Found mouse! = = 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 \"s\"", 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 = = '%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;
}
}