Abstract
Key re-mapping is a very common practice for a variety of computer users. For anything from swapping two keys to be in a more optimal place on the keyboard, to completely changing the keyboard layout to something like Colemak. Additionally, some keyboards require the use of different layers to provide all of the functionality that a standard keyboard would provide. Layers become more necessary as the keyboards get smaller, for example many of these keyboards would need multiple layers to be useful for most people. Generally, these re-mappings and layers are handled by the keyboard in firmware, or is handled by the host operating system. This blog post will be going over one of the operating system based solutions for this problem, kMonad.
What is KMonad
KMonad is a tool that allows for remapping keys on one or more keyboards on the system with the same or different configurations. From the project’s GitHub page:
KMonad offers advanced customization features such as layers, multi-tap, tap-hold, and much more. These features are usually available at the hardware level on the QMK-firmware enabled keyboard. However, KMonad allows you to enjoy such features in virtually any keyboard by low-level system manipulations.
Setting Up
Kmonad can be installed via their release page, just
download the binary and put it in /usr/local/bin
on a Linux
system. Things get slightly more difficult (in my opinion) in the world
of Microsoft Windows, but ultimately adding the exe to the path is
all that needs to occur. From there, the application can be run with the
file of the keyboard layout as an argument…at least in theory. I did
this without major issues in Void Linux, simply add yourself to the
input
group if not already:
sudo usermod -aG input ${USER}
Logout and log back in for the changes to take effect; can confirm
group membership by running groups
in a terminal session as
your user. From there we just need to start the configuration of the
keyboard layout file. I keep mind in ~/.config/kmonad/
, but
the location doesn’t really matter if you would prefer somewhere
else.
(defcfg
;; For Linux
input (device-file "/dev/input/by-id/usb-Razer_Razer_Huntsman_Mini_00000000001A-event-kbd")
output (uinput-sink "My KMonad output")
;; Comment this is you want unhandled events not to be emitted
fallthrough true
;; Set this to false to disable any command-execution in KMonad
allow-cmd true
)
I also setup kmonad on Slackware Linux with slightly more challenges;
most prominently setting up permissions for /dev/uinput
; I
accomplished that by setting up a udev
rule:
KERNEL=="uinput", MODE="0660", GROUP="input", OPTIONS+="static_node=uinput"
Upon rebooting the system, /dev/uinput
will then be
owned by the input
group and allow anyone in the
input
group to use kmonad. That is not something I had to
do on my Void Linux machine, but might be helpful to know in the event
that it is necessary.
Creating Keyboard Layout
Now for the part that is actually fun, creating the keyboard layout. The first step to set a custom layout is to define the keys that your keyboard will be sending to the operating system when they are pressed. Below I am using the ten keyless layout template provided by the project as an example:
(defsrc
esc f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12
grv 1 2 3 4 5 6 7 8 9 0 - = bspc ins home pgup
tab q w e r t y u i o p [ ] \ del end pgdn
caps a s d f g h j k l ; ' ret
lsft z x c v b n m , . / rsft up
lctl lmet lalt spc ralt rmet cmp rctl left down rght
)
The project also provides several other keyboard templates including:
- Apple
- Atreus
- Freestyle2
- ThinkPad T430
- ThinkPad x220
- ISO and ANSI 100%
- ISO and ANSI ten keyless
- ISO and ANSI 60%
You can obviously create a new template if none of those work for
you; the only really syntax requirements are that the keyboard layout is
between the defsrc
and the closing parenthesis, each key is
separated by spaces, and each row is on its own row in the layout.
Making an attempt to make the keyboard layout look like the physical
keyboard is not a requirement, but can make working with it a bit
easier.
Once the defsrc
is made, we then need to create the
layers that we want on the keyboard; there is no limit to the quantity
of layers on the keyboard, but the layout does have to match the
defsrc
. The way I usually make a new layer is just to copy
the defsrc
and change it from defsrc
to
deflayer
followed by the layer name. This might be an
example of a basic first layer with a modification:
(deflayer qwerty
esc f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12
grv 1 2 3 4 5 6 7 8 9 0 - = bspc ins home pgup
tab q w e r t y u i o p [ ] \ del end pgdn
esc a s d f g h j k l ; ' ret
lsft z x c v b n m , . / rsft up
lctl lmet lalt spc ralt rmet cmp rctl left down rght
)
As you can see, the caps lock key was replaced with escape in that layer. Even with just this basic functionality, it can already be used to entirely change the keyboard layout from something like qwerty to dvorak or colmak. If the goal was to create a layer called ‘colmak’ with a colmak keyboard layout, that might look as follows:
(deflayer colmak
esc f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12
grv 1 2 3 4 5 6 7 8 9 0 - = bspc ins home pgup
tab q w f p g j l u y ; [ ] \ del end pgdn
caps a r s t d h n e i o ' ret
lsft z x c v b k m , . / rsft up
lctl lmet lalt spc ralt rmet cmp rctl left down rght
)
Kmonad will automatically pick the first deflayer
statement as the default when it is started; to be able to switch layers
and have more complex functionality than switching key behavior, a
defalias
statement will need to be made.
Defalias
This section is where the magic of kmonad really comes into play. Keys can be setup to have different functionality depending on whether the key was pressed or held, or have different functionality depending on how many times the key was pressed. I am just going to go over the basics for things I have implemented with my keyboard; there is a tutorial layout that goes over each of the functions in depth. Use that for a more complete reference for what is possible with the tool as well as how to go about accomplishing it.
The two main functions I use are the ‘layer-switch’ and the ‘tap-hold’ functions. Layer-switch does basically what it sounds like, simply switching to a different layer. The main layer I use this with is to re-implement a numpad on my keyboard that does not already have one. The actual layout for that isn’t particularly important, but the defalias would look something like this:
(defalias
default (layer-switch qwerty)
numlayer (layer-switch numpad)
num (tap-hold 300 @numlayer ralt)
cap (tap-hold 300 esc caps)
)
As stated previously, the ‘switch-layer’ function is simply just to
switch to a different layer defined in a ‘deflayer’ statement. So when
the key bound to that function is pressed, the new layer will be
activated. The ‘tap-hold’ function is a bit more interesting; when the
tap-hold function is written, it is given a time in milliseconds (300
has been a good timing for me personally), then the behavior on a tap,
then finally the behavior when the button is held for more than the
timing. Each of the functions are given a name that can be bound to a
key. For example, in the above defalias statement, binding the ‘cap’
function (that acts like escape on a press but caps lock on hold) could
be defined on a key with @cap
. You can also see that we can
combine functions together in multiple functions to get more complex
behavior; I have a ‘layer-switch’ function setup that is used in a
‘tap-hold’ function so that if the key is pressed it will switch to the
numpad layer, but if it is held, it will act as a right alt key.
Again, I am using just the most basic functionality of this tool and it has completely changed how I interact with my keyboard. Kmonad is capable of doing much, much more than I am describing here.
Outstanding Challenges
While I do like this tool, and I am certainly going to continue to use it, I have had two minor challenges with it. The first one is that the key remapping is not always detected by software correctly. I have only had this happen in games, and it very well could be something that Proton is doing rather than kmonad, but it has certainly happened where I had to force quit a game I was playing because I couldn’t open the pause menu. This can easily be worked around by having a “gaming” layer that is mostly the default layout with one unimportant key remapped to switch to the other layers.
The second challenge is that I have not found a good way to run it on FreeBSD yet; it is software that might run in the Linuxulator, but it did not compile naively. This is something that I have a hard time griping at too hard though. It would be nice to have FreeBSD support, but the devs certainly are not bound to my whims. And ultimately it is open source software, if I wanted FreeBSD support bad enough, I could make a PR for it.
Closing Thoughts
Kmonad is an overall amazing tool for remapping keyboards that is
much more powerful than something like setxkbmap
, which is
what I was using previously to rebind my caps lock key to escape. This
tool allows me to do quite a bit more, also making using small keyboards
much more pleasant. Normally I would put a ‘more resources’ section
here, but the documentation in the projects GitHub page is quite good
and explains things fairly well, so I would recommend trying that out
before doing much digging around online.