Crate evdev

Source
Available on Unix only.
Expand description

Linux event device handling.

The Linux kernel’s “evdev” subsystem exposes input devices to userspace in a generic, consistent way. I’ll try to explain the device model as completely as possible. The upstream kernel documentation is split across two files:

The evdev kernel system exposes input devices as character devices in /dev/input, typically /dev/input/eventX where X is an integer. Userspace applications can use ioctl system calls to interact with these devices. Libraries such as this one abstract away the low level calls to provide a high level interface.

Applications can interact with uinput by writing to /dev/uinput to create virtual devices and send events to the virtual devices. Virtual devices are created in /sys/devices/virtual/input.

§Devices

Devices can be opened directly via their path:

use evdev::Device;
let device = Device::open("/dev/input/event0")?;

This approach requires the calling process to have the appropriate privileges to open the device node (typically this requires running as root user). Alternatively a device can be created from an already open file descriptor. This approach is useful where the file descriptor is provided by an external privileged process (e.g. systemd’s logind):

use evdev::Device;
use std::fs::File;
use std::os::fd::OwnedFd;
let f = File::open("/dev/input/event0")?;
let fd = OwnedFd::from(f);
let device = Device::from_fd(fd)?;

§Input Events

Devices emit events, represented by the InputEvent struct. A input event has three main fields: event type, code and value

The kernel documentation specifies different event types, reperesented by the EventType struct. Each device can support a subset of those types. See Device::supported_events(). For each of the known event types there is a new-type wrapper around InputEvent
in event_variants see the module documenation for more info about those.

For most event types the kernel documentation also specifies a set of codes, represented by a new-type e.g. KeyCode. The individual codes of a EventType that a device supports can be retrieved through the Device::supported_*() methods, e.g. Device::supported_keys():

use evdev::{Device, KeyCode};
let device = Device::open("/dev/input/event0")?;
// check if the device has an ENTER key
if device.supported_keys().map_or(false, |keys| keys.contains(KeyCode::KEY_ENTER)) {
    println!("are you prepared to ENTER the world of evdev?");
} else {
    println!(":(");
}

A InputEvent with a type of EventType::KEY a code of KeyCode::KEY_ENTER and a value of 1 is emitted when the Enter key is pressed.

All events (even single events) are sent in batches followed by a synchronization event: EV_SYN / SYN_REPORT / 0. Events are grouped into batches based on if they are related and occur simultaneously, for example movement of a mouse triggers a movement event for the X and Y axes separately in a batch of 2 events.

The evdev crate exposes functions to query the current state of a device from the kernel, as well as a function that can be called continuously to provide an iterator over update events as they arrive.

§Matching Events

When reading from an input Device it is often useful to check which type/code or value the event has. This library provides the EventSummary enum which can be used to match specific events. Calling InputEvent::destructure will return that enum.

use evdev::*;
let mut device = Device::open("/dev/input/event0")?;
loop {
    for event in device.fetch_events().unwrap(){
        match event.destructure(){
            EventSummary::Key(ev, KeyCode::KEY_A, 1) => {
                println!("Key 'a' was pressed, got event: {:?}", ev);
            },
            EventSummary::Key(_, key_type, 0) => {
                println!("Key {:?} was released", key_type);
            },
            EventSummary::AbsoluteAxis(_, axis, value) => {
                println!("The Axis {:?} was moved to {}", axis, value);
            },
            _ => println!("got a different event!")
        }
    }
}

§Synchronizing versus Raw modes

This library can be used in either Raw or Synchronizing modes, which correspond roughly to evdev’s LIBEVDEV_READ_FLAG_NORMAL and LIBEVDEV_READ_FLAG_SYNC modes, respectively. In both modes, calling fetch_events and driving the resulting iterator to completion will provide a stream of real-time events from the underlying kernel device state. As the state changes, the kernel will write events into a ring buffer. If the buffer becomes full, the kernel will drop events from the ring buffer and leave an event telling userspace that it did so. At this point, if the application were using the events it received to update its internal idea of what state the hardware device is in, it will be wrong: it is missing some events.

In synchronous mode, this library tries to ease that pain by removing the corrupted events and injecting fake events as if the device had updated normally. Note that this is best-effort; events can never be recovered once lost. This synchronization comes at a performance cost: each set of input events read from the kernel in turn updates an internal state buffer, and events must be internally held back until the end of each frame. If this latency is unacceptable or for any reason you want to see every event directly, a raw stream reader is also provided.

As an example of how synchronization behaves, if a switch is toggled twice there will be two switch events in the buffer. However, if the kernel needs to drop events, when the device goes to synchronize state with the kernel only one (or zero, if the switch is in the same state as it was before the sync) switch events will be visible in the stream.

This cache can also be queried. For example, the DeviceState::led_vals method will tell you which LEDs are currently lit on the device. As calling code consumes each iterator, this state will be updated, and it will be fully re-synchronized with the kernel if the stream drops any events.

It is recommended that you dedicate a thread to processing input events, or use epoll or an async runtime with the fd returned by <Device as AsRawFd>::as_raw_fd to process events when they are ready.

For demonstrations of how to use this library in blocking, nonblocking, and async (tokio) modes, please reference the “examples” directory.

Re-exports§

pub use event_variants::*;

Modules§

event_variants
The event_variants module contains new-type wrappers around InputEvent for each known EventType.
raw_stream
A device implementation with no userspace synchronization performed.
uinput
Virtual device emulation for evdev via uinput.

Structs§

AbsInfo
A wrapped input_absinfo returned by EVIOCGABS and used with uinput to set up absolute axes
AbsoluteAxisCode
A type of absolute axis measurement, typically used for touch events and joysticks.
AttributeSet
AttributeSetRef
A collection of bits representing either device capability or state.
AutoRepeat
Auto-repeat settings for a device.
BusType
The bus type of an InputId.
Device
A physical or virtual device supported by evdev.
DeviceState
A cached representation of device state at a certain time.
EnumParseError
An error type for the FromStr implementation for enum-like types in this crate.
EnumerateDevices
An iterator over currently connected evdev devices.
EventStreamtokio
An asynchronous stream of input events.
EventType
Event types supported by the device.
FFCondition
Describes a spring or friction force feedback effect.
FFEffect
Represents a force feedback effect that has been successfully uploaded to the device for playback.
FFEffectCode
Force feedback effect types
FFEffectData
FFEnvelope
Describes a generic force feedback effect envelope.
FFReplay
Scheduling information for the force feedback effect.
FFStatusCode
Force feedback effect status
FFTrigger
Trigger information for the force feedback effect.
FetchEventsSynced
An iterator over events of a Device, produced by Device::fetch_events.
InputEvent
A wrapped input_event returned by the input device via the kernel.
InputId
KeyCode
Scancodes for key presses.
LedCode
LEDs specified by USB HID.
MiscCode
Various miscellaneous event types.
OtherCode
PowerCode
PropType
Device properties.
RelativeAxisCode
A type of relative axis measurement, typically produced by mice.
RepeatCode
SoundCode
A type associated with simple sounds, such as beeps or tones.
SwitchCode
An event type corresponding to a physical or virtual switch.
SynchronizationCode
A “synchronization” message type published by the kernel into the events stream.
UInputCode
A uinput event published by the kernel into the events stream for uinput devices.
UinputAbsSetup
A wrapped uinput_abs_setup, used to set up analogue axes with uinput

Enums§

EventSummary
A convenience mapping for matching a InputEvent while simultaniously checking its kind (type, code) and capturing the value
FFEffectKind
FFWaveform
Describes the waveform for periodic force feedback effects.

Traits§

EvdevEnum

Functions§

enumerate
Crawls /dev/input for evdev devices.