I'm using Xmonad and I have a quite long list of custom keyboard short cuts defined in my config.
I would like to add something like a catch all at the bottom of the config which locks my screen if anybody presses a key combination that isn't defined, so any Ctrl+*
or Alt+*
which isn't defined to do something else should just lock the screen.
Is there any good way to do that without having to list all of the currently undefined combos?
Best Answer
You should understand that it's not simply "lock on any unknown combo". You probably don't want to block things like Control-R that lets you reverse-search your shell's history, or Control-P that opens printing dialogue in your favourite office suite.
With that said, the cleanest way to achieve your goal is to redefine how keybindings are looked up in XMonad so that any "not founds" turn into "lock the screen". Unfortunatelly, XMonad doesn't provide such facilities to the user; you'll have to hack on the XMonad itself.
The next best thing you can do is generate a map of all valid key combos, strip it of ones you already have defined, and then bind all the remaining ones to "lock screen" command. Fortunatelly, this can all be automated.
I'll assume that you have your screen-locking command defined like that:
Key combinations consist of a mask and a key, which are all listed in
Graphics.X11.Types
.First, let's define a list of possible masks:
Here I assumed that you only want to block combos starting with Control and Alt. There are 8 masks, and they can be combined, so this line could be much more complicated. However, the more masks we define here, the more careful we should be when generating bindings—we don't want to accidentially block something important!
Okay, next stop is list of keys. These are listed in
Graphics.X11.Types
, too, and start withxK_
. They have typeKeySym
, but what they really are isWord64
. However, I advise not to go crazy and avoid writing something like[0 .. maxBound :: KeySym]
—this will result in a huge map that will consume a lot of memory.So instead, just look up the numbers of keys you want to cover and group those into small definitions. Here, for example, I cover the most common keys:
Now we're ready to define a list of keybindings:
This will generate a keybind definition for every possible combination of given masks and keys.
Now we have to apply these definitions to your config.
XMonad.Util.EZConfig
has a very usefuladditionalKeys
combinator that, given a config and a list of key binding definitions, will add the latter to the former, overwriting existing definitions if there's any clash. What we want is exactly the opposite: we want to applyfallbackKeys
in such a way that they fill only undefined places, leaving already defined keybinds as they are. To achieve that, we'll define another function:This is a direct copy-paste of
additionalKeys
, but the arguments toData.Map.union
there are swapped, resulting in the behaviour we want. (Seeunion
's documentation to understand how this works.)And now we can finally use all that. Somewhere in your
xmonad.hs
you have a line like this:Amend it as follows:
Recompile and restart XMonad, and enjoy your new settings!