Search code examples
cx11keypressxlib

Why can't I capture these KeyPress / KeyRelease events from inside my loop?


I want to record all incoming keypress events, no matter which window is in focus or where the pointer is. I have written sample code which should capture the key pressed events of the current window in focus (see below). To keep my code readable, I have given the sample code only for the window in focus. As my final aim is to capture key press events on the screen irrespective of the Window in focus, I plan to use XQueryTree to get all the Windows and apply the same logic.

I am calling XGrabKeyboard to capture the keyboard, as the window in focus might already be grabbing the keyboard events. With my sample code, I am able to grab the keyboard, but cannot receive KeyPress or KeyRelease events for any keyboard keys inside the while loop.

What am I missing in the code to allow me to receive the events?

Sample Code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <locale.h>
#include <stdint.h>
#include <stdarg.h>
#include <errno.h>
#include <pthread.h>
#include <X11/Xlib.h>
#include <X11/Xos.h>
#include <X11/Xfuncs.h>
#include <X11/Xutil.h>

#include <X11/Xatom.h>
int _invalid_window_handler(Display *dsp, XErrorEvent *err) {
    return 0;
}

int main() 
{
    Display *display = XOpenDisplay(NULL); 
    int iError;
    KeySym k;
    int revert_to;
    Window window;
    XEvent event;
    Time time;
    XSetErrorHandler(_invalid_window_handler);
    XGetInputFocus(display, &window, &revert_to);
    XSelectInput(display, window, KeyPressMask | KeyReleaseMask );
    iError = XGrabKeyboard(display, window,
                          KeyPressMask | KeyReleaseMask,
                          GrabModeAsync,
                          GrabModeAsync,
                          CurrentTime); 
    if (iError != GrabSuccess && iError == AlreadyGrabbed) {
        XUngrabPointer(display, CurrentTime);
        XFlush(display);
        printf("Already Grabbed\n");    
    } else if (iError == GrabSuccess) {
        printf("Grabbed\n");
    }
    while(1) {
          XNextEvent(display,&event);
          switch (event.type) {
              case KeyPress : printf("Key Pressed\n"); break;
              case KeyRelease : printf("Key Released\n"); break;
              case EnterNotify : printf("Enter\n"); break;
          }
    }
    XCloseDisplay(display);
    return 0;
}

Solution

  • Argument 3 of XGrabKeyboard is to quote the man page:

    owner_events : Specifies a Boolean value that indicates whether the keyboard events are to be reported as usual.

    so should be True or False, not an event mask.