I'm attempting to capture all keyboard input based on the code from this answer. The actual key capturing is working fine. However, running the code on Linux Mint Cinnamon causes other issues:

  1. I'm unable to drag or resize any windows using the mouse
  2. Clicking on the options in the menu bar in xed and nemo (file, view, etc...) doesn't bring up the submenu options
  3. Clicking on the start menu brings up the list of applications but focus is retained by the window behind it so I can't hover, scroll or click on items from the application list.

A simplified but functional version of the code follows. I have narrowed down the cause to the presence of StructureNotifyMask event mask in XSelectInput. Without that event mask, none of above issues are present. But this also means the program isn't notified when the window is mapped and thus the capturing doesn't work.

How can I get capturing to work without any of the above issues? I've tried including a second XSelectInput after the program is notified of the mapping that only has the key press and release event masks. However, that does not seem to resolve the issue.

#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <stdio.h>

int main()
    Display *display;
    Window   window, rootwindow;
    XEvent   event;
    KeySym   escape;

    display = XOpenDisplay(NULL);
    rootwindow = DefaultRootWindow(display);
    window = XCreateWindow(display, rootwindow,
                           -99, -99, 1, 1, /* x, y, width, height */
                           0, 0, InputOnly, /* border, depth, class */
                           CopyFromParent, /* visual */
                           0, NULL); /* valuemask and attributes */

    XSelectInput(display, window, StructureNotifyMask | KeyPressMask | KeyReleaseMask);    

    XMapWindow(display, window);

    do {
        XNextEvent(display, &event);
    } while (event.type != MapNotify);

    XGrabKeyboard(display, window, False, GrabModeAsync, GrabModeAsync, CurrentTime);

    escape = XKeysymToKeycode(display, XK_Escape);
    printf("\nPress ESC to exit.\n\n");

    while (1) {

        XNextEvent(display, &event);

        if (event.type == KeyPress) {
            printf("KeyPress: keycode %u state %u\n", event.xkey.keycode, event.xkey.state);

        } else
        if (event.type == KeyRelease) {

            printf("KeyRelease: keycode %u state %u\n", event.xkey.keycode, event.xkey.state);

            if (event.xkey.keycode == escape)
        } else {

            printf("Event type %d\n", event.type);

    XUngrabKeyboard(display, CurrentTime);

    XDestroyWindow(display, window);
    return 0;
  • Note, there is a specific extension for recording events without interfering with the server.
    – meuh
    Commented Nov 2, 2017 at 19:45

1 Answer 1


You can't do a permanent XGrabKeyboard. This grab is only meant to be used temporarily, as long as some kind of interaction is ongoing.

If you keep holding the grab, all other functions that need a grab themselves (like the WM operations you mention) are not going to work.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .