drmkit_input/lib.rs
1// SPDX-FileCopyrightText: (c) 2026 Joel Winarske
2// SPDX-License-Identifier: MIT
3
4//! Keyboard, pointer and touch input.
5//!
6//! Two halves that are useful apart. [`Keyboard`] compiles an xkb keymap and
7//! turns evdev keycodes into keysyms and text; the libinput side reads the
8//! devices those codes come from. A caller with its own event source -- a
9//! remote protocol, a test harness, a replay -- wants the first without the
10//! second, so they are separate and each is behind its own feature.
11//!
12//! # Features
13//!
14//! `xkb` (default) brings in [`Keyboard`]; `libinput` (default) brings in
15//! [`Seat`]. Without either, the event types, [`Repeat`] and [`KeyRepeater`]
16//! still build and test -- which is what a cross target with neither library
17//! in its sysroot can do.
18//!
19//! # Not here
20//!
21//! `SeatOptions::log_handler`, the reference's per-seat sink for libinput's
22//! diagnostics. libinput carries one `user_data` slot per context and the
23//! `input` crate has already spent it on the device opener, so a per-context
24//! sink would need a registry keyed on the context pointer -- for a hook
25//! whose stated purpose is separating libinput's stream from the library's
26//! own, which [`drmkit_log::set_log_sink`] can already do process-wide.
27//! [`SeatOptions::log_priority`] still gates how much libinput says.
28//!
29//! The `Pointer` accumulator and `EventDispatcher`. The first turns relative
30//! motion into a position, which needs a screen extent to clamp against and
31//! belongs where that is known; the second is a list of callbacks, which is
32//! what a caller writes around a `Vec` of events anyway.
33
34#![cfg_attr(docsrs, feature(doc_cfg))]
35// The docs link to `Keyboard` and `Seat` wherever they explain what those do,
36// and each is behind a feature. A build without one keeps the prose and loses
37// the link rather than failing; the default build, which has both, is the one
38// that checks every link resolves.
39#![cfg_attr(
40 not(all(feature = "xkb", feature = "libinput")),
41 allow(rustdoc::broken_intra_doc_links)
42)]
43
44mod event;
45mod leds;
46
47#[cfg(feature = "libinput")]
48mod libinput_log;
49
50#[cfg(feature = "libinput")]
51mod seat;
52
53mod repeat;
54mod repeater;
55#[cfg(all(test, feature = "libinput"))]
56mod seat_tests;
57
58#[cfg(test)]
59mod repeat_tests;
60
61#[cfg(test)]
62mod repeater_tests;
63
64#[cfg(feature = "xkb")]
65mod keyboard;
66
67#[cfg(all(test, feature = "xkb"))]
68mod keyboard_tests;
69
70pub use leds::Leds;
71
72#[cfg(feature = "libinput")]
73pub use input::LibinputInterface;
74#[cfg(feature = "libinput")]
75pub use libinput_log::LogPriority;
76pub use repeat::{Repeat, RepeatConfig, Timer};
77pub use repeater::KeyRepeater;
78#[cfg(feature = "libinput")]
79pub use seat::{Seat, SeatOptions};
80
81pub use event::{
82 InputEvent, KeyEvent, PointerAbsolute, PointerAxis, PointerButton, PointerEvent, PointerMotion,
83 ScrollSource, Switch, SwitchEvent, TouchEvent, TouchPhase,
84};
85
86#[cfg(feature = "xkb")]
87pub use keyboard::{Keyboard, KeymapNames, Modifiers};
88
89/// What can go wrong reading input.
90#[derive(Debug, thiserror::Error)]
91#[non_exhaustive]
92pub enum InputError {
93 /// The keymap did not compile.
94 ///
95 /// A layout that is not installed, a variant that does not exist, an
96 /// option xkb does not know. xkb reports the detail through its own log,
97 /// not through a return value, so there is nothing more to pass on here.
98 #[error("the keymap did not compile")]
99 Keymap,
100
101 /// The configuration cannot work.
102 #[error("{0}")]
103 Config(&'static str),
104
105 /// A timer could not be created or read.
106 #[error("repeat timer")]
107 Timer(#[source] std::io::Error),
108
109 /// libinput could not enumerate the seat through udev, opening it or
110 /// after a resume. Carries the seat's name, or `resume`.
111 ///
112 /// Not "no such seat": libinput accepts a seat name udev does not know
113 /// and simply finds no devices on it.
114 #[error("libinput could not enumerate the seat through udev: {0}")]
115 Seat(String),
116
117 /// libinput could not read its devices.
118 #[error("libinput dispatch")]
119 Dispatch(#[source] std::io::Error),
120
121 /// A keymap file could not be read.
122 #[error("reading {path}")]
123 Io {
124 /// The file that could not be read.
125 path: std::path::PathBuf,
126 /// Why.
127 source: std::io::Error,
128 },
129}