anybox-rs 0.10.0

one API for the most popular passthrough boxes
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
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 {
    /// a physical button
    #[non_exhaustive]
    Button {
        button: Button,
        pressed: bool,
        at: Stamp,
    },
    /// a physical key on the keyboard behind the box. just know that you see every key typed there, passwords
    /// included
    #[non_exhaustive]
    Key {
        key: Key,
        pressed: bool,
        at: Stamp,
    },
    /// a physical media key, like volume or play
    #[non_exhaustive]
    Media {
        key: MediaKey,
        pressed: bool,
        at: Stamp,
    },
    /// physical motion. the wheel is positive going up and pan (horizontal scroll) is positive going right
    #[non_exhaustive]
    Motion {
        dx: i32,
        dy: i32,
        wheel: i32,
        pan: i32,
        at: Stamp,
    },
    /// how many events never reached you since the last `Dropped` from the same source. one from the box can mean
    /// it restarted a stream, so what you knew about which physical buttons and keys were held may be out of date.
    /// the one for your own queue (`DropSource::Host`) sits at the front of the queue, not where the loss happened,
    /// and on Medius the one from the box comes from a box wide counter read about once a second, so it can also
    /// count what your own subscriptions through `medius()` lost
    #[non_exhaustive]
    Dropped {
        count: u64,
        source: DropSource,
    },
    /// the box lost its state, so the buttons and keys you were holding got released (on a box with
    /// `Quirk::KeepsHeld` they stay held). what you knew about which physical buttons and keys were held is out of
    /// date too, because one held through the reset can show a second press or never show its release
    SessionReset,
    /// the box refused something after the call already returned ok, MAKCU does that when its command queue is
    /// full. slow down and send it again if it mattered. `count` is how many of that action got refused since you
    /// last read one, so a flood of refusals never pushes your input out of the queue
    #[non_exhaustive]
    Rejected {
        action: Action,
        count: u64,
    },
    Disconnected,
    /// the box is back, the buttons and keys you were holding got released (on a box with `Quirk::KeepsHeld`
    /// they stay held), and the snapshot may have changed. on a MAKCU you also get this when a mouse or keyboard
    /// gets plugged into the box or pulled out, and on a Medius when the device it clones gets swapped. what you
    /// knew about which physical buttons and keys were held is out of date, same as after `SessionReset`
    Reconnected,
    /// the snapshot changed with no reconnect, so read `snapshot()` again. a mouse or keyboard set or pulled on a
    /// Ferrum, a YSC turning its keys off, or a Medius clone whose details changed come this way. so does a Ferrum
    /// unplugged from this PC, because the app's port stays open and the app just loses its devices, and once it's
    /// back you get a `SessionReset` after this one, since the box forgot its locks. a MAKCU gets a `Reconnected`
    /// for those instead, so watch both. two of these never wait unread in the same receiver
    Changed,
}

/// for tests and for code that builds events itself. the variants stay `#[non_exhaustive]` so a field added
/// later doesn't break anyone, and these are how you make them from outside
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 {
    /// one of each event with every field it has filled in, for testing how code handles them with no box. the
    /// input ones carry `at` as their host time and a fixed box time
    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,
        ]
    }
}

/// which input a receiver wants, combined with `|`. a receiver only gets what it asked for, the box streams what
/// any receiver wants, and connection events and drops reach every receiver
#[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
    };
    /// everything the box can stream, what `events()` gives you
    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
    }

    /// the kind an event belongs to, none for the ones every receiver gets
    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,
        }
    }

    /// the kind a stream's action is about, so its refusal only goes to the receivers that wanted it
    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,
        }
    }

    /// each single kind in this set with the action that streams it
    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 {
    /// the box's own counters
    Device,
    /// your receiver fell behind and its queue overflowed
    Host,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub struct Stamp {
    /// the best guess at when the event happened, on the PC's clock. on Medius it's the box clock mapped onto the
    /// PC's through the medius crate, which keeps it from ever going backwards and smooths it after bursts, so it's
    /// an estimate there and NOT when the PC got the event, use `received` for that
    pub arrived: Instant,
    /// the same moment as the time since the device was opened, for code that can't use `Instant`
    pub since_open: Duration,
    pub box_time: Option<BoxTime>,
    /// when anybox got the event. on MAKCU that's right after the port read returned with the report's last byte,
    /// on Medius it's when anybox took it from the medius crate, which reads the port on its own thread, so it's a
    /// bit after the read there. either way it's the read and not the USB arrival, driver buffering and a backlog
    /// make it late, and reports that came in one read share it
    pub received: Instant,
    /// the same moment as `received`, as the time since the device was opened
    pub received_since_open: Duration,
    /// the raw QueryPerformanceCounter value at `received`, on Windows only, since an `Instant` can't be turned
    /// back into one and a USB capture stamps its packets in QPC
    pub received_qpc: Option<i64>,
}

impl Stamp {
    /// for tests and for code that builds events itself. `received` starts out as `arrived`, and `since_open`
    /// isn't checked against `arrived`
    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
    }

    /// `arrived` in nanoseconds on the clock `monotonic_ns` reads, so it lines up with stamps from other devices
    /// and other programs on this machine
    pub fn arrived_ns(&self) -> u64 {
        instant_ns(self.arrived)
    }

    /// `received` in nanoseconds on the clock `monotonic_ns` reads
    pub fn received_ns(&self) -> u64 {
        instant_ns(self.received)
    }

    /// `received_since_open` comes out of `received` and `since_open`, so set those right first
    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
    }
}

/// now in nanoseconds on the OS monotonic clock, the one `Instant` reads: QueryPerformanceCounter on Windows,
/// CLOCK_MONOTONIC on Linux and CLOCK_UPTIME_RAW on macOS. Python's `time.perf_counter_ns()` and .NET's `Stopwatch`
/// read the same one on Windows and Linux. it only compares on the same machine within one boot
pub fn monotonic_ns() -> u64 {
    crate::transport::monotonic_ns()
}

/// `Instant` hides its raw value, so this is off by the anchor's bracket, which is tens of nanoseconds unless
/// every sample got preempted
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)))
    }
}

/// an `Instant` and the clock read around it, the tightest of a few brackets so one preempted sample doesn't count
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 }
    }
}

/// each box clock is its own counter, so only compare stamps that come from the same one
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum Clock {
    MediusHostChip,
    MediusDeviceChip,
}

impl Clock {
    /// a u32 microsecond counter rolls over every 71.6 minutes
    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,
}

/// one receiver's queue. when it's full the oldest events get thrown out and one `Dropped` at the front counts
/// them, so a busy producer can never push that report out. only input events get thrown out, never a `Dropped`
/// from the box or a disconnect or reconnect, so a slow reader still finds out that what it held got let go
#[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;
        // the snapshot is read live, so one unread is as good as many, and these never get evicted
        if matches!(event, Event::Changed) && events.iter().any(|e| matches!(e, Event::Changed)) {
            return;
        }
        if let Event::Rejected { action, count } = event {
            // an unread refusal of the same action just gets its count bumped, so refusals take a few slots at most
            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 {
                // a queue full of presses and releases keeps them and the new motion gets thrown out instead.
                // the `Dropped` at the front still needs a slot though, so the oldest press or release makes room
                // for it once
                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 {
                // motion gets thrown out first, otherwise a flood of it could push out the release of a key that's
                // still held
                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();
    }

    /// the receiver's own close, which throws out what's queued instead of leaving it to be read
    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),
        }
    }
}

/// lets a receiver tell the device when it's dropped, so the box only streams input while someone listens
pub(crate) trait Listeners: Send + Sync {
    fn receiver_dropped(&self, id: u64);
}

/// a receiver of events from one device. it ends once the device is gone and you've read everything queued, or
/// once you close it
pub struct Events {
    queue: Arc<Queue>,
    listeners: Weak<dyn Listeners>,
    id: u64,
    // the device hears about a receiver going once, whether that's a close, a drop or both
    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),
        }
    }

    /// ends this receiver now, from any thread, so share it in an `Arc` when another thread reads it. a `recv`
    /// waiting on it returns `Closed` right away, whatever was queued is thrown out, and the box stops streaming
    /// what only this receiver wanted. a second close does nothing
    pub fn close(&self) {
        // the queue goes first, so a reader wakes without waiting on the device
        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> {
        // a timeout too long for the clock to add is the same as waiting forever
        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;