全球热键与X11 / Xlib

我的目标是有一个程序,睡在后台,但可以由用户通过一些“热键”激活。 从Xlib手册和Xlib O'reilly手册的深入挖掘中,我可以得出正确的方法是使用XGrabKey。 然而,我对这个过程的理解是不正确的,因为一个简单的概念certificate是行不通的。

我的理解是,如果我用根窗口作为grab_window调用XGrabKey,并且owner_events为false,那么无论何时按下我的热键,事件将只发送到根窗口。 如果我然后从根窗口中selectKeyPress事件,然后监听X事件,当按下热键时,我应该得到一个按键事件。 我在下面贴了一个简单的例子。

我期望的是当程序运行时,不pipe窗口有什么焦点,如果按下Ctrl + Shift + K,我的程序应该输出“Hot key pressed! 在控制台中,然后终止。

此外,这是我的理解,如果XGrabKey失败,默认的error handling程序将显示一条消息,因为它不,我假设调用成功。

显然,我的理解有点不对劲。 任何人都可以指向正确的方向吗?

#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; } 

你的程序在这里工作。 我的猜测是你有另一个修饰符活跃,如NumLock。 GrabKey只能用于确切的修饰符掩码。

例如,这里是一些来自metacity窗口pipe理器的(GPL)代码

 /* Grab/ungrab, ignoring all annoying modifiers like NumLock etc. */ static void meta_change_keygrab (MetaDisplay *display, Window xwindow, gboolean grab, int keysym, unsigned int keycode, int modmask) { unsigned int ignored_mask; /* Grab keycode/modmask, together with * all combinations of ignored modifiers. * X provides no better way to do this. */ meta_topic (META_DEBUG_KEYBINDINGS, "%s keybinding %s keycode %d mask 0x%x on 0x%lx\n", grab ? "Grabbing" : "Ungrabbing", keysym_name (keysym), keycode, modmask, xwindow); /* efficiency, avoid so many XSync() */ meta_error_trap_push (display); ignored_mask = 0; while (ignored_mask <= display->ignored_modifier_mask) { if (ignored_mask & ~(display->ignored_modifier_mask)) { /* Not a combination of ignored modifiers * (it contains some non-ignored modifiers) */ ++ignored_mask; continue; } if (meta_is_debugging ()) meta_error_trap_push_with_return (display); if (grab) XGrabKey (display->xdisplay, keycode, modmask | ignored_mask, xwindow, True, GrabModeAsync, GrabModeSync); else XUngrabKey (display->xdisplay, keycode, modmask | ignored_mask, xwindow); if (meta_is_debugging ()) { int result; result = meta_error_trap_pop_with_return (display, FALSE); if (grab && result != Success) { if (result == BadAccess) meta_warning (_("Some other program is already using the key %s with modifiers %x as a binding\n"), keysym_name (keysym), modmask | ignored_mask); else meta_topic (META_DEBUG_KEYBINDINGS, "Failed to grab key %s with modifiers %x\n", keysym_name (keysym), modmask | ignored_mask); } } ++ignored_mask; } meta_error_trap_pop (display, FALSE); } 

如果您在X11上使用/ targeting gtk,则有一个C库,其接口更简单:

https://github.com/engla/keybinder

包括Python,Lua和Vala绑定。 ( 这里也提到)

用你的面具ControlMask | ShiftMask ControlMask | ShiftMask你不会得到钥匙,如果另一个修改键被举行。 这首先听起来不错,但也有一个陷阱: NumLockCapsLock等等都被视为修饰符。

你有两个select:

  • 您可以多次调用XGrabKey() ,对于您感兴趣的每个显式组合XGrabKey()调用一次。
  • 你用AnyModifier调用XGrabKey() ,并使用event.xkey.state来检查修饰符是否如你所期望的那样。

头文件<Xh> ShiftMask <Xh>定义了ShiftMaskLockMaskControlMaskMod1MaskMod2MaskMod3MaskMod4MaskMod5MaskAnyModifier

关键是:

 Mask | Value | Key ------------+-------+------------ ShiftMask | 1 | Shift LockMask | 2 | Caps Lock ControlMask | 4 | Ctrl Mod1Mask | 8 | Alt Mod2Mask | 16 | Num Lock Mod3Mask | 32 | Scroll Lock Mod4Mask | 64 | Windows Mod5Mask | 128 | ??? 

警告我尝试了解ModNMask键,我不知道这是否在所有机器/configuration/版本/操作系统上有效。

在你的情况下,你可能要确保ShiftMask | CtrlMask ShiftMask | CtrlMask被设置, Mod1Mask | Mod4Mask Mod1Mask | Mod4Mask是清楚的,其他的被忽略。

我会这样做来设置密钥抓取:

 XGrabKey(dpy, keycode, AnyModifier, grab_window, owner_events, pointer_mode, keyboard_mode); 

这是为了检查是否设置了正确的修饰符:

 switch (ev.type) { case KeyPress: if ((ev.xkey.state & (ShiftMask | CtrlMask | Mod1Mask | Mod4Mask)) == (ShiftMask | CtrlMask)) // ... }