[xmonad] Capturing modkey release

Matthew Hague matthewhague at zoho.com
Tue Jul 3 11:06:39 CEST 2012

>    This is because there are no grabs established on the bare modifiers, nor
>    is there a generic "send all key events" mask in place, so X11 doesn't
>    bother to send events for them. A If it sent an event for every little
>    thing that happened, unsolicited, most programs would be busy-looping on
>    noise events instead of doing useful work; as such, you should always
>    remember to *request* the events you want.
>    So in this case you probably want to use grabKey (aka XGrabKey()) to
>    select for interest in the modifier key by itself; the handleEventHook
>    handler should ungrab the keyboard (you don't *really* want xmonad to
>    seize ownership of the keyboard every time you touch the key), do whatever
>    you want to do, and pass the event on.
>    (This is largely what the other suggestion does, once you poke at the
>    code.)

Bearing all this in mind, and stealing liberally from CycleWindows (suggested
by wagnerdm, though it doesn't quite do what i wanted), i finally settled on
this arrangement (modulo a bunch of conditionals on when i want it to switch to

For the key bindings:

    , ((modm, xK_j), changeFocus W.focusDown)
    , ((modm, xK_k), changeFocus W.focusUp  )

For the capture:

    changeFocus f = do
        windows f

    setModReleaseCatch :: X ()
    setModReleaseCatch = do
        XConf { theRoot = root, display = disp } <- ask 
        io $ grabKeyboard disp root False grabModeAsync grabModeAsync currentTime
        return ()

    onModRelease = do
          XConf { display = disp, theRoot = root } <- ask
          io $ ungrabKeyboard disp currentTime
          windows W.shiftMaster
          return (All True)

Plus an adjustment to event hooks:

    modKeyEvents :: Event -> X All
    modKeyEvents (KeyEvent {ev_event_type = t, ev_keycode = code}) 
      | (t == keyRelease) && (code == modKeyCode) = onModRelease
    myEventHook = modKeyEvents

This isn't super elegant, being spread around my config like that, and grabbing the whole keyboard, but there are reasons for this:

1) Using the following instead of grabKeyboard:

       io $ grabKey disp modkc anyModifier root False grabModeAsync grabModeAsync
       io $ ungrabKey disp modkc anyModifier root

   had the problem that i didn't get the next release of the modkey, but
   the second release.  That is: i pressed mod4, pressed and released j,
   released mod4, got no notification, pressed mod4 again, released it
   again, got notified.

2) Putting everything together, a-la the implementation of cycleStacks' in


   meant that the whole keyboard had to be intercepted while the window
   selection was taking place -- so new implementations for mod4+j, mod4+k had
   to be provided, plus bindings for any other keys you might want to still
   use.  I decided to do it my slightly messy way and keep all the xmonad

Thanks for feedback,


More information about the xmonad mailing list