我有一些代码使用 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
中删除 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
我们观察到按钮事件,当按下多个时,继承第一个状态。您还可以使用 ltrace
、strace
、xev
等查看此内容。即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 如果事件 不匹配,则从队列中移除该事件!因此,如果您实现一个返回 False
的 predicate
函数,如果事件是 Button1Press - 该事件将保留在队列中。
关于c - 按住另一个按钮时,XGrabButton 不会捕获点击,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9977945/