I have some code that uses XGrabButton to capture mouse clicks. I want it to always capture all clicks on the specified buttons, regardless of any other concerns. It currently uses the following invocation:
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);
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. How do I prevent this from happening?
Edit for clarification:
- I want to capture buttons 2-4 always, and button 1 never.
- The above invocation captures buttons 2-4 just fine normally.
- It does NOT capture button 1 (left click).
- It will NOT capture buttons 2-4 while button 1 is held down.
How do I make it capture buttons 2-4 while button 1 is held down?
Hope there is more to the code if it acts as you say:
The line:
will cause all buttons to be captured. The additional
XGrabButtoncalls are (redundant?) as you do not specify any parameters that differ from the default ones.However; if it in fact is how you say, that even with that code
Button1is not captured, or you have some other code where i.e.XSelectInputis not called – I’ll take that as base to start with.Event distribution
Every window has a event queue. An event is sent to a window when it is generated in that window. But, the window only receives the event if it has selected it or it is always selected. Or as a side effect to an Xlib routine. Only when it receives the event it is placed in the queue.
If we use
XSelectInput()and select most masks, /usr/include/X11/X.h EVENT DEFINITIONS, and useXNextEvent()to have a look we’ll typically see something like this:If we remove ButtonPressMask and ButtonReleaseMask from
XSelectInputand useXGrabButton()to grab events for every button except1and run the program again the events is mapping a tendency:We observe that the button events, when pressing multiple, inherits status of first. You can also see this with
ltrace,strace,xevetc. I.e. xev registers buttons that are not captured internally. As mentioned earlier; events are sent to the window, but only registered are received. That is with exception of some side effects as one for example can see when:A button press on one that is not set to capture results in LeaveNotify, (window is left) – and parallel events are blocked.
How to solve
There are so many things to take into account here. All depending on the logic of the rest of the code project etc. There are however some basics. The simplest being to capture all buttons and flag and track; XNextEvent.
Resulting in something like:
Another way could be to use XIfEvent,
XCheckIfEvent()etc. It all depends on structure. One thing to remember / check is that some of the functions; i.e.XIfEventdoes not remove the event from queue if it is not a match! So if you implement apredicatefunction that returnFalseif event is i.e. Button1Press – that event will remain in queue.