Buttplug sex toy control library
1// Buttplug Rust Source Code File - See https://buttplug.io for more info.
2//
3// Copyright 2016-2024 Nonpolynomial Labs LLC. All rights reserved.
4//
5// Licensed under the BSD 3-Clause license. See LICENSE file in the project root
6// for full license information.
7
8use super::xinput_hardware::XInputHardwareConnector;
9use async_trait::async_trait;
10use buttplug_core::errors::ButtplugDeviceError;
11use buttplug_server::device::hardware::communication::{
12 HardwareCommunicationManager,
13 HardwareCommunicationManagerBuilder,
14 HardwareCommunicationManagerEvent,
15 TimedRetryCommunicationManager,
16 TimedRetryCommunicationManagerImpl,
17};
18use rusty_xinput::XInputHandle;
19use std::string::ToString;
20use tokio::sync::mpsc;
21
22// 1-index this because we use it elsewhere for showing which controller is which.
23#[derive(Debug, Display, Clone, Copy)]
24#[repr(u8)]
25pub enum XInputControllerIndex {
26 XInputController1 = 0,
27 XInputController2 = 1,
28 XInputController3 = 2,
29 XInputController4 = 3,
30}
31
32#[derive(Default, Clone)]
33pub struct XInputDeviceCommunicationManagerBuilder {}
34
35impl HardwareCommunicationManagerBuilder for XInputDeviceCommunicationManagerBuilder {
36 fn finish(
37 &mut self,
38 sender: mpsc::Sender<HardwareCommunicationManagerEvent>,
39 ) -> Box<dyn HardwareCommunicationManager> {
40 Box::new(TimedRetryCommunicationManager::new(
41 XInputDeviceCommunicationManager::new(sender),
42 ))
43 }
44}
45
46pub struct XInputDeviceCommunicationManager {
47 sender: mpsc::Sender<HardwareCommunicationManagerEvent>,
48 handle: XInputHandle,
49}
50
51impl XInputDeviceCommunicationManager {
52 fn new(sender: mpsc::Sender<HardwareCommunicationManagerEvent>) -> Self {
53 Self {
54 sender,
55 handle: rusty_xinput::XInputHandle::load_default()
56 .expect("Always loads in windows, this shouldn't run elsewhere."),
57 }
58 }
59}
60
61#[async_trait]
62impl TimedRetryCommunicationManagerImpl for XInputDeviceCommunicationManager {
63 fn name(&self) -> &'static str {
64 "XInputDeviceCommunicationManager"
65 }
66
67 async fn scan(&self) -> Result<(), ButtplugDeviceError> {
68 trace!("XInput manager scanning for devices");
69 for i in &[
70 XInputControllerIndex::XInputController1,
71 XInputControllerIndex::XInputController2,
72 XInputControllerIndex::XInputController3,
73 XInputControllerIndex::XInputController4,
74 ] {
75 match self.handle.get_state(*i as u32) {
76 Ok(_) => {
77 let index = *i as u32;
78 debug!("XInput manager found device {}", index);
79 let device_creator = Box::new(XInputHardwareConnector::new(*i));
80
81 if self
82 .sender
83 .send(HardwareCommunicationManagerEvent::DeviceFound {
84 name: i.to_string(),
85 address: i.to_string(),
86 creator: device_creator,
87 })
88 .await
89 .is_err()
90 {
91 error!("Error sending device found message from Xinput.");
92 break;
93 }
94 }
95 Err(_) => {
96 continue;
97 }
98 }
99 }
100 Ok(())
101 }
102
103 // We should always be able to at least look at xinput if we're up on windows.
104 fn can_scan(&self) -> bool {
105 true
106 }
107}