X11/Xlib 的全局热键
我的目标是拥有一个在后台休眠但可以由用户通过某些“热键”激活的程序。通过深入研究 Xlib 手册和 Xlib O'reilly 手册,我发现正确的方法是使用 XGrabKey。然而,我对这个过程的理解是不正确的,因为简单的概念证明不起作用。
我的理解是,如果我使用根窗口作为grab_window调用XGrabKey,并且owner_events为假,那么每当按下我的热键时,事件将仅发送到根窗口。如果我然后从根窗口中选择 KeyPress 事件,然后监听 X 事件,那么当按下热键时,我应该得到一个按键事件。我在下面粘贴了一个最小的例子。
我期望的是,当程序运行时,无论哪个窗口具有焦点,如果按下 Ctrl+Shift+K,我的程序应该输出“按下热键!”在控制台中,然后终止。
此外,据我了解,如果 XGrabKey 失败,默认错误处理程序将显示一条消息,并且由于它不会显示,因此我假设调用成功。
显然,我的理解在某种程度上是有缺陷的。有人能指出我正确的方向吗?
#include <iostream>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
using namespace std;
int main()
{
Display* dpy = XOpenDisplay(0);
Window root = DefaultRootWindow(dpy);
XEvent ev;
unsigned int modifiers = ControlMask | ShiftMask;
int keycode = XKeysymToKeycode(dpy,XK_Y);
Window grab_window = root;
Bool owner_events = False;
int pointer_mode = GrabModeAsync;
int keyboard_mode = GrabModeAsync;
XGrabKey(dpy, keycode, modifiers, grab_window, owner_events, pointer_mode,
keyboard_mode);
XSelectInput(dpy, root, KeyPressMask );
while(true)
{
bool shouldQuit = false;
XNextEvent(dpy, &ev);
switch(ev.type)
{
case KeyPress:
cout << "Hot key pressed!" << endl;
XUngrabKey(dpy,keycode,modifiers,grab_window);
shouldQuit = true;
default:
break;
}
if(shouldQuit)
break;
}
XCloseDisplay(dpy);
return 0;
}
My goal is to have a program that sleeps in the background but can be activated by the user via some "hotkey". From digging around the Xlib manual and the Xlib O'reilly manual, I gather that the correct way to to this is with XGrabKey. However my understanding of the process is incorrect as a simple proof of concept does not work.
My understanding is that if I call XGrabKey with the root window as the grab_window, and owner_events false, then whenever my hotkey is pressed the event will be sent only to the root window. If I then select KeyPress events from the root window, and then listen for X events, I should get a key press event when the hotkey is pressed. I've pasted a minimal example below.
What I expect is that when the program is run, regardless of what window has focus, if Ctrl+Shift+K is pressed, my program should output "Hot key pressed!" in the console, and then terminate.
Furthermore, it is my understanding that if the XGrabKey fails, the default error handler will display a message, and since it does not I am assuming that the call succeeds.
Obviously, my understanding is flawed somehow. Can anyone point me in the right direction?
#include <iostream>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
using namespace std;
int main()
{
Display* dpy = XOpenDisplay(0);
Window root = DefaultRootWindow(dpy);
XEvent ev;
unsigned int modifiers = ControlMask | ShiftMask;
int keycode = XKeysymToKeycode(dpy,XK_Y);
Window grab_window = root;
Bool owner_events = False;
int pointer_mode = GrabModeAsync;
int keyboard_mode = GrabModeAsync;
XGrabKey(dpy, keycode, modifiers, grab_window, owner_events, pointer_mode,
keyboard_mode);
XSelectInput(dpy, root, KeyPressMask );
while(true)
{
bool shouldQuit = false;
XNextEvent(dpy, &ev);
switch(ev.type)
{
case KeyPress:
cout << "Hot key pressed!" << endl;
XUngrabKey(dpy,keycode,modifiers,grab_window);
shouldQuit = true;
default:
break;
}
if(shouldQuit)
break;
}
XCloseDisplay(dpy);
return 0;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
你的程序在这里运行。我的猜测是您有另一个处于活动状态的修饰符,例如 NumLock。 GrabKey 仅适用于 exact 修饰符掩码。
例如,这是来自metacity窗口管理器的一些(GPL)代码
Your program works here. My guess is you have another modifier active, such as NumLock. GrabKey only works on the exact modifier mask.
For example here is some (GPL) code from metacity window manager
使用您的面罩
ControlMask | ShiftMask
如果按住另一个修饰键,您将无法获得该键。这听起来不错,但有一个陷阱:NumLock、CapsLock 等都被视为修饰符。您有两种选择:
XGrabKey()
,针对您感兴趣的每个显式组合调用一次。AnyModifier< 调用
XGrabKey()
/code> 并使用event.xkey.state
检查修饰符是否符合您的预期。头文件
定义了ShiftMask
、LockMask
、ControlMask
、Mod1Mask
、Mod2Mask
、Mod3Mask
、Mod4Mask
、Mod5Mask
和AnyModifier
。这些键是:
警告 我通过尝试发现了
ModNMask
键,但我不知道这是否在所有机器/配置/版本/操作系统上都有效。就您而言,您可能需要确保 ShiftMask | CtrlMask 已设置,
Mod1Mask | Mod4Mask
很清楚,其他的可以忽略。我这样做是为了设置按键抓取:
这是为了检查是否设置了正确的修饰符:
With your mask
ControlMask | ShiftMask
you will not get the key if another modifier key is held. This sounds okay in the first place, but there's a pitfall: NumLock, CapsLock and alike all are treated as modifiers, too.You have two options:
XGrabKey()
multiple times, once for each explicit combination that you're interested in.XGrabKey()
withAnyModifier
and useevent.xkey.state
to check whether the modifiers are as you expected.The header file
<X.h>
definesShiftMask
,LockMask
,ControlMask
,Mod1Mask
,Mod2Mask
,Mod3Mask
,Mod4Mask
,Mod5Mask
andAnyModifier
.The keys are:
Warning I found out about the
ModNMask
keys by trying and I do not know if this is valid on all machines / configurations / versions / operating systems.In your case, you probably want to make sure that
ShiftMask | CtrlMask
is set,Mod1Mask | Mod4Mask
are clear, and the others to be ignored.I'd do this to setup the key grab:
And this to check whether the right modifiers are set:
如果您在 X11 上使用/定位 gtk,则有一个具有更简单界面的 C 库:
https://github .com/engla/keybinder
包括 Python、Lua 和 Vala 绑定。 (此处也提到了。)
If you're using/targeting gtk on X11, there's a C library with a much simpler interface:
https://github.com/engla/keybinder
Includes Python, Lua and Vala bindings. (Also mentioned here.)