3

I'm trying to create an app that is all hotkey based, I wrote some code using Xlib that works great on CentOS 6.. When I tried in our Ubuntu (14.04) development environment I get this exception

X Error of failed request:  BadAccess (attempt to access private resource denied)
  Major opcode of failed request:  33 (X_GrabKey)
  Serial number of failed request:  10
  Current serial number in output stream:  13

Here is the code

void* manage_hotkeys(void* arg)
    {
        Window root;
        XEvent ev;
        Display* dpy = XOpenDisplay(0);    
        char* ckeystr = "c";
        ...

        if (!dpy)
        {
            printf("Failed to get Display\n");
            exit(EXIT_FAILURE);
        }

        root = DefaultRootWindow(dpy);
        KeyCode ckey = XKeysymToKeycode(dpy, XStringToKeysym(ckeystr)); // control panel

        // grab keys
        XGrabKey(dpy, ckey, AnyModifier, root, True, GrabModeAsync, GrabModeAsync);
        ....
        while (1)
        {
            printf("Beginning of hotkey loop\n");
            XNextEvent(dpy, &ev);
            if (ev.type == KeyPress)
            {
                printf("Key press event!\n");

                if (ev.xkey.keycode == ckey)
                {
                    // stuff...
                } else if .....
            } // if
        } // while

    ...
        XUngrabKey(dpy, ckey, AnyModifier, root);
    ...

        pthread_exit(NULL);
    } // hotkeythread

I've looked at other SO threads (like this one) but they don't seem applicable to me, I'm listening for single keys (e.g. 'c'). I don't code much in C so I'm a bit rusty and went with the first example that worked (on CentOS at least), please help me debug.

From what I've researched, I think some process in Ubuntu has already grabbed the keys or something? How do I figure out what that process is? Is there another approach I'm overlooking? I just need to to grab keyboard input regardless of the window in focus, xgrabkey looked like the simplest approach... Please help

Community
  • 1
  • 1
Crushing
  • 487
  • 1
  • 9
  • 24
  • Maybe that thread helps: https://unix.stackexchange.com/questions/261371/how-do-i-find-out-what-program-owns-a-hotkey?noredirect=1&lq=1 – Arminius Aug 14 '19 at 10:04

1 Answers1

2

The "X Error of failed request" errors, also seen as exceptions, can be intercepted in your application by using XSetErrorHandler function.

Setting this error handler alone eliminates unexpected exits completely. Thus, what is probably wanted instead is to intercept the specific error, ignore or log it, then make all the others still terminate the application. This can be done by interpreting the XErrorEvent structure, doing something like this:

// Early in your application
XSetErrorHandler( x_error_handler );

//...

int x_error_handler( Display* dpy, XErrorEvent* pErr )
{
    printf("X Error Handler called, values: %d/%lu/%d/%d/%d\n",
        pErr->type,
        pErr->serial,
        pErr->error_code,
        pErr->request_code,
        pErr->minor_code );
    if( pErr->request_code == 33 ){  // 33 (X_GrabKey)
        if( pErr->error_code == BadAccess ){
            printf("ERROR: A client attempts to grab a key/button combination already\n"
                   "        grabbed by another client. Ignoring.\n");
            return 0;
        }
    }
    exit(1);  // exit the application for all unhandled errors.
    return 0;
}

Otherwise, interpretation of these error values alone can't lead to exact key combination and what process/client already grabbed it, I think.

MaxLZ
  • 89
  • 1
  • 4