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 bitvec::prelude::*;
|
||||||
use std::fmt;
|
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)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct AttributeSet<'a, T> {
|
pub struct AttributeSet<'a, T> {
|
||||||
bitslice: &'a BitSlice<Lsb0, u8>,
|
bitslice: &'a BitSlice<Lsb0, u8>,
|
||||||
|
@ -17,11 +22,13 @@ impl<'a, T: EvdevEnum> AttributeSet<'a, T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
/// Returns `true` if this AttributeSet contains the passed T.
|
||||||
pub fn contains(&self, attr: T) -> bool {
|
pub fn contains(&self, attr: T) -> bool {
|
||||||
self.bitslice.get(attr.to_index()).map_or(false, |b| *b)
|
self.bitslice.get(attr.to_index()).map_or(false, |b| *b)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
/// Provides an iterator over all "set" bits in the collection.
|
||||||
pub fn iter(&self) -> impl Iterator<Item = T> + 'a {
|
pub fn iter(&self) -> impl Iterator<Item = T> + 'a {
|
||||||
self.bitslice.iter_ones().map(T::from_index)
|
self.bitslice.iter_ones().map(T::from_index)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
/// Event types supported by the device.
|
/// 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)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
pub struct EventType(pub u16);
|
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)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
pub struct Synchronization(pub u16);
|
pub struct Synchronization(pub u16);
|
||||||
|
|
||||||
impl Synchronization {
|
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;
|
pub const SYN_REPORT: u16 = 0;
|
||||||
/// Appears to be unused.
|
/// Appears to be unused.
|
||||||
pub const SYN_CONFIG: u16 = 1;
|
pub const SYN_CONFIG: u16 = 1;
|
||||||
|
@ -97,6 +100,7 @@ impl PropType {
|
||||||
pub(crate) const COUNT: usize = 0x20;
|
pub(crate) const COUNT: usize = 0x20;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A type of relative axis measurement, typically produced by mice.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
pub struct RelativeAxisType(pub u16);
|
pub struct RelativeAxisType(pub u16);
|
||||||
|
|
||||||
|
@ -121,6 +125,7 @@ impl RelativeAxisType {
|
||||||
pub(crate) const COUNT: usize = 0x10;
|
pub(crate) const COUNT: usize = 0x10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A type of absolute axis measurement, typically used for touch events and joysticks.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
pub struct AbsoluteAxisType(pub u16);
|
pub struct AbsoluteAxisType(pub u16);
|
||||||
|
|
||||||
|
@ -188,6 +193,7 @@ impl AbsoluteAxisType {
|
||||||
pub(crate) const COUNT: usize = 0x40;
|
pub(crate) const COUNT: usize = 0x40;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An event type corresponding to a physical or virtual switch.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
pub struct SwitchType(pub u16);
|
pub struct SwitchType(pub u16);
|
||||||
|
|
||||||
|
@ -260,7 +266,7 @@ impl LedType {
|
||||||
pub(crate) const COUNT: usize = 0x10;
|
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)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
pub struct MiscType(pub u16);
|
pub struct MiscType(pub u16);
|
||||||
|
|
||||||
|
@ -323,6 +329,7 @@ impl MiscType {
|
||||||
// pub(crate) const COUNT: usize = 0x02;
|
// pub(crate) const COUNT: usize = 0x02;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
/// A type associated with simple sounds, such as beeps or tones.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
pub struct SoundType(pub u16);
|
pub struct SoundType(pub u16);
|
||||||
|
|
||||||
|
|
126
src/lib.rs
126
src/lib.rs
|
@ -81,6 +81,8 @@ use std::{ffi::CString, mem::MaybeUninit};
|
||||||
pub use crate::attribute_set::AttributeSet;
|
pub use crate::attribute_set::AttributeSet;
|
||||||
pub use crate::constants::*;
|
pub use crate::constants::*;
|
||||||
pub use crate::scancodes::*;
|
pub use crate::scancodes::*;
|
||||||
|
#[cfg(feature = "tokio")]
|
||||||
|
pub use crate::tokio_stream::EventStream;
|
||||||
|
|
||||||
fn ioctl_get_cstring(
|
fn ioctl_get_cstring(
|
||||||
f: unsafe fn(RawFd, &mut [u8]) -> nix::Result<libc::c_int>,
|
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;
|
const DEFAULT_EVENT_COUNT: usize = 32;
|
||||||
|
|
||||||
impl Device {
|
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
|
/// Paths are typically something like `/dev/input/event0`.
|
||||||
/// to just call the appropriate `supported_*` function instead.
|
pub fn open(path: impl AsRef<Path>) -> io::Result<Device> {
|
||||||
pub fn supported_events(&self) -> AttributeSet<'_, EventType> {
|
Self::_open(path.as_ref())
|
||||||
AttributeSet::new(&self.ty)
|
}
|
||||||
|
|
||||||
|
/// 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.
|
/// Returns the device's name as read from the kernel.
|
||||||
|
@ -388,6 +423,14 @@ impl Device {
|
||||||
self.driver_version
|
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.
|
/// 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,
|
/// For keyboards, this is the set of all possible keycodes the keyboard may emit. Controllers,
|
||||||
|
@ -513,14 +556,6 @@ impl Device {
|
||||||
&self.state
|
&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> {
|
fn _open(path: &Path) -> io::Result<Device> {
|
||||||
let mut options = OpenOptions::new();
|
let mut options = OpenOptions::new();
|
||||||
|
|
||||||
|
@ -826,7 +861,7 @@ impl Device {
|
||||||
/// O_NONBLOCK, this will block.
|
/// O_NONBLOCK, this will block.
|
||||||
///
|
///
|
||||||
/// Returns the number of events that were read, or an error.
|
/// 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();
|
let fd = self.as_raw_fd();
|
||||||
self.read_buf.clear();
|
self.read_buf.clear();
|
||||||
self.read_buf.reserve_exact(num);
|
self.read_buf.reserve_exact(num);
|
||||||
|
@ -851,42 +886,12 @@ impl Device {
|
||||||
fn pop_event(&mut self) -> Option<InputEvent> {
|
fn pop_event(&mut self) -> Option<InputEvent> {
|
||||||
self.pending_events.pop_front().map(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)]
|
#[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 {
|
pub enum InputEventKind {
|
||||||
Synchronization(Synchronization),
|
Synchronization(Synchronization),
|
||||||
Key(Key),
|
Key(Key),
|
||||||
|
@ -900,26 +905,41 @@ pub enum InputEventKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[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);
|
pub struct InputEvent(libc::input_event);
|
||||||
|
|
||||||
impl InputEvent {
|
impl InputEvent {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
/// Returns the timestamp associated with the event.
|
||||||
pub fn timestamp(&self) -> SystemTime {
|
pub fn timestamp(&self) -> SystemTime {
|
||||||
timeval_to_systime(&self.0.time)
|
timeval_to_systime(&self.0.time)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
/// Returns the type of event this describes, e.g. Key, Switch, etc.
|
||||||
pub fn event_type(&self) -> EventType {
|
pub fn event_type(&self) -> EventType {
|
||||||
EventType(self.0.type_)
|
EventType(self.0.type_)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
/// Returns the raw "code" field directly from input_event.
|
||||||
pub fn code(&self) -> u16 {
|
pub fn code(&self) -> u16 {
|
||||||
self.0.code
|
self.0.code
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A convenience function to return `self.code()` wrapped in a certain newtype determined by
|
/// A convenience function to return `self.code()` wrapped in a certain newtype determined by
|
||||||
/// the type of this event.
|
/// 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]
|
#[inline]
|
||||||
pub fn kind(&self) -> InputEventKind {
|
pub fn kind(&self) -> InputEventKind {
|
||||||
let code = self.code();
|
let code = self.code();
|
||||||
|
@ -937,15 +957,23 @@ impl InputEvent {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[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 {
|
pub fn value(&self) -> i32 {
|
||||||
self.0.value
|
self.0.value
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn from_raw(raw: libc::input_event) -> Self {
|
impl From<libc::input_event> for InputEvent {
|
||||||
|
fn from(raw: libc::input_event) -> Self {
|
||||||
Self(raw)
|
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
|
&self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ use std::pin::Pin;
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
use tokio::io::unix::AsyncFd;
|
use tokio::io::unix::AsyncFd;
|
||||||
|
|
||||||
|
/// An async stream of events.
|
||||||
pub struct EventStream {
|
pub struct EventStream {
|
||||||
device: AsyncFd<Device>,
|
device: AsyncFd<Device>,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue