我想记录所有传入的按键事件,无论焦点在哪个窗口或指针在哪里。
我编写了一个示例代码,该代码应该捕获当前Window的关键按下事件。
#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捕获键盘,因为创建窗口的应用程序可能已经抓取了键盘事件。使用上面提到的代码,我可以抓住键盘,但是无法接收while循环内键盘上任何键的KeyPress或KeyRelease事件。由于我无法接收事件,代码中是否有任何遗漏?任何帮助都非常感谢。
我的最终目标是捕捉屏幕上的关键新闻事件,而不管窗口是否对焦。我只给出了焦点窗口的示例代码,以便代码可读。我会做XQueryTree来获取所有的Windows并应用上面给出的相同逻辑来获得预期的结果。
答案 0 :(得分:5)
您需要有一个映射窗口才能抓取键盘。这是一个概念证明:
#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)通信,使窗口无装饰,透明或图标化,以便屏幕上没有可见窗口;上面的代码没有打扰。
我使用的技巧是每当用户设法取消映射窗口时 - 比如移动到另一个工作区 - 代码会破坏旧窗口,创建一个新窗口,然后重新抓取键盘。它应该足够快,不会丢失任何按键。可能还有其他方法可以做到,但我怀疑它们需要与窗口管理器进行更密切的交互。
请注意,我从来不需要如此持久地抓住键盘,所以上述方法可能不是最简单的。这只是我认为有效的方法;可能会有更好的。
答案 1 :(得分:3)
以下命令将整个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: