我正在尝试根据以下代码捕获所有键盘输入这个答案。实际的按键捕获工作正常。然而,在 Linux Mint Cinnamon 上运行代码会导致其他问题:
- 我无法使用鼠标拖动任何窗口或调整其大小
- 单击 xed 和 nemo 菜单栏中的选项(文件、视图等...)不会显示子菜单选项
- 单击开始菜单会显示应用程序列表,但焦点由其后面的窗口保留,因此我无法悬停、滚动或单击应用程序列表中的项目。
下面是代码的简化但实用的版本。我已将原因缩小到StructureNotifyMask
中存在事件掩码XSelectInput
。如果没有该事件掩码,则不会出现上述问题。但这也意味着当窗口被映射时程序不会收到通知,因此捕获不起作用。
如何在不出现上述任何问题的情况下开始捕获工作?我尝试XSelectInput
在程序收到仅具有按键和释放事件掩码的映射通知后添加一秒钟。然而,这似乎并不能解决问题。
#include <X11/Xlib.h> #include <X11/keysym.h> #include <stdio.h> int main() { 显示*显示; 窗口window、rootwindow; XEvent事件; KeySym 转义; 显示 = XOpenDisplay(NULL); rootwindow = DefaultRootWindow(显示); 窗口 = XCreateWindow(显示, 根窗口, -99, -99, 1, 1, /* x, y, 宽度, 高度 */ 0, 0, InputOnly, /* 边框、深度、类 */ CopyFromParent, /* 视觉 */ 0、空); /* 值掩码和属性 */ XSelectInput(显示、窗口、StructureNotifyMask | KeyPressMask | KeyReleaseMask); XMapWindow(显示,窗口); 做 { XNextEvent(显示,&事件); while (event.type != MapNotify); XGrabKeyboard(显示、窗口、False、GrabModeAsync、GrabModeAsync、CurrentTime); 转义 = XKeysymToKeycode(显示, XK_Escape); printf("\n按 ESC 退出。\n\n"); fflush(标准输出); 而(1){ XNextEvent(显示,&事件); if (event.type == KeyPress) { printf("按键:按键代码 %u 状态 %u\n", event.xkey.keycode, event.xkey.state); fflush(标准输出); } 别的 if (event.type == KeyRelease) { printf("KeyRelease: 键码 %u 状态 %u\n", event.xkey.keycode, event.xkey.state); fflush(标准输出); if (event.xkey.keycode == escape) 休息; } 别的 { printf("事件类型 %d\n", event.type); fflush(标准输出); } } XUngrabKeyboard(显示,当前时间); XDestroyWindow(显示, 窗口); X关闭显示(显示); 返回0; }
答案1
你不能做一个永久的XGrabKeyboard
。只要某种交互正在进行,这种抓取就只能暂时使用。
如果你继续按住抓取,所有其他需要抓取的功能(比如你提到的 WM 操作)将无法工作。