2010-10-27 97 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