c++x11xlibxinput

XISelectEvent throws X Error: BadValue (integer out of range for operation)


I'm trying to read events from X11, here's my minimal repro:

#include <X11/Xlib.h>
#include <X11/extensions/XInput2.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <iostream>
#include <string.h>

int main() {
    if (getenv("DISPLAY") == NULL) return 1;

    void *x11 = dlopen("libX11.so.6", RTLD_GLOBAL | RTLD_LAZY);
    if (x11 == NULL) return 1;

    void *xInput2 = dlopen("libXi.so.6", RTLD_GLOBAL | RTLD_LAZY);
    if (xInput2 == NULL) return 1;

    // Check XInput2 functions are present, since libXi may contain XInput or XInput2.
    void *f = dlsym(xInput2, "XISelectEvents");
    if (f == NULL) return 1;

    // Load definitions
    dlsym(x11, "XOpenDisplay");
    dlsym(x11, "XDefaultRootWindow");
    dlsym(x11, "XQueryExtension");
    dlsym(x11, "XSync");
    dlsym(x11, "XNextEvent");
    dlsym(x11, "XSendEvent");
    dlsym(x11, "XFreeEventData");
    dlsym(x11, "XGetEventData");
    dlsym(xInput2, "XISelectEvents");

    Display *display = XOpenDisplay(NULL);
    if (display == NULL) return 1;

    int xiOpcode;
    int queryEvent;
    int queryError;
    XQueryExtension(display, "XInputExtension", &xiOpcode, &queryEvent, &queryError);

    Window root = XDefaultRootWindow(display);
    XIEventMask *xiMask = new XIEventMask;
    xiMask->deviceid = XIAllMasterDevices;
    xiMask->mask_len = XIMaskLen(XI_LASTEVENT);
    xiMask->mask = new unsigned char[xiMask->mask_len];

    XISetMask(xiMask->mask, XI_RawKeyPress);
    XISetMask(xiMask->mask, XI_RawKeyRelease);
    XISelectEvents(display, root, xiMask, 1);
    XSync(display, 0);

    delete [] xiMask->mask;
}

The code is compiled using g++ test.cpp -lX11 -ldl -lXi

It throws the following error:

X Error of failed request:  BadValue (integer parameter out of range for operation)
  Major opcode of failed request:  132 (XInputExtension)
  Minor opcode of failed request:  46 ()
  Value in failed request:  0xb
  Serial number of failed request:  14
  Current serial number in output stream:  15

I'm unable to understand and react to it, any help will be highly appreciated.

I tried debugging and found that error is exactly occured when XISelectEvent is executed.


Solution

  • I feel dumb now, I forgot that the array allocated in the heap using the new keyword has garbage in it.

    I had to use the

    memset(xiMask->mask, 0, xiMask->mask_len);
    

    to set all the values in the array to 0, then start setting the value of each element as needed.

    Update:

    We can just use less-known feature of C++ to directly fill the recently allocated array to 0s using new T() in the single expression.

    So does this:

    xiMask->mask = new unsigned char[xiMask->mask_len]();