use std::collections::VecDeque;
use std::fmt;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Condvar, Mutex, MutexGuard, OnceLock, 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,
Changed,
}
impl Event {
pub fn button(button: Button, pressed: bool, at: Stamp) -> Self {
Self::Button {
button,
pressed,
at,
}
}
pub fn key(key: Key, pressed: bool, at: Stamp) -> Self {
Self::Key { key, pressed, at }
}
pub fn media(key: MediaKey, pressed: bool, at: Stamp) -> Self {
Self::Media { key, pressed, at }
}
pub fn motion(dx: i32, dy: i32, wheel: i32, pan: i32, at: Stamp) -> Self {
Self::Motion {
dx,
dy,
wheel,
pan,
at,
}
}
pub fn dropped(count: u64, source: DropSource) -> Self {
Self::Dropped { count, source }
}
pub fn rejected(action: Action, count: u64) -> Self {
Self::Rejected { action, count }
}
}
#[cfg(feature = "mock")]
impl Event {
pub fn examples(at: Stamp) -> Vec<Event> {
let stamped = at.with_box_time(BoxTime::new(4_000_000_000, Clock::MediusDeviceChip));
vec![
Event::button(Button::Side2, true, stamped),
Event::key(Key::LEFT_SHIFT, false, stamped),
Event::media(MediaKey::VOLUME_DOWN, true, stamped),
Event::motion(-3, 7, -1, 2, stamped),
Event::dropped(12, DropSource::Device),
Event::dropped(3, DropSource::Host),
Event::SessionReset,
Event::rejected(Action::Move, 4),
Event::Disconnected,
Event::Reconnected,
Event::Changed,
]
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct EventKinds {
buttons: bool,
motion: bool,
keys: bool,
media: bool,
}
impl EventKinds {
pub const NONE: Self = Self {
buttons: false,
motion: false,
keys: false,
media: false,
};
pub const BUTTONS: Self = Self {
buttons: true,
..Self::NONE
};
pub const MOTION: Self = Self {
motion: true,
..Self::NONE
};
pub const KEYS: Self = Self {
keys: true,
..Self::NONE
};
pub const MEDIA: Self = Self {
media: true,
..Self::NONE
};
pub const ALL: Self = Self {
buttons: true,
motion: true,
keys: true,
media: true,
};
pub fn contains(self, other: Self) -> bool {
self & other == other
}
pub fn is_empty(self) -> bool {
self == Self::NONE
}
pub(crate) fn of(event: &Event) -> Option<Self> {
match event {
Event::Button { .. } => Some(Self::BUTTONS),
Event::Motion { .. } => Some(Self::MOTION),
Event::Key { .. } => Some(Self::KEYS),
Event::Media { .. } => Some(Self::MEDIA),
Event::Rejected { action, .. } => Self::of_action(*action),
_ => None,
}
}
pub(crate) fn of_action(action: Action) -> Option<Self> {
match action {
Action::ButtonEvents => Some(Self::BUTTONS),
Action::MotionEvents => Some(Self::MOTION),
Action::KeyEvents => Some(Self::KEYS),
Action::MediaEvents => Some(Self::MEDIA),
_ => None,
}
}
pub(crate) fn to_input(self) -> crate::backend::InputKinds {
crate::backend::InputKinds {
buttons: self.buttons,
motion: self.motion,
keys: self.keys,
media: self.media,
}
}
pub(crate) fn from_input(kinds: crate::backend::InputKinds) -> Self {
Self {
buttons: kinds.buttons,
motion: kinds.motion,
keys: kinds.keys,
media: kinds.media,
}
}
pub(crate) fn each(self) -> impl Iterator<Item = (Self, Action)> {
[
(Self::BUTTONS, Action::ButtonEvents),
(Self::MOTION, Action::MotionEvents),
(Self::KEYS, Action::KeyEvents),
(Self::MEDIA, Action::MediaEvents),
]
.into_iter()
.filter(move |(kind, _)| self.contains(*kind))
}
}
impl std::ops::BitOr for EventKinds {
type Output = Self;
fn bitor(self, other: Self) -> Self {
Self {
buttons: self.buttons || other.buttons,
motion: self.motion || other.motion,
keys: self.keys || other.keys,
media: self.media || other.media,
}
}
}
impl std::ops::BitAnd for EventKinds {
type Output = Self;
fn bitand(self, other: Self) -> Self {
Self {
buttons: self.buttons && other.buttons,
motion: self.motion && other.motion,
keys: self.keys && other.keys,
media: self.media && other.media,
}
}
}
#[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>,
pub received: Instant,
pub received_since_open: Duration,
pub received_qpc: Option<i64>,
}
impl Stamp {
pub fn new(arrived: Instant, since_open: Duration) -> Self {
Self {
arrived,
since_open,
box_time: None,
received: arrived,
received_since_open: since_open,
received_qpc: None,
}
}
pub fn with_box_time(mut self, box_time: BoxTime) -> Self {
self.box_time = Some(box_time);
self
}
pub fn arrived_ns(&self) -> u64 {
instant_ns(self.arrived)
}
pub fn received_ns(&self) -> u64 {
instant_ns(self.received)
}
pub fn with_received(mut self, received: Instant, qpc: Option<i64>) -> Self {
self.received = received;
self.received_since_open = if received >= self.arrived {
self.since_open
.saturating_add(received.duration_since(self.arrived))
} else {
self.since_open
.saturating_sub(self.arrived.duration_since(received))
};
self.received_qpc = qpc;
self
}
}
pub fn monotonic_ns() -> u64 {
crate::transport::monotonic_ns()
}
fn instant_ns(at: Instant) -> u64 {
let (anchor, anchor_ns) = anchor();
if at >= anchor {
anchor_ns.saturating_add(nanos(at.duration_since(anchor)))
} else {
anchor_ns.saturating_sub(nanos(anchor.duration_since(at)))
}
}
fn anchor() -> (Instant, u64) {
static ANCHOR: OnceLock<(Instant, u64)> = OnceLock::new();
*ANCHOR.get_or_init(|| {
let mut best = (u64::MAX, Instant::now(), 0);
for _ in 0..16 {
let before = monotonic_ns();
let at = Instant::now();
let after = monotonic_ns();
let bracket = after.saturating_sub(before);
if bracket < best.0 {
best = (bracket, at, before + bracket / 2);
}
}
(best.1, best.2)
})
}
fn nanos(duration: Duration) -> u64 {
u64::try_from(duration.as_nanos()).unwrap_or(u64::MAX)
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub struct BoxTime {
pub micros: u32,
pub clock: Clock,
}
impl BoxTime {
pub fn new(micros: u32, clock: Clock) -> Self {
Self { micros, 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 matches!(event, Event::Changed) && events.iter().any(|e| matches!(e, Event::Changed)) {
return;
}
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 close_now(&self) {
let mut state = self.lock();
state.events.clear();
state.closed = true;
drop(state);
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, id: u64);
}
pub struct Events {
queue: Arc<Queue>,
listeners: Weak<dyn Listeners>,
id: u64,
gone: AtomicBool,
}
impl Events {
pub(crate) fn new(queue: Arc<Queue>, listeners: Weak<dyn Listeners>, id: u64) -> Self {
Self {
queue,
listeners,
id,
gone: AtomicBool::new(false),
}
}
pub fn close(&self) {
self.queue.close_now();
self.leave();
}
fn leave(&self) {
if !self.gone.swap(true, Ordering::AcqRel)
&& let Some(listeners) = self.listeners.upgrade()
{
listeners.receiver_dropped(self.id);
}
}
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 Some(deadline) = Instant::now().checked_add(timeout) else {
return self.recv().map_err(|Closed| RecvTimeoutError::Closed);
};
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) {
self.leave();
}
}
impl fmt::Debug for Events {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Events").finish_non_exhaustive()
}
}
impl std::ops::Not for EventKinds {
type Output = Self;
fn not(self) -> Self {
Self {
buttons: !self.buttons,
motion: !self.motion,
keys: !self.keys,
media: !self.media,
}
}
}
#[cfg(test)]
mod tests;