gpt4 book ai didi

linux - X KeyPress/Release 事件捕获,与焦点窗口无关

转载 作者:IT王子 更新时间:2023-10-29 00:48:39 26 4
gpt4 key购买 nike

我想记录所有传入的按键事件,无论哪个窗口处于焦点或指针位于何处。

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

#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 并应用上面给出的相同逻辑以获得预期结果。

最佳答案

您需要有一个映射窗 Eloquent 能抓取键盘。这是一个概念证明:

#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)通信,使窗口无装饰且透明,或者图标化,以便屏幕上没有可见窗口;上面的代码没有打扰。

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

请注意,我从来不需要如此执着地捕获键盘,因此上述方法可能不是最简单的。这只是我认为可行的一种方法;可能有更好的。

关于linux - X KeyPress/Release 事件捕获,与焦点窗口无关,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11315001/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com