X KeyPress /释放事件捕获,无论窗口焦点

我想要logging所有传入按键事件,无论窗口在哪个焦点或指针在哪里。

我已经写了一个示例代码,它应该捕获当前窗口焦点的按键事件。

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <locale.h> #include <stdint.h> #include <stdarg.h> #include <errno.h> #include <pthread.h> #include <X11/Xlib.h> #include <X11/Xos.h> #include <X11/Xfuncs.h> #include <X11/Xutil.h> #include <X11/Xatom.h> int _invalid_window_handler(Display *dsp, XErrorEvent *err) { return 0; } int main() { Display *display = XOpenDisplay(NULL); int iError; KeySym k; int revert_to; Window window; XEvent event; Time time; XSetErrorHandler(_invalid_window_handler); XGetInputFocus(display, &window, &revert_to); XSelectInput(display, window, KeyPressMask | KeyReleaseMask ); iError = XGrabKeyboard(display, window, KeyPressMask | KeyReleaseMask, GrabModeAsync, GrabModeAsync, CurrentTime); if (iError != GrabSuccess && iError == AlreadyGrabbed) { XUngrabPointer(display, CurrentTime); XFlush(display); printf("Already Grabbed\n"); } else if (iError == GrabSuccess) { printf("Grabbed\n"); } while(1) { XNextEvent(display,&event); switch (event.type) { case KeyPress : printf("Key Pressed\n"); break; case KeyRelease : printf("Key Released\n"); break; case EnterNotify : printf("Enter\n"); break; } } XCloseDisplay(display); return 0; } 

我调用XGrabKeyboard来捕获键盘,因为创build窗口的应用程序可能已经获取了键盘事件。 通过上面提到的代码,我可以抓住键盘,但是无法接收KeyPress或KeyRelease事件中的while循环内的键盘上的任何键。 在代码中是否有任何我没有收到的事件? 任何帮助,高度赞赏。

我的最终目标是在屏幕上捕捉关键的新闻事件,而不pipe窗口焦点。 我已经给出了只有窗口焦点的示例代码才能读取代码。 我会做XQueryTree得到所有的Windows,并应用上面给出的相同的逻辑来获得预期的结果。

Solutions Collecting From Web of "X KeyPress /释放事件捕获,无论窗口焦点"

您需要有一个映射的窗口才能够抓住键盘。 这是一个概念的证明:

 #include <X11/Xlib.h> #include <X11/keysym.h> #include <stdio.h> int main() { Display *display; Window window, rootwindow; XEvent event; KeySym escape; display = XOpenDisplay(NULL); rootwindow = DefaultRootWindow(display); window = XCreateWindow(display, rootwindow, -99, -99, 1, 1, /* x, y, width, height */ 0, 0, InputOnly, /* border, depth, class */ CopyFromParent, /* visual */ 0, NULL); /* valuemask and attributes */ XSelectInput(display, window, StructureNotifyMask | SubstructureRedirectMask | ResizeRedirectMask | KeyPressMask | KeyReleaseMask); XLowerWindow(display, window); XMapWindow(display, window); do { XNextEvent(display, &event); } while (event.type != MapNotify); XGrabKeyboard(display, window, False, GrabModeAsync, GrabModeAsync, CurrentTime); XLowerWindow(display, window); escape = XKeysymToKeycode(display, XK_Escape); printf("\nPress ESC to exit.\n\n"); fflush(stdout); while (1) { XNextEvent(display, &event); if (event.type == KeyPress) { printf("KeyPress: keycode %u state %u\n", event.xkey.keycode, event.xkey.state); fflush(stdout); } else if (event.type == KeyRelease) { printf("KeyRelease: keycode %u state %u\n", event.xkey.keycode, event.xkey.state); fflush(stdout); if (event.xkey.keycode == escape) break; } else if (event.type == UnmapNotify) { XUngrabKeyboard(display, CurrentTime); XDestroyWindow(display, window); XCloseDisplay(display); display = XOpenDisplay(NULL); rootwindow = DefaultRootWindow(display); window = XCreateWindow(display, rootwindow, -99, -99, 1, 1, /* x, y, width, height */ 0, 0, InputOnly, /* border, depth, class */ CopyFromParent, /* visual */ 0, NULL); /* valuemask and attributes */ XSelectInput(display, window, StructureNotifyMask | SubstructureRedirectMask | ResizeRedirectMask | KeyPressMask | KeyReleaseMask); XLowerWindow(display, window); XMapWindow(display, window); do { XNextEvent(display, &event); } while (event.type != MapNotify); XGrabKeyboard(display, window, False, GrabModeAsync, GrabModeAsync, CurrentTime); XLowerWindow(display, window); escape = XKeysymToKeycode(display, XK_Escape); } else { printf("Event type %d\n", event.type); fflush(stdout); } } XUngrabKeyboard(display, CurrentTime); XDestroyWindow(display, window); XCloseDisplay(display); return 0; } 

它使用一个小窗口(我甚至懒得为它设置一个标题),它降低到窗口堆栈的底部,所以它落后于任何现有的窗口。 您可以与窗口管理器(WM)进行通信,使窗口无装饰,透明或图标化,以便屏幕上没有可见的窗口。 上面的代码不会打扰。

我使用的技巧是每当用户设法取消映射窗口 – 例如,移动到另一个工作区 – 代码销毁旧窗口,创建一个新窗口,并重新抓住键盘。 它应该足够快,不会丢失任何按键。 可能还有其他方法可以做到这一点,但我怀疑他们需要与窗口管理器进行更密切的交互。

请注意,我从来没有需要真正抓住键盘如此持久,所以上述方法可能不是最简单的。 这只是我认为可行的方法。 有可能是更好的。

以下命令将打印整个X会话的所有事件列表到控制台:

 $ xinput test-xi2 --root 

示例输出:

 ⎡ Virtual core pointer id=2 [master pointer (3)] ⎜ ↳ Virtual core XTEST pointer id=4 [slave pointer (2)] ⎜ ↳ USB Mouse id=10 [slave pointer (2)] ⎜ ↳ MCE IR Keyboard/Mouse (ite-cir) id=11 [slave pointer (2)] ⎣ Virtual core keyboard id=3 [master keyboard (2)] ↳ Virtual core XTEST keyboard id=5 [slave keyboard (3)] ↳ Power Button id=6 [slave keyboard (3)] ↳ Video Bus id=7 [slave keyboard (3)] ↳ Power Button id=8 [slave keyboard (3)] ↳ Oracle USB Keyboard id=9 [slave keyboard (3)] ↳ ITE8713 CIR transceiver id=12 [slave keyboard (3)] EVENT type 14 (RawKeyRelease) device: 3 (9) detail: 36 valuators: EVENT type 3 (KeyRelease) device: 9 (9) detail: 36 flags: root: 1324.55/821.81 event: 1324.55/821.81 buttons: modifiers: locked 0x10 latched 0 base 0 effective: 0x10 group: locked 0 latched 0 base 0 effective: 0 valuators: windows: root 0x9c event 0x9c child 0x7291d5 EVENT type 15 (RawButtonPress) device: 2 (10) detail: 1 valuators: flags: EVENT type 4 (ButtonPress) device: 10 (10) detail: 1 flags: root: 1324.55/821.81 event: 1324.55/821.81 buttons: modifiers: locked 0x10 latched 0 base 0 effective: 0x10 group: locked 0 latched 0 base 0 effective: 0 valuators: windows: root 0x9c event 0x9c child 0x7291d5 EVENT type 16 (RawButtonRelease) device: 2 (10) detail: 1 valuators: flags: