c - 按住另一个按钮时,XGrabButton 不会捕获点击

标签 c xlib

我有一些代码使用 XGrabButton 来捕获鼠标点击。我希望它始终捕获对指定按钮的所有点击,而不考虑任何其他问题。它目前使用以下调用:

XSelectInput(display, window, ButtonPressMask);
XGrabButton(display, Button2, AnyModifier, window, True,
    ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
XGrabButton(display, Button3, AnyModifier, window, True,
    ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
XGrabButton(display, Button4, AnyModifier, window, True,
    ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);

但是,按住按钮 1(鼠标左键,我的代码未捕获)会导致无法捕获其他按钮上的点击。我该如何防止这种情况发生?

编辑澄清:

  • 我想始终捕获按钮 2-4,而永远不要捕获按钮 1。
  • 上面的调用可以正常捕获按钮 2-4。
  • 捕获按钮 1(左键单击)。
  • 当按钮 1 被按住时,它不会捕获按钮 2-4。

如何让它在按住按钮 1 时捕获按钮 2-4?

最佳答案

如果代码如您所说,希望有更多内容:

"However, pressing and holding button 1 (the left mouse button, which is not captured by my code) causes clicks on the other buttons to not be captured."

行:

XSelectInput(display, window, ButtonPressMask);

将导致所有按钮被捕获。额外的 XGrabButton 调用是(多余的?),因为您没有指定任何不同于默认参数的参数。

但是;如果它实际上是你所说的,即使使用该代码 Button1 也没有被捕获,或者你有一些其他代码,即 XSelectInput 没有被调用 - 我会接受以此为基础。


事件分发

每个窗口都有一个事件队列。当一个事件在窗口中生成时,它被发送到该窗口。但是,如果窗口选择了它或始终选择它,则该窗口只会接收事件。 或者作为 Xlib 例程的副作用。只有当它收到事件时,它才会被放入队列中。

如果我们使用 XSelectInput() 并选择大多数掩码,/usr/include/X11/X.h EVENT DEFINITIONS,并使用 XNextEvent() 看看我们通常会看到这样的东西:

 ...
 19: Event EnterNotify     # Window Entry/Exit Events
 20: Event KeymapNotify    # X send after every EnterNotify and FocusIn event
 21: Event MotionNotify    # Keyboard and Pointer Events
 22: Event ButtonPress   2 # Button 2 down
 23: Event ButtonRelease 2 # Button 2 up
 24: Event ButtonPress   1 # Button 1 down
 25: Event ButtonPress   2 # Button 1 and 2 down
 ...

如果我们从 XSelectInput 中删除 ButtonPressMaskButtonReleaseMask 并使用 XGrabButton() 为除 1 之外的每个按钮抓取事件并再次运行程序事件映射趋势:

 22: Event LeaveNotify       # Button 1 pressed causes "blurring" of window.
 23: Event EnterNotify       # Button 1 released
 24: Event KeymapNotify
 25: Event ButtonPress   3   # Button 3 down
 26: Event ButtonPress   1   # Button 3 + 1 down; 1 registers as Press 
                             #                    even if not tracked.
 27: Event ButtonRelease 3   # Button 3 up
 28: Event MotionNotify
 29: Event ButtonRelease 1   # Button 1 up
 30: Event LeaveNotify       # Button 1 pressed, 1+2 pressed, 1+2+3 …
 31: Event EnterNotify       # Button 1 released, 2 released, …
 32: Event KeymapNotify
 33: Event ButtonPress   2
 34: Event ButtonPress   3
 35: Event ButtonPress   1
 36: Event ButtonRelease 2
 37: Event ButtonRelease 3

我们观察到按钮事件,当按下多个时,继承第一个状态。您还可以使用 ltracestracexev 等查看此内容。即xev 注册内部捕获的按钮。如前面提到的;事件发送到窗口,但只有注册的接收。这是一些副作用的异常(exception),例如在以下情况下可以看到:

  • 第一个 按下的按钮设置为捕获;然后是的 - 不是的也将在事件列表中排队。
  • 第一个 按下的按钮设置为捕获;然后一个 - 然后两者都不排队。

按下未设置为在 LeaveNotify 中捕获结果的按钮,(左侧窗口)- 并行事件被阻止。


如何解决

这里有很多事情要考虑。一切都取决于代码项目等其他部分的逻辑。但是有一些基础知识。最简单的是捕获所有按钮并标记和跟踪; XNextEvent .

static const char *event_names[] = {
    "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
    "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
    "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
    "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
    "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
    "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
    "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
    "ClientMessage", "MappingNotify"
};

/* ... */

Display *dpy;
XEvent  ev;
int k = 0;

/* ... */

for (;;) {
    XNextEvent(dpy, &ev);
    if ((ev.type == ButtonPress || ev.type == ButtonRelease) &&
                            ev.xbutton.button == Button1) {
        fprintf(stderr,
                "%04d: BLOCK!     %-18s %d\n",
                k++, event_names[ev.type],
                ev.xbutton.button);
        continue;
    }
    fprintf(stderr, "%04d: PASS! Work %-18s", k++, event_names[ev.type]);
    switch (ev.type) {
        case ButtonPress:
        case ButtonRelease:
            fprintf(stderr, " %d", ev.xbutton.button);
            break;
    }
    putchar('\n');
}

结果是这样的:

0005: PASS! Work FocusIn           
0006: BLOCK!     ButtonPress        1
0007: BLOCK!     ButtonRelease      1
0008: BLOCK!     ButtonPress        1
0009: BLOCK!     ButtonRelease      1
0010: BLOCK!     ButtonPress        1
0011: PASS! Work ButtonPress        3 # Button 1 is also down
0012: PASS! Work ButtonRelease      3
0013: BLOCK!     ButtonRelease      1
0014: PASS! Work ButtonPress        3
0015: PASS! Work ButtonRelease      3
0016: BLOCK!     ButtonPress        1
0017: PASS! Work ButtonPress        3
0018: PASS! Work ButtonRelease      3
0019: BLOCK!     ButtonRelease      1
0020: PASS! Work ButtonPress        2
0021: PASS! Work ButtonPress        3
0022: BLOCK!     ButtonPress        1
0023: BLOCK!     ButtonRelease      1
0024: PASS! Work ButtonRelease      2
0025: PASS! Work ButtonRelease      3
0026: BLOCK!     ButtonPress        1
0027: PASS! Work ButtonPress        3
0028: PASS! Work ButtonRelease      3
0029: PASS! Work ButtonPress        2
0030: PASS! Work ButtonRelease      2
0031: BLOCK!     ButtonRelease      1
0032: PASS! Work FocusOut          

另一种方法是使用 XIfEvent , XCheckIfEvent() 等。这一切都取决于结构。要记住/检查的一件事是一些功能;即 XIfEvent not 如果事件 不匹配,则从队列中移除该事件!因此,如果您实现一个返回 Falsepredicate 函数,如果事件是 Button1Press - 该事件将保留在队列中。

关于c - 按住另一个按钮时,XGrabButton 不会捕获点击,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9977945/

相关文章:

c - 在 CBMC 中表达 “exactly once” 的更好方法

c++ - Xlib 这个(去掉窗饰)是怎么工作的?

python - 捕获键盘不允许改变焦点

php - 在 PHP7 扩展中创建循环对象时发生内存泄漏

c - 获取窗口的输入元素

c++ - 没有标题栏的简单窗口

c - 增加结构成员

c - 将 X.509 证书存储在 C 字符串中并将其加载到 SSL_CTX 对象中?

c - 使用 .call() 从 R 和 C 传递数据帧