This program is a middleware layer that integrated into interception tools for debouncing.
I've been troubled by keyboard chattering for months. It's hard for me to replace the keyboard or fix hardware problems, so I tried software debouncing.
I implemented this middleware layer. It can create a virtual device that receives information from previous hardware layer and provide input.
This middleware is flexible, loosely coupled and easy-to-use. After bringing it into use, my problem is resolved successfully.
See also: Interception Tools#how it works
The intercept
, debouncer-udevmon
and uinput
form a whole virtual device. The data flow is in this middleware is shown as follows:
(keyboard device) -> intercept -> debouncer-udevmon -> uinput -> (next layer)
intercept
captures your input from previous layer, and write raw input tostdout
;debouncer-udevmon
get the raw input data fromstdin
, process them and write back tostdout
;uinput
convert the raw input from last step, and write it to this virtual device (can be found as/dev/input/eventX
);
The "next layer" can be evtest, X server or Wayland compositor.
See input.h in Linux kernel. Each input behaviour is represented by a bunch of input_event
object. For example, if you press a key on your machine, there would be 3 input events: a miscellaneous input data, a key event, and a sync event.
A key event has 3 possible values: 1 (pressed), 0 (released) or 2 (autorepeat).
The role of debouncer-udevmon
is that, it can delay the keyboard "release" event for some time (see #Configurations), which is similar to the "spuious" mode of libinput.
Once debouncer-udevmon
received a "release" event, it will wait for some time. During this time, if no "press" event of the same key comes, it will write the "release" event to stdout
; otherwise, it will neglect this event.
You need the following build dependencies:
$ cargo b # for debug version
$ cargo b -r # for release version
The debug version will write more detailed info to stderr
.
You need the following runtime dependencies:
Before using it, you would better create a yaml file as config. For example, here is my udevmon.yaml
:
- JOB: intercept -g $DEVNODE | /usr/local/bin/debouncer-udevmon | uinput -d $DEVNODE
DEVICE:
LINK: "/dev/input/by-path/platform-i8042-serio-0-event-kbd"
Then run udevmon
as root loading your config.
$ sudo udevmon -c udevmon.yaml
If you look into /dev/input
you will found a new virtual device.
I don't want to run udevmon
every time I start my machine. I want to use it as an autostart daemon.
Just place the yaml file in /etc/interception/
, and enable the udevmon.service
.
$ sudo systemctl enable udevmon.service --now
Keyd is a key remapping daemon for linux. I use it to remap my keyboard.
This debouncer is easy to integrated with keyd, because they are both modularized middleware layer in libevdev.
Just run debouncer-udevmon
first and keyd
then, you will get a debounced and remapped keyboard! the data flow from keyboard to applications is:
(keyboard device) -> debouncer-udevmon -> keyd -> (next layer)
You can also integrate udevmon.service
and keyd.service
. But notice that the order and time of services matter. keyd
needs to start after udevmon
starts, and udevmon
needs a few microseconds to be ready. So you should create a drop-in configuration file that wants udevmon
as optional dependency and sleep for some time before executing the command.
Here is my drop-in config:
[Unit]
Wants=udevmon.service
After=udevmon.service
[Service]
ExecStartPre=/usr/bin/sleep .7 # 700ms is fine on my machine
You can set some configurations in /etc/debouncer.toml
. Here is my configurations:
exceptions=[29,42,54,56,97,100,125]
debounce_time=14
Currently supported items are:
exceptions
: array ofu16
keycodes. Keys in the exceptions will not delayed. For example, I want to neglect modifier keys such as Ctrl, Alt, Shift and Meta.debounce_time
:u64
value in milliseconds. Indicates how long should a release event delayed. For example, 14ms is ideal for my machine.