使用ncurses在控制台应用程序中捕获鼠标点击

14
我正在为Unix平台制作一个控制台应用程序,我在使用curses(或ncurses)库来处理键盘和鼠标输入。问题在于,除了这个页面这个页面之外,我几乎找不到有关如何使用它的文档,并且这些页面没有非常详细的示例。 我已经成功捕获了左键点击事件,但我无法使右键点击事件生效,因为终端模拟器的选项菜单出现在光标位置,但该事件未由应用程序处理。我该如何避免这种情况并让应用程序捕获该事件?
以下是我用于配置鼠标事件的代码行:
// Set up mouse event throwing
mousemask(BUTTON1_PRESSED | BUTTON2_PRESSED, NULL);

在处理输入的方法中,我有以下内容:

int c = getch();
MEVENT event;
switch(c)
{
    case KEY_UP:
        ... do stuff
        break;
    case KEY_DOWN:
        ... do stuff
        break;
    case KEY_MOUSE:
        if(getmouse(&event) == OK)
        {
            if(event.bstate & BUTTON1_PRESSED) // This works for left-click
            {
                ... do stuff
            }
            else if(event.bstate & BUTTON2_PRESSED) // This doesn't capture right-click
            {
                ... do other stuff
            }
            else
                fprintf(stderr, "Event: %i", event.bstate); // Doesn't print anything on right-click
        }
        break;
    default:
        return;
}

我还尝试使用ALL_MOUSE_EVENTS掩码配置mousemask(),但在最后的else子句中仍然没有打印任何事件,所以我认为事件根本没有触发。非常感谢您的任何帮助。


看起来你的终端仿真器没有将右键事件传递到终端窗口。大多数仿真器都有选项,可以禁用输入设备的特殊处理,并直接将事件传递到终端。 - Hristo Iliev
嗯,我已经尝试在多个终端上运行它:Ubuntu 11.10的默认终端,Guake,NetBeans IDE的内部终端,但它们都不起作用。你知道我该如何配置其中一个终端以将事件传递给应用程序吗? - Pedro Cori
5
类似的问题在http://askubuntu.com/questions/21330/how-to-disable-right-click-menu-in-terminal上有部分答案,即使用xterm。请参考。 - ctrl-alt-delor
1
太好了!它在Xterm上运行。可用的事件是BUTTON0_CLICKED表示左键单击和BUTTON3_CLICKED表示右键单击。 - Pedro Cori
实际上,如果你有开发库(无需引用1990年代晚期的ncurses手册页面副本),手册页已经在你的计算机上了。 - Thomas Dickey
对我来说,BUTTON1_*BUTTON2_*BUTTON3_*BUTTON4_*BUTTON5_*分别与左键中键右键、向上滚动和向下滚动有关。在Ubuntu 20.04.1 LTS中没有BUTTON0_*BUTTON6_* - schneiderfelipe
4个回答

23

如果有其他人在这里尝试解决为什么使用Ncurses无法捕获鼠标事件的问题,那么很可能您需要这行代码:

keypad(window, TRUE);      

如果没有这个,getch() 不会触发任何鼠标事件。

我在所有的教程/示例中都没有找到这个,所以我花费了很多时间才弄清楚我的代码出了什么问题——也许这个答案可以帮助其他人比我更快地找到解决方案。


这似乎解决了我在Debian/terminator环境中的问题。没有它,似乎没有事件会触发。我认为这个答案应该被标记为正确的。 - Andrei Bârsan
这也可以在OS X上解决。 - AdUki

3

正确的鼠标右键是按钮3,而不是按钮2。按钮2是中间的那个。


是的,我注意到了,但事件仍然没有传递到应用程序。我在问题的最后一条评论中放置了正确的按钮事件。 - Pedro Cori

2
原问题是关于终端仿真器(以及菜单激活干扰将鼠标点击传递给应用程序)。这可能可以通过一些特定于终端的文档(甚至一些教程)来解决。其他答案忽略了这一点,而是集中在ncurses应用程序接收(并理解)xterm协议鼠标事件方面的问题。
后者的问题在手册页面中有记录。
在关闭 Keypad 模式的窗口中,鼠标事件在xterm下将不能正确检测,因为它们被解释为各种功能键。您的 terminfo 描述应该设置 kmous"\E[M" (鼠标单击的 xterm 响应开始部分)。其他值的kmous也是允许的,但是在相同的假设下,即它是响应的开头。这不是新问题,在1995年就已经提到过。
在关闭了键盘位的窗口中,xterm下的鼠标事件将无法被正确检测到。

0

我正在使用你的代码,但是没有任何反应。甚至左键也不起作用。

这是你的完整代码吗?

#include <ncurses.h> 

int main(int argc, char **argv){ 

while(1) 
{ 

    mousemask( ALL_MOUSE_EVENTS, NULL); 
        int c = getch(); 
        MEVENT event; 
        switch(c) 
        { 
            case KEY_UP: 
                printf("keyup"); 
                break; 
            case KEY_DOWN: 
                printf("keydown"); 
                break; 
            case KEY_MOUSE: 
                if(getmouse(&event) == OK) 
                { 
                    if(event.bstate & BUTTON1_PRESSED) // This works for left-click 
                    { 
                        printf("button1"); 
                    } 
                    else if(event.bstate & BUTTON2_PRESSED) // This doesn't capture right-click 
                    { 
                        printf("button2"); 
                    } 
                    else 
                        printf("Event: %i", event.bstate); // Doesn't print anything on right-click 
                } 
                break; 
        } 
} 
return 0; 
}

1
你看到问题上的最后一条评论了吗?你正在使用Xterm和事件BUTTON0_CLICKEDBUTTON3_CLICKED来处理左右按钮吗?对我来说,按下的那些没有起作用。 - Pedro Cori
问题在于我没有终端窗口。我使用无头Ubuntu,没有任何窗口管理... - user1455085
我猜你就不会有上下文菜单的问题了(在无头模式下没有)。它应该可以使用默认的 shell,虽然我不能保证。你试过用修正后的代码吗?你确定鼠标驱动程序正在运行吗(也许你的无头启动默认不加载它,因为通常不需要)? - Pedro Cori

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接