Computer keyboards were designed with historical baggage and for entirely different workflows than we use today and with very little regard for usability. Ergonomic keyboards are great and I personally use a 42-key Corne keyboard with my desktop and that’s what got me to learn to fully touch type and significantly aleviated shoulder stiffness. But what if I could have a similar experience on a laptop, well with Kanata keyboard remapping I can get some of the important pieces. Kanata is a lot more powerful than what I’ll describe here but this should set someone up enough to dive deeper into customizing.
Disclaimer
By the nature of keyboard re-mapping, you’re essentially running a key-logger. So please use this based on your personal risk profile, as the software will process every keystroke, like your passwords. As of the time of writing this guide, March 2024, I personally believe this software is safe to run. This isn’t meant to scare anyone but it’s meant to inform your consent.
Personal Background / Motivation
I didn’t learn to type at all until I was in tenth grade, due to lack of opportunities. So when we finally got a computer and started attending a school that required submitting typed homework, I had to learn in a hurry. But the real motivator was being able to chat with friends on ICQ1 and MSN Messenger. I was so horrid at typing that instead of SHIFTing to capitalize I would just leave CAPS LOCK on until my friend asked why I was yelling, I had to idea you could SHOUT with text. So I evolved an excellent 7 finger typing style that got up to 70+ words per minute on good days. Switching to the Corne meant learning split ergo key layout along-side proper 10 finger touch typing. But once I got used to that, anything else felt so clunky, especially typing on a laptop keyboard. The biggest things I missed were home row mods, layer switching with my thumbs so I could use the home row for more functions (primarily arrow key navigation with h j k l
), and left-thumb space
and right thumb backspace
, enter Kanata.
Intended audience
Apparently I’m writing guides for very niche audiences, a likely audience of one, perhaps. This particular post is for anyone that is interested in non-standard mappings for their keyboard but slanted more towards those who want to get cross-platform QMK-like functionality with any standard keyboard. Running the application will be geared towards Linux for now, since that’s my primary operating system but I’ll link to instructions for other OSes (since cross-platform is a desired feature for me, no lock-ins ever!).2
Terminology basics
There are some potentially confusing terms so I’ll try to capture those here:
- Input: this is an overloaded term to mean both the input (key presses), as well as the device (keyboard), and the operating system mapping of the device to a file (especially in Linux since everything is a file in Unix and friends land).
- Process: this is the actual Kanata application that is running and capturing your keystrokes from input (all three meanings of input) changing them based on your config before the Operating System “sees” the keystroke.
- Config: the customization that you define for Kanata to do the mapping from the physical keys being pressed to what you what you want to happen.
Installation
This is a potential can of worms and very dependent on your operating system, skill-level, and preferences. So here’s a way to do it and it’s definitely not the best way since it won’t automatically update the software.3
I recommend making a folder in your .local
directory to store the executable that can be downloaded from the releases page. Make sure the executable is named kanata
|
|
I wouldn’t advice adding the directory to your path, but explicit call Kanata with a full path. During the initial configuration and testing it would be best to just run the application directly, once you’re happy with the original layout (you’ll absolutely be tweaking stuff later) then we’ll write a service to automatically run it.
Permissions
In order for Kanata to run, it needs to be able to read the keyboard input before any other process does. Since this is a security concern the process needs to be run as root (administrator access level) to read input directly. However, that means the process would have root access to everything, which is also not a good idea.
So we’ll follow the principle of least privillege. One way to do that is to create groups and give each group just a specific permission and if an user needs to do a few specific things then that user can be added to those specific groups and get one permission from each specific group.
The documentation in the Kanata covers how to set this up on Linux, but I’ll include commands and commentary here.
- Create the specific group that will only have permission to read input devices
uinput
- Add our user to the
input
anduinput
groups - Define the rules for the group
uinput
by creating a rules file - Reload the devices with the new permission in place
- Reload the drivers
|
|
Configuration
Kanata has many different ways of picking up which configuration file to use4. The configuration guide is exhaustive and a great resource but it can also be intimidating so here’s a getting started overview.
Here we’ll stick with the default method of creating a file called kanata.kbd
in the ~/.config/kanata/
directory. The minimal.kbd is a good place to start to see how things work. The basic premise is that there are different sections (explained below) all of which follow the structure:
|
|
defcfg
This section stores the “global” options that applies to all of Kanata. I want Kanata to process every key pressed whether I explicitly told it to remap it or not. And I want it to show me what layer (the current map) it’s on when I press a key to change the layer. We’ll want to set this to no later on after we’ve finalized our mapping to make Kanata run faster.
|
|
defsrc
This section can only appear once in the configuration, it tells Kanata which source keys it should expect to map to other things. There’s no specific reason for which keys appear on what line, I have it organized it the way it appears on my laptop keyboard from top left to right, just for visual ease. You can find a list of all keys in the repo.
|
|
deflayer
You can define many layers and activate them by pressing keys you define. I’m just defining two layers: the always active layer which means keys that I want to permanently remap to do something different and a second layer that only activates when I hold down the caps lock
, which I’m calling cap-mod, you can pick any key and call the layer anything you want.
Note that the keys that are being remapped need to be in the same order as the source layer above. Also there are _
, these are called transparent keys. As in their mapping isn’t changed and passed through transparently. The @
denotes an alias, discussed a bit later.
In this example, the default layer is changing the functionality of all the keys, except g
, h
, and spc
because they’re transparent. I’m also “permanently” changing the left-alt to be escape
and the right-alt to be backspace
. The cap-mod layer changes h
j
k
l
to become the arrow keys.5
|
|
defvar
Kanata lets you fine tune behavior quite a bit by specifying things like how long a key should be pressed for it to be counted as “held”. While you can type in those values (in milliseconds) each time, it’s easier to define them as a variable in one place and refer to throughout.
|
|
defalias
This is where we define all the aliases (@
) we used in the default layer. An alias take the form of:
name-of-alias-without-@sign (type-of-functionality options-for-that-function multiple-options-are-space-separated)
I’m using three types of functionality, what Kanata calls Actions to change the functionality of the esc,
`,
and the home-row keys to act as home-row modifiers.
- tap-hold: This let’s us define what happens when we tap a key vs. hold a key. Let’s take
@a
for example, there are two a’s in there a¹ and a², I’ll explain the difference:a¹ (tap-hold $tap-time $hold-time a² lmet)
a¹
is the name of the alias, it could be anything; like alpha.tap-hold
is the name of the action which takes 4 options.$tap-time
the number of milliseconds the key can be pressed while still being considered a single press.$hold-time
the number of milliseconds for which the key must remain pressed for it count as a hold.a²
is the key code we want Kanata to use when tapped, so this has to bea
if we want to type the letter a.lmet
is the key code we want Kanata to use when the key is held, in this case left-meta (Windows or Mac logo key).
- tap-hold-press: Similar to tap-hold but helps managing pressing timing situations better, especially for
caps lock
which I use as a layer switcher to activate thecap-mod
layer for the movement keys. - caps-word: This is an excellent function that lets you type CAPITALIZED_WORDS and automatically turns off the CAPS if it’s not a letter or an underscore. Useful for typing environment variables which are typically written in that form.
|
|
Putting the config together
Here's the full kanata.kbd file that you can save as ~/.config/kanata/kanata.kbd
if you want to try my config (click arrow to expand).
|
|
Testing Kanata
We can finally give it a spin. It’s best to just run Kanata in a terminal window and see the output to make sure it’s doing what you expect. You can specify the full path and the full path to the config to take away any weird path issues:
|
|
If there are any errors in the config or the permissions, Kanata gives really good/descriptive errors:
Continue testing until the layout feels comfortable. Once you’re ready, set log-layer-changes false
and now we’re ready to run it as a service.
Running Kanata as a service
I’ve discussed running something as a service in another post, so some of the why’s and details are there. For Kanata, create a file called kanata.service
and place it in ~/.config/systemd/user/
:
|
|
To enable the service, so it starts every time you are logged in, run:
|
|
If you need to make changes to your config you have to restart the service or you can setup live re-loading.
|
|
Hope this gets you further in your system crafting and ergonomic computing journey!
-
Apparently ICQ still exists, I fully expected it to be a historical footnote. Looks like it has had an interesting and somewhat checkered past. ↩︎
-
There are other key mapping software available as discussed in the Kanata repo but I wanted to stick with the QMK familiarity in terms of terminology, platform independence, and even easier key-mapping. ↩︎
-
Not automatically updating is generally not a good idea, but unless this package makes it into your distribution’s maintained repo it might be a good idea to just manually update. This might mitigate any malicious repo takeover since you’re literally running a key-logger. ↩︎
-
Running Kanata with the
--cfg
option would be a good way to test out a few different configurations by supplying a different file:1
~/.local/share/bin/kanata --cfg ~/dotfiles/kanata/example1.cfg
Kanata also provides the ability to load multiple configuration files and switch at run-time. ↩︎
-
g
is never remapped but since the entire “home-row” is being mapped it’s easier to leaveg
in there to make visually matching up the config easier. ↩︎