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}