evdevil/reader.rs
1//! A convenient API for robustly reading device events.
2
3use std::{
4 collections::VecDeque,
5 fmt, io,
6 time::{Instant, SystemTime},
7};
8
9use crate::{
10 Evdev, Slot,
11 batch::BatchReader,
12 bits::{BitSet, BitValue},
13 drop::on_drop,
14 event::{
15 Abs, AbsEvent, EventKind, InputEvent, Key, KeyEvent, KeyState, Led, LedEvent, Sound,
16 SoundEvent, Switch, SwitchEvent, Syn, SynEvent,
17 },
18 raw::input::EVIOCGMTSLOTS,
19};
20
21const MAX_MT_SLOTS: i32 = 60; // matches the limit libevdev documents
22
23/// Storage for the current multitouch state.
24#[derive(Clone)]
25struct MtStorage {
26 /// The data buffer contains `codes` number of groups, each prefixed by the `ABS_MT_*` axis
27 /// code followed by `slots` values of that code.
28 data: Vec<i32>,
29 /// Number of MT slots supported by the device (`maximum` value of the `ABS_MT_SLOT` axis).
30 slots: u32,
31 /// Number of supported `ABS_*` codes between `ABS_MT_SLOT+1` and `ABS_MAX`.
32 codes: u32,
33 /// Selected MT slot (current value of the `ABS_MT_SLOT` axis).
34 active_slot: u32,
35}
36
37impl fmt::Debug for MtStorage {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 struct FmtData<'a> {
40 data: &'a [i32],
41 slots: usize,
42 }
43
44 impl fmt::Debug for FmtData<'_> {
45 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46 let mut list = f.debug_list();
47 for chunk in self.data.chunks(self.slots + 1) {
48 list.entry(&Abs::from_raw(chunk[0] as u16));
49 list.entries(&chunk[1..]);
50 }
51 list.finish()
52 }
53 }
54
55 f.debug_struct("MtStorage")
56 .field("slots", &self.slots)
57 .field("codes", &self.codes)
58 .field("active_slot", &self.active_slot)
59 .field(
60 "data",
61 &FmtData {
62 data: &self.data,
63 slots: self.slots as usize,
64 },
65 )
66 .finish()
67 }
68}
69
70impl MtStorage {
71 fn empty() -> Self {
72 Self {
73 data: Vec::new(),
74 slots: 0,
75 codes: 0,
76 active_slot: 0,
77 }
78 }
79
80 fn resync(&mut self, evdev: &Evdev, abs_axes: &BitSet<Abs>) -> io::Result<()> {
81 if !abs_axes.contains(Abs::MT_SLOT) {
82 return Ok(());
83 }
84 if !abs_axes.contains(Abs::MT_TRACKING_ID) {
85 log::warn!(
86 "device {} advertises support for `ABS_MT_SLOT` but not `ABS_MT_TRACKING_ID`; multitouch support will not work",
87 evdev.name().unwrap_or_else(|e| e.to_string()),
88 );
89 *self = Self::empty();
90 return Ok(());
91 }
92
93 let mt_slot_info = evdev.abs_info(Abs::MT_SLOT)?;
94 if mt_slot_info.minimum() != 0 {
95 log::warn!("`ABS_MT_SLOT` has a non-0 minimum: {:?}", mt_slot_info);
96 }
97
98 let slot_count = mt_slot_info.maximum().saturating_add(1);
99 if mt_slot_info.maximum() > MAX_MT_SLOTS {
100 log::warn!(
101 "`ABS_MT_SLOT` declares too many slots: {:?} (only the first {} will be used)",
102 mt_slot_info,
103 MAX_MT_SLOTS,
104 );
105 }
106 self.slots = slot_count.clamp(0, MAX_MT_SLOTS) as u32;
107 self.slots = (mt_slot_info.maximum() + 1) as u32;
108 self.active_slot = mt_slot_info.value().max(0) as u32;
109 self.data.clear();
110 self.codes = 0;
111
112 for mt_code in Abs::MT_SLOT.raw() + 1..Abs::MAX.raw() {
113 if !abs_axes.contains(Abs::from_raw(mt_code)) {
114 continue;
115 }
116
117 // `mt_code` is supported; fetch its current value for all slots, appending it to `data`
118 self.codes += 1;
119 let start_idx = self.data.len();
120 self.data
121 .resize(self.data.len() + 1 + self.slots as usize, 0);
122 self.data[start_idx] = mt_code.into();
123
124 unsafe {
125 EVIOCGMTSLOTS((self.slots as usize + 1) * 4)
126 .ioctl(evdev, self.data[start_idx..].as_mut_ptr().cast())?;
127 }
128 }
129 self.data.shrink_to_fit();
130
131 Ok(())
132 }
133
134 /// Iterator over code groups; each slice has `slots + 1` entries, the first one being the
135 /// `ABS_MT_*` code of the group.
136 fn groups(&self) -> impl Iterator<Item = &[i32]> + '_ {
137 self.data
138 .chunks((self.slots + 1) as usize)
139 .take(self.codes as usize)
140 }
141 fn groups_mut(&mut self) -> impl Iterator<Item = &mut [i32]> + '_ {
142 self.data
143 .chunks_mut((self.slots + 1) as usize)
144 .take(self.codes as usize)
145 }
146
147 /// Returns a slice with 1 value of `code` per slot.
148 ///
149 /// `code` must be one of the `ABS_MT_*` codes (but not `ABS_MT_SLOT`).
150 fn group_for_code(&self, code: Abs) -> Option<&[i32]> {
151 if code.raw() <= Abs::MT_SLOT.raw() || code.raw() > Abs::MAX.raw() {
152 return None;
153 }
154 self.groups().find_map(|grp| {
155 if grp[0] == i32::from(code.raw()) {
156 Some(&grp[1..])
157 } else {
158 None
159 }
160 })
161 }
162
163 fn mut_group_for_code(&mut self, code: Abs) -> Option<&mut [i32]> {
164 if code.raw() <= Abs::MT_SLOT.raw() || code.raw() > Abs::MAX.raw() {
165 return None;
166 }
167 self.groups_mut().find_map(|grp| {
168 if grp[0] == i32::from(code.raw()) {
169 Some(&mut grp[1..])
170 } else {
171 None
172 }
173 })
174 }
175
176 /// Iterator over all slot indices with valid data in them.
177 fn valid_slots(&self) -> impl Iterator<Item = Slot> + '_ {
178 self.group_for_code(Abs::MT_TRACKING_ID)
179 .unwrap_or(&[])
180 .iter()
181 .enumerate()
182 .filter_map(|(slot, id)| {
183 if *id == -1 {
184 None
185 } else {
186 Some(Slot::from(slot as u16))
187 }
188 })
189 }
190}
191
192#[derive(Debug)]
193struct DeviceState {
194 keys: BitSet<Key>,
195 leds: BitSet<Led>,
196 sounds: BitSet<Sound>,
197 switches: BitSet<Switch>,
198 abs: [i32; Abs::MT_SLOT.raw() as usize],
199 abs_axes: BitSet<Abs>, // supported axes
200 mt_storage: MtStorage,
201 last_event: SystemTime,
202}
203
204impl DeviceState {
205 fn new(abs_axes: BitSet<Abs>) -> Self {
206 Self {
207 keys: BitSet::new(),
208 leds: BitSet::new(),
209 sounds: BitSet::new(),
210 switches: BitSet::new(),
211 abs: [0; Abs::MT_SLOT.raw() as usize],
212 abs_axes,
213 mt_storage: MtStorage::empty(),
214 // We emit events to update to the current device state, but without having any device
215 // events available to get a timestamp from.
216 // Default to `now()` so that there's a reasonable default time.
217 // This should be the correct default time source, too.
218 last_event: SystemTime::now(),
219 }
220 }
221
222 /// Fetches the current device state, and injects synthetic events to compensate for any
223 /// difference to the expected state.
224 fn resync(&mut self, evdev: &Evdev, queue: &mut VecDeque<InputEvent>) -> io::Result<()> {
225 fn sync_bitset<V: BitValue>(
226 dest: &mut BitSet<V>,
227 src: BitSet<V>,
228 mut cb: impl FnMut(V, /* became set */ bool),
229 ) {
230 for value in dest.symmetric_difference(&src) {
231 cb(value, src.contains(value));
232 }
233
234 *dest = src;
235 }
236
237 let now = Instant::now();
238 let _d = on_drop(|| log::debug!("`EventReader::resync` took {:?}", now.elapsed()));
239
240 let mut did_emit = false;
241 let mut emit = |ev: InputEvent| {
242 did_emit = true;
243 queue.push_back(ev.with_time(self.last_event));
244 };
245
246 sync_bitset(&mut self.keys, evdev.key_state()?, |key, on| {
247 emit(
248 KeyEvent::new(
249 key,
250 if on {
251 KeyState::PRESSED
252 } else {
253 KeyState::RELEASED
254 },
255 )
256 .into(),
257 );
258 });
259 sync_bitset(&mut self.leds, evdev.led_state()?, |led, on| {
260 emit(LedEvent::new(led, on).into());
261 });
262 sync_bitset(&mut self.sounds, evdev.sound_state()?, |snd, playing| {
263 emit(SoundEvent::new(snd, playing).into());
264 });
265 sync_bitset(&mut self.switches, evdev.switch_state()?, |sw, on| {
266 emit(SwitchEvent::new(sw, on).into());
267 });
268
269 // Re-fetch values of all non-MT absolute axes
270 for abs in self.abs_axes {
271 if abs.raw() >= Abs::MT_SLOT.raw() {
272 break;
273 }
274
275 let prev = self.abs[abs.raw() as usize];
276 let cur = evdev.abs_info(abs)?.value();
277 if prev != cur {
278 emit(AbsEvent::new(abs, cur).into());
279 }
280 }
281
282 if self.abs_axes.contains(Abs::MT_SLOT) {
283 // Re-fetch the state of every MT slot
284 self.mt_storage.resync(&evdev, &self.abs_axes)?;
285 }
286 // FIXME: we don't currently *emit* synthetic events for multitouch changes
287 // (expectation is that the `valid_slots()` and `slot_state()` API is preferred)
288
289 // If we emitted any synthetic events, follow up with a SYN_REPORT.
290 // It's not clear if this is *strictly* necessary after a SYN_DROPPED: the kernel seems to
291 // emit an empty report consisting of just a SYN_REPORT event after a SYN_DROPPED.
292 // It is useful after the `EventReader` is just constructed though, since the event would
293 // otherwise be missing.
294 if did_emit {
295 queue.push_back(SynEvent::new(Syn::REPORT).with_time(self.last_event));
296 }
297
298 Ok(())
299 }
300
301 /// Ingests an [`InputEvent`] and updates the local device state accordingly.
302 fn update_state(&mut self, ev: InputEvent) {
303 match ev.kind() {
304 Some(EventKind::Abs(ev)) => {
305 if ev.abs().raw() < Abs::MT_SLOT.raw() {
306 self.abs[ev.abs().raw() as usize] = ev.value();
307 } else if ev.abs() == Abs::MT_SLOT {
308 self.mt_storage.active_slot = ev.value() as u32;
309 } else {
310 let slot = self.mt_storage.active_slot;
311 if let Some(group) = self.mt_storage.mut_group_for_code(ev.abs()) {
312 if let Some(slot) = group.get_mut(slot as usize) {
313 *slot = ev.value();
314 }
315 }
316 }
317 }
318 Some(EventKind::Key(ev)) => match ev.state() {
319 KeyState::PRESSED => {
320 self.keys.insert(ev.key());
321 }
322 KeyState::RELEASED => {
323 self.keys.remove(ev.key());
324 }
325 _ => {}
326 },
327 Some(EventKind::Led(ev)) => {
328 if ev.is_on() {
329 self.leds.insert(ev.led());
330 } else {
331 self.leds.remove(ev.led());
332 }
333 }
334 Some(EventKind::Switch(ev)) => {
335 if ev.is_pressed() {
336 self.switches.insert(ev.switch());
337 } else {
338 self.switches.remove(ev.switch());
339 }
340 }
341 Some(EventKind::Sound(ev)) => {
342 if ev.is_playing() {
343 self.sounds.insert(ev.sound());
344 } else {
345 self.sounds.remove(ev.sound());
346 }
347 }
348 _ => {}
349 }
350 }
351}
352
353/// Stores a userspace view of a device, and reads events emitted by it.
354///
355/// Created by [`Evdev::into_reader`].
356///
357/// This is the recommended way of ingesting input events from an `evdev`.
358///
359/// In addition to reading the raw events emitted by the device, [`EventReader`] will:
360/// - Keep a view of the current device state that the user can query.
361/// - Fetch the current device state on creation and when a `SYN_DROPPED` event is received
362/// (indicating that one or more events have been lost due to the buffer filling up).
363/// - Synthesize events so that the consumer will see an up-to-date state.
364///
365/// The current device state from the [`EventReader`]'s PoV can be queried via
366/// [`EventReader::key_state`], [`EventReader::abs_state`], [`EventReader::slot_state`], and similar
367/// methods.
368/// These methods are faster than the equivalent methods on [`Evdev`], since they do not have to
369/// perform a system call to fetch the data (they just return data already stored in the
370/// [`EventReader`]).
371/// The reader's view of the device state is automatically updated as events are pulled from it, but
372/// can also be manually updated by calling [`EventReader::update`], which will pull and discard all
373/// available events.
374#[derive(Debug)]
375pub struct EventReader {
376 evdev: Evdev,
377 batch: BatchReader,
378 state: DeviceState,
379
380 /// Queues outgoing input events.
381 ///
382 /// Events received from the raw [`Evdev`] event stream are only committed once they are
383 /// followed up by a `SYN_REPORT` event. Only then do we write an event batch to this queue.
384 queue: VecDeque<InputEvent>,
385 /// Whether we need to discard (instead of queuing) all events until the next `SYN_REPORT`.
386 ///
387 /// Set after we get a `SYN_DROPPED` to clear out incomplete reports.
388 discard_events: bool,
389}
390
391impl EventReader {
392 pub(crate) fn new(evdev: Evdev) -> io::Result<Self> {
393 let abs_axes = evdev.supported_abs_axes()?;
394
395 let mut this = Self {
396 batch: BatchReader::new(),
397 state: DeviceState::new(abs_axes),
398 queue: VecDeque::new(),
399 evdev,
400 discard_events: false,
401 };
402
403 // resync to inject events that represent the current device state.
404 this.state.resync(&this.evdev, &mut this.queue)?;
405
406 Ok(this)
407 }
408
409 /// Destroys this [`EventReader`] and returns the original [`Evdev`].
410 ///
411 /// This will drop all input events buffered in the [`EventReader`].
412 pub fn into_evdev(self) -> Evdev {
413 self.evdev
414 }
415
416 /// Returns a reference to the [`Evdev`] this [`EventReader`] was created from.
417 pub fn evdev(&self) -> &Evdev {
418 &self.evdev
419 }
420
421 /// Update the local device state by reading all available events from the kernel, and
422 /// discarding them.
423 ///
424 /// This does not block.
425 pub fn update(&mut self) -> io::Result<()> {
426 let now = Instant::now();
427 let _d = on_drop(|| log::trace!("`EventReader::update` took {:?}", now.elapsed()));
428
429 let was_nonblocking = self.evdev.set_nonblocking(true)?;
430
431 let mut count = 0;
432 let mut events = self.events();
433 let err = loop {
434 match events.next() {
435 None => break None,
436 Some(Ok(_)) => count += 1,
437 Some(Err(e)) => break Some(e),
438 }
439 };
440 log::trace!("`EventReader::update` processed {count} events");
441
442 let res = self.evdev.set_nonblocking(was_nonblocking);
443 match err {
444 Some(e) => Err(e),
445 None => res.map(drop),
446 }
447 }
448
449 /// Returns the [`EventReader`]'s view of the device's key state.
450 pub fn key_state(&self) -> &BitSet<Key> {
451 &self.state.keys
452 }
453
454 /// Returns the [`EventReader`]'s view of the device's LED state.
455 pub fn led_state(&self) -> &BitSet<Led> {
456 &self.state.leds
457 }
458
459 /// Returns the [`EventReader`]'s view of the device's sound state.
460 pub fn sound_state(&self) -> &BitSet<Sound> {
461 &self.state.sounds
462 }
463
464 /// Returns the [`EventReader`]'s view of the device's switch state.
465 pub fn switch_state(&self) -> &BitSet<Switch> {
466 &self.state.switches
467 }
468
469 /// Returns the current value of an absolute axis.
470 ///
471 /// `abs` must be less than [`Abs::MT_SLOT`], or this method will panic. To access
472 /// multitouch slots, use [`EventReader::slot_state`] instead.
473 ///
474 /// Call [`EventReader::update`], or drain incoming events using the iterator interface in order
475 /// to update the multitouch slot state.
476 pub fn abs_state(&self, abs: Abs) -> i32 {
477 self.state.abs[abs.raw() as usize]
478 }
479
480 /// Returns an iterator that yields all [`Slot`]s that have valid data in them.
481 ///
482 /// A [`Slot`] is considered valid if its value of [`Abs::MT_TRACKING_ID`] is non-negative.
483 ///
484 /// Call [`EventReader::update`], or drain incoming events using the iterator interface in order
485 /// to update the multitouch slot state.
486 pub fn valid_slots(&self) -> impl Iterator<Item = Slot> + '_ {
487 self.state.mt_storage.valid_slots()
488 }
489
490 /// Returns an [`Abs`] axis value for a multitouch slot.
491 ///
492 /// `code` must be one of the `Abs::MT_*` codes (but not [`Abs::MT_SLOT`]), as only those are
493 /// associated with a multitouch slot.
494 /// Non-MT [`Abs`] codes can be queried via [`EventReader::abs_state`].
495 ///
496 /// Returns [`None`] if `code` isn't advertised by the device (ie. the property does not exist)
497 /// or if `slot` is out of range (ie. the device does not have the requested slot).
498 ///
499 /// If `slot` isn't valid (yielded by [`EventReader::valid_slots`]), invalid stale data may be
500 /// returned.
501 pub fn slot_state(&self, slot: impl TryInto<Slot>, code: Abs) -> Option<i32> {
502 let slot: Slot = slot.try_into().ok()?;
503 assert!(
504 code.raw() > Abs::MT_SLOT.raw(),
505 "`slot_state` requires an `ABS_MT_*` value above `ABS_MT_SLOT`"
506 );
507 self.state
508 .mt_storage
509 .group_for_code(code)?
510 .get(slot.raw() as usize)
511 .copied()
512 }
513
514 /// Returns the currently selected multitouch slot.
515 ///
516 /// Events with `ABS_MT_*` code affect *this* slot, but not other slots.
517 pub fn current_slot(&self) -> Slot {
518 Slot::from_raw(self.state.mt_storage.active_slot as i32)
519 }
520
521 /// Returns an iterator over incoming events.
522 ///
523 /// Events read from the iterator will automatically update the state of the [`EventReader`].
524 ///
525 /// If the underlying device is in non-blocking mode, the iterator will return [`None`] when no
526 /// more events are available.
527 /// If the device is *not* in non-blocking mode, the iterator will block until more events
528 /// arrive.
529 pub fn events(&mut self) -> Events<'_> {
530 Events(self)
531 }
532
533 fn next_event(&mut self) -> Option<io::Result<InputEvent>> {
534 if let Some(event) = self.queue.pop_front() {
535 return Some(Ok(event));
536 }
537
538 // No more queued events to deliver. We've been asked to block until the next one is
539 // available, so do that.
540 // Incoming raw events get batch-read into `self.incoming.`
541 loop {
542 let batch = match self.batch.fill(&self.evdev.file) {
543 Ok(None) => continue, // read some events, but no SYN_x event
544 Ok(Some(batch)) => batch,
545 // Return `None` when the device is in non-blocking mode and no events are available.
546 Err(e) if e.kind() == io::ErrorKind::WouldBlock => return None,
547 Err(e) => return Some(Err(e)),
548 };
549
550 // We've been handed a `batch` of events, the last of which is guaranteed to either be
551 // a SYN_REPORT or a SYN_DROPPED.
552 let ev = batch.as_slice().last().expect("got empty batch");
553 let syn = match ev.kind() {
554 Some(EventKind::Syn(ev)) => ev,
555 _ => unreachable!("got invalid event at the end of a batch: {ev:?}"),
556 };
557
558 // Save the timestamp of the last event in the batch.
559 self.state.last_event = ev.time();
560
561 match syn.syn() {
562 Syn::REPORT => {
563 if self.discard_events {
564 // We have to drop this batch.
565 self.discard_events = false;
566 continue;
567 } else {
568 // We can commit this batch.
569 for ev in batch.as_slice() {
570 self.state.update_state(*ev);
571 }
572 self.queue.extend(batch);
573
574 let event = self.queue.pop_front().unwrap(/* not empty */);
575 return Some(Ok(event));
576 }
577 }
578 Syn::DROPPED => {
579 // At least one event has been lost, so we have to resynchronize.
580 // According to the `libevdev` documentation, we we have to:
581 // - Drop all uncommitted events (events that weren't followed up by a `SYN_REPORT`).
582 // - Drop all *future* events until we get a `SYN_REPORT`.
583 log::debug!("SYN_DROPPED: events were lost! resyncing");
584 self.discard_events = true;
585
586 // Fetch device state and synthesize events.
587 if let Err(e) = self.state.resync(&self.evdev, &mut self.queue) {
588 return Some(Err(e));
589 }
590 // Start sending the synthetic events to the consumer.
591 if let Some(ev) = self.queue.pop_front() {
592 return Some(Ok(ev));
593 }
594 // We will return to normal operation once the synthetic events have been
595 // cleared out and all events until the next `SYN_REPORT` have been discarded.
596 }
597 _ => unreachable!("unexpected SYN event at the end of a batch: {syn:?}"),
598 }
599 }
600 }
601}
602
603impl<'a> IntoIterator for &'a mut EventReader {
604 type Item = io::Result<InputEvent>;
605 type IntoIter = Events<'a>;
606
607 fn into_iter(self) -> Self::IntoIter {
608 self.events()
609 }
610}
611
612impl IntoIterator for EventReader {
613 type Item = io::Result<InputEvent>;
614 type IntoIter = IntoEvents;
615
616 fn into_iter(self) -> Self::IntoIter {
617 IntoEvents(self)
618 }
619}
620
621/// An [`Iterator`] over the events produced by an [`EventReader`].
622///
623/// Returned by [`EventReader::events`].
624#[derive(Debug)]
625pub struct Events<'a>(&'a mut EventReader);
626
627impl Iterator for Events<'_> {
628 type Item = io::Result<InputEvent>;
629
630 fn next(&mut self) -> Option<Self::Item> {
631 self.0.next_event()
632 }
633}
634
635/// An owning [`Iterator`] over the events produced by an [`EventReader`].
636#[derive(Debug)]
637pub struct IntoEvents(EventReader);
638
639impl IntoEvents {
640 /// Consumes this [`IntoEvents`] iterator and returns back the original [`EventReader`].
641 pub fn into_reader(self) -> EventReader {
642 self.0
643 }
644}
645
646impl Iterator for IntoEvents {
647 type Item = io::Result<InputEvent>;
648
649 fn next(&mut self) -> Option<Self::Item> {
650 self.0.next_event()
651 }
652}