2010-10-27 99 views
24

我的目标是让一个程序在后台睡觉,但可以通过用户通过一些“热键”激活。从围绕Xlib手册和Xlib O'reilly手册开始,我了解到正确的方法是使用XGrabKey。然而,我对这个过程的理解是不正确的,因为一个简单的概念证明不起作用。X11/Xlib全球热键

我的理解是,如果我叫XGrabKey与根窗口作为grab_window和owner_events假的,那么只要按下快捷键我的事件将被发送仅到根窗口。如果我然后从根窗口中选择KeyPress事件,然后监听X事件,那么当按下热键时,我应该得到一个按键事件。我在下面贴了一个简单的例子。

我期望的是当程序运行时,不管窗口有什么焦点,如果按下Ctrl + Shift + K,我的程序应该输出“Hot key pressed!”在控制台中,然后终止。此外,这是我的理解,如果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; 
} 
+2

在你的代码使用'XK_Y',你可能想要说'XK_K'吗? – 2012-12-21 18:51:17

回答

19

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

例如这里是Metacity窗口管理器

/* 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); 
} 
+4

哦,伙计。你是绝对正确的。 Num锁已打开。非常感谢。我今天因为愚蠢而浪费了几个小时,但我认为你让我免于浪费几次。 – cheshirekow 2010-10-27 21:00:24

8

一些(GPL)的代码如果您使用/目标上X11 GTK,有一个C库以更简单的界面:

https://github.com/engla/keybinder

包括Python,Lua和Vala绑定。 (还提到here。)

+1

一个不错的图书馆。为你+1。谢谢:-) – madper 2013-04-08 14:08:22

7

随着你的面具ControlMask | ShiftMask你不会得到钥匙,如果另一个修饰键。这听起来不错,但有一个陷阱:NumLock,CapsLock和所有都被视为修饰符。

你有两个选择:

  • 你叫XGrabKey()多次,一次为您感兴趣的各组合的明确
  • 你叫XGrabKey()AnyModifier和使用event.xkey.state检查修饰符是否如你所料。

头文件<X.h>定义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键通过尝试,我不知道这是不是在所有机器/配置/版本/操作系统有效。

在你的情况下,你可能想要确保ShiftMask | CtrlMask已设置,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)) 
     // ... 
} 
+2

值'128'对应于我系统上的__ISO_Level3_Shift__。 – 2016-11-14 03:01:38