KMonad and the power of infinite leader keys
Tags: emacs, linux, kmonad, tutorial
Published: 2021-08-06 20:32:32

First of all that was a title clickbait.
Title clickbaits are still legal in Mexico (I think).

Jokes aside, I will show you how every key in your keyboard can be a leader key.

Since most of the Emacs community are keyboard driven freaks, I hope you will see the potential in your workflow.


<a id="orga9f6b1b"></a>

## What is KMonad?

It is a program that lets you remap the keys of your keyboard.


<a id="org6678310"></a>

## Install KMonad

Download the executable from <https://github.com/kmonad/kmonad/releases>.

Put it somewhere your PATH enviroment variable points.

In my case I like to put executables in `$HOME/bin`.
So I add this line `export PATH="$HOME/bin:$PATH"` in the `.profile` file.

Then run the following commands.

    # Add self to the input and uinput groups
    sudo usermod -aG input $USER
    sudo groupadd uinput
    sudo usermod -aG uinput $USER
    
    echo 'KERNEL=="uinput", MODE="0660", GROUP="uinput", OPTIONS+="static_node=uinput"' | sudo tee /etc/udev/rules.d/90-uinput.rules
    
    # This seems to be needed because uinput isn't compiled as a loadable module these days.
    # See https://github.com/chrippa/ds4drv/issues/93#issuecomment-265300511
    echo uinput | sudo tee /etc/modules-load.d/uinput.conf

For more info check <https://github.com/kmonad/kmonad/issues/160#issuecomment-766121884>.


<a id="orgfd88775"></a>

## Create a KMonad configuration file

    mkdir -p ~/.config/kmonad
    touch ~/.config/kmonad/config.kbd


<a id="orge23ec56"></a>

## Add system information

On the top of `config.kbd` add the next.

    (defcfg
      input  (device-file "<path to your keyboard input>")
      output (uinput-sink "KMonad kbd"))

Go to `/dev/input/by-path/` or `/dev/input/by-id/` and look for any file ending in `kbd`.

I think if your keyboard is plugable, it should appear in `/dev/input/by-id/`
and your build-in laptop keyboard should appear in `/dev/input/by-path/`.

In my case I am using my build-in laptop keyboard. This is what I added in the configuration file. Yours should be different, modify it with your information.

    (defcfg
      input  (device-file "/dev/input/by-path/platform-i8042-serio-0-event-kbd")
      output (uinput-sink "KMonad kbd"))

`uinput-sink` will be the name given to the virtual keyboard that KMonad creates.
You can write anything in there.


<a id="org604120b"></a>

## Keyboard blueprint

Now we need to create the blueprint of our keyboard. The layouts that will create later will base of this blueprint.

This is the blueprint of my keyboard. Modify it as you need.

    (defsrc
      esc   f1   f2   f3   f4   f5   f6   f7   f8   f9   f10  f11   f12    pause  prnt  ins  del
      `     1    2    3    4    5    6    7    8    9    0    -     =      bspc              home
      tab   q    w    e    r    t    y    u    i    o    p    [     ]      ret               pgup
      caps  a    s    d    f    g    h    j    k    l    ;    '     \                        pgdn
      lsft  z    x    c    v    b    n    m    ,    .    /    rsft         up                end
      lctl  lmet lalt      spc       ralt cmps rctl                 left   down   rght
      )


<a id="orge8f2fa4"></a>

## Base layout (default)

KMonad takes the first layout as the default layout.
Let's create our first layout and named it `base`.
And let's also swap `capslock` and `escape`.

    (deflayer base
      caps    f1    f2   f3   f4   f5   f6   f7   f8   f9   f10  f11   f12    pause  prnt  ins  del
      `       1     2    3    4    5    6    7    8    9    0    -     =      bspc              home
      tab     q     w    e    r    t    y    u    i    o    p    [     ]      ret               pgup
      esc     a     s    d    f    g    h    j    k    l    ;    '     \                        pgdn
      lsft    z     x    c    v    b    n    m    ,    .    /    rsft         up                end
      lctl    lmet  lalt      spc       ralt cmps rctl                 left   down   rght
      )

Now if we run:

    kmonad ~/.config/kmonad/config.kbd

You will notice that `capslock` and `escape` have been swaped.


<a id="org58d8a92"></a>

## Create a second layout

Let's call the second layout `syms`, short for symbols.
First lets modify our `base layout` so when we hold `a`, it calls the `syms
layout`.

    (deflayer base
      caps    f1    f2   f3   f4   f5   f6   f7   f8   f9   f10  f11   f12    pause  prnt  ins  del
      `       1     2    3    4    5    6    7    8    9    0    -     =      bspc              home
      tab     q     w    e    r    t    y    u    i    o    p    [     ]      ret               pgup
      esc     (layer-toggle syms)  s    d    f    g    h    j    k    l    ;    '     \         pgdn
      lsft    z     x    c    v    b    n    m    ,    .    /    rsft         up                end
      lctl    lmet  lalt      spc       ralt cmps rctl                 left   down   rght
      )

But that is too messy. Let's create an alias for that command.

    (defalias
      sym (layer-toggle syms))

And now we can modify out `base layout` like this:

    (deflayer base
      caps    f1    f2   f3   f4   f5   f6   f7   f8   f9   f10  f11   f12    pause  prnt  ins  del
      `       1     2    3    4    5    6    7    8    9    0    -     =      bspc              home
      tab     q     w    e    r    t    y    u    i    o    p    [     ]      ret               pgup
      esc     @sym  s    d    f    g    h    j    k    l    ;    '     \                        pgdn
      lsft    z     x    c    v    b    n    m    ,    .    /    rsft         up                end
      lctl    lmet  lalt      spc       ralt cmps rctl                 left   down   rght
      )

Let's create our `syms layout`.
We will start simple and just add two symbols to make everything more clear.

    (deflayer syms
      _     _    _    _    _    _    _    _    _    _    _   _   _   _   _     _    _
      _     _    _    _    _    _    _    _    _    _    _   _   _   _              _
      _     _    _    _    _    _    _    _    _    _    _   _   _   _              _
      _     _    _    _    _    _    _    [    ]    _    _   _   _                  _
      _     _    _    _    _    _    _    _    _    _    _   _       _              _
      _     _    _         _         _    _    _                 _   _   _
      )

Now if we if we run our configuration.

    kmonad ~/.config/kmonad/config.kbd

When we hold `a` and press `j`, we get `[`.
And when we hold `a` and press `k`, we get `]`.

The bad news is that we lost the ability to type the letter `a`.


<a id="org58a9210"></a>

## Let's use `a` key  a leader key

From our last example let's modify the alias we made for calling the `syms layout`.

    (defalias
      sym (tap-next a (layer-toggle syms)))

With this modification, if we just tap `a`, we get `a`.
But if we hold `a` and press `j`, we get `[`.
And also if we hold `a` and press `k`, we get `]`.


<a id="org8be7d0a"></a>

## Let's create another leader key

    (defcfg
      input  (device-file "<path to your keyboard input>")
      output (uinput-sink "KMonad kbd"))
    
    (defalias
      sym (tap-next bspc (layer-toggle syms)))
    
    (defsrc
      esc   f1   f2   f3   f4   f5   f6   f7   f8   f9   f10  f11   f12    pause  prnt  ins  del
      `     1    2    3    4    5    6    7    8    9    0    -     =      bspc              home
      tab   q    w    e    r    t    y    u    i    o    p    [     ]      ret               pgup
      caps  a    s    d    f    g    h    j    k    l    ;    '     \                        pgdn
      lsft  z    x    c    v    b    n    m    ,    .    /    rsft         up                end
      lctl  lmet lalt      spc       ralt cmps rctl                 left   down   rght
      )
    
    (deflayer base
      esc   f1   f2   f3   f4   f5   f6   f7   f8   f9   f10  f11   f12    pause  prnt  ins  del
      `     1    2    3    4    5    6    7    8    9    0    -     =      bspc              home
      tab   q    w    e    r    t    y    u    i    o    p    [     ]      ret               pgup
      @sym  a    s    d    f    g    h    j    k    l    ;    '     \                        pgdn
      lsft  z    x    c    v    b    n    m    ,    .    /    rsft         up                end
      lctl  lmet lalt      spc       ralt cmps rctl                 left   down   rght
      )
    
    (deflayer syms
      _     _    _    _    _    _    _    _    _    _    _   _   _   _   _     _    _
      _     _    _    _    _    _    _    _    _    _    _   _   _   _              _
      _     _    _    _    _    _    _    _    _    _    _   _   _   _              _
      _     _    _    _    _    _    _    [    ]    _    _   _   _                  _
      _     _    _    _    _    _    _    _    _    _    _   _       _              _
      _     _    _         _         _    _    _                 _   _   _
      )

That is a full configuration.
In this configuration when we tap `caplocks`, get a `backspace`.
If we hold `caplocks` and press `j`, we get `[`.
If we hold `caplocks` and press `k`, we get `]`.
And the good news is that we got rid of `caplocks` previous life functionality.


<a id="org4903c05"></a>

## Conclusion

There is much more you can do with KMonad.
I suggest you to read the [official tutorial](https://github.com/kmonad/kmonad/blob/master/keymap/tutorial.kbd) to learn more about KMonad.

Now you know how covert every key in a leader key.

One last thing. Since I use Linux Mint and Stumpwm.
I added this line `kmonad $HOME/.config/kmonad/config.kbd &` to my `.profile` file, so kmonad starts when I log in.


<a id="orgb954da3"></a>

## Extra

    (defcfg
      input  (device-file "<path to your keyboard input>")
      output (uinput-sink "KMonad kbd"))
    
    (defalias
      d  (tap-hold-next 150 d [)
      f  (tap-hold-next 150 f ]))
    
    (defsrc
      esc   f1   f2   f3   f4   f5   f6   f7   f8   f9   f10  f11   f12    pause  prnt  ins  del
      `     1    2    3    4    5    6    7    8    9    0    -     =      bspc              home
      tab   q    w    e    r    t    y    u    i    o    p    [     ]      ret               pgup
      caps  a    s    d    f    g    h    j    k    l    ;    '     \                        pgdn
      lsft  z    x    c    v    b    n    m    ,    .    /    rsft         up                end
      lctl  lmet lalt      spc       ralt cmps rctl                 left   down   rght
      )
    
    (deflayer base
      esc   f1   f2   f3   f4   f5   f6   f7   f8   f9   f10  f11   f12    pause  prnt  ins  del
      `     1    2    3    4    5    6    7    8    9    0    -     =      bspc              home
      tab   q    w    e    r    t    y    u    i    o    p    [     ]      ret               pgup
      caps  a    s    @d   @f   g    h    j    k    l    ;    '     \                        pgdn
      lsft  z    x    c    v    b    n    m    ,    .    /    rsft         up                end
      lctl  lmet lalt      spc       ralt cmps rctl                 left   down   rght
      )

If you hold `d` more than 150 milliseconds, you will get `[`.
If you quickly tap `d`, you will get `d`.
If you hold `f` more than 150 milliseconds, you will get `]`.
If you quickly tap `f`, you will get `f`.