Linux X11 - Global Keyboard Hook

Viewed 16355

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:

  1. Global / system-wide - catching events regardless of the window that has focus
  2. The possibility of "catch-hold" and "catch-pass through"
  3. 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

5 Answers

no idea if this helps, but I just found this in some code:



    void XFakeKeypress(Display *display, int keysym)
    { 
       XKeyEvent event;                     
       Window current_focus_window;         
       int current_focus_revert;

       XGetInputFocus(/* display = */ display, /* focus_return = */ 
          ¤t_focus_window, /* revert_to_return = */ ¤t_focus_revert);

       event.type = /* (const) */ KeyPress;
       event.display = display;
       event.window = current_focus_window;
       event.root = DefaultRootWindow(/* display = */ display);
       event.subwindow = /* (const) */ None;
       event.time = 1000 * time(/* tloc = */ NULL);
       event.x = 0;
       event.y = 0;
       event.x_root = 0;
       event.y_root = 0;
       event.state = /* (const) */ ShiftMask;   
       event.keycode = XKeysymToKeycode(/* display = */ display, 
          /* keysym = */ keysym);
       event.same_screen = /* (const) */ True;  

       XSendEvent(/* display = */ display, /* w = (const) */ InputFocus,
          /* propagate = (const) */ True, /* event_mask = (const) */ 
          KeyPressMask, /* event_send = */ (XEvent *)(&event));

       event.type = /* (const) */ KeyRelease;   
       event.time = 1000 * time(/* tloc = */ NULL);

       XSendEvent(/* display = */ display, /* w = (const) */ InputFocus,
          /* propagate = (const) */ True, /* event_mask = (const) */ 
          KeyReleaseMask, /* event_send = */ (XEvent *)(&event));
    }

Related