Writing keyboard shortcuts for XMonad in native Haskell is straightforward. Yet there is an even shorter, “EZ” notation.
In this tutorial we go over the relevant ways to write EZ shortcuts for XMonad:
- how to write EZ shortcuts and add them to the
keys
setting in XMonad’s main datastructureXConfig
. ➡ - how to check if our shortcuts are valid. ➡
Emacs “EZ” shortcut notation
A native Haskell shortcut looks as follows:
.|. shiftMask, xK_Return), spawn $ terminal conf) ((modMask
This shortcut opens a new terminal when we press Mod + Shift + Enter at the same time.
It’s simply a pair of a key combination and an action:
<key-combination>, <action>) (
Since this is normal Haskell, it can be checked by XMonad and doesn’t compile if we make a syntax error.
However, there is an Emacs-like notation with plain strings, called “EZ”, that is nicer to read and write
"M-S-<Enter>", spawn $ terminal conf) (
but cannot be checked (that easily) by XMonad. ➡ how to check
In this notation the upper case "M"
represents the modMask
key, the upper case "S"
the shift key, and normal keys like letters and digits are written in lower case.
Key | Note |
---|---|
"M"
|
Standard Mod key. |
"C"
|
The Ctrl key. |
"S"
|
The Shift key. |
"M1"-"M5"
|
The keyboard modifier keys. ➡ Mod1 to Mod5 |
"<Enter>"
|
The Enter key. |
There’s a list of all the EZ key codes ➡ Documentation which includes other special keys like volume up/down, mute, display brightness etc. as well as normal keys.
More: Useful shortcut examples
More: Haskell native shortcut notation
More: What are mod-keys?
More: How to change XMonad’s modkey
See: EZ documentation
See: The best editor: (Doom) Emacs
Add our own shortcuts
To add our own shortcuts we first have to define them and then add them to our XConfig
value:
import XMonad.EZConfig (additionalKeysP)
-- myKeys :: XConfig -> List
=
myKeys conf "M-f", spawn "firefox")
[ ("M-a s", spawn "steam")
, ("M-a k", spawn "keypassxc")
, (
]
-- myConfig :: XConfig
-- Set everything up except keys
= def
myConfig -- all other settings
{ ..
= mod4Mask
, modMask ..
}
-- Now add our keys
= myConfig `additionalKeysP` (myKeys myConfig) myConfig'
import
- Load values from other Haskell packages. ➡ How to import
myKeys
- Custom name for our function that takes an
XConfig
value as input and returns a list with our custom shortcuts. ➡ Haskell function syntax conf
- The single argument to the
myKeys
function. [ .. , .. ]
- A list in Haskell. Elements are separated by comma.
"M-f"
- A key combination for Mod + f at the same time.
"M-a s"
- A key combination for an Emacs-like “key sequence”: First press Mod + a at the same time, release, then press only s.
spawn
- An function that runs a terminal command, e.g.
spawn "firefox"
launches a Firefox browser. ➡ documentation def
- XMonad variable that holds a default
XConfig
value configured by the XMonad creators. ➡ source code myConfig
- Custom variable for our configured
XConfig
value but without our shortcuts. def { modMask = mod4Mask }
- Create a copy of
def
containing our modifications. We replace the oldmodMask
value withmod4Mask
, which represents the Win key. ➡ Override notation myConfig'
- A slight variant of
myConfig
that also contains our custom shortcuts. The single quote'
at the end (pronounced “prime” in Math and Haskell) makes it a completely different name to XMonad, but we use it to express that it’s just a small variation ofmyConfig
(without the single quote). In Haskell it is common to add'
to a name of a value that is just a small variation of another value, because inventing new good names is hard.
`additionalKeysP`
- A helper function (in infix notation) to converts our EZ shortcuts into native ones and adds them to the built-in shortcuts. It takes two arguments, an
XConfig
value and a list of shortcuts, and creates a newXConfig
value. ➡ Function infix notation
➡ Documentation
A specialty of this notation is that we can define “key sequences” like "M-a s"
and "M-a k"
. We first press Mod + a simulateneously, release, then press s. This allows us to group related XMonad actions under a common key combination prefix like "M-a"
with a mnemonic “a for apps”.
More: In-depth XMonad (Haskell native) shortcuts
More: Useful shortcut examples
More: How to change XMonad’s modkey
See: EZ documentation
See: List of all EZ keys
Check EZ keymaps for validity
Key combinations like "M-f"
are written as plain strings, so the Haskell compiler can’t check if our string represents a real key combination. As a workaround there is a helper function checkKeymap
that we can add to our startup hooks at the top of all the others:
-- myKeys = ...
= do
myStartupHook return ()
checkKeymap myConfig' (myKeys myConfig')..
= def
myConfig = myStartupHook
{ startupHook -- other settings
}
-- myConfig' = myConfig `additionalKeysP` (myKeys myConfig)
This hook shows an error window if we have a typo or accidently use a key combination twice. Startup hooks are actions that are performed at every (re)start of XMonad. These can be actions like starting background apps or in this case checking your key combinations for validity and warning us if not. You should add the return ()
line before checkKeymap
to avoid a possible infinite loop, because myStartupHook
depends on myConfig'
, which in turn depends on myStartupHook
.
More: Startup hooks
See: checkKeymap documentation