Blogg

Här finns tekniska artiklar, presentationer och nyheter om arkitektur och systemutveckling. Håll dig uppdaterad, följ oss på LinkedIn

Callista medarbetare Henrik Starefors

Year of the homerow mods

// Henrik Starefors

Today i will share my initial experinces with adding modifers to my keyboards homerow keys. Aka Homerow Mods.

Intro

Hello and welcome to the year 20²+25², which might turn out to be the year of the home row mods?

Banner

During the holidays, I did not continue on my NixOS project from the last NixOS Post, but instead, I found a new shiny gem of a project to tinker with: Homerow mods.

So what are Homerow mods?

For a more thorough explanation, I invite you to read this excellent guide and inspiration for this post, but the TLDR version can be summed up:

The goal is to move the modifier keys (Ctrl, Alt/Option, Meta/Command, and Shift) closer to the fingers’ natural resting position when touch typing. This will make for a more comfortable and quicker typing, editing, and keyboard navigation experience.

For me, this is more about comfort than speed; since I have been genetically “blessed” with short, stubby fingers, my top priority is avoiding twisting and stretching my fingers into a mix of a failed gang sign and a nosferatu-like claw grip when sending some convoluted key-combo.

But how can this be achieved? Do we have to switch the position of the modifier keys and home row keys?

Not at all. Today’s implementation will use either software or firmware to add a “tap & hold” pattern on the keyboard, doubling the functionality of specific keys.

One action is tapping the key, and a secondary action is when the key is held down.

One such mod, which I have been using for the last couple of months, is modifying the Capslock key to function as an Esc key when tapped and a Control modifier when held down.

This simple modification adds a nice, comfy combo of actions closer to the home row fingers: a quick flick with the pinky, and both Esc and Ctrl are right there. Since this overrides just the Capslock key, I see this as a lossless modification and an absolute win.

Control-Escape is nifty, but let’s return to the home row again.


layout

Now that we know what to do, let’s examine the “where”: In which order should we place our mods?

There are four main configurations to look into, and to simply a bit I will abbreviate the modifiers:

  • Control: C
  • Shift: S
  • Alt/Option: A
  • Meta/Command: M


SCMA

The simplest option is to place the modifier in their standard order.

As the name suggests, the order here would be: ‘a’ + Shift ‘s’ + Control ‘d’ + Meta ‘f’ + Alt But how do we type a capital a or Ctrl + S to save a document? We just mirror the setup to the right-hand side, so typing capital letters with the right uses the left-handed shift, and right-hand capitals use the left-handed shift instead. With mirroring, this layout would look like the following:

tap A S D F G H J K L ;
hold Shift Control Meta Alt - - Alt Meta Control Shift

It is easy to map spatially, but most heavy lifting uses the pinky, which is not ideal.


MACS

If you instead take into account how frequently the modifiers are used, making sure that the strong, steady index finger does most of the work, the setup would look like this:

tap A S D F G H J K L ;
hold Meta Alt Control Shift - - Shift Control Alt Meta

This moves the modifiers around but emphasizes using the index finger for the most common modifiers in a Linux environment.


MASC

In addition to the previous layout, the MASC layout switches the order of the Control and Shift keys around:

tap A S D F G H J K L ;
hold Meta Alt Shift Control - - Control Shift Alt Meta

This layout allows easier access to capitalized letters around the index finger by holding down the shift with your middle finger, leaving the index free to wander. It also provides for easy modifier combinations such as Control+Shift and Alt+Shift.


CAMS

Finally, the layout I have chosen to start with is CAMS ( or CAGS as it’s called in the original guide)

tap A S D F G H J K L ;
hold Control Alt Meta Shift - - Shift Meta Alt Control

This layout ranks the modifiers from a MacOS point of view, and since most of my coding is done on a Mac nowadays, this is the more sensible starting position for me.


implementation

The preamble is complete, and we know what to do: Add tap-hold modifiers to the home row key in a CAMS layout. Let’s implement.

I have two solutions up my sleeves to cover my everyday use cases.

Firmware (QMK)

First is the home office, where I can’t help being contrarian and have been using a split keyboard for many years.

Currently, I’m using one called Moonlander from ZSA.

Keyboard

It supports the open-source keyboard firmware QMK, allowing for custom configuration, but it also has its own GUI, making the configuration process even simpler.

My current layout consists of three layers I can toggle or switch between, and can be found here

Layer 0: Base

Base Layer

Some quick notes about this one:

  • Due to my generally short fingers, I have removed and moved around some keys that otherwise require too much finger gymnastics to reach for me.

  • Removed the innermost column of keys since I deemed them out of reach.

  • The outermost thumb cluster keys might as well be in a different timezone from my thumbs, so they are relegated to seldom if ever, used modifier combos.

  • The Escape key has been moved from the top corner to be located next to the pinky on the left for quick access, tap-and-hold style.

  • The tab key is in the left corner and also available in the thumb cluster; I’m trying to use the left thumb more, but alt-tabbing between applications with my thumb and ring finger is a hard habit to break, so I’m leaving both options open.

  • Even with home row mods active, I’m keeping the original placement of modifiers intact as a fallback solution and the default layout for playing games. In contrast, a WASD-focused layout places them perfectly for my hands.

Layer 1: Utils

Utils Layer

From the base layer, pressing the topmost key on the left thumb cluster activates a “one-shot” layer switch to this utility layer. A one-shot switch toggles the layer only for one key-press and then reverts to the base layer once a key has been pressed. I mostly use it for the F1-12 keys, occasional numpad typing, and changing the keyboard’s background lights. This layer even has a Music mode key, allowing the keyboard to play notes instead of sending keys when pressed, because why not?

Layer 2: Code

Code Layer

Here, we have the home row layer, which can be toggled from the base layer using the right thumb-cluster.

Most of the keys are “transparent,” meaning they work just like the base layer, but the home row has the added functionality of tap-and-hold actions. I am currently testing the CAMS layout ( Control, Alt/Option, Meta/Command, Shift ).

For now, the firmware is set up with a 250ms delay or “tapping-term” to activate the hold action, so keys pressed and released before this timer expires will send the tap action instead of the hold action. In the future, I will probably reduce this timeout to around 100-150ms, if not even lower, depending on how easily a misclick might happen.

I have also edited some options to prefer the tapping action during “tap-dancing.” If you roll your fingers between keys, such as when typing “fast”…Fast, the firmware should err on the side of the tap action at the cost of a slightly slower response time.

You can also see I’m experimenting with moving the Esc key down near my left thumb. It’s still in the early stages, and I’m not entirely sold on it yet, so I will probably revert this in the future.

Software (Kanata)

So, QMK solves the problem for my custom mechanical keyboard, but what if I’m traveling with only the laptop’s built-in keyboard? Or if I am at the office and only bring my Apple-approved, minimalistic magic keyboard instead of the Moonlander chunk?

Here, we move away from firmware and find our solution in the software world. In this case, I landed on Kanata, with inspiration from this video

Kanata is an open-source project that allows you to remap keyboard input using software instead of modifying the hardware or firmware of a specific keyboard. This allows you to use any physical keyboard while still reaping the benefits of custom configurations.

Kanata then sits between the physical and virtual keyboard, intercepting input and remapping it according to our configuration. This allows us to add virtual layers, similar to QMK’s firmware layers, directly to the OS instead of the keyboards connected to the machine.

To get up and running, all we have to do is install Kanata itself, either using package managers like

Homebrew

brew install kanata

Nix

environment.systemPackages = [
    pkgs.kanata
  ];

or directly from Cargo

cargo install kanata

Since I’m on MacOS, A virtual HID device is also required to be installed, here provided by the Karabiner project

With that out of the way, all we need to do now is add some configuration. My Kanata configuration can be found in a single Kanata.kbd file, which is written using Lisp-like syntax.

Kanata.kbd

  ;; home row-mods

  ;; un-mapped keys behave as normally
  (defcfg
    process-unmapped-keys yes
  )

  ;; define the keys to remap
  (defsrc
   caps a s d f j k l ;
  )

  ;; define values for tap time and hold time
  (defvar
    tap-time 150
    hold-time 200
  )

  ;; alias definitions
  (defalias
    escctrl (tap-hold $tap-time $hold-time esc lctl)
    a (tap-hold $tap-time $hold-time a lctrl)
    s (tap-hold $tap-time $hold-time s lalt)
    d (tap-hold $tap-time $hold-time d lmet)
    f (tap-hold $tap-time $hold-time f lsft)
    j (tap-hold $tap-time $hold-time j rsft)
    k (tap-hold $tap-time $hold-time k rmet)
    l (tap-hold $tap-time $hold-time l ralt)
    ; (tap-hold $tap-time $hold-time ; rctrl)
  )

  (deflayer base
    @escctrl @a @s @d @f @j @k @k @l @;
  )

This configuration provides a single layer and adds our home row mods keys, with the added bonus of Esc+control on the Capslock key.

The variable defined in the config provides some customization similar to QMK.

“tap-time” is the timeout period where a quick tap => release => hold of key results in the tap action being held down instead of the alternative modifier in our case, so a “double-click” on the ‘a’ key will write out “aaaaaaaa” instead of acting as Control, neat.

“hold-time” is required before the hold action activates to avoid sending accidental modifier commands.

With this setup, we only need to ensure Kanata starts when logging in. We are good to go, so either create a new list entry for Kanata and add it to your launchDeamons, or better yet, if you happened to have Nix installed, you could simply add the Kanata service to your config:

services.kanata.enable = true;

Initial impressions

So, how is it using home row mods? Is this the secret to unlocking your inner 10x Engineer? Am I suddenly typing and navigating at the speed of thought, smattering away at 300+ words per minute? Not quite, at least not yet…

I’m barely two weeks into this experiment, so the experience has been mainly fat-finger, fumbling, undoing, and redoing—even more so than usual. But it’s quickly growing on me; it might not be faster right now, but I’m already finding it more comfortable.

There are no more finger acrobatics for navigation and no more contortionist yoga poses for the hand when doing an awkward triple key combo. All I have to do now is correctly map the modifiers in my head until it is second nature, and that gets easier every day.

Sounds great right? However, one caveat, one small spanner in the works, might halt the entire machinery: input delay.

Utils Layer

Since neither firmware nor software can read our minds, the keyboard has to wait for the key release before determining which action you want to perform instead of the snappier “action on key-press” that is the default.

The difference is not massive, but it feels like a slight input lag, only for the home row keys.

The configuration I have for QMK does add some extra input delay. I need to tweak the settings in the coming weeks, reducing tap/hold timings and maybe trying to rewrite my muscle memory to be more “bouncy” when typing, quickly tapping the key and lifting the fingers right away.

Letting go of the key faster would improve things. However, there is still no way around the keyboard’s having to wait for a key release to determine which action to take.

But as I’m typing this, interesting developments and experiments are happening in the Kanata Repository, in this Discussion testing is ongoing to find an approach that could disable the home row mods during typing, something to definitely keep an eye on.

I have also been eyeing even more additions to my config; combo keys that send commands when multiple keys are pressed simultaneously do sound intriguing: “J+I+L” sending an Enter command feels promising, but one step at a time, for now, I will stick to getting used to the home row mods.

But that’s all I have to say for now. I will continue experimenting, tweaking, fiddling, and exploring, and hopefully, I will find a home for my latest row of configurations.

Best wishes and a happy new year of 1³+2³+3³+4³+5³+6³+7³+8³+9³

//Henrik Starefors

Tack för att du läser Callistas blogg.
Hjälp oss att nå ut med information genom att dela nyheter och artiklar i ditt nätverk.

Kommentarer