#![cfg(unix)]
#[macro_use]
mod attribute_set;
mod constants;
mod device_state;
mod inputid;
pub mod raw_stream;
mod scancodes;
mod sync_stream;
mod sys;
pub mod uinput;
#[cfg(feature = "tokio")]
mod tokio_stream;
use std::time::{Duration, SystemTime};
use std::{fmt, io};
pub use attribute_set::{AttributeSet, AttributeSetRef};
pub use constants::*;
pub use device_state::DeviceState;
pub use inputid::*;
pub use scancodes::*;
pub use sync_stream::*;
const EVENT_BATCH_SIZE: usize = 32;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum InputEventKind {
Synchronization(Synchronization),
Key(Key),
RelAxis(RelativeAxisType),
AbsAxis(AbsoluteAxisType),
Misc(MiscType),
Switch(SwitchType),
Led(LedType),
Sound(SoundType),
Other,
}
#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct InputEvent(libc::input_event);
impl InputEvent {
#[inline]
pub fn timestamp(&self) -> SystemTime {
timeval_to_systime(&self.0.time)
}
#[inline]
pub fn event_type(&self) -> EventType {
EventType(self.0.type_)
}
#[inline]
pub fn code(&self) -> u16 {
self.0.code
}
#[inline]
pub fn kind(&self) -> InputEventKind {
let code = self.code();
match self.event_type() {
EventType::SYNCHRONIZATION => InputEventKind::Synchronization(Synchronization(code)),
EventType::KEY => InputEventKind::Key(Key::new(code)),
EventType::RELATIVE => InputEventKind::RelAxis(RelativeAxisType(code)),
EventType::ABSOLUTE => InputEventKind::AbsAxis(AbsoluteAxisType(code)),
EventType::MISC => InputEventKind::Misc(MiscType(code)),
EventType::SWITCH => InputEventKind::Switch(SwitchType(code)),
EventType::LED => InputEventKind::Led(LedType(code)),
EventType::SOUND => InputEventKind::Sound(SoundType(code)),
_ => InputEventKind::Other,
}
}
#[inline]
pub fn value(&self) -> i32 {
self.0.value
}
pub fn new(type_: EventType, code: u16, value: i32) -> Self {
InputEvent(libc::input_event {
time: libc::timeval {
tv_sec: 0,
tv_usec: 0,
},
type_: type_.0,
code,
value,
})
}
pub fn new_now(type_: EventType, code: u16, value: i32) -> Self {
InputEvent(libc::input_event {
time: systime_to_timeval(&SystemTime::now()),
type_: type_.0,
code,
value,
})
}
}
impl From<libc::input_event> for InputEvent {
fn from(raw: libc::input_event) -> Self {
Self(raw)
}
}
impl AsRef<libc::input_event> for InputEvent {
fn as_ref(&self) -> &libc::input_event {
&self.0
}
}
impl fmt::Debug for InputEvent {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut debug = f.debug_struct("InputEvent");
debug.field("time", &self.timestamp());
let kind = self.kind();
if let InputEventKind::Other = kind {
debug
.field("type", &self.event_type())
.field("code", &self.code());
} else {
debug.field("kind", &kind);
}
debug.field("value", &self.value()).finish()
}
}
pub fn enumerate() -> EnumerateDevices {
EnumerateDevices {
inner: raw_stream::enumerate(),
}
}
pub struct EnumerateDevices {
inner: raw_stream::EnumerateDevices,
}
impl Iterator for EnumerateDevices {
type Item = Device;
fn next(&mut self) -> Option<Device> {
self.inner.next().map(Device::from_raw_device)
}
}
fn systime_to_timeval(time: &SystemTime) -> libc::timeval {
let (sign, dur) = match time.duration_since(SystemTime::UNIX_EPOCH) {
Ok(dur) => (1, dur),
Err(e) => (-1, e.duration()),
};
libc::timeval {
tv_sec: dur.as_secs() as libc::time_t * sign,
tv_usec: dur.subsec_micros() as libc::suseconds_t,
}
}
fn timeval_to_systime(tv: &libc::timeval) -> SystemTime {
let dur = Duration::new(tv.tv_sec.abs() as u64, tv.tv_usec as u32 * 1000);
if tv.tv_sec >= 0 {
SystemTime::UNIX_EPOCH + dur
} else {
SystemTime::UNIX_EPOCH - dur
}
}
pub(crate) fn nix_err(err: nix::Error) -> io::Error {
match err {
nix::Error::Sys(errno) => io::Error::from_raw_os_error(errno as i32),
nix::Error::InvalidPath => io::Error::new(io::ErrorKind::InvalidInput, err),
nix::Error::InvalidUtf8 => io::Error::new(io::ErrorKind::Other, err),
nix::Error::UnsupportedOperation => io::Error::new(io::ErrorKind::Other, err),
}
}
pub(crate) unsafe fn cast_to_bytes<T: ?Sized>(mem: &T) -> &[u8] {
std::slice::from_raw_parts(mem as *const T as *const u8, std::mem::size_of_val(mem))
}