Global Hotkey with X11/Xlib

后端 未结 3 1683
夕颜
夕颜 2020-11-28 04:18

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 m

相关标签:
3条回答
  • 2020-11-28 04:54

    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:

    • You call XGrabKey() multiple times, once for each explicit combination that you're interested in.
    • You call XGrabKey() with AnyModifier and use event.xkey.state to check whether the modifiers are as you expected.

    The header file <X.h> defines ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask and AnyModifier.

    The keys are:

    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 | ???
    

    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:

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

    And this to check whether the right modifiers are set:

    switch (ev.type)  {
    case KeyPress:
        if ((ev.xkey.state & (ShiftMask | CtrlMask | Mod1Mask | Mod4Mask)) == (ShiftMask | CtrlMask))
            // ...
    }
    
    0 讨论(0)
  • 2020-11-28 05:01

    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.)

    0 讨论(0)
  • 2020-11-28 05:05

    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

    /* 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);
    }
    
    0 讨论(0)
提交回复
热议问题