Skip to main content

anybox/
device.rs

1use std::borrow::Cow;
2use std::collections::{HashMap, HashSet};
3use std::fmt;
4use std::sync::mpsc::{self, Receiver, Sender};
5use std::sync::{Arc, Mutex, MutexGuard, PoisonError, RwLock, Weak};
6use std::thread::{self, JoinHandle};
7use std::time::{Duration, Instant};
8
9use crate::backend::{
10    Backend, Command, Input, InputKinds, LOCKED, LockSlot, Sign, Signal, UNLOCKED, Usage,
11};
12use crate::capability::{Action, Axis, Button, Direction, Execution, Quirk, Snapshot};
13use crate::click::{Click, ClickTiming, Holds, Timing};
14use crate::error::{Error, Result};
15use crate::event::{
16    DropSource, Event, EventKinds, Events, Listeners, QUEUE_CAPACITY, Queue, Stamp,
17};
18use crate::key::{Key, MediaKey};
19
20/// how long drop waits for the backend and the link thread before it gives up on them
21const SHUTDOWN_DEADLINE: Duration = Duration::from_secs(1);
22/// how close two refusals of one stream have to be to count as the same one, see `publish`
23const MERGE: Duration = Duration::from_secs(1);
24
25/// one connected box. every call checks what the box can do first, so nothing is faked and nothing is
26/// silently dropped. dropping it lets go of every button and key you were holding and closes the port
27pub struct Device {
28    core: Arc<Core>,
29    link: Mutex<Option<(JoinHandle<()>, Receiver<()>)>>,
30    /// held for the whole shutdown, so a second `close` waits for the first one to finish
31    closed: Mutex<bool>,
32}
33
34struct Core {
35    backend: Box<dyn Backend>,
36    snapshot: RwLock<Arc<Snapshot>>,
37    output: Mutex<Output>,
38    receivers: Mutex<Receivers>,
39    click_timing: ClickTiming,
40    holds: Mutex<Holds>,
41    opened: Instant,
42    signals: Sender<Signal>,
43    port: String,
44    /// when each stream action was last refused, see `publish`
45    refused: Mutex<Refusals>,
46}
47
48/// when each stream action was last refused, and a number that goes up every time a refusal actually went out, so
49/// a new receiver can tell whether one reached it since it was registered
50#[derive(Default)]
51struct Refusals {
52    last: HashMap<Action, (Instant, u64)>,
53    sent: u64,
54}
55
56impl Refusals {
57    fn note(&mut self, action: Action, at: Instant) {
58        self.sent += 1;
59        self.last.insert(action, (at, self.sent));
60    }
61}
62
63/// what was sent to the box, kept under one lock with the sending so the record never disagrees with the box
64struct Output {
65    held: HashSet<Usage>,
66    /// held buttons and keys where the app was told it failed, like a press that ran out of time or a tap timed
67    /// on the PC that couldn't let go. a box that keeps held buttons on its own would press these again after a
68    /// reconnect, so they get let go
69    unsure: HashSet<Usage>,
70    /// what anybox locked or scaled, with how much of the physical input each slot keeps. it all gets unlocked on
71    /// drop, and on a box that doesn't keep locks itself it gets sent again after a disconnect or a reset
72    locked: HashMap<LockSlot, i16>,
73    link_up: bool,
74    /// set once drop or close starts, and after that nothing from the link brings the device back
75    closing: bool,
76    /// goes up on every disconnect, reconnect and box reset, so a tap timed on the PC can tell its press was
77    /// already let go
78    session: u64,
79}
80
81struct Receivers {
82    next_id: u64,
83    entries: Vec<Entry>,
84}
85
86/// one receiver and the kinds of input it asked for
87struct Entry {
88    id: u64,
89    kinds: EventKinds,
90    queue: Weak<Queue>,
91}
92
93impl Receivers {
94    /// every kind some receiver wants, which is what the box streams
95    fn union(&self) -> EventKinds {
96        self.entries
97            .iter()
98            .fold(EventKinds::NONE, |all, entry| all | entry.kinds)
99    }
100}
101
102pub(crate) struct Start {
103    pub(crate) backend: Box<dyn Backend>,
104    pub(crate) snapshot: Snapshot,
105    pub(crate) signals: Sender<Signal>,
106    pub(crate) incoming: Receiver<Signal>,
107    pub(crate) click_timing: ClickTiming,
108    pub(crate) holds: Holds,
109    pub(crate) port: String,
110}
111
112impl Device {
113    pub(crate) fn start(start: Start) -> Result<Self> {
114        let core = Arc::new(Core {
115            snapshot: RwLock::new(prepare(start.snapshot, start.click_timing, &start.port)),
116            backend: start.backend,
117            output: Mutex::new(Output {
118                held: HashSet::new(),
119                locked: HashMap::new(),
120                unsure: HashSet::new(),
121                link_up: true,
122                closing: false,
123                session: 0,
124            }),
125            receivers: Mutex::new(Receivers {
126                next_id: 0,
127                entries: Vec::new(),
128            }),
129            click_timing: start.click_timing,
130            holds: Mutex::new(start.holds),
131            opened: Instant::now(),
132            signals: start.signals,
133            port: start.port.clone(),
134            refused: Mutex::new(Refusals::default()),
135        });
136        let link = spawn_link(Arc::downgrade(&core), start.incoming)?;
137        Ok(Self {
138            core,
139            link: Mutex::new(Some(link)),
140            closed: Mutex::new(false),
141        })
142    }
143
144    /// who the box is and what it can do, both read from the current connection. it can change after
145    /// `Reconnected`
146    pub fn snapshot(&self) -> Arc<Snapshot> {
147        self.core.snapshot()
148    }
149
150    /// moves by counts, going through whatever smoothing the box has on
151    pub fn move_by(&self, dx: i16, dy: i16) -> Result<()> {
152        self.core
153            .run(Action::Move, Timing::Any, Command::Move(dx, dy))
154    }
155
156    /// moves by counts on the box's next report, skipping its smoothing for this move
157    pub fn move_now(&self, dx: i16, dy: i16) -> Result<()> {
158        self.core
159            .run(Action::MoveNow, Timing::Any, Command::MoveNow(dx, dy))
160    }
161
162    pub fn press(&self, button: Button) -> Result<()> {
163        self.core
164            .run(Action::Press, Timing::Any, Command::Press(button))
165    }
166
167    pub fn release(&self, button: Button) -> Result<()> {
168        self.core
169            .run(Action::Release, Timing::Any, Command::Release(button))
170    }
171
172    /// the box's own click, or a click timed on the PC with the device's `ClickTiming` if the box doesn't have one
173    pub fn click(&self, button: Button) -> Result<()> {
174        self.click_with(button, Click::default())
175    }
176
177    pub fn click_with(&self, button: Button, click: Click) -> Result<()> {
178        self.core.tap(Usage::Button(button), click)
179    }
180
181    /// holds a key down until `release_key`
182    pub fn press_key(&self, key: Key) -> Result<()> {
183        self.core
184            .run(Action::KeyPress, Timing::Any, Command::KeyPress(key))
185    }
186
187    pub fn release_key(&self, key: Key) -> Result<()> {
188        self.core
189            .run(Action::KeyRelease, Timing::Any, Command::KeyRelease(key))
190    }
191
192    /// presses and lets go, timed by the box, or on the PC with the device's `ClickTiming` if the box can't
193    pub fn tap_key(&self, key: Key) -> Result<()> {
194        self.tap_key_with(key, Click::default())
195    }
196
197    pub fn tap_key_with(&self, key: Key, tap: Click) -> Result<()> {
198        self.core.tap(Usage::Key(key), tap)
199    }
200
201    /// holds a media key down until `release_media`
202    pub fn press_media(&self, key: MediaKey) -> Result<()> {
203        self.core
204            .run(Action::MediaPress, Timing::Any, Command::MediaPress(key))
205    }
206
207    pub fn release_media(&self, key: MediaKey) -> Result<()> {
208        self.core.run(
209            Action::MediaRelease,
210            Timing::Any,
211            Command::MediaRelease(key),
212        )
213    }
214
215    pub fn tap_media(&self, key: MediaKey) -> Result<()> {
216        self.tap_media_with(key, Click::default())
217    }
218
219    pub fn tap_media_with(&self, key: MediaKey, tap: Click) -> Result<()> {
220        self.core.tap(Usage::Media(key), tap)
221    }
222
223    /// keeps the physical button from reaching the PC until `unlock_button`. your own presses still go through and
224    /// its events still come, so you can take the button over
225    pub fn lock_button(&self, button: Button) -> Result<()> {
226        self.core
227            .lock(Action::LockButton, &[LockSlot::Button(button)], LOCKED)
228    }
229
230    pub fn unlock_button(&self, button: Button) -> Result<()> {
231        self.core
232            .lock(Action::LockButton, &[LockSlot::Button(button)], UNLOCKED)
233    }
234
235    /// keeps the physical key from reaching the PC until `unlock_key`
236    pub fn lock_key(&self, key: Key) -> Result<()> {
237        self.core
238            .lock(Action::LockKey, &[LockSlot::Key(key)], LOCKED)
239    }
240
241    pub fn unlock_key(&self, key: Key) -> Result<()> {
242        self.core
243            .lock(Action::LockKey, &[LockSlot::Key(key)], UNLOCKED)
244    }
245
246    /// keeps physical motion one way or both ways along an axis from reaching the PC until `unlock_axis`. your own
247    /// moves still go through
248    pub fn lock_axis(&self, axis: Axis, direction: Direction) -> Result<()> {
249        self.core
250            .lock(Action::LockAxis, &slots(axis, direction), LOCKED)
251    }
252
253    /// unlocks that way along the axis and leaves the other way as it was. it also undoes a scale there
254    pub fn unlock_axis(&self, axis: Axis, direction: Direction) -> Result<()> {
255        self.core
256            .lock(Action::LockAxis, &slots(axis, direction), UNLOCKED)
257    }
258
259    /// keeps `percent` of the physical motion one way or both ways along an axis, from -255 to 255. 100 leaves it
260    /// alone, 0 blocks it and -100 inverts it. `unlock_axis` puts it back to 100
261    pub fn scale_axis(&self, axis: Axis, direction: Direction, percent: i16) -> Result<()> {
262        self.core
263            .lock(Action::ScaleAxis, &slots(axis, direction), percent)
264    }
265
266    pub fn wheel(&self, notches: i16) -> Result<()> {
267        self.core
268            .run(Action::Wheel, Timing::Any, Command::Wheel(notches))
269    }
270
271    /// horizontal scroll, positive goes right
272    pub fn pan(&self, notches: i16) -> Result<()> {
273        self.core
274            .run(Action::Pan, Timing::Any, Command::Pan(notches))
275    }
276
277    /// throws away the moves the box took but hasn't sent yet. while the link is down it fails with `Disconnected`,
278    /// and on a Medius with riding on, the moves it holds back are then only bounded by its riding window
279    pub fn discard_pending_moves(&self) -> Result<()> {
280        self.core.run(
281            Action::DiscardPendingMoves,
282            Timing::Any,
283            Command::DiscardPendingMoves,
284        )
285    }
286
287    /// a new receiver for all the input the box can stream, plus the connection events. the box only streams while
288    /// at least one receiver is alive. just know that a receiver of keys sees every key typed on the keyboard behind
289    /// the box, passwords included
290    pub fn events(&self) -> Events {
291        self.receiver(EventKinds::ALL, false)
292    }
293
294    /// a receiver for only these kinds of input, plus the connection events. the box streams what any receiver
295    /// wants, so a receiver for buttons alone doesn't make it send motion. a kind this box can't stream gets one
296    /// `Rejected` for it right away, and so does a kind the box refuses to switch on, even when an older receiver
297    /// was just told the same thing. on Medius each kind is its own subscription, so the order between two kinds
298    /// is only as good as their box time
299    pub fn events_of(&self, kinds: EventKinds) -> Events {
300        // `ALL` means everything this box has, so it never gets refusals for what it doesn't
301        self.receiver(kinds, !kinds.contains(EventKinds::ALL))
302    }
303
304    fn receiver(&self, kinds: EventKinds, report_unsupported: bool) -> Events {
305        let listeners: Weak<dyn Listeners> = Arc::downgrade(&self.core) as Weak<Core>;
306        let (queue, id) = self.core.add_receiver(kinds, report_unsupported);
307        Events::new(queue, listeners, id)
308    }
309
310    /// the medius crate's own device for this box, for everything only Medius does (clips, rendering, raw catch
311    /// etc), and none on other boxes. it's also where you get the polling rate (`query_rate()`) and the identity the
312    /// box shows the PC (`device_info()`)
313    ///
314    /// to tell a mouse from a keyboard, check the capabilities and not the crate's `DeviceKind`, which calls a mouse
315    /// with a full key bitmap a keyboard
316    ///
317    /// a clone you keep holds the port open after this device is gone. anybox doesn't know about anything you press
318    /// or lock through it, and its `reset()` lets go of and unlocks everything, including what you did through this
319    /// device. `events()` comes back by itself after a `Dropped`, though a button held through the reset can show a
320    /// second press with no release in between. anybox's stream takes up to four of the box's 32 catch entries, so
321    /// if your own subscriptions fill the table the receiver gets a `Rejected` instead. once you've freed some,
322    /// any receiver coming or going asks again. a reboot into a download target keeps the box down
323    /// until you replug it
324    #[cfg(feature = "medius")]
325    pub fn medius(&self) -> Option<medius::Device> {
326        if lock(&self.core.output).closing {
327            return None;
328        }
329        self.core
330            .backend
331            .as_any()
332            .downcast_ref::<crate::family::medius::MediusBackend>()
333            .and_then(crate::family::medius::MediusBackend::device)
334    }
335
336    /// what drop does, but you get to see whether letting go of what you held and unlocking worked, and you choose
337    /// the thread that waits for it (up to about 2 seconds when the box doesn't answer). it works on a shared
338    /// device too. after it every command fails with `Error::Closed` and the receivers end, `events()` gives one
339    /// that's already ended, `snapshot()` still works and `medius()` gives none. a second `close` waits for the
340    /// first one and then says `Closed`. that's not the `Closed` an ended receiver returns
341    pub fn close(&self) -> Result<()> {
342        let mut closed = lock(&self.closed);
343        if *closed {
344            return Err(Error::Closed);
345        }
346        *closed = true;
347        self.shutdown()
348    }
349
350    fn shutdown(&self) -> Result<()> {
351        let released = self.core.release_everything();
352        let stopped = self.core.backend.close(SHUTDOWN_DEADLINE);
353        let _ = self.core.signals.send(Signal::Stop);
354        if let Some((handle, done)) = lock(&self.link).take() {
355            // a link thread stuck in a dead backend gets left behind, otherwise it would hang the caller
356            if done.recv_timeout(SHUTDOWN_DEADLINE).is_ok() {
357                let _ = handle.join();
358            }
359        }
360        self.core.close_receivers();
361        released.and(stopped)
362    }
363}
364
365impl Drop for Device {
366    fn drop(&mut self) {
367        let mut closed = lock(&self.closed);
368        if !*closed {
369            *closed = true;
370            let _ = self.shutdown();
371        }
372    }
373}
374
375impl fmt::Debug for Device {
376    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
377        f.debug_struct("Device")
378            .field("info", &self.snapshot().info)
379            .finish_non_exhaustive()
380    }
381}
382
383fn prepare(snapshot: Snapshot, click_timing: ClickTiming, port: &str) -> Arc<Snapshot> {
384    let Snapshot {
385        mut info,
386        capabilities,
387    } = snapshot;
388    // a backend's snapshot doesn't know the path, the core does and keeps it on every new snapshot
389    info.port = port.to_owned();
390    Arc::new(Snapshot::new(
391        info,
392        capabilities.with_host_taps(click_timing),
393    ))
394}
395
396fn keeps_locked(snapshot: &Snapshot) -> bool {
397    [Action::LockButton, Action::LockAxis, Action::LockKey]
398        .into_iter()
399        .any(|lock| {
400            snapshot
401                .capabilities
402                .get(lock)
403                .quirks
404                .contains(&Quirk::KeepsLocked)
405        })
406}
407
408fn whole_axis_only(snapshot: &Snapshot) -> bool {
409    snapshot
410        .capabilities
411        .get(Action::LockAxis)
412        .quirks
413        .contains(&Quirk::WholeAxisOnly)
414}
415
416/// the other way along the same axis, none for anything that isn't an axis
417fn other_way(slot: LockSlot) -> Option<LockSlot> {
418    match slot {
419        LockSlot::Axis(axis, Sign::Positive) => Some(LockSlot::Axis(axis, Sign::Negative)),
420        LockSlot::Axis(axis, Sign::Negative) => Some(LockSlot::Axis(axis, Sign::Positive)),
421        _ => None,
422    }
423}
424
425/// the slots for one way, or both ways, along an axis
426fn slots(axis: Axis, direction: Direction) -> Vec<LockSlot> {
427    let signs: &[Sign] = match direction {
428        Direction::Both => &[Sign::Positive, Sign::Negative],
429        Direction::Positive => &[Sign::Positive],
430        Direction::Negative => &[Sign::Negative],
431    };
432    signs
433        .iter()
434        .map(|&sign| LockSlot::Axis(axis, sign))
435        .collect()
436}
437
438/// a box keeps held buttons and keys for all of them or none, so the quirk sits on whichever press it has
439fn keeps_held(snapshot: &Snapshot) -> bool {
440    [Action::Press, Action::KeyPress, Action::MediaPress]
441        .into_iter()
442        .any(|press| {
443            snapshot
444                .capabilities
445                .get(press)
446                .quirks
447                .contains(&Quirk::KeepsHeld)
448        })
449}
450
451fn max_keys_held(snapshot: &Snapshot) -> Option<u8> {
452    snapshot
453        .capabilities
454        .get(Action::KeyPress)
455        .quirks
456        .iter()
457        .find_map(|quirk| match quirk {
458            Quirk::MaxKeysHeld(max) => Some(*max),
459            _ => None,
460        })
461}
462
463/// the action of the tap itself, then the actions of its press and its release
464fn tap_actions(usage: Usage) -> (Action, Action, Action) {
465    match usage {
466        Usage::Button(_) => (Action::Click, Action::Press, Action::Release),
467        Usage::Key(_) => (Action::KeyTap, Action::KeyPress, Action::KeyRelease),
468        Usage::Media(_) => (Action::MediaTap, Action::MediaPress, Action::MediaRelease),
469    }
470}
471
472fn lock<T>(mutex: &Mutex<T>) -> MutexGuard<'_, T> {
473    mutex.lock().unwrap_or_else(PoisonError::into_inner)
474}
475
476fn stream_kinds(snapshot: &Snapshot) -> InputKinds {
477    let capabilities = &snapshot.capabilities;
478    InputKinds {
479        buttons: capabilities.get(Action::ButtonEvents).is_supported(),
480        motion: capabilities.get(Action::MotionEvents).is_supported(),
481        keys: capabilities.get(Action::KeyEvents).is_supported(),
482        media: capabilities.get(Action::MediaEvents).is_supported(),
483    }
484}
485
486impl Core {
487    fn snapshot(&self) -> Arc<Snapshot> {
488        self.snapshot
489            .read()
490            .unwrap_or_else(PoisonError::into_inner)
491            .clone()
492    }
493
494    fn unsupported(
495        snapshot: &Snapshot,
496        action: Action,
497        reason: impl Into<Cow<'static, str>>,
498    ) -> Error {
499        Error::Unsupported {
500            action,
501            family: snapshot.info.family,
502            reason: reason.into(),
503        }
504    }
505
506    /// checks a command against what the box can do. it runs under the output lock, and the link thread swaps
507    /// snapshots under that same lock, so the snapshot checked here is the one the command goes out with
508    fn gate(snapshot: &Snapshot, action: Action, timing: Timing, command: Command) -> Result<()> {
509        let capability = snapshot.capabilities.get(action);
510        match &capability.execution {
511            Execution::Unsupported { reason } => {
512                return Err(Self::unsupported(snapshot, action, reason.clone()));
513            }
514            Execution::Host if timing == Timing::NativeOnly => {
515                return Err(Self::unsupported(
516                    snapshot,
517                    action,
518                    "the box can't do it by itself and you asked for native timing only",
519                ));
520            }
521            _ => {}
522        }
523        match command {
524            Command::Press(button) | Command::Release(button) | Command::Click { button, .. }
525                if !snapshot.capabilities.buttons().contains(&button) =>
526            {
527                Err(Error::InvalidArgument {
528                    action,
529                    detail: format!("the box has no {button} button").into(),
530                })
531            }
532            Command::KeyPress(key) | Command::KeyRelease(key) | Command::KeyTap { key, .. }
533                if !key.is_valid() =>
534            {
535                Err(Error::InvalidArgument {
536                    action,
537                    detail: format!("{key} isn't a key, keys go from 0x04 to 0xE7").into(),
538                })
539            }
540            Command::MediaPress(key)
541            | Command::MediaRelease(key)
542            | Command::MediaTap { key, .. }
543                if key.0 == 0 =>
544            {
545                Err(Error::InvalidArgument {
546                    action,
547                    detail: "media key 0 isn't a key".into(),
548                })
549            }
550            Command::Click {
551                hold: Some(hold), ..
552            }
553            | Command::KeyTap {
554                hold: Some(hold), ..
555            }
556            | Command::MediaTap {
557                hold: Some(hold), ..
558            } => {
559                for quirk in &capability.quirks {
560                    match quirk {
561                        Quirk::MaxHold(max) if hold > *max => {
562                            return Err(Error::InvalidArgument {
563                                action,
564                                detail: format!("the box holds it down for at most {max:?}").into(),
565                            });
566                        }
567                        _ => {}
568                    }
569                }
570                Ok(())
571            }
572            Command::Wheel(notches) => {
573                for quirk in &capability.quirks {
574                    if let Quirk::NotchesPerCommand(max) = quirk
575                        && notches.unsigned_abs() > *max
576                    {
577                        return Err(Self::unsupported(
578                            snapshot,
579                            action,
580                            match max {
581                                1 => {
582                                    "it takes one wheel notch per command, send them one at a time"
583                                        .into()
584                                }
585                                _ => format!(
586                                    "it takes at most {max} wheel notches per command, so split it up"
587                                ),
588                            },
589                        ));
590                    }
591                }
592                Ok(())
593            }
594            Command::Lock { slot, keep } => {
595                let detail = match slot {
596                    LockSlot::Button(button)
597                        if !snapshot.capabilities.buttons().contains(&button) =>
598                    {
599                        Some(format!("the box has no {button} button"))
600                    }
601                    LockSlot::Key(key) if !key.is_valid() => {
602                        Some(format!("{key} isn't a key, keys go from 0x04 to 0xE7"))
603                    }
604                    LockSlot::Axis(axis, _) if !snapshot.capabilities.axes().contains(&axis) => {
605                        Some(format!("the box can't lock the {axis} axis"))
606                    }
607                    LockSlot::Button(_) | LockSlot::Key(_) | LockSlot::Axis(..)
608                        if !(-255..=255).contains(&keep) =>
609                    {
610                        Some(format!(
611                            "{keep} is out of range, a scale goes from -255 to 255"
612                        ))
613                    }
614                    LockSlot::Button(_) | LockSlot::Key(_) | LockSlot::Axis(..) => None,
615                };
616                match detail {
617                    Some(detail) => Err(Error::InvalidArgument {
618                        action,
619                        detail: detail.into(),
620                    }),
621                    None => Ok(()),
622                }
623            }
624            Command::Move(..)
625            | Command::MoveNow(..)
626            | Command::Press(_)
627            | Command::Release(_)
628            | Command::Click { hold: None, .. }
629            | Command::Pan(_)
630            | Command::DiscardPendingMoves
631            | Command::KeyPress(_)
632            | Command::KeyRelease(_)
633            | Command::KeyTap { hold: None, .. }
634            | Command::MediaPress(_)
635            | Command::MediaRelease(_)
636            | Command::MediaTap { hold: None, .. } => Ok(()),
637        }
638    }
639
640    /// refuses a key that would go past what the box can hold down at once, counting what anybox already holds
641    fn check_rollover(
642        output: &Output,
643        snapshot: &Snapshot,
644        action: Action,
645        command: Command,
646    ) -> Result<()> {
647        let (Command::KeyPress(key) | Command::KeyTap { key, .. }) = command else {
648            return Ok(());
649        };
650        let Some(max) = max_keys_held(snapshot) else {
651            return Ok(());
652        };
653        if key.is_modifier() || output.held.contains(&Usage::Key(key)) {
654            return Ok(());
655        }
656        let held = output
657            .held
658            .iter()
659            .filter(|usage| matches!(usage, Usage::Key(held) if !held.is_modifier()))
660            .count();
661        if held >= usize::from(max) {
662            return Err(Self::unsupported(
663                snapshot,
664                action,
665                format!("this box holds at most {max} keys at once, let one go first"),
666            ));
667        }
668        Ok(())
669    }
670
671    fn open_output(&self) -> Result<(MutexGuard<'_, Output>, Arc<Snapshot>)> {
672        let output = lock(&self.output);
673        if output.closing {
674            return Err(Error::Closed);
675        }
676        if !output.link_up {
677            return Err(Error::Disconnected);
678        }
679        let snapshot = self.snapshot();
680        Ok((output, snapshot))
681    }
682
683    fn send_locked(
684        &self,
685        output: &mut Output,
686        snapshot: &Snapshot,
687        action: Action,
688        timing: Timing,
689        command: Command,
690    ) -> Result<()> {
691        let held = command.holds();
692        // letting go of something held always goes out, even when the box can't do it any more, otherwise a
693        // keyboard that got pulled out would leave a key anybox can never release
694        let releasing_held = matches!(held, Some((usage, false)) if output.held.contains(&usage));
695        if !releasing_held {
696            Self::gate(snapshot, action, timing, command)?;
697        }
698        Self::check_rollover(output, snapshot, action, command)?;
699        let sent = self.backend.send(command);
700        match (held, &sent) {
701            // a press that ran out of time may still have gone out, and releasing something the box doesn't hold
702            // does nothing, so it counts as held and the cleanup lets go of it
703            (Some((usage, true)), Ok(())) => {
704                output.held.insert(usage);
705                output.unsure.remove(&usage);
706            }
707            (Some((usage, true)), Err(Error::Disconnected)) => {
708                output.held.insert(usage);
709                output.unsure.insert(usage);
710            }
711            (Some((usage, false)), Ok(())) => {
712                output.held.remove(&usage);
713                output.unsure.remove(&usage);
714            }
715            _ => {}
716        }
717        sent
718    }
719
720    fn run(&self, action: Action, timing: Timing, command: Command) -> Result<()> {
721        let (mut output, snapshot) = self.open_output()?;
722        self.send_locked(&mut output, &snapshot, action, timing, command)
723    }
724
725    /// locks, unlocks or scales each slot. unlocking a slot anybox locked always goes out, same as releasing
726    /// something held. every slot gets checked before any of them goes out, so a refused call changes nothing
727    fn lock(&self, action: Action, slots: &[LockSlot], keep: i16) -> Result<()> {
728        let (mut output, snapshot) = self.open_output()?;
729        // one way of an axis that's held alone (locked while the box could still do one way) can still be
730        // unlocked, the box then unlocks the whole axis, which is all that's locked on it
731        if let [slot] = *slots
732            && let Some(other) = other_way(slot)
733            && whole_axis_only(&snapshot)
734            && !(keep == UNLOCKED
735                && output.locked.contains_key(&slot)
736                && !output.locked.contains_key(&other))
737        {
738            return Err(Self::unsupported(
739                &snapshot,
740                action,
741                "it only locks a whole axis, so use Direction::Both",
742            ));
743        }
744        for &slot in slots {
745            let unlocking_held = keep == UNLOCKED && output.locked.contains_key(&slot);
746            if !unlocking_held {
747                Self::gate(&snapshot, action, Timing::Any, Command::Lock { slot, keep })?;
748            }
749        }
750        let mut first = Ok(());
751        for &slot in slots {
752            let sent = self.backend.send(Command::Lock { slot, keep });
753            if keep == UNLOCKED {
754                if sent.is_ok() {
755                    output.locked.remove(&slot);
756                }
757            } else if matches!(sent, Ok(()) | Err(Error::Disconnected)) {
758                // a lock that ran out of time may still have gone out, and unlocking a slot that isn't locked does
759                // nothing, so it counts as locked
760                output.locked.insert(slot, keep);
761            }
762            if first.is_ok() {
763                first = sent;
764            }
765        }
766        first
767    }
768
769    /// a click or a key or media tap. it's the box's own if it has one, otherwise anybox presses, waits and
770    /// releases from the PC
771    fn tap(&self, usage: Usage, tap: Click) -> Result<()> {
772        let (action, press, release) = tap_actions(usage);
773        let (mut output, snapshot) = self.open_output()?;
774        let capability = snapshot.capabilities.get(action);
775        // a box whose own click has fixed timing can't take a hold, so a hold gets timed from the PC with a press and a
776        // release, the way Ferrum's docs say to do it
777        let fixed = tap.hold.is_some() && capability.quirks.contains(&Quirk::FixedClickTiming);
778        if capability.execution != Execution::Host && !fixed {
779            return self.send_locked(
780                &mut output,
781                &snapshot,
782                action,
783                tap.timing,
784                usage.tap(tap.hold),
785            );
786        }
787        if tap.timing == Timing::NativeOnly {
788            let reason = if fixed {
789                "the box's own click can't take a hold and you asked for native timing only"
790            } else {
791                "the box can't time it by itself and you asked for native timing only"
792            };
793            return Err(Self::unsupported(&snapshot, action, reason));
794        }
795        let hold = match tap.hold {
796            Some(hold) => hold,
797            None => lock(&self.holds).pick(self.click_timing).ok_or_else(|| {
798                Self::unsupported(
799                    &snapshot,
800                    action,
801                    "the box can't time it by itself and ClickTiming is off, so give it a hold",
802                )
803            })?,
804        };
805        // checked as the tap first, so a bad key or a full box gives an error about the tap and not about its press
806        Self::gate(&snapshot, action, tap.timing, usage.tap(None))?;
807        Self::check_rollover(&output, &snapshot, action, usage.press())?;
808        self.send_locked(&mut output, &snapshot, press, Timing::Any, usage.press())?;
809        let session = output.session;
810        drop(output);
811        thread::sleep(hold);
812        let (mut output, snapshot) = match self.open_output() {
813            Ok(open) => open,
814            Err(error) => {
815                lock(&self.output).unsure.insert(usage);
816                return Err(error);
817            }
818        };
819        if output.session != session && !keeps_held(&snapshot) {
820            // the box disconnected or reset during the hold, so this press was already let go, and the button or
821            // key may belong to a new press by now
822            return Err(Error::Interrupted { action });
823        }
824        let released = self.send_locked(
825            &mut output,
826            &snapshot,
827            release,
828            Timing::Any,
829            usage.release(),
830        );
831        if released.is_err() {
832            output.unsure.insert(usage);
833        }
834        released
835    }
836
837    fn add_receiver(&self, kinds: EventKinds, report_unsupported: bool) -> (Arc<Queue>, u64) {
838        let output = lock(&self.output);
839        let queue = Arc::new(Queue::new(QUEUE_CAPACITY));
840        let (id, seen) = {
841            // registered under the merge lock, so a refusal published after this reaches it
842            let refused = lock(&self.refused);
843            let mut receivers = lock(&self.receivers);
844            let id = receivers.next_id;
845            receivers.next_id += 1;
846            if output.closing {
847                queue.close();
848                return (queue, id);
849            }
850            receivers.entries.push(Entry {
851                id,
852                kinds,
853                queue: Arc::downgrade(&queue),
854            });
855            (id, refused.last.clone())
856        };
857        let snapshot = self.snapshot();
858        if report_unsupported {
859            let streamable = EventKinds::from_input(stream_kinds(&snapshot));
860            for (_, action) in (kinds & !streamable).each() {
861                queue.push(Event::Rejected { action, count: 1 });
862            }
863        }
864        let refused = self.apply_streams(&output, &snapshot);
865        drop(output);
866        // the merge in publish is for the box saying the same refusal twice. this receiver just asked, so it hears
867        // its answer once, otherwise a receiver made right after a refused one would wait forever for a stream
868        // that never came on
869        for action in refused {
870            let event = Event::Rejected { action, count: 1 };
871            let mut merge = lock(&self.refused);
872            let last = merge.last.get(&action).copied();
873            // a MAKCU's reader can publish the refusal before the switch returns, and then this receiver has it
874            let heard = last.map(|(_, n)| n) != seen.get(&action).map(|(_, n)| *n);
875            if !heard && EventKinds::of(&event).is_some_and(|kind| !(kinds & kind).is_empty()) {
876                queue.push(event.clone());
877            }
878            let now = Instant::now();
879            match last {
880                Some((at, n)) if now.duration_since(at) < MERGE => {
881                    // counted from this answer, so the box's second report of it merges for this receiver too
882                    merge.last.insert(action, (now, n));
883                }
884                _ => {
885                    merge.note(action, now);
886                    self.deliver(&event, Some(id));
887                }
888            }
889        }
890        (queue, id)
891    }
892
893    /// to each receiver that wants this kind of event. connection events and drops from the box go to everyone
894    fn publish(&self, event: Event) {
895        // a MAKCU reports one refused stream switch twice, the refusal itself and the switch that then failed, in
896        // either order, so a second one within a second is the same refusal. ponytail: a real second refusal that
897        // close is merged too, which only costs one count
898        if let Event::Rejected { action, .. } = &event
899            && EventKinds::of_action(*action).is_some()
900        {
901            let now = Instant::now();
902            // held while it goes out, so add_receiver can tell whether a refusal reached its new receiver
903            let mut merge = lock(&self.refused);
904            if merge
905                .last
906                .get(action)
907                .is_some_and(|(at, _)| now.duration_since(*at) < MERGE)
908            {
909                return;
910            }
911            merge.note(*action, now);
912            self.deliver(&event, None);
913            return;
914        }
915        self.deliver(&event, None);
916    }
917
918    fn deliver(&self, event: &Event, skip: Option<u64>) {
919        let kind = EventKinds::of(event);
920        let mut receivers = lock(&self.receivers);
921        receivers
922            .entries
923            .retain(|entry| match entry.queue.upgrade() {
924                Some(queue) => {
925                    if Some(entry.id) != skip
926                        && kind.is_none_or(|kind| !(entry.kinds & kind).is_empty())
927                    {
928                        queue.push(event.clone());
929                    }
930                    true
931                }
932                None => false,
933            });
934    }
935
936    fn publish_refused(&self, actions: Vec<Action>) {
937        for action in actions {
938            self.publish(Event::Rejected { action, count: 1 });
939        }
940    }
941
942    /// only to the receivers that want one of these kinds
943    fn publish_to(&self, kinds: EventKinds, event: Event) {
944        let receivers = lock(&self.receivers);
945        for entry in &receivers.entries {
946            if !(entry.kinds & kinds).is_empty()
947                && let Some(queue) = entry.queue.upgrade()
948            {
949                queue.push(event.clone());
950            }
951        }
952    }
953
954    fn close_receivers(&self) {
955        for entry in lock(&self.receivers).entries.drain(..) {
956            if let Some(queue) = entry.queue.upgrade() {
957                queue.close();
958            }
959        }
960    }
961
962    /// streams what the receivers want and the box can, the empty set too, so nothing streams that nobody wants.
963    /// called with the output lock held, which is what orders it against reconnects and the other receivers. it
964    /// returns the refusals to publish once the output lock is let go, `Disconnected` isn't one because the
965    /// reconnect asks again
966    fn apply_streams(&self, output: &Output, snapshot: &Snapshot) -> Vec<Action> {
967        if output.closing || !output.link_up {
968            return Vec::new();
969        }
970        let union = lock(&self.receivers).union();
971        let wanted = union & EventKinds::from_input(stream_kinds(snapshot));
972        match self.backend.set_streams(wanted.to_input()) {
973            Err(failure) if !matches!(failure.error, Error::Disconnected) => {
974                (EventKinds::from_input(failure.failed) & wanted)
975                    .each()
976                    .map(|(_, action)| action)
977                    .collect()
978            }
979            _ => Vec::new(),
980        }
981    }
982
983    /// after a reconnect or a reset this lets go of everything that's held. a box that keeps held buttons and keys
984    /// on its own only gets the ones the app was told failed. a release that fails stays in the record, so drop
985    /// tries it again
986    fn release_held(&self, output: &mut Output, snapshot: &Snapshot) -> bool {
987        let usages = if keeps_held(snapshot) {
988            &output.unsure
989        } else {
990            &output.held
991        };
992        let usages: Vec<Usage> = usages.iter().copied().collect();
993        let mut all_released = true;
994        for usage in usages {
995            if self.backend.send(usage.release()).is_ok() {
996                output.held.remove(&usage);
997                output.unsure.remove(&usage);
998            } else {
999                all_released = false;
1000            }
1001        }
1002        all_released
1003    }
1004
1005    fn release_everything(&self) -> Result<()> {
1006        let mut output = lock(&self.output);
1007        output.closing = true;
1008        output.link_up = false;
1009        output.unsure.clear();
1010        let held: Vec<Usage> = output.held.drain().collect();
1011        let released = if held.is_empty() {
1012            Ok(())
1013        } else {
1014            self.backend.release_all(&held)
1015        };
1016        let locked: Vec<LockSlot> = output.locked.drain().map(|(slot, _)| slot).collect();
1017        let unlocked = if locked.is_empty() {
1018            Ok(())
1019        } else {
1020            self.backend.unlock_all(&locked)
1021        };
1022        released.and(unlocked)
1023    }
1024
1025    /// sends the app's locks again after a reconnect or a reset, on a box that doesn't keep them itself. a lock the
1026    /// box can't do right now waits for a snapshot that can, and if sending one fails the backend fixes it itself
1027    fn relock(&self, output: &Output, snapshot: &Snapshot) {
1028        if keeps_locked(snapshot) {
1029            return;
1030        }
1031        for (&slot, &keep) in &output.locked {
1032            // a box that only locks a whole axis only gets it back when both ways were locked the same, a lone way
1033            // waits for a box that can do it
1034            if whole_axis_only(snapshot)
1035                && let Some(other) = other_way(slot)
1036                && output.locked.get(&other) != Some(&keep)
1037            {
1038                continue;
1039            }
1040            let command = Command::Lock { slot, keep };
1041            if Self::gate(snapshot, command.action(), Timing::Any, command).is_ok() {
1042                let _ = self.backend.send(command);
1043            }
1044        }
1045    }
1046
1047    fn handle(&self, signal: Signal) {
1048        match signal {
1049            Signal::Input {
1050                input,
1051                arrived,
1052                box_time,
1053                read,
1054            } => {
1055                let mut at = Stamp::new(arrived, arrived.saturating_duration_since(self.opened));
1056                at.box_time = box_time;
1057                if let Some(read) = read {
1058                    at.received = read.at;
1059                    at.received_since_open = read.at.saturating_duration_since(self.opened);
1060                    at.received_qpc = read.qpc;
1061                }
1062                self.publish(match input {
1063                    Input::Button { button, pressed } => Event::Button {
1064                        button,
1065                        pressed,
1066                        at,
1067                    },
1068                    Input::Motion { dx, dy, wheel, pan } => Event::Motion {
1069                        dx,
1070                        dy,
1071                        wheel,
1072                        pan,
1073                        at,
1074                    },
1075                    Input::Key { key, pressed } => Event::Key { key, pressed, at },
1076                    Input::Media { key, pressed } => Event::Media { key, pressed, at },
1077                });
1078            }
1079            Signal::Dropped(count, source, kind) => match kind {
1080                Some(kind) => self.publish_to(
1081                    EventKinds::from_input(kind.kinds()),
1082                    Event::Dropped { count, source },
1083                ),
1084                None => self.publish(Event::Dropped { count, source }),
1085            },
1086            Signal::StreamLost(kind) => {
1087                let output = lock(&self.output);
1088                if output.closing {
1089                    return;
1090                }
1091                let lost = EventKinds::from_input(kind.kinds());
1092                // the box doesn't say how many it lost, so this means at least one, and only to the receivers of
1093                // that kind
1094                self.publish_to(
1095                    lost,
1096                    Event::Dropped {
1097                        count: 1,
1098                        source: DropSource::Device,
1099                    },
1100                );
1101                // only restart it while someone still wants it, checked under the same lock a dropped receiver takes,
1102                // so a stream nobody wants stays off. and only the lost one, because the others are still running
1103                if output.link_up && lock(&self.receivers).union().contains(lost) {
1104                    let restarted = self.backend.restart_stream(kind);
1105                    drop(output);
1106                    if let Err(error) = restarted
1107                        && !matches!(error, Error::Disconnected)
1108                    {
1109                        for (_, action) in lost.each() {
1110                            self.publish(Event::Rejected { action, count: 1 });
1111                        }
1112                    }
1113                }
1114            }
1115            Signal::Refused(action) => self.publish(Event::Rejected { action, count: 1 }),
1116            Signal::Disconnected => {
1117                let mut output = lock(&self.output);
1118                if output.closing {
1119                    return;
1120                }
1121                // a box that came back but never got up again was already said to be down
1122                let was_up = output.link_up;
1123                output.link_up = false;
1124                output.session += 1;
1125                drop(output);
1126                if was_up {
1127                    self.publish(Event::Disconnected);
1128                }
1129            }
1130            Signal::Reconnected(snapshot) => {
1131                let mut output = lock(&self.output);
1132                if output.closing {
1133                    return;
1134                }
1135                output.session += 1;
1136                let snapshot = prepare(*snapshot, self.click_timing, &self.port);
1137                *self
1138                    .snapshot
1139                    .write()
1140                    .unwrap_or_else(PoisonError::into_inner) = snapshot.clone();
1141                if !self.release_held(&mut output, &snapshot) {
1142                    // a release failing right after the box came back means it's gone again, so stay down until
1143                    // the next reconnect gets a clean slate
1144                    let was_up = output.link_up;
1145                    output.link_up = false;
1146                    drop(output);
1147                    if was_up {
1148                        self.publish(Event::Disconnected);
1149                    }
1150                    return;
1151                }
1152                self.relock(&output, &snapshot);
1153                output.link_up = true;
1154                let refused = self.apply_streams(&output, &snapshot);
1155                drop(output);
1156                self.publish(Event::Reconnected);
1157                self.publish_refused(refused);
1158            }
1159            Signal::Changed(snapshot) => {
1160                let output = lock(&self.output);
1161                if output.closing {
1162                    return;
1163                }
1164                let snapshot = prepare(*snapshot, self.click_timing, &self.port);
1165                let changed = {
1166                    let mut current = self
1167                        .snapshot
1168                        .write()
1169                        .unwrap_or_else(PoisonError::into_inner);
1170                    // compared after `prepare`, the backend's own snapshot has no port and no host taps
1171                    let changed = *current != snapshot;
1172                    *current = snapshot.clone();
1173                    changed
1174                };
1175                // a device that came or went can change which kinds the box streams
1176                let refused = self.apply_streams(&output, &snapshot);
1177                drop(output);
1178                if changed {
1179                    self.publish(Event::Changed);
1180                }
1181                self.publish_refused(refused);
1182            }
1183            Signal::SessionReset => {
1184                let mut output = lock(&self.output);
1185                if output.closing {
1186                    return;
1187                }
1188                output.session += 1;
1189                let snapshot = self.snapshot();
1190                self.release_held(&mut output, &snapshot);
1191                self.relock(&output, &snapshot);
1192                let refused = self.apply_streams(&output, &snapshot);
1193                drop(output);
1194                self.publish(Event::SessionReset);
1195                self.publish_refused(refused);
1196            }
1197            #[cfg(test)]
1198            Signal::Barrier(done) => {
1199                let _ = done.send(());
1200            }
1201            #[cfg(feature = "mock")]
1202            Signal::Examples(events) => {
1203                for event in events {
1204                    self.publish(event);
1205                }
1206            }
1207            Signal::Stop => {}
1208        }
1209    }
1210}
1211
1212impl Listeners for Core {
1213    fn receiver_dropped(&self, id: u64) {
1214        let output = lock(&self.output);
1215        lock(&self.receivers).entries.retain(|entry| entry.id != id);
1216        let refused = self.apply_streams(&output, &self.snapshot());
1217        drop(output);
1218        self.publish_refused(refused);
1219    }
1220}
1221
1222fn spawn_link(
1223    core: Weak<Core>,
1224    incoming: Receiver<Signal>,
1225) -> Result<(JoinHandle<()>, Receiver<()>)> {
1226    let (done, finished) = mpsc::channel();
1227    let handle = thread::Builder::new()
1228        .name("anybox-link".into())
1229        .spawn(move || {
1230            while let Ok(signal) = incoming.recv() {
1231                if matches!(signal, Signal::Stop) {
1232                    break;
1233                }
1234                match core.upgrade() {
1235                    Some(core) => core.handle(signal),
1236                    None => break,
1237                }
1238            }
1239            let _ = done.send(());
1240        })?;
1241    Ok((handle, finished))
1242}
1243
1244#[cfg(feature = "mock")]
1245impl Device {
1246    /// sends every receiver one of each event from `Event::examples`, through the same queue as real ones, without
1247    /// any of them doing to the device what the real one would. for testing how code reads every kind of event
1248    pub fn mock_example_events(&self) {
1249        let now = Instant::now();
1250        let at = Stamp::new(now, now.saturating_duration_since(self.core.opened));
1251        let _ = self
1252            .core
1253            .signals
1254            .send(Signal::Examples(Event::examples(at)));
1255    }
1256}
1257
1258#[cfg(test)]
1259impl Device {
1260    /// only the first part of what drop does, so a test can send link events into a device that's closing
1261    pub(crate) fn start_closing(&self) {
1262        let _ = self.core.release_everything();
1263    }
1264
1265    pub(crate) fn backend_for_tests(&self) -> &dyn std::any::Any {
1266        self.core.backend.as_any()
1267    }
1268
1269    pub(crate) fn held(&self) -> HashSet<Usage> {
1270        lock(&self.core.output).held.clone()
1271    }
1272
1273    /// waits until the link thread handled everything that was signaled before this call
1274    pub(crate) fn settle(&self) {
1275        let (done, wait) = mpsc::channel();
1276        let _ = self.core.signals.send(Signal::Barrier(done));
1277        let _ = wait.recv_timeout(Duration::from_secs(5));
1278    }
1279}
1280
1281#[cfg(test)]
1282mod tests;