
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 master): 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 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 CycleWindows: http://xmonad.org/xmonad-docs/xmonad-contrib/src/XMonad-Actions-CycleWindows... 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 bindings. Thanks for feedback, Matt