Using the Keypad as Hotkeys

written 2024-01-14

Enhancing productivity with additional hotkeys can be a game-changer, especially when using underutilized parts of your keyboard, like the numpad. This post explores how to transform your numpad into a dynamic hotkey pad, functioning as both a number pad and a hotkey pad based on its status.

The challenge lies in the fact that the numpad shares keycodes in both states, making it hard to distinguish between them. After some research, I found keyd, which introduces the concept of layers, though it lacks programmable keys. The solution? Kmonad, a tool allowing for key programmability. As its name implies, Kmonad dives into Lisp territory, and it’s written in Haskell.

Installation

On Arch Linux, install Kmonad from the AUR using yay -S kmonad-bin. Add your user to the input group to use it without root privileges: sudo usermod -aG input $USER, and then relog.

Configuration

Kmonad’s tutorial is an excellent starting point. My configuration is simple as I only remap the numpad:

(defcfg
        input (device-file "/dev/input/by-id/usb-Logitech_USB_Keyboard-event-kbd")
        output (uinput-sink "My KMonad output")
        cmp-seq ralt
        cmp-seq-delay 5

        fallthrough true
        allow-cmd true
    )

    ;; 100 % Keyboard
    (defsrc
    esc  f1   f2   f3   f4   f5   f6   f7   f8   f9   f10  f11  f12        ssrq slck pause
    grv  1    2    3    4    5    6    7    8    9    0    -    =    bspc  ins  home pgup  nlck kp/  kp*  kp-
    tab  q    w    e    r    t    y    u    i    o    p    [    ]    ret   del  end  pgdn  kp7  kp8  kp9  kp+
    caps a    s    d    f    g    h    j    k    l    ;    '    \                          kp4  kp5  kp6
    lsft 102d z    x    c    v    b    n    m    ,    .    /    rsft            up         kp1  kp2  kp3  kprt
    lctl lmet lalt           spc                 ralt rmet cmp  rctl       left down rght  kp0  kp.
    )

    #|
    (deflayer template
    _    _    _    _    _    _    _    _    _    _    _    _    _          _    _    _
    _    _    _    _    _    _    _    _    _    _    _    _    _    _     _    _    _    _    _    _    _
    _    _    _    _    _    _    _    _    _    _    _    _    _    _     _    _    _    _    _    _    _
    _    _    _    _    _    _    _    _    _    _    _    _    _                         _    _    _
    _    _    _    _    _    _    _    _    _    _    _    _    _               _         _    _    _    _
    _    _    _              _                   _    _    _    _          _    _    _    _    _
    )
    |#

    (defalias
        mcr (layer-switch macros)
        main (layer-switch main )
    )

    (deflayer main
    _    _    _    _    _    _    _    _    _    _    _    _    _          _    _    _
    _    _    _    _    _    _    _    _    _    _    _    _    _    _     _    _    _    @mcr    /    *    -
    _    _    _    _    _    _    _    _    _    _    _    _    _    _     _    _    _    7   8    9    +
    _    _    _    _    _    _    _    _    _    _    _    _    _                         4    5    6
    _    _    _    _    _    _    _    _    _    _    _    _    _               _         1    2    3    kprt
    _    _    _              _                   _    _    _    _          _    _    _    0    .
    )


    (defalias
        code (cmd-button "code")

    )

    (deflayer macros
    _    _    _    _    _    _    _    _    _    _    _    _    _          _    _    _
    _    _    _    _    _    _    _    _    _    _    _    _    _    _     _    _    _    @main    _    _    _
    _    _    _    _    _    _    _    _    _    _    _    _    _    _     _    _    _    @code    _    _    _
    _    _    _    _    _    _    _    _    _    _    _    _    _                         _    _    _
    _    _    _    _    _    _    _    _    _    _    _    _    _               _         _    _    _    _
    _    _    _              _                   _    _    _    _          _    _    _    _    _
    )

In this configuration, defsrc declares your source keyboard. Use deflayer to define layers, and switch between them with layer-switch. defalias sets aliases for keys, useful for creating macros with cmd-button. You can also use cmd-seq for a sequence of keys.

With this setup, I toggle between layers using the NumLock key. However, note that the LED indicator doesn’t change stateā€”a known issue pending a Pull Request fix. Haskell experts, your contributions are welcome!

Advanced Configuration

For multiple keyboards, you’ll need separate configurations for each, identifiable through /dev/input/by-id/. Use lsusb or ls -l /dev/input/by-id/ to find the device file. Here’s a script to start Kmonad with the correct configuration:

#!/bin/bash

    # Directory containing keyboard devices
    keyboard_device_dir="/dev/input/by-id/"

    # Directory containing kmonad configurations
    kmonad_config_dir="${HOME}/.config/kmonad/"

    flash_numlock() {
        for i in {1..6}; do
            xdotool key Num_Lock
            xdotool key Caps_Lock
            sleep 0.2
        done
    }

    # Loop through each keyboard device
    for keyboard_device in "${keyboard_device_dir}"*kbd; do
        # Extract the keyboard name
        keyboard_name=$(basename "$keyboard_device")

        # Corresponding kmonad configuration file
        kmonad_config="${kmonad_config_dir}${keyboard_name}.kbd"

        # Check if the kmonad configuration file exists
        if [[ -f "$kmonad_config" ]]; then
            # Run kmonad for this keyboard
            kmonad "$kmonad_config" &
            echo "Started kmonad for ${keyboard_name}"
            flash_numlock
        else
            echo "No kmonad configuration found for ${keyboard_name} and ${kmonad_config}"
        fi
    done

    # Inform the user that the script has finished
    echo "All keyboards processed."

Conclusion

The final setup is quite satisfying, despite the lack of a visual layer-change indicator. I’m hopeful for a fix to the pull request. For any queries or suggestions, feel free to reach out.

Bithive signing off!

There is no comment system. If you want to contact me about this article, you can do so via e-mail or Mastodon.