blob: 5e8451ccf6242b058a1274c5a98aadf1c9e53d5a [file] [log] [blame]
//! 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:
//!
//! - <https://www.kernel.org/doc/Documentation/input/event-codes.txt>
//! - <https://www.kernel.org/doc/Documentation/input/multi-touch-protocol.txt>
//!
//! 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:
//! ```no_run
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! use evdev::Device;
//! let device = Device::open("/dev/input/event0")?;
//! # Ok(())
//! # }
//! ```
//! 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):
//!
//! ```no_run
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! 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)?;
//! # Ok(())
//! # }
//! ```
//!
//! # Input Events
//!
//! Devices emit events, represented by the [`InputEvent`] struct.
//! A input event has three main fields: event [type](InputEvent::event_type), [code](InputEvent::code)
//! and [value](InputEvent::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()`]:
//! ```no_run
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! 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!(":(");
//! }
//! # Ok(())
//! # }
//! ```
//! 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.
//!
//! ```no_run
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! 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!")
//! }
//! }
//! }
//! # unreachable!()
//! # }
//! ```
//!
//! # 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.
// should really be cfg(target_os = "linux") and maybe also android?
#![cfg(unix)]
// Flag items' docs' with their required feature flags, but only on docsrs so
// that local docs can still be built on stable toolchains.
// As of the time of writing, the stabilization plan is such that:
// - Once stabilized, this attribute should be replaced with #![doc(auto_cfg)]
// - Then in edition 2024, doc(auto_cfg) will become the default and the
// attribute can be removed entirely
// (see https://github.com/rust-lang/rust/pull/100883#issuecomment-1264470491)
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
// has to be first for its macro
#[macro_use]
mod attribute_set;
mod compat;
mod constants;
mod device_state;
pub mod event_variants;
mod ff;
mod inputid;
pub mod raw_stream;
mod scancodes;
mod sync_stream;
mod sys;
pub mod uinput;
use crate::compat::{input_absinfo, input_event, uinput_abs_setup};
use std::fmt::{self, Display};
use std::io;
use std::os::fd::{AsFd, AsRawFd, OwnedFd};
use std::path::PathBuf;
use std::time::{Duration, SystemTime};
pub use attribute_set::{AttributeSet, AttributeSetRef, EvdevEnum};
pub use constants::*;
pub use device_state::DeviceState;
pub use event_variants::*;
pub use ff::*;
pub use inputid::*;
pub use scancodes::*;
pub use sync_stream::*;
macro_rules! common_trait_impls {
($raw:ty, $wrapper:ty) => {
impl From<$raw> for $wrapper {
fn from(raw: $raw) -> Self {
Self(raw)
}
}
impl From<$wrapper> for $raw {
fn from(wrapper: $wrapper) -> Self {
wrapper.0
}
}
impl AsRef<$raw> for $wrapper {
fn as_ref(&self) -> &$raw {
&self.0
}
}
};
}
const EVENT_BATCH_SIZE: usize = 32;
/// A convenience mapping for matching a [`InputEvent`] while simultaniously checking its kind `(type, code)`
/// and capturing the value
///
/// Note This enum can not enforce that `InputEvent.code() == ` enum variant(code).
/// It is suggested to not construct this enum and instead use [`InputEvent::destructure`] to obtain instances.
#[derive(Debug)]
pub enum EventSummary {
Synchronization(SynchronizationEvent, SynchronizationCode, i32),
Key(KeyEvent, KeyCode, i32),
RelativeAxis(RelativeAxisEvent, RelativeAxisCode, i32),
AbsoluteAxis(AbsoluteAxisEvent, AbsoluteAxisCode, i32),
Misc(MiscEvent, MiscCode, i32),
Switch(SwitchEvent, SwitchCode, i32),
Led(LedEvent, LedCode, i32),
Sound(SoundEvent, SoundCode, i32),
Repeat(RepeatEvent, RepeatCode, i32),
ForceFeedback(FFEvent, FFEffectCode, i32),
Power(PowerEvent, PowerCode, i32),
ForceFeedbackStatus(FFStatusEvent, FFStatusCode, i32),
UInput(UInputEvent, UInputCode, i32),
Other(OtherEvent, OtherCode, i32),
}
impl From<InputEvent> for EventSummary {
fn from(value: InputEvent) -> Self {
match value.event_type() {
EventType::SYNCHRONIZATION => SynchronizationEvent::from_event(value).into(),
EventType::KEY => KeyEvent::from_event(value).into(),
EventType::RELATIVE => RelativeAxisEvent::from_event(value).into(),
EventType::ABSOLUTE => AbsoluteAxisEvent::from_event(value).into(),
EventType::MISC => MiscEvent::from_event(value).into(),
EventType::SWITCH => SwitchEvent::from_event(value).into(),
EventType::LED => LedEvent::from_event(value).into(),
EventType::SOUND => SoundEvent::from_event(value).into(),
EventType::REPEAT => RepeatEvent::from_event(value).into(),
EventType::FORCEFEEDBACK => FFEvent::from_event(value).into(),
EventType::POWER => PowerEvent::from_event(value).into(),
EventType::FORCEFEEDBACKSTATUS => FFStatusEvent::from_event(value).into(),
EventType::UINPUT => UInputEvent::from_event(value).into(),
_ => OtherEvent(value).into(),
}
}
}
/// A wrapped `input_absinfo` returned by EVIOCGABS and used with uinput to set up absolute
/// axes
///
/// `input_absinfo` is a struct containing six fields:
/// - `value: s32`
/// - `minimum: s32`
/// - `maximum: s32`
/// - `fuzz: s32`
/// - `flat: s32`
/// - `resolution: s32`
///
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[repr(transparent)]
pub struct AbsInfo(input_absinfo);
impl AbsInfo {
#[inline]
pub fn value(&self) -> i32 {
self.0.value
}
#[inline]
pub fn minimum(&self) -> i32 {
self.0.minimum
}
#[inline]
pub fn maximum(&self) -> i32 {
self.0.maximum
}
#[inline]
pub fn fuzz(&self) -> i32 {
self.0.fuzz
}
#[inline]
pub fn flat(&self) -> i32 {
self.0.flat
}
#[inline]
pub fn resolution(&self) -> i32 {
self.0.resolution
}
/// Creates a new AbsInfo, particurarily useful for uinput
pub fn new(
value: i32,
minimum: i32,
maximum: i32,
fuzz: i32,
flat: i32,
resolution: i32,
) -> Self {
AbsInfo(input_absinfo {
value,
minimum,
maximum,
fuzz,
flat,
resolution,
})
}
}
common_trait_impls!(input_absinfo, AbsInfo);
/// A wrapped `uinput_abs_setup`, used to set up analogue axes with uinput
///
/// `uinput_abs_setup` is a struct containing two fields:
/// - `code: u16`
/// - `absinfo: input_absinfo`
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[repr(transparent)]
pub struct UinputAbsSetup(uinput_abs_setup);
impl UinputAbsSetup {
#[inline]
pub fn code(&self) -> u16 {
self.0.code
}
#[inline]
pub fn absinfo(&self) -> AbsInfo {
AbsInfo(self.0.absinfo)
}
/// Creates new UinputAbsSetup
pub fn new(code: AbsoluteAxisCode, absinfo: AbsInfo) -> Self {
UinputAbsSetup(uinput_abs_setup {
code: code.0,
absinfo: absinfo.0,
})
}
}
common_trait_impls!(uinput_abs_setup, UinputAbsSetup);
/// A wrapped `input_event` returned by the input device via the kernel.
///
/// `input_event` is a struct containing four fields:
/// - `time: timeval`
/// - `type_: u16`
/// - `code: u16`
/// - `value: s32`
///
/// The meaning of the "code" and "value" fields will depend on the underlying type of event.
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
#[repr(transparent)]
pub struct InputEvent(input_event);
common_trait_impls!(input_event, InputEvent);
impl InputEvent {
/// Returns the timestamp associated with the event.
#[inline]
pub fn timestamp(&self) -> SystemTime {
timeval_to_systime(&self.0.time)
}
/// Returns the type of event this describes, e.g. Key, Switch, etc.
#[inline]
pub fn event_type(&self) -> EventType {
EventType(self.0.type_)
}
/// Returns the raw "code" field directly from input_event.
#[inline]
pub fn code(&self) -> u16 {
self.0.code
}
/// Returns the raw "value" field directly from input_event.
///
/// For keys and switches the values 0 and 1 map to pressed and not pressed respectively.
/// For axes, the values depend on the hardware and driver implementation.
#[inline]
pub fn value(&self) -> i32 {
self.0.value
}
/// A convenience function to destructure the InputEvent into a [`EventSummary`].
///
/// # Example
/// ```
/// use evdev::*;
/// let event = InputEvent::new(1, KeyCode::KEY_A.0, 1);
/// match event.destructure() {
/// EventSummary::Key(KeyEvent, KeyCode::KEY_A, 1) => (),
/// _=> panic!(),
/// }
/// ```
pub fn destructure(self) -> EventSummary {
self.into()
}
/// Create a new InputEvent. Only really useful for emitting events on virtual devices.
pub fn new(type_: u16, code: u16, value: i32) -> Self {
let raw = input_event {
time: libc::timeval {
tv_sec: 0,
tv_usec: 0,
},
type_,
code,
value,
};
Self(raw)
}
/// Create a new InputEvent with the time field set to "now" on the system clock.
///
/// Note that this isn't usually necessary simply for emitting events on a virtual device, as
/// even though [`InputEvent::new`] creates an `input_event` with the time field as zero,
/// the kernel will update `input_event.time` when it emits the events to any programs reading
/// the event "file".
pub fn new_now(type_: u16, code: u16, value: i32) -> Self {
let raw = input_event {
time: systime_to_timeval(&SystemTime::now()),
type_,
code,
value,
};
Self(raw)
}
}
impl fmt::Debug for InputEvent {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let summary = self.destructure();
let code: &dyn fmt::Debug = match &summary {
EventSummary::Synchronization(_, code, _) => code,
EventSummary::Key(_, code, _) => code,
EventSummary::RelativeAxis(_, code, _) => code,
EventSummary::AbsoluteAxis(_, code, _) => code,
EventSummary::Misc(_, code, _) => code,
EventSummary::Switch(_, code, _) => code,
EventSummary::Led(_, code, _) => code,
EventSummary::Sound(_, code, _) => code,
EventSummary::Repeat(_, code, _) => code,
EventSummary::ForceFeedback(_, code, _) => code,
EventSummary::Power(_, code, _) => code,
EventSummary::ForceFeedbackStatus(_, code, _) => code,
EventSummary::UInput(_, code, _) => code,
EventSummary::Other(_, code, _) => &code.1,
};
f.debug_struct("InputEvent")
.field("time", &self.timestamp())
.field("type", &self.event_type())
.field("code", code)
.field("value", &self.value())
.finish()
}
}
/// Crawls `/dev/input` for evdev devices.
///
/// Will not bubble up any errors in opening devices or traversing the directory. Instead returns
/// an empty iterator or omits the devices that could not be opened.
pub fn enumerate() -> EnumerateDevices {
EnumerateDevices {
inner: raw_stream::enumerate(),
}
}
/// An iterator over currently connected evdev devices.
pub struct EnumerateDevices {
inner: raw_stream::EnumerateDevices,
}
impl Iterator for EnumerateDevices {
type Item = (PathBuf, Device);
fn next(&mut self) -> Option<(PathBuf, Device)> {
self.inner
.next()
.map(|(pb, dev)| (pb, Device::from_raw_device(dev)))
}
}
/// A safe Rust version of clock_gettime against CLOCK_REALTIME
fn systime_to_timeval(time: &SystemTime) -> libc::timeval {
let (sign, dur) = match time.duration_since(SystemTime::UNIX_EPOCH) {
Ok(dur) => (1, dur),
Err(e) => (-1, e.duration()),
};
libc::timeval {
tv_sec: dur.as_secs() as libc::time_t * sign,
tv_usec: dur.subsec_micros() as libc::suseconds_t,
}
}
fn timeval_to_systime(tv: &libc::timeval) -> SystemTime {
let dur = Duration::new(tv.tv_sec as u64, tv.tv_usec as u32 * 1000);
if tv.tv_sec >= 0 {
SystemTime::UNIX_EPOCH + dur
} else {
SystemTime::UNIX_EPOCH - dur
}
}
/// SAFETY: T must not have any padding or otherwise uninitialized bytes inside of it
pub(crate) unsafe fn cast_to_bytes<T: ?Sized>(mem: &T) -> &[u8] {
std::slice::from_raw_parts(mem as *const T as *const u8, std::mem::size_of_val(mem))
}
/// An error type for the `FromStr` implementation for enum-like types in this crate.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct EnumParseError(());
impl Display for EnumParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "failed to parse Key from string")
}
}
impl std::error::Error for EnumParseError {}
fn fd_write_all(fd: std::os::fd::BorrowedFd<'_>, mut data: &[u8]) -> nix::Result<()> {
loop {
match nix::unistd::write(fd, data) {
Ok(0) => return Ok(()),
Ok(n) => data = &data[n..],
Err(nix::Error::EINTR) => {}
Err(e) => return Err(e),
}
}
}
fn write_events(fd: std::os::fd::BorrowedFd<'_>, events: &[InputEvent]) -> nix::Result<()> {
let bytes = unsafe { cast_to_bytes(events) };
fd_write_all(fd, bytes)
}
/// Represents a force feedback effect that has been successfully uploaded to the device for
/// playback.
#[derive(Debug)]
pub struct FFEffect {
fd: OwnedFd,
id: u16,
}
impl FFEffect {
/// Returns the effect ID.
pub fn id(&self) -> u16 {
self.id
}
/// Plays the force feedback effect with the `count` argument specifying how often the effect
/// should be played.
pub fn play(&mut self, count: i32) -> io::Result<()> {
let events = [*FFEvent::new(FFEffectCode(self.id), count)];
crate::write_events(self.fd.as_fd(), &events)?;
Ok(())
}
/// Stops playback of the force feedback effect.
pub fn stop(&mut self) -> io::Result<()> {
let events = [*FFEvent::new(FFEffectCode(self.id), 0)];
crate::write_events(self.fd.as_fd(), &events)?;
Ok(())
}
/// Updates the force feedback effect.
pub fn update(&mut self, data: FFEffectData) -> io::Result<()> {
let mut effect: sys::ff_effect = data.into();
effect.id = self.id as i16;
unsafe { sys::eviocsff(self.fd.as_raw_fd(), &effect)? };
Ok(())
}
}
impl Drop for FFEffect {
fn drop(&mut self) {
let _ = unsafe { sys::eviocrmff(self.fd.as_raw_fd(), self.id as _) };
}
}
/// Auto-repeat settings for a device.
#[derive(Debug, Clone)]
#[repr(C)]
pub struct AutoRepeat {
/// The duration, in milliseconds, that a key needs to be held down before
/// it begins to auto-repeat.
pub delay: u32,
/// The duration, in milliseconds, between auto-repetitions of a held-down key.
pub period: u32,
}