[ACCEPTED]-Global Hotkey with X11/Xlib-xlib

Accepted answer
Score: 25

Your program works here. My guess is you 4 have another modifier active, such as NumLock. GrabKey 3 only works on the exact modifier mask.

For example 2 here is some (GPL) code from metacity window 1 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.

              "%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)

      if (meta_is_debugging ())
        meta_error_trap_push_with_return (display);
      if (grab)
        XGrabKey (display->xdisplay, keycode,
                  modmask | ignored_mask,
                  GrabModeAsync, GrabModeSync);
        XUngrabKey (display->xdisplay, keycode,
                    modmask | ignored_mask,

      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);
                meta_topic (META_DEBUG_KEYBINDINGS,
                            "Failed to grab key %s with modifiers %x\n",
                            keysym_name (keysym), modmask | ignored_mask);


  meta_error_trap_pop (display, FALSE);
Score: 14

With your mask ControlMask | ShiftMask you will not get the key 12 if another modifier key is held. This sounds 11 okay in the first place, but there's a pitfall: NumLock, CapsLock and 10 alike all are treated as modifiers, too.

You 9 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 8 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 7 out about the ModNMask keys by trying and I do not 6 know if this is valid on all machines / configurations 5 / versions / operating systems.

In your case, you 4 probably want to make sure that ShiftMask | CtrlMask is set, Mod1Mask | Mod4Mask are 3 clear, and the others to be ignored.

I'd 2 do this to setup the key grab:

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

And this to 1 check whether the right modifiers are set:

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

If you're using/targeting gtk on X11, there's 3 a C library with a much simpler interface:


Includes 2 Python, Lua and Vala bindings. (Also mentioned 1 here.)

More Related questions