Is it possible (or how) to create a mechanism (in Linux X11, C++) that works like a global hook in windows (SetWindowsHookEx())?
I would like to be able to catch the key event but with the possibility of further propagation. I'm trying to use a XGrabKey solution (like in xbindkeys) but when I set capturing the key event, this event is "consumed".
Requirements for this mechanism are the following:
- Global / system-wide - catching events regardless of the window that has focus
- The possibility of "catch-hold" and "catch-pass through"
- It must be quite fast
Sample code looks like this:
bool myFlagIsSet = false;
XEvent event;
while (true) {
while (XPending(display) > 0) {
usleep(SLEEP_TIME);
}
XNextEvent(display, &event);
switch (e.type) {
case KeyPress:
if (myFlagIsSet) {
//do not propagate
}
// propagate
break;
case KeyRelease:
if (myFlagIsSet) {
//do not propagate
}
// propagate
break;
}
}
On Windows I simply wrote:
if(event.isConsumed()) {
return LRESULT(1);
}
//...
return CallNextHookEx(hookHandle, nCode, wParam, lParam);
I've also tried using XUngrabKey and XSendEvent:
switch (event.type) {
case KeyPress:
if (myFlagIsSet) {
//do not propagate
}
// propagate
XUngrabKey(...);
XSendEvent(..., &event);
XGrabKey(...);
break;
case KeyRelease:
...
}
Unfortunately XSendEvent for unknown reasons to me - do not send this event even if XGrabKey line is commented.
Is it possible to successfully complete this approach?
Please suggest some other approach if I am condemned to failure
EDIT
I would like to implement this on Ubuntu Gnome using Compiz Window Manager
no idea if this helps, but I just found this in some code:
Use XTestFakeKeyEvent() from the XTest extension library to propagate fake key press / release events.
XSendEvent()
probably does send it; but as it's widely regarded as a security hole, most programs ignore UI events with thesend_event
flag set.The standard X11 protocol doesn't allow this. The XInput 2.0 extension might, but I doubt it; while Windows assumes a single event queue that every program listens to, so that a program can intercept an event and prevent it from being sent down the queue to other listeners, every X11 client has its own independent queue and all clients that register interest in an event receive an independent copy of it in their queue. This means that under normal circumstances it's impossible for an errant program to block other programs from running; but it also means that, for those times when a client must block other clients, it must do a server grab to prevent the server from processing events for any other client.
Try compile easy code from this page:
http://webhamster.ru/site/page/index/articles/comp/367
It's sample of get global keyboard event. This small app working as xinput.
Remark 1: Write device ID to mian.cpp (get ID by running xinput without parameters):
Remark 2: Compile command:
Remakr 3: Before compile, install libxi-dev package:
File main.h
File main.cpp
Instead of doing this on the X11 level I recommend to do it on the input device level.
/dev/input/event<n>
give you the input events. You can read off the keypresses there and decide if they should propagate further or be consumed. Unfortunately there's no real documentation for this, but the header filelinux/include/input.h
is quite self explanatory. Also the evdev maintainer will gladly answer emails.