Device Input
When you push a button on your keyboard, how does that keystroke find its way to an application? What about moving around your mouse, or interacting with a touchscreen or touchpad? As is true for basically all software, it's all just layers on top of layers of abstraction.
Kernel Space Programs
For the other space nerds out there, sorry, I couldn't resist the title <3
As is the case for basically all hardware, Linux exposes input devices through files mounted on your filesystem. You might remember /dev/dri/* from the "Linux > Rendering" notes page for interacting with your GPU. Well, you'll find all your input devices inside /dev/input/*. There are a lot of ./eventX character device files in there, and each of your input devices (mice, keyboards, etc) is represented by one or more of them. The reason one device is likely split up across multiple character device files is because the events your devices emit are oftentimes grouped into categories, and each category of events gets its own file.
There are 2 pieces of software that are running in the Linux kernel that help make this stuff happen: devtmpfs and evdev.
- devtmpfs is responsible for creating and removing the
eventXfiles found in/dev/input/*. ...more generally, it's responsible for creating and removing all files within/dev/*, not just the input subdirectory ... but we're just focused on input events right now. - evdev is an input handler inside the kernel which defines an interface for input events, as well as serves as the handler for passing them along. When a device is plugged in or removed, it sends a message to devtmpfs to create the character device files. Additionally, when an event happens on an input device (ex: the user presses a button on their keyboard), evdev writes that event to the appropriate
/dev/input/eventNnode.
There are a few fun science experiments you can do to browse / interact with these pieces of software:
View the kernel thread responsible for creating/removing the /dev/* files in the output of a ps command:
$ ps -ef | grep kdevtmpfs
root 164 2 0 17:46 ? 00:00:00 [kdevtmpfs]View your character device nodes -- all the files beginning with "event", and whose "file type" shows as a "c" in the first character of each line.
$ ls -al /dev/input/Try plugging in or removing a USB input device, and then run that again to see how the output changes.
Surely there must be more?
What, are you so used to simple things in Linux requiring 10 different pieces of software with multiple layers of abstraction that two items just feels wrong now? Well, you're right. There are actually three (and a half) more things that we're going to cover: (e)udev, libinput, and xkbcommon.
- (e)udev - This is where the "half" comes in. udev is software created by systemd which works very closely with devtmpfs to manage the character device files inside
/dev/input/*. If you were checking out that directory earlier (ls -al /dev/input), you probably spotted a few surprise directories:./by-idand./by-path. Whenever a new device node shows up, udev alerts all the applications who are on the lookout for hotplugged devices by publishing a notice for all to read. Additionally, it takes a look at the device, categorizes it, manages permissions for it (sorootisn't the only user who can interact with device nodes), and creates links insideby-idandby-pathto make it easier to find the device file you're looking for. - "...so what about the 'half'..?" Well, eudev is the same thing as udev, but with all the "systemd" things removed (similar to how elogind is just logind but without the systemd ties).
- libinput is a event abstraction layer that reads hotplug events published by udev, along with evdev events for keypresses, mouse movements, etc. It converts lower-level events into more consumable event types.
- It's probably worth stuffing in the back of your head that you don't strictly need (e)udev. libinput can be configured to work directly with your
/dev/input/eventXnodes, but you'd miss out on all the advantages (e)udev provides. - xkbcommon sits on top of libinput, and is specific to just keyboard events. It provides a few big benefits over libinput, such as allowing for different keymaps (keyboard layouts), tracking modifier key states (shift, ctrl, caps lock, ...), and converting device-specific numeric keycodes into generic key symbols ("keysyms").
Caution: Don't confuse evdev (the kernel API that generates events) with eudev (the user space daemon that tracks devices).
In usual fashion, here are a couple "fun" experiments you can do, though you'll likely need admin permissions to do them (hence the sudos) and the libinput binary installed if it's not already.
# View all input devices
sudo libinput list-devices
# View a stream of all input events as they occur. (Press "Ctrl-C" to exit.)
sudo libinput debug-events