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)
interceptcaptures your input from previous layer, and write raw input tostdout;debouncer-udevmonget the raw input data fromstdin, process them and write back tostdout;uinputconvert 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 versionThe 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.yamlIf 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 --nowKeyd 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=14Currently supported items are:
exceptions: array ofu16keycodes. Keys in the exceptions will not delayed. For example, I want to neglect modifier keys such as Ctrl, Alt, Shift and Meta.debounce_time:u64value in milliseconds. Indicates how long should a release event delayed. For example, 14ms is ideal for my machine.