2

I am working on one "practical" program I need and it needs to be written in something like Xlib. One thing the program will do is read ALL key presses made by the user, to do this I must "open" the XDevices that are XI_KEYBOARDs.

So I have a loop which "opens" the XDevices that need to be opened

for(i = 0; i < devicesN; i++) {
        if(deviceInfo[i].type == keyboardAtom) {
                printf("%s %d %d %d\n", deviceInfo[i].name, deviceInfo[i].type, deviceInfo[i].id, keyboardAtom);

                device = XOpenDevice(display, deviceInfo[i].id);

                inputInfo = device->classes;
                for(j = 0; j < deviceInfo->num_classes; j++, inputInfo++) {
                        printf("%d %d\n", inputInfo->input_class, KeyClass);
                        if(inputInfo->input_class == KeyClass) {
                                DeviceKeyPress(device, keypressType, events[eventsN++]);
                        }
                }

                if(XSelectExtensionEvent(display, RootWindow(display, screen), events, eventsN))
                        return 1;
        }
}

Now the first time the loops executes everything goes fine. It first prints out Power Button 101 6 101 meaning name of device i: Power Button, type: 101, id: 6 and finally the keyboard atom 101, meaning that this device is something we should open and "listen" to. Well this works it does open this first device. Now the second time it executes this loop something odd happens,it again prints out Power Button 101 7 101 everything is fine and the id is 7 this time which is good. But after printing that out this error occurs:

X Error of failed request:  XI_BadClass (invalid Class parameter)
  Major opcode of failed request:  131 (XInputExtension)
  Minor opcode of failed request:  6 (X_SelectExtensionEvent)
  Class id in failed request: 0x6bf
  Serial number of failed request:  19
  Current serial number in output stream:  20

According to my debugging this error happens during the opening of the device so on this line: device = XOpenDevice(display, deviceInfo[i].id);.

I have tried skipping the 7th device and going straight to the next device and it the error still occurs. It looks like it always happens on the second device "opening".

All help is appreciated!

PS: If you think this can be done more easily and less painfully on xcb then you can also suggest a way of doing it with xcb.

Victor Ocampo
  • 378
  • 2
  • 6
  • 15

1 Answers1

0

I also have a similar problem when writing something similar. However, I don't think I can reproduce your issue. So this is what I have:

  1. If you Move XSelectExtensionEvent outside the for loop, you will probably successfully call XOpenDevice and get the X Error on XSelectExtensionEvent. (this is a strange behavior that I have no idea what's going on)

  2. You can try using xinput test [-proximity] <device-id> to make sure that your device can be opened. For some of my devices, if I add the -proximity flag, xinput also throws the X Error:

$ xinput test -proximity 4
X Error of failed request:  XI_BadClass (invalid Class parameter)
  Major opcode of failed request:  131 (XInputExtension)
  Minor opcode of failed request:  6 (X_SelectExtensionEvent)
  Class id in failed request: 0x135
  Serial number of failed request:  19
  Current serial number in output stream:  19
$ 
  1. This is my program. Does it work on your end?
// gcc -lX11 -lXi

#include <stdio.h>
#include <assert.h>
#include <X11/extensions/XInput.h>

Display* display;
unsigned long screen;
Window root_win;

#define INVALID_EVENT_TYPE  -1

static int motion_type = INVALID_EVENT_TYPE;
static int button_press_type = INVALID_EVENT_TYPE;
static int button_release_type = INVALID_EVENT_TYPE;
static int key_press_type = INVALID_EVENT_TYPE;
static int key_release_type = INVALID_EVENT_TYPE;
static int proximity_in_type = INVALID_EVENT_TYPE;
static int proximity_out_type = INVALID_EVENT_TYPE;

#define ADD_EVENT(EVENT, TYPE) \
 do { EVENT(device, TYPE, event_list[number]); number++; } while(0)

void register_extension_events() {
    // Copied from test.c in xinput
    XDeviceInfo* devices;
    int ndevices;
    devices = XListInputDevices(display, &ndevices);
    int number = 0;
    XEventClass event_list[8 * ndevices];
    for (int i = 0; i < ndevices; i++) {
        // Filter out master devices. See XListInputDevices(3) and XI.h
        if (devices[i].use < IsXExtensionDevice)
            continue;
        if (!"list all devices")
            printf("%d\t%d\t%s\t%s\n", i, devices[i].id, 
                devices[i].type ? XGetAtomName(display, devices[i].type) : "",
                devices[i].name);
        XDevice* device = XOpenDevice(display, devices[i].id);
        for (int i = 0; i < device->num_classes; i++) {
            switch (device->classes[i].input_class) {
            case KeyClass:
                ADD_EVENT(DeviceKeyPress, key_press_type);
                ADD_EVENT(DeviceKeyRelease, key_release_type);
                break;
            case ButtonClass:
                ADD_EVENT(DeviceButtonPress, button_press_type);
                ADD_EVENT(DeviceButtonRelease, button_release_type);
                break;
            case ValuatorClass:
                ADD_EVENT(DeviceMotionNotify, motion_type);
                // Also errors with `xinput test -proximity <id>`
                // ADD_EVENT(ProximityIn, proximity_in_type);
                // ADD_EVENT(ProximityOut, proximity_out_type);
                break;
            default:
                // fprintf(stderr, "unknown class\n");
                break;
            }
        }
    }
    assert(number <= 8 * ndevices);
    if (number && XSelectExtensionEvent(display, root_win, event_list, number))
        fprintf(stderr, "error selecting extended events\n");
    while (1) {
        XEvent Event;
        XNextEvent(display, &Event);
        printf(".");
        fflush(stdout);
    }
}

int main() {
    display = XOpenDisplay(NULL);
    if (display == NULL) {
        fprintf(stderr, "Unable to connect to X server\n");
        return 1;
    }
    screen = DefaultScreen(display);
    root_win = RootWindow(display, screen);
    register_extension_events();
}
Eric Stdlib
  • 1,292
  • 1
  • 18
  • 32