Skip to main content

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
36mod event;
37mod leds;
38
39#[cfg(feature = "libinput")]
40mod libinput_log;
41
42#[cfg(feature = "libinput")]
43mod seat;
44
45mod repeat;
46mod repeater;
47#[cfg(all(test, feature = "libinput"))]
48mod seat_tests;
49
50#[cfg(test)]
51mod repeat_tests;
52
53#[cfg(test)]
54mod repeater_tests;
55
56#[cfg(feature = "xkb")]
57mod keyboard;
58
59#[cfg(all(test, feature = "xkb"))]
60mod keyboard_tests;
61
62pub use leds::Leds;
63
64#[cfg(feature = "libinput")]
65pub use input::LibinputInterface;
66#[cfg(feature = "libinput")]
67pub use libinput_log::LogPriority;
68pub use repeat::{Repeat, RepeatConfig, Timer};
69pub use repeater::KeyRepeater;
70#[cfg(feature = "libinput")]
71pub use seat::{Seat, SeatOptions};
72
73pub use event::{
74    InputEvent, KeyEvent, PointerAbsolute, PointerAxis, PointerButton, PointerEvent, PointerMotion,
75    ScrollSource, Switch, SwitchEvent, TouchEvent, TouchPhase,
76};
77
78#[cfg(feature = "xkb")]
79pub use keyboard::{Keyboard, KeymapNames, Modifiers};
80
81/// What can go wrong reading input.
82#[derive(Debug, thiserror::Error)]
83#[non_exhaustive]
84pub enum InputError {
85    /// The keymap did not compile.
86    ///
87    /// A layout that is not installed, a variant that does not exist, an
88    /// option xkb does not know. xkb reports the detail through its own log,
89    /// not through a return value, so there is nothing more to pass on here.
90    #[error("the keymap did not compile")]
91    Keymap,
92
93    /// The configuration cannot work.
94    #[error("{0}")]
95    Config(&'static str),
96
97    /// A timer could not be created or read.
98    #[error("repeat timer")]
99    Timer(#[source] std::io::Error),
100
101    /// The seat could not be opened.
102    #[error("no such seat, or no permission for it: {0}")]
103    Seat(String),
104
105    /// libinput could not read its devices.
106    #[error("libinput dispatch")]
107    Dispatch(#[source] std::io::Error),
108
109    /// A keymap file could not be read.
110    #[error("reading {path}")]
111    Io {
112        /// The file that could not be read.
113        path: std::path::PathBuf,
114        /// Why.
115        source: std::io::Error,
116    },
117}