#![cfg(unix)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#[macro_use]
mod attribute_set;
mod compat;
mod constants;
mod device_state;
pub mod event_variants;
mod ff;
mod inputid;
pub mod raw_stream;
mod scancodes;
mod sync_stream;
mod sys;
pub mod uinput;
use crate::compat::{input_absinfo, input_event, uinput_abs_setup};
use std::fmt::{self, Display};
use std::io;
use std::os::fd::{AsFd, AsRawFd, OwnedFd};
use std::path::PathBuf;
use std::time::{Duration, SystemTime};
pub use attribute_set::{AttributeSet, AttributeSetRef, EvdevEnum};
pub use constants::*;
pub use device_state::DeviceState;
pub use event_variants::*;
pub use ff::*;
pub use inputid::*;
pub use scancodes::*;
pub use sync_stream::*;
macro_rules! common_trait_impls {
($raw:ty, $wrapper:ty) => {
impl From<$raw> for $wrapper {
fn from(raw: $raw) -> Self {
Self(raw)
}
}
impl From<$wrapper> for $raw {
fn from(wrapper: $wrapper) -> Self {
wrapper.0
}
}
impl AsRef<$raw> for $wrapper {
fn as_ref(&self) -> &$raw {
&self.0
}
}
};
}
const EVENT_BATCH_SIZE: usize = 32;
#[derive(Debug)]
pub enum EventSummary {
Synchronization(SynchronizationEvent, SynchronizationCode, i32),
Key(KeyEvent, KeyCode, i32),
RelativeAxis(RelativeAxisEvent, RelativeAxisCode, i32),
AbsoluteAxis(AbsoluteAxisEvent, AbsoluteAxisCode, i32),
Misc(MiscEvent, MiscCode, i32),
Switch(SwitchEvent, SwitchCode, i32),
Led(LedEvent, LedCode, i32),
Sound(SoundEvent, SoundCode, i32),
Repeat(RepeatEvent, RepeatCode, i32),
ForceFeedback(FFEvent, FFEffectCode, i32),
Power(PowerEvent, PowerCode, i32),
ForceFeedbackStatus(FFStatusEvent, FFStatusCode, i32),
UInput(UInputEvent, UInputCode, i32),
Other(OtherEvent, OtherCode, i32),
}
impl From<InputEvent> for EventSummary {
fn from(value: InputEvent) -> Self {
match value.event_type() {
EventType::SYNCHRONIZATION => SynchronizationEvent::from_event(value).into(),
EventType::KEY => KeyEvent::from_event(value).into(),
EventType::RELATIVE => RelativeAxisEvent::from_event(value).into(),
EventType::ABSOLUTE => AbsoluteAxisEvent::from_event(value).into(),
EventType::MISC => MiscEvent::from_event(value).into(),
EventType::SWITCH => SwitchEvent::from_event(value).into(),
EventType::LED => LedEvent::from_event(value).into(),
EventType::SOUND => SoundEvent::from_event(value).into(),
EventType::REPEAT => RepeatEvent::from_event(value).into(),
EventType::FORCEFEEDBACK => FFEvent::from_event(value).into(),
EventType::POWER => PowerEvent::from_event(value).into(),
EventType::FORCEFEEDBACKSTATUS => FFStatusEvent::from_event(value).into(),
EventType::UINPUT => UInputEvent::from_event(value).into(),
_ => OtherEvent(value).into(),
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[repr(transparent)]
pub struct AbsInfo(input_absinfo);
impl AbsInfo {
#[inline]
pub fn value(&self) -> i32 {
self.0.value
}
#[inline]
pub fn minimum(&self) -> i32 {
self.0.minimum
}
#[inline]
pub fn maximum(&self) -> i32 {
self.0.maximum
}
#[inline]
pub fn fuzz(&self) -> i32 {
self.0.fuzz
}
#[inline]
pub fn flat(&self) -> i32 {
self.0.flat
}
#[inline]
pub fn resolution(&self) -> i32 {
self.0.resolution
}
pub fn new(
value: i32,
minimum: i32,
maximum: i32,
fuzz: i32,
flat: i32,
resolution: i32,
) -> Self {
AbsInfo(input_absinfo {
value,
minimum,
maximum,
fuzz,
flat,
resolution,
})
}
}
common_trait_impls!(input_absinfo, AbsInfo);
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[repr(transparent)]
pub struct UinputAbsSetup(uinput_abs_setup);
impl UinputAbsSetup {
#[inline]
pub fn code(&self) -> u16 {
self.0.code
}
#[inline]
pub fn absinfo(&self) -> AbsInfo {
AbsInfo(self.0.absinfo)
}
pub fn new(code: AbsoluteAxisCode, absinfo: AbsInfo) -> Self {
UinputAbsSetup(uinput_abs_setup {
code: code.0,
absinfo: absinfo.0,
})
}
}
common_trait_impls!(uinput_abs_setup, UinputAbsSetup);
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
#[repr(transparent)]
pub struct InputEvent(input_event);
common_trait_impls!(input_event, InputEvent);
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 value(&self) -> i32 {
self.0.value
}
pub fn destructure(self) -> EventSummary {
self.into()
}
pub fn new(type_: u16, code: u16, value: i32) -> Self {
let raw = input_event {
time: libc::timeval {
tv_sec: 0,
tv_usec: 0,
},
type_,
code,
value,
};
Self(raw)
}
pub fn new_now(type_: u16, code: u16, value: i32) -> Self {
let raw = input_event {
time: systime_to_timeval(&SystemTime::now()),
type_,
code,
value,
};
Self(raw)
}
}
impl fmt::Debug for InputEvent {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let summary = self.destructure();
let code: &dyn fmt::Debug = match &summary {
EventSummary::Synchronization(_, code, _) => code,
EventSummary::Key(_, code, _) => code,
EventSummary::RelativeAxis(_, code, _) => code,
EventSummary::AbsoluteAxis(_, code, _) => code,
EventSummary::Misc(_, code, _) => code,
EventSummary::Switch(_, code, _) => code,
EventSummary::Led(_, code, _) => code,
EventSummary::Sound(_, code, _) => code,
EventSummary::Repeat(_, code, _) => code,
EventSummary::ForceFeedback(_, code, _) => code,
EventSummary::Power(_, code, _) => code,
EventSummary::ForceFeedbackStatus(_, code, _) => code,
EventSummary::UInput(_, code, _) => code,
EventSummary::Other(_, code, _) => &code.1,
};
f.debug_struct("InputEvent")
.field("time", &self.timestamp())
.field("type", &self.event_type())
.field("code", code)
.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 = (PathBuf, Device);
fn next(&mut self) -> Option<(PathBuf, Device)> {
self.inner
.next()
.map(|(pb, dev)| (pb, Device::from_raw_device(dev)))
}
}
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 as u64, tv.tv_usec as u32 * 1000);
if tv.tv_sec >= 0 {
SystemTime::UNIX_EPOCH + dur
} else {
SystemTime::UNIX_EPOCH - dur
}
}
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))
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct EnumParseError(());
impl Display for EnumParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "failed to parse Key from string")
}
}
impl std::error::Error for EnumParseError {}
fn fd_write_all(fd: std::os::fd::BorrowedFd<'_>, mut data: &[u8]) -> nix::Result<()> {
loop {
match nix::unistd::write(fd, data) {
Ok(0) => return Ok(()),
Ok(n) => data = &data[n..],
Err(nix::Error::EINTR) => {}
Err(e) => return Err(e),
}
}
}
fn write_events(fd: std::os::fd::BorrowedFd<'_>, events: &[InputEvent]) -> nix::Result<()> {
let bytes = unsafe { cast_to_bytes(events) };
fd_write_all(fd, bytes)
}
#[derive(Debug)]
pub struct FFEffect {
fd: OwnedFd,
id: u16,
}
impl FFEffect {
pub fn id(&self) -> u16 {
self.id
}
pub fn play(&mut self, count: i32) -> io::Result<()> {
let events = [*FFEvent::new(FFEffectCode(self.id), count)];
crate::write_events(self.fd.as_fd(), &events)?;
Ok(())
}
pub fn stop(&mut self) -> io::Result<()> {
let events = [*FFEvent::new(FFEffectCode(self.id), 0)];
crate::write_events(self.fd.as_fd(), &events)?;
Ok(())
}
pub fn update(&mut self, data: FFEffectData) -> io::Result<()> {
let mut effect: sys::ff_effect = data.into();
effect.id = self.id as i16;
unsafe { sys::eviocsff(self.fd.as_raw_fd(), &effect)? };
Ok(())
}
}
impl Drop for FFEffect {
fn drop(&mut self) {
let _ = unsafe { sys::eviocrmff(self.fd.as_raw_fd(), self.id as _) };
}
}
#[derive(Debug, Clone)]
#[repr(C)]
pub struct AutoRepeat {
pub delay: u32,
pub period: u32,
}