Introduction

In the old times, when we had a physical phone, it was easy to answer a call, just pick the phone.

Since the migration to software which substitue the phone, I want to recreate the workflow to answer a call: no need to find some button in some window just to answer a call.

Using a numeric keypad it is possible to replicate the workflow… bind a key to answer the call, and more buttons, more actions we can automate.

Keyboard

First we need a dedicated keyboard for this function, and any keyboard should do.

Laying arround I just have full size keyboard, so I bought a new MITSAI Q20 from a local shop.

I like it, because the keys are squared and low profile. Easy to customize with stickers.

pluging keyboard the first time

In systemd journal, you will find information about the keyboard. As you can see, the brand name from my local shop do not show up anywhere.

kernel: usb 1-1.4.3: new low-speed USB device number 15 using xhci_hcd
kernel: usb 1-1.4.3: New USB device found, idVendor=1a2c, idProduct=0e24, bcdDevice= 1.10
kernel: usb 1-1.4.3: New USB device strings: Mfr=1, Product=2, SerialNumber=0
kernel: usb 1-1.4.3: Product: USB Keyboard
kernel: usb 1-1.4.3: Manufacturer: SEM
kernel: input: SEM USB Keyboard as /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1.4/1-1.4.3/1-1.4.3:1.0/0003:1A2C:0E24.000B/input/input29
kernel: hid-generic 0003:1A2C:0E24.000B: input,hidraw5: USB HID v1.10 Keyboard [SEM USB Keyboard] on usb-0000:00:14.0-1.4.3/input0

System configuration

udev

udev will allow us to do some setup and start actkbd service.

My udev rule file is:

ACTION=="add", \ # match the event, device and parent device
SUBSYSTEM=="input", \ 
ATTRS{name}=="SEM USB Keyboard", \
MODE="0666", \ # set mode to other read from the device, without root
SYMLINK+="macrokeyboard", \ # create a nicer symbolic link
TAG+="systemd", \ # this will used systemd to start actkbd
ENV{SYSTEMD_USER_WANTS}="actkbd.service"

To reload the configuration, we can use

udevadm control --reload-rules 

To check if the udev rule file is working

udevadm test /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1.4/1-1.4.3/1-1.4.3:1.0/0003:1A2C:0E24.000B/input/input29

To create an udev rule can be hit and miss. Doing the wrong filters, can lead to diferent devices be found, but is is possible to get all information

udevadm info --attribute-walk --path /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1.4/1-1.4.3/1-1.4.3:1.0/0003:1A2C:0E24.000B/input/input29

In case of problems, read Writing udev rules to learn how to write it.

systemd

As configured in udev rule, this unit will start the service.

[Unit]
Description=Actkbd: Daemon for X-independent shortcuts
ConditionPathIsSymbolicLink=/dev/macrokeyboard

[Service]
Environment=DISPLAY=:0
ExecStart=actkbd --device /dev/macrokeyboard --daemon --pidfile /tmp/actkbd.pid
Type=forking
PIDFile=/tmp/actkbd.pid
Restart=on-failure
RestartSec=1

X

Without instrcut XOrg to ignore this numeric keypad, when we press a key, it will send that key code the application.

So we need to place a file in /usr/share/X11/xorg.conf.d/, with:

Section "InputClass"
  Identifier "Ignore macro keyboard"
  MatchProduct "SEM USB Keyboard"
  Option "Ignore" "on"
EndSection

To test this, it is needed to restart X server…

actkbd

Warning, by project author:

…but here’s the catch: actkbd (a) is single-threaded and (b) uses system() in the same thread to execute commands. Yes, I know, not nice; the whole program is basically a hack - it just worked well enough for me and a few friends back when I wrote it.

It can be an hack, but actkbd have work without problems for me.

After installation we need to find the keycodes from our keyboard.

KeyCodes

I’ve found two ways to do it…

using actkbd

$ actkbd --showexec --showkey --noexec --device /dev/macrokeyboard
Keys: 79
Keys: 80
Keys: 81
Keys: 96

or using showkeys

$ sudo showkey 
press any key (program terminates 10s after last keypress)...
keycode  28 release
keycode  79 press
keycode  79 release
keycode  80 press
keycode  80 release

configuration

The default location for the configuration file is /etc/actkbd.conf

I opted by send all keycodes to a single script…

    #1st line
    172:::/usr/bin/keyboardScript.sh 172 &
     15:::/usr/bin/keyboardScript.sh 15 &
    155:::/usr/bin/keyboardScript.sh 155 &
    140:::/usr/bin/keyboardScript.sh 140 &

Each line can execute any command, but I decided to have a script which will deal with all of it… it is easier to reuse code and maintain it. Also, I can change the script without to bother to restart actkbd to reload new actions.

testing

actkbd --showexec --showkey --device /dev/macrokeyboard

It should show somethig like

Keys: 76
Executing: /home/fcarvalho/bin/keyboardScript.sh 76 &
Keys: 69
Executing: /home/fcarvalho/bin/keyboardScript.sh 69 &

The Script

My script, is a giant case, something like:

case $1 in
    79) 
        # xdotool key U1f600
        xdotool type 😀
        # slow https://github.com/jordansissel/xdotool/issues/10
    ;;
    71)
    mpc status | grep playing 2>&1 > /dev/null
    if [ $? -eq 0 ]; then
        # it is playing
        mpc --quiet stop
        dbusSend Pause
    else 
        mpc --quiet play
        dbusSend Play
    fi
    ;;
    76)
        # take a area screenshot
        flameshot gui &
    ;;
    (...)

and several tools were used

xdotool

Without xdotool it cloud not do the automations.

xdotool lets us programmatically simulate keyboard input and mouse.

As example, pressing a key to toggle video in MS Teams.

82) # mute unmute video
    WID=$(xdotool search --onlyvisible --name "Microsoft Teams")    if [ $WID ]; then
        xdotool windowfocus --sync $WID ②
        xdotool key --window $WID "ctrl+shift+o"    fi
;;

where:

  • ① Search for Teams window
  • ② Put the window on focus
  • ③ Send the Teams shortcut to Toggle video

mpc

My music is streamed from other machine, where I’ve mpd running, so I use mpc to control it remotelly.

dbus

dbus-send + MPRIS allow to abstract which music player I’m using, as long as they support it.

note use d-feet to explore dbus

Final Result

Besides the software, the final touch was to print in photo papper some nice icons. Then with double face tape and a scissor, convert them to little stickers.

All the files are in Building a macro keyboard.

Future

Most of this work was done with xdotool, on top X… which is being substituted by Wayland.

So, it is time to look into xdotool replacement options:

other resources

Font Awesome or Nerd Fonts

Scripting with udev

Service unit configuration