Custom keyboard layout work on every Linux, MacOS and Windows using KMonad

A comprehensive guide to creating and implementing a custom keyboard layout across multiple operating systems using KMonad

By FabricSoul

Recently I wanted to remap my keyboard because QWERTY layout makes my hand and wrist hurt.

As I am using mainly Arch Linux, I needed a software level remap. So I found a project called KMonad. It can work on all the platform, no matter it’s X11, Wayland, MacOS or Windows.

First, create a file called layout.kbd, this will be our config file. Then set the Vim to parse the file as lisp

:set filetype=lisp

Then copy the following lines of boilerplate code, and note to change the device file to your keyboard file.

(defcfg
  ;; For Linux
  input  (device-file "/dev/input/by-path/pci-0000:02:00.0-usb-0:5:1.0-event-kbd")
  output (uinput-sink "My KMonad output"
    ;; To understand the importance of the following line, see the section on
    ;; Compose-key sequences at the near-bottom of this file.
    "/run/current-system/sw/bin/sleep 1 && /run/current-system/sw/bin/setxkbmap -option compose:ralt")
  cmp-seq ralt    ;; Set the compose key to `RightAlt'
  cmp-seq-delay 5 ;; 5ms delay between each compose-key sequence press

  ;; For Windows
  ;; input  (low-level-hook)
  ;; output (send-event-sink)

  ;; For MacOS
  ;; input  (iokit-name "my-keyboard-product-string")
  ;; output (kext)

  ;; Comment this if you want unhandled events not to be emitted
  fallthrough true

  ;; Set this to false to disable any command-execution in KMonad
  allow-cmd true

  ;; Set the implicit around to `around`
  implicit-around around
)

The defsrc is where you describe how your physical keyboard looks like, it is the base layout of your keyboard.

(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
  tab  q    w    e    r    t    y    u    i    o    p    [    ]    \
  caps a    s    d    f    g    h    j    k    l    ;    '    ret
  lsft z    x    c    v    b    n    m    ,    .    /    rsft
  lctl lmet lalt           spc                 ralt rmet cmp  rctl
)

The default layer is the base layer of your custom layout.

(deflayer default
  esc  f1   f2   f3   f4   f5   f6   f7   f8   f9   f10  f11  f12
  $    +    [    {    \(    &    =    \)    }    ]    *    !    |    bspc
  tab  ;    ,    .    p    y    f    g    c    r    l    /    @    \
  caps a    o    e    u    i    d    h    t    n    s    -    ret
  @shift '    q    j    k    x    b    m    w    v    z    rsft
  lctl lmet lalt           spc            ralt rmet cmp  rctl
)

You can define other layers with custom name and use them as alias.

(deflayer shift
  esc  f1   f2   f3   f4   f5   f6   f7   f8   f9   f10  f11  f12
  ~    1    2    3    4    5    6    7    8    9    0    %    `    bspc
  tab  :    <    >    P    Y    F    G    C    R    L    ?    ^    #
  caps A    O    E    U    I    D    H    T    N    S    _    ret
  lsft "    Q    J    K    X    B    M    W    V    Z    rsft
  lctl lmet lalt           spc            ralt rmet cmp  rctl
)

(defalias
  shift (layer-toggle shift)
)

Now we need to add a systemd service to enable KMonad.

Create a systemd service

sudo nvim /etc/systemd/system/kmonad.service

Write the config as following

[Unit]
Description=kmonad
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/kmonad /home/fabric/.kmonad/real-programmers-dvorak.kbd
Restart=always
User=root
Group=root

[Install]
WantedBy=multi-user.target

Now enable and start the service

sudo systemctl enable --now kmonad.service

Now you will have a working custom layout.