为什么 XGrabKey return BadRequest?
Why does XGrabKey return BadRequest?
所以我正在研究 Gtk/X11/Linux app that does screen capture to .gif and one of the methods of stopping the capture is a key press (Esc, Space or End). You can also use a timeout. However to implement the key press to end capture I have to be able to grab the key such that I can get an event even though my window doesn't have focus (it's actually invisible during capture). I believe 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);
其中 'HotKeyCode' 表示 XK_Escape 或其他内容,例如:
XGrabKey(0x3e00003, 0xff1b/9)=1
XGrabKey 正在返回“1”或 BadRequest。我在这里做错了什么?
仅供参考,有问题的实际 Xorg Xserver 代码似乎是 here。
编辑:代码的最新版本是:
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);
AnyModifier 实际上会导致错误。 '0' 没有。我知道 NumLock 问题...
1
的 return 值 而不是 表示发生了 BadRequest 错误。 Xlib handles errors via an error handler,并且该函数将 始终 return 1
,如果 return 根本没有。
您的代码不起作用,因为您必须在根 window (GetDefaultRootWindow(Gtk::gdk_display)
) 上执行 XGrabKey
。这是一个纯 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);
}
}
然后从 GTK 捕获 X11 事件,在 NULL
或根 window 上使用 gdk_window_add_filter
和处理与您的全局关联的事件的 GdkFilterFunc
热键:
#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();
}
作为旁注,0
的修饰符掩码意味着必须启用 no 修饰符,即使是那些不会修改键的含义的修饰符。使用 0
修饰符抓住字母 "A" 不会匹配 NumLock + A。这就是我使用 AnyModifer
.
的原因
所以我正在研究 Gtk/X11/Linux app that does screen capture to .gif and one of the methods of stopping the capture is a key press (Esc, Space or End). You can also use a timeout. However to implement the key press to end capture I have to be able to grab the key such that I can get an event even though my window doesn't have focus (it's actually invisible during capture). I believe 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);
其中 'HotKeyCode' 表示 XK_Escape 或其他内容,例如:
XGrabKey(0x3e00003, 0xff1b/9)=1
XGrabKey 正在返回“1”或 BadRequest。我在这里做错了什么?
仅供参考,有问题的实际 Xorg Xserver 代码似乎是 here。
编辑:代码的最新版本是:
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);
AnyModifier 实际上会导致错误。 '0' 没有。我知道 NumLock 问题...
1
的 return 值 而不是 表示发生了 BadRequest 错误。 Xlib handles errors via an error handler,并且该函数将 始终 return 1
,如果 return 根本没有。
您的代码不起作用,因为您必须在根 window (GetDefaultRootWindow(Gtk::gdk_display)
) 上执行 XGrabKey
。这是一个纯 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);
}
}
然后从 GTK 捕获 X11 事件,在 NULL
或根 window 上使用 gdk_window_add_filter
和处理与您的全局关联的事件的 GdkFilterFunc
热键:
#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();
}
作为旁注,0
的修饰符掩码意味着必须启用 no 修饰符,即使是那些不会修改键的含义的修饰符。使用 0
修饰符抓住字母 "A" 不会匹配 NumLock + A。这就是我使用 AnyModifer
.