From 6b13fd3d45d661212e68aa45f1d65ce35638d99c Mon Sep 17 00:00:00 2001 From: Jeff Hiner Date: Mon, 1 Mar 2021 14:27:03 -0700 Subject: [PATCH] Add more rustdoc; reorder pub fns for clarity --- src/attribute_set.rs | 7 +++ src/constants.rs | 11 +++- src/lib.rs | 126 ++++++++++++++++++++++++++----------------- src/tokio_stream.rs | 1 + 4 files changed, 94 insertions(+), 51 deletions(-) diff --git a/src/attribute_set.rs b/src/attribute_set.rs index da37b73..b8c673a 100644 --- a/src/attribute_set.rs +++ b/src/attribute_set.rs @@ -1,6 +1,11 @@ use bitvec::prelude::*; use std::fmt; +/// A collection of bits representing either device capability or state. +/// +/// This can be used to iterate across all keys supported by a keyboard, or all buttons supported +/// by a joystick. You can also query directly whether a specific bit is set (corresponding to +/// whether a key or button is depressed). #[derive(Copy, Clone)] pub struct AttributeSet<'a, T> { bitslice: &'a BitSlice, @@ -17,11 +22,13 @@ impl<'a, T: EvdevEnum> AttributeSet<'a, T> { } #[inline] + /// Returns `true` if this AttributeSet contains the passed T. pub fn contains(&self, attr: T) -> bool { self.bitslice.get(attr.to_index()).map_or(false, |b| *b) } #[inline] + /// Provides an iterator over all "set" bits in the collection. pub fn iter(&self) -> impl Iterator + 'a { self.bitslice.iter_ones().map(T::from_index) } diff --git a/src/constants.rs b/src/constants.rs index f12a9f1..8e41bdd 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -1,4 +1,6 @@ /// Event types supported by the device. +/// +/// This is implemented as a newtype around the u16 "type" field of `libc::input_event`. #[derive(Copy, Clone, PartialEq, Eq)] pub struct EventType(pub u16); @@ -44,11 +46,12 @@ impl EventType { } +/// A "synchronization" message type published by the kernel into the events stream. #[derive(Copy, Clone, PartialEq, Eq)] pub struct Synchronization(pub u16); impl Synchronization { - /// Terminates a packet of events from the device. + /// Used to mark the end of a single atomic "reading" from the device. pub const SYN_REPORT: u16 = 0; /// Appears to be unused. pub const SYN_CONFIG: u16 = 1; @@ -97,6 +100,7 @@ impl PropType { pub(crate) const COUNT: usize = 0x20; } +/// A type of relative axis measurement, typically produced by mice. #[derive(Copy, Clone, PartialEq, Eq)] pub struct RelativeAxisType(pub u16); @@ -121,6 +125,7 @@ impl RelativeAxisType { pub(crate) const COUNT: usize = 0x10; } +/// A type of absolute axis measurement, typically used for touch events and joysticks. #[derive(Copy, Clone, PartialEq, Eq)] pub struct AbsoluteAxisType(pub u16); @@ -188,6 +193,7 @@ impl AbsoluteAxisType { pub(crate) const COUNT: usize = 0x40; } +/// An event type corresponding to a physical or virtual switch. #[derive(Copy, Clone, PartialEq, Eq)] pub struct SwitchType(pub u16); @@ -260,7 +266,7 @@ impl LedType { pub(crate) const COUNT: usize = 0x10; } -/// Various miscellaneous event types. Current as of kernel 4.1. +/// Various miscellaneous event types. #[derive(Copy, Clone, PartialEq, Eq)] pub struct MiscType(pub u16); @@ -323,6 +329,7 @@ impl MiscType { // pub(crate) const COUNT: usize = 0x02; // } +/// A type associated with simple sounds, such as beeps or tones. #[derive(Copy, Clone, PartialEq, Eq)] pub struct SoundType(pub u16); diff --git a/src/lib.rs b/src/lib.rs index a9bef54..43d3c8e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -81,6 +81,8 @@ use std::{ffi::CString, mem::MaybeUninit}; pub use crate::attribute_set::AttributeSet; pub use crate::constants::*; pub use crate::scancodes::*; +#[cfg(feature = "tokio")] +pub use crate::tokio_stream::EventStream; fn ioctl_get_cstring( f: unsafe fn(RawFd, &mut [u8]) -> nix::Result, @@ -350,12 +352,45 @@ impl fmt::Display for Device { const DEFAULT_EVENT_COUNT: usize = 32; impl Device { - /// Returns a set of the event types supported by this device (Key, Switch, etc) + #[inline(always)] + /// Opens a device, given its system path. /// - /// If you're interested in the individual keys or switches supported, it's probably easier - /// to just call the appropriate `supported_*` function instead. - pub fn supported_events(&self) -> AttributeSet<'_, EventType> { - AttributeSet::new(&self.ty) + /// Paths are typically something like `/dev/input/event0`. + pub fn open(path: impl AsRef) -> io::Result { + Self::_open(path.as_ref()) + } + + /// Fetches and returns events from the kernel ring buffer without doing synchronization on + /// SYN_DROPPED. + /// + /// By default this will block until events are available. Typically, users will want to call + /// this in a tight loop within a thread. + pub fn fetch_events_no_sync(&mut self) -> io::Result + '_> { + self.fill_events(DEFAULT_EVENT_COUNT)?; + Ok(self.pending_events.drain(..).map(InputEvent)) + } + + /// Fetches and returns events from the kernel ring buffer, doing synchronization on SYN_DROPPED. + /// + /// By default this will block until events are available. Typically, users will want to call + /// this in a tight loop within a thread. + /// Will insert "fake" events. + pub fn fetch_events(&mut self) -> io::Result + '_> { + self.fill_events(DEFAULT_EVENT_COUNT)?; + self.compensate_dropped()?; + + Ok(self.pending_events.drain(..).map(InputEvent)) + } + + #[cfg(feature = "tokio")] + /// Return a `futures::stream` asynchronous stream of `InputEvent` compatible with Tokio. + /// + /// The stream does NOT compensate for SYN_DROPPED events and will not update internal cached + /// state. + /// The Tokio runtime is expected to keep up with typical event rates. + /// This operation consumes the Device. + pub fn into_event_stream_no_sync(self) -> io::Result { + tokio_stream::EventStream::new(self) } /// Returns the device's name as read from the kernel. @@ -388,6 +423,14 @@ impl Device { self.driver_version } + /// Returns a set of the event types supported by this device (Key, Switch, etc) + /// + /// If you're interested in the individual keys or switches supported, it's probably easier + /// to just call the appropriate `supported_*` function instead. + pub fn supported_events(&self) -> AttributeSet<'_, EventType> { + AttributeSet::new(&self.ty) + } + /// Returns the set of supported keys reported by the device. /// /// For keyboards, this is the set of all possible keycodes the keyboard may emit. Controllers, @@ -513,14 +556,6 @@ impl Device { &self.state } - #[inline(always)] - /// Opens a device, given its system path. - /// - /// Paths are typically something like `/dev/input/event0`. - pub fn open(path: impl AsRef) -> io::Result { - Self::_open(path.as_ref()) - } - fn _open(path: &Path) -> io::Result { let mut options = OpenOptions::new(); @@ -826,7 +861,7 @@ impl Device { /// O_NONBLOCK, this will block. /// /// Returns the number of events that were read, or an error. - pub fn fill_events(&mut self, num: usize) -> io::Result { + fn fill_events(&mut self, num: usize) -> io::Result { let fd = self.as_raw_fd(); self.read_buf.clear(); self.read_buf.reserve_exact(num); @@ -851,42 +886,12 @@ impl Device { fn pop_event(&mut self) -> Option { self.pending_events.pop_front().map(InputEvent) } - - /// Fetches and returns events from the kernel ring buffer without doing synchronization on - /// SYN_DROPPED. - /// - /// By default this will block until events are available. Typically, users will want to call - /// this in a tight loop within a thread. - pub fn fetch_events_no_sync(&mut self) -> io::Result + '_> { - self.fill_events(DEFAULT_EVENT_COUNT)?; - Ok(self.pending_events.drain(..).map(InputEvent)) - } - - /// Fetches and returns events from the kernel ring buffer, doing synchronization on SYN_DROPPED. - /// - /// By default this will block until events are available. Typically, users will want to call - /// this in a tight loop within a thread. - /// Will insert "fake" events. - pub fn fetch_events(&mut self) -> io::Result + '_> { - self.fill_events(DEFAULT_EVENT_COUNT)?; - self.compensate_dropped()?; - - Ok(self.pending_events.drain(..).map(InputEvent)) - } - - #[cfg(feature = "tokio")] - /// Return a `futures::stream` asynchronous stream of `InputEvent` compatible with Tokio. - /// - /// The stream does NOT compensate for SYN_DROPPED events and will not update internal cached - /// state. - /// The Tokio runtime is expected to keep up with typical event rates. - /// This operation consumes the Device. - pub fn into_event_stream_no_sync(self) -> io::Result { - tokio_stream::EventStream::new(self) - } } #[derive(Debug, Copy, Clone, PartialEq, Eq)] +/// A convenience mapping from an event `(type, code)` to an enumeration. +/// +/// Note that this does not capture an event's value, just the type and code. pub enum InputEventKind { Synchronization(Synchronization), Key(Key), @@ -900,26 +905,41 @@ pub enum InputEventKind { } #[repr(transparent)] +/// A wrapped `libc::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. pub struct InputEvent(libc::input_event); impl InputEvent { #[inline] + /// Returns the timestamp associated with the event. pub fn timestamp(&self) -> SystemTime { timeval_to_systime(&self.0.time) } #[inline] + /// Returns the type of event this describes, e.g. Key, Switch, etc. pub fn event_type(&self) -> EventType { EventType(self.0.type_) } #[inline] + /// Returns the raw "code" field directly from input_event. pub fn code(&self) -> u16 { self.0.code } /// A convenience function to return `self.code()` wrapped in a certain newtype determined by /// the type of this event. + /// + /// This is useful if you want to match events by specific key codes or axes. Note that this + /// does not capture the event value, just the type and code. #[inline] pub fn kind(&self) -> InputEventKind { let code = self.code(); @@ -937,15 +957,23 @@ impl InputEvent { } #[inline] + /// 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. pub fn value(&self) -> i32 { self.0.value } +} - pub fn from_raw(raw: libc::input_event) -> Self { +impl From for InputEvent { + fn from(raw: libc::input_event) -> Self { Self(raw) } +} - pub fn as_raw(&self) -> &libc::input_event { +impl<'a> Into<&'a libc::input_event> for &'a InputEvent { + fn into(self) -> &'a libc::input_event { &self.0 } } diff --git a/src/tokio_stream.rs b/src/tokio_stream.rs index 318fc7c..0f26595 100644 --- a/src/tokio_stream.rs +++ b/src/tokio_stream.rs @@ -8,6 +8,7 @@ use std::pin::Pin; use std::task::{Context, Poll}; use tokio::io::unix::AsyncFd; +/// An async stream of events. pub struct EventStream { device: AsyncFd, }