为什么XGrabKey返回BadRequest?

fre*_*ret 4 x11 gtk

因此,我正在开发一个Gtk / X11 / Linux 应用程序,该应用程序将屏幕捕获到.gif,并且停止捕获的方法之一是按键(Esc,Space或End)。您也可以使用超时。但是,要实现按下按键来结束捕获,我必须能够抓住键,以便即使我的窗口没有焦点(捕获过程中它实际上是不可见的)也可以得到一个事件。我相信XGrabKey是适合此任务的X11函数:

Window w = Gtk::gdk_x11_drawable_get_xid(Gtk::gtk_widget_get_window(Handle()));
KeyCode kc = XKeysymToKeycode(Gtk::gdk_display, HotKeyCode);
int r = XGrabKey(   Gtk::gdk_display,
                    kc,
                    0               /* modifiers */,
                    w               /* grab_window */,
                    TRUE            /* owner_events */,
                    GrabModeAsync   /* pointer_mode */,
                    GrabModeAsync   /* keyboard_mode */);
printf("XGrabKey(%p, 0x%x/%x)=%i\n", w, HotKeyCode, kc, r);
Run Code Online (Sandbox Code Playgroud)

其中“ HotKeyCode”是XK_Escape之类的,例如:

XGrabKey(0x3e00003, 0xff1b/9)=1
Run Code Online (Sandbox Code Playgroud)

XGrabKey返回“ 1”或BadRequest。我在这里做错了什么?

仅供参考,实际的Xorg Xserver代码似乎在这里

编辑:该代码的最新化身为:

int x_err_callback(Display *d, XErrorEvent *e)
{
    char msg[256];

    XGetErrorText(d, e->error_code, msg, sizeof(msg));

    printf("X11Error %d (%s): request %d.%d\n",
        e->error_code, msg, e->request_code,
        e->minor_code);

    return 0;
}

Gtk::GdkFilterReturn key_filter(Gtk::GdkXEvent *gdk_xevent,
                                Gtk::GdkEvent *event,
                                Gtk::gpointer data)
{
    XKeyEvent *xevent = gdk_xevent;
    if (xevent->type == KeyPress)
    {
        int key = ((XKeyEvent *)gdk_xevent)->keycode;
        int keysym = XKeycodeToKeysym(Gtk::gdk_display, key, 0);

        printf("caught keysym %i\n", keysym);

        switch (keysym)
        {
            case 1: // your_keysym
                // your key handler code
                break;
        }
    }

    return Gtk::GDK_FILTER_CONTINUE;
}


Gtk::GdkWindow *Root = Gtk::gdk_get_default_root_window();
KeyCode kc = XKeysymToKeycode(Gtk::gdk_display, HotKeyCode);

XSetErrorHandler(x_err_callback);

int r = XGrabKey(   Gtk::gdk_display,
                    kc,
                    AnyModifier /* modifiers */,
                    GDK_WINDOW_XWINDOW(Root) /* grab_window */,
                    TRUE            /* owner_events */,
                    GrabModeAsync   /* pointer_mode */,
                    GrabModeSync    /* keyboard_mode */);

Gtk::gdk_window_set_events(Root,
    (Gtk::GdkEventMask)
    (Gtk::GDK_KEY_PRESS_MASK |
    Gtk::GDK_KEY_RELEASE_MASK));
Gtk::gdk_window_add_filter(NULL, key_filter, this);
Run Code Online (Sandbox Code Playgroud)

AnyModifier实际上会导致错误。“ 0”不是。我知道NumLock问题...

Phi*_*lip 5

的返回值1并不意味着一个错误请求时出现错误。Xlib通过错误处理程序处理错误,如果函数完全返回,它将始终返回1

您的代码无效,因为您必须XGrabKey在根窗口(GetDefaultRootWindow(Gtk::gdk_display))上执行。这是一个纯Xlib演示:

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

int main() {
    Display *d = XOpenDisplay(0);
    Window root = DefaultRootWindow(d);
    int keycode = XKeysymToKeycode(d, XK_BackSpace);

    int rv = XGrabKey(d, keycode, AnyModifier, root, 1, GrabModeAsync, GrabModeAsync);
    printf("XGrabKey returned %d\n", rv);

    XEvent evt;
    while(1) {
        XNextEvent(d, &evt);
        printf("Got event %d\n", evt.type);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,要从GTK捕获X11事件,请gdk_window_add_filterNULL或根窗口上使用和GdkFilterFunc处理与全局热键关联的事件的a :

#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <stdio.h>

GdkFilterReturn filter(GdkXEvent *xevent, GdkEvent *event, gpointer data) {
    XKeyEvent *ev = (XKeyEvent *)xevent;
    if(ev->type == 2) {
        printf("Backspace hit.\n");
    }

    return GDK_FILTER_CONTINUE;
}

int main(int argc, char *argv[]) {
    gtk_init(&argc, &argv);

    GdkScreen *scr = gdk_screen_get_default();
    GdkWindow *groot = gdk_screen_get_root_window(scr);
    gdk_window_set_events(groot, GDK_KEY_PRESS_MASK);
    gdk_window_add_filter(groot, filter, NULL);

    Display *d = gdk_x11_get_default_xdisplay();
    Window root = GDK_WINDOW_XID(groot);
    int keycode = XKeysymToKeycode(d, XK_BackSpace);
    XGrabKey(d, keycode, AnyModifier, root, 1, GrabModeAsync, GrabModeAsync);

    gtk_main();
}
Run Code Online (Sandbox Code Playgroud)

附带说明一下,修饰符掩码0表示无需启用任何修饰符,即使那些不会修改键含义的修饰符也是如此。带有0修饰符的字母“ A” 不匹配NumLock +A。这就是我使用的原因AnyModifer