hid_api_rs/
lib.rs

1use std::io::{BufWriter, Error, ErrorKind};
2use std::thread;
3use std::time::Duration;
4
5use once_cell::sync::Lazy;
6
7use gadgets::keyboard::{self, Keyboard, KeyboardState};
8use gadgets::mouse::{self, Mouse};
9
10use crate::gadgets::mouse::MouseRaw;
11
12pub mod gadgets;
13pub mod hid;
14
15#[derive(Clone)]
16pub struct HidSpecification {
17    pub mouse_inputs: Option<Vec<HidMouse>>,
18    pub keyboard_inputs: Option<Vec<String>>,
19    pub gadget_output: String,
20}
21
22#[derive(Clone)]
23pub struct HidMouse {
24    pub mouse_path: String,
25    pub mouse_poll_rate: Option<i32>,
26    pub mouse_side_buttons: bool,
27}
28
29static mut HID_SPEC: Option<HidSpecification> = None;
30static mut MOUSE_INTERFACES: Lazy<Vec<Mouse>> = Lazy::new(Vec::new);
31static mut MOUSE_READING: bool = true;
32
33static mut KEYBOARD_INTERFACES: Vec<Keyboard> = Vec::new();
34static mut KEYBOARD_READING: bool = true;
35
36static mut GLOBAL_KEYBOARD_STATE: Lazy<KeyboardState> = Lazy::new(KeyboardState::default);
37
38pub fn start_pass_through(specification: HidSpecification) -> Result<(), Error> {
39    unsafe {
40        HID_SPEC = Some(specification.clone());
41    }
42
43    start_hot_reload(specification.mouse_inputs.clone(), specification.keyboard_inputs.clone());
44
45    unsafe {
46        if specification.mouse_inputs.is_some() {
47            let mouse_spec = specification.clone();
48            thread::spawn(move || {
49                static mut MOUSE_THREADS: Vec<String> = Vec::new();
50                loop {
51                    if !MOUSE_READING {
52                        return;
53                    }
54
55                    if MOUSE_INTERFACES.is_empty() {
56                        thread::sleep(Duration::from_millis(1));
57                        continue;
58                    }
59
60                    for (mouse_interface_index, mouse) in MOUSE_INTERFACES.iter_mut().enumerate() {
61                        if !MOUSE_THREADS.contains(&mouse.mouse_path) || MOUSE_THREADS.is_empty() {
62                            let gadget_mouse = match hid::open_gadget_device(mouse_spec.gadget_output.clone()) {
63                                Ok(gadget_device) => gadget_device,
64                                Err(_) => continue,
65                            };
66
67                            MOUSE_THREADS.push(mouse.mouse_path.clone());
68
69                            let mut mouse_writer = BufWriter::new(gadget_mouse);
70                            thread::spawn(move || {
71                                loop {
72                                    if !MOUSE_READING {
73                                        break;
74                                    }
75
76                                    if mouse::attempt_read(mouse, &mut mouse_writer).is_err() {
77                                        MOUSE_INTERFACES.remove(mouse_interface_index);
78                                        MOUSE_THREADS.remove(mouse_interface_index);
79
80                                        break;
81                                    };
82                                }
83                            });
84                        }
85                    }
86
87                    thread::sleep(Duration::from_millis(1));
88                }
89            });
90        }
91
92        if specification.keyboard_inputs.is_some() {
93            let keyboard_spec = specification.clone();
94            thread::spawn(move || {
95                static mut KEYBOARD_THREADS: Vec<String> = Vec::new();
96                loop {
97                    if !KEYBOARD_READING {
98                        break;
99                    }
100
101                    if KEYBOARD_INTERFACES.is_empty() {
102                        thread::sleep(Duration::from_millis(1));
103                        continue;
104                    }
105
106                    for (keyboard_interface_index, keyboard) in KEYBOARD_INTERFACES.iter_mut().enumerate() {
107                        if !KEYBOARD_THREADS.contains(&keyboard.keyboard_path) || KEYBOARD_THREADS.is_empty() {
108                            let gadget_keyboard = match hid::open_gadget_device(keyboard_spec.gadget_output.clone()) {
109                                Ok(gadget_device) => gadget_device,
110                                Err(_) => continue,
111                            };
112
113                            KEYBOARD_THREADS.push(keyboard.keyboard_path.clone());
114
115                            let mut keyboard_writer = BufWriter::new(gadget_keyboard);
116                            thread::spawn(move || {
117                                loop {
118                                    if !KEYBOARD_READING {
119                                        break;
120                                    }
121
122                                    if keyboard::attempt_read(keyboard, &mut GLOBAL_KEYBOARD_STATE, &mut keyboard_writer).is_err() {
123                                        KEYBOARD_INTERFACES.remove(keyboard_interface_index);
124                                        KEYBOARD_THREADS.remove(keyboard_interface_index);
125
126                                        break;
127                                    };
128                                }
129                            });
130                        }
131                    }
132
133                    thread::sleep(Duration::from_millis(1));
134                }
135            });
136        }
137    }
138
139    Ok(())
140}
141
142pub fn stop_pass_through() -> Result<(), Error> {
143    unsafe {
144        MOUSE_READING = false;
145        KEYBOARD_READING = false;
146
147        match &HID_SPEC {
148            Some(spec) => {
149                let gadget_device = match hid::open_gadget_device(spec.gadget_output.clone()) {
150                    Ok(gadget_device) => gadget_device,
151                    Err(err) => return Err(err),
152                };
153
154                let mut gadget_writer = BufWriter::new(gadget_device);
155
156                MOUSE_INTERFACES.clear();
157                mouse::push_mouse_event(MouseRaw::default(), None, &mut gadget_writer)?;
158
159                KEYBOARD_INTERFACES.clear();
160                static mut DEFAULT_KEYBOARD_STATE: Lazy<KeyboardState> =
161                    Lazy::new(KeyboardState::default);
162                keyboard::attempt_flush(&mut DEFAULT_KEYBOARD_STATE, &mut gadget_writer)?;
163
164                Ok(())
165            }
166            None => Err(Error::new(
167                ErrorKind::Other,
168                String::from("Hid specification not defined cannot open gadget device"),
169            ))
170        }
171    }
172}
173
174fn start_hot_reload(
175    mouse_inputs: Option<Vec<HidMouse>>,
176    keyboard_inputs: Option<Vec<String>>,
177) {
178    if let Some(mouse_inputs) = mouse_inputs {
179        if !mouse_inputs.is_empty() {
180            thread::spawn(move || unsafe {
181                loop {
182                    if !MOUSE_READING {
183                        break;
184                    }
185
186                    mouse::check_mouses(&mouse_inputs, &mut MOUSE_INTERFACES);
187                }
188            });
189        }
190    }
191
192    if let Some(keyboard_inputs) = keyboard_inputs {
193        if !keyboard_inputs.is_empty() {
194            thread::spawn(move || unsafe {
195                loop {
196                    if !KEYBOARD_READING {
197                        break;
198                    }
199
200                    keyboard::check_keyboards(&keyboard_inputs, &mut KEYBOARD_INTERFACES);
201                }
202            });
203        }
204    }
205}
206
207pub fn get_mouses() -> &'static mut Lazy<Vec<Mouse>, fn() -> Vec<Mouse>> {
208    unsafe { &mut MOUSE_INTERFACES }
209}
210
211pub fn get_keyboard() -> &'static mut KeyboardState {
212    unsafe { &mut GLOBAL_KEYBOARD_STATE }
213}