当按下另一个按钮时,XGrabButton不会捕获点击次数

时间:2012-04-02 14:04:59

标签: 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。
  • NOT 捕获按钮1(左键单击)。
  • 按住按钮1时,捕获按钮2-4。

按住按钮1时,如何捕捉按钮2-4?

2 个答案:

答案 0 :(得分:0)

不确定这是否有效,但您可以强制不要通过以下方式获取代码中的button1:

XUngrabButton(display, Button1, AnyModifier, window);

答案 1 :(得分:0)

希望代码有更多内容,如果它按照您的说法行事:

  

但是,按住按钮1(鼠标左键,未被我的代码捕获)会导致其他按钮无法捕获。

该行:

XSelectInput(display, window, ButtonPressMask);

将导致捕获所有按钮。其他XGrabButton调用是(冗余?),因为您没有指定任何与默认参数不同的参数。

然而;如果它实际上就是你说的那样,即使代码Button1没有被捕获,或者你有一些其他代码,即XSelectInput未被调用 - 我将把它作为基础开始


事件分发

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

如果我们使用XSelectInput()并选择大多数掩码, / usr / include / X11 / Xh 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删除 ButtonPressMask ButtonReleaseMask 并使用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 注册内部捕获的按钮。如前面提到的;事件已发送到窗口,但只有已注册已收到。除了一些副作用之外,例如可以看到:

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

按下一个未设置为捕获的按钮会导致 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          

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