use std::collections::VecDeque;
use std::fmt;
use std::sync::{Arc, Condvar, Mutex, MutexGuard, PoisonError, Weak};
use std::time::{Duration, Instant};
use crate::capability::{Action, Button};
use crate::key::{Key, MediaKey};
#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum Event {
#[non_exhaustive]
Button {
button: Button,
pressed: bool,
at: Stamp,
},
#[non_exhaustive]
Key {
key: Key,
pressed: bool,
at: Stamp,
},
#[non_exhaustive]
Media {
key: MediaKey,
pressed: bool,
at: Stamp,
},
#[non_exhaustive]
Motion {
dx: i32,
dy: i32,
wheel: i32,
pan: i32,
at: Stamp,
},
#[non_exhaustive]
Dropped {
count: u64,
source: DropSource,
},
SessionReset,
#[non_exhaustive]
Rejected {
action: Action,
count: u64,
},
Disconnected,
Reconnected,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum DropSource {
Device,
Host,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub struct Stamp {
pub arrived: Instant,
pub since_open: Duration,
pub box_time: Option<BoxTime>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub struct BoxTime {
pub micros: u32,
pub clock: Clock,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum Clock {
MediusHostChip,
MediusDeviceChip,
}
impl Clock {
pub fn wraps_after(self) -> Duration {
Duration::from_micros(u64::from(u32::MAX) + 1)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Closed;
impl fmt::Display for Closed {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("the device is gone, no more events will come")
}
}
impl std::error::Error for Closed {}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RecvTimeoutError {
Timeout,
Closed,
}
impl fmt::Display for RecvTimeoutError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Timeout => f.write_str("no event came in time"),
Self::Closed => Closed.fmt(f),
}
}
}
impl std::error::Error for RecvTimeoutError {}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TryRecvError {
Empty,
Closed,
}
impl fmt::Display for TryRecvError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Empty => f.write_str("no event is waiting"),
Self::Closed => Closed.fmt(f),
}
}
}
impl std::error::Error for TryRecvError {}
pub(crate) const QUEUE_CAPACITY: usize = 1024;
#[derive(Debug)]
struct State {
events: VecDeque<Event>,
closed: bool,
}
#[derive(Debug)]
pub(crate) struct Queue {
state: Mutex<State>,
ready: Condvar,
capacity: usize,
}
impl Queue {
pub(crate) fn new(capacity: usize) -> Self {
Self {
state: Mutex::new(State {
events: VecDeque::new(),
closed: false,
}),
ready: Condvar::new(),
capacity: capacity.max(2),
}
}
fn lock(&self) -> MutexGuard<'_, State> {
self.state.lock().unwrap_or_else(PoisonError::into_inner)
}
pub(crate) fn push(&self, event: Event) {
let mut state = self.lock();
if state.closed {
return;
}
let events = &mut state.events;
if let Event::Rejected { action, count } = event {
let unread = events.iter_mut().find_map(|queued| match queued {
Event::Rejected {
action: queued_action,
count: queued_count,
} if *queued_action == action => Some(queued_count),
_ => None,
});
if let Some(queued_count) = unread {
*queued_count += count;
return;
}
}
if events.len() >= self.capacity {
let counted = matches!(
events.front(),
Some(Event::Dropped {
source: DropSource::Host,
..
})
);
if !counted {
events.push_front(Event::Dropped {
count: 0,
source: DropSource::Host,
});
}
let motion_queued = events.iter().any(|e| matches!(e, Event::Motion { .. }));
if matches!(event, Event::Motion { .. }) && !motion_queued {
let mut lost = 1;
if events.len() > self.capacity
&& let Some(oldest) = events.iter().skip(1).position(|e| {
matches!(
e,
Event::Button { .. } | Event::Key { .. } | Event::Media { .. }
)
})
{
events.remove(oldest + 1);
lost += 1;
}
if let Some(Event::Dropped { count, .. }) = events.front_mut() {
*count += lost;
}
drop(state);
self.ready.notify_all();
return;
}
while events.len() >= self.capacity {
let motion = events
.iter()
.skip(1)
.position(|e| matches!(e, Event::Motion { .. }));
let edge = || {
events.iter().skip(1).position(|e| {
matches!(
e,
Event::Button { .. } | Event::Key { .. } | Event::Media { .. }
)
})
};
let Some(oldest) = motion.or_else(edge) else {
break;
};
events.remove(oldest + 1);
if let Some(Event::Dropped { count, .. }) = events.front_mut() {
*count += 1;
}
}
}
events.push_back(event);
drop(state);
self.ready.notify_all();
}
pub(crate) fn close(&self) {
self.lock().closed = true;
self.ready.notify_all();
}
fn try_pop(state: &mut State) -> Result<Event, TryRecvError> {
match state.events.pop_front() {
Some(event) => Ok(event),
None if state.closed => Err(TryRecvError::Closed),
None => Err(TryRecvError::Empty),
}
}
}
pub(crate) trait Listeners: Send + Sync {
fn receiver_dropped(&self);
}
pub struct Events {
queue: Arc<Queue>,
listeners: Weak<dyn Listeners>,
}
impl Events {
pub(crate) fn new(queue: Arc<Queue>, listeners: Weak<dyn Listeners>) -> Self {
Self { queue, listeners }
}
pub fn recv(&self) -> Result<Event, Closed> {
let mut state = self.queue.lock();
loop {
match Queue::try_pop(&mut state) {
Ok(event) => return Ok(event),
Err(TryRecvError::Closed) => return Err(Closed),
Err(TryRecvError::Empty) => {
state = self
.queue
.ready
.wait(state)
.unwrap_or_else(PoisonError::into_inner);
}
}
}
}
pub fn recv_timeout(&self, timeout: Duration) -> Result<Event, RecvTimeoutError> {
let deadline = Instant::now() + timeout;
let mut state = self.queue.lock();
loop {
match Queue::try_pop(&mut state) {
Ok(event) => return Ok(event),
Err(TryRecvError::Closed) => return Err(RecvTimeoutError::Closed),
Err(TryRecvError::Empty) => {
let left = deadline.saturating_duration_since(Instant::now());
if left.is_zero() {
return Err(RecvTimeoutError::Timeout);
}
state = self
.queue
.ready
.wait_timeout(state, left)
.unwrap_or_else(PoisonError::into_inner)
.0;
}
}
}
}
pub fn try_recv(&self) -> Result<Event, TryRecvError> {
Queue::try_pop(&mut self.queue.lock())
}
}
impl Iterator for Events {
type Item = Event;
fn next(&mut self) -> Option<Event> {
self.recv().ok()
}
}
impl Drop for Events {
fn drop(&mut self) {
if let Some(listeners) = self.listeners.upgrade() {
listeners.receiver_dropped();
}
}
}
impl fmt::Debug for Events {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Events").finish_non_exhaustive()
}
}
#[cfg(test)]
mod tests;