Add more rustdoc; reorder pub fns for clarity
This commit is contained in:
parent
fa4838e5f8
commit
6b13fd3d45
4 changed files with 94 additions and 51 deletions
|
@ -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<Lsb0, u8>,
|
||||
|
@ -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<Item = T> + 'a {
|
||||
self.bitslice.iter_ones().map(T::from_index)
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
130
src/lib.rs
130
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<libc::c_int>,
|
||||
|
@ -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<Path>) -> io::Result<Device> {
|
||||
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<impl Iterator<Item = InputEvent> + '_> {
|
||||
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<impl Iterator<Item = InputEvent> + '_> {
|
||||
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> {
|
||||
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<Path>) -> io::Result<Device> {
|
||||
Self::_open(path.as_ref())
|
||||
}
|
||||
|
||||
fn _open(path: &Path) -> io::Result<Device> {
|
||||
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<usize> {
|
||||
fn fill_events(&mut self, num: usize) -> io::Result<usize> {
|
||||
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<InputEvent> {
|
||||
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<impl Iterator<Item = InputEvent> + '_> {
|
||||
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<impl Iterator<Item = InputEvent> + '_> {
|
||||
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> {
|
||||
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 {
|
||||
Self(raw)
|
||||
}
|
||||
|
||||
pub fn as_raw(&self) -> &libc::input_event {
|
||||
impl From<libc::input_event> for InputEvent {
|
||||
fn from(raw: libc::input_event) -> Self {
|
||||
Self(raw)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Into<&'a libc::input_event> for &'a InputEvent {
|
||||
fn into(self) -> &'a libc::input_event {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Device>,
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue