hid_api_rs/gadgets/
mouse.rs

1use std::fs::{File, OpenOptions};
2use std::io::{BufWriter, Error, ErrorKind, Read, Write};
3use std::path::Path;
4use std::thread;
5use std::time::Duration;
6
7use once_cell::sync::Lazy;
8
9use crate::{hid, HidMouse};
10
11pub struct Mouse {
12    pub mouse_data_buffer: Vec<MouseRaw>,
13    mouse_state: MouseState,
14    mouse_device_file: File,
15
16    pub mouse_settings: MouseSettings,
17    pub mouse_path: String,
18
19    side_buttons: bool
20}
21
22impl Mouse {
23    pub fn get_state(&self) -> &MouseState {
24        &self.mouse_state
25    }
26}
27
28#[derive(Copy, Clone, Default)]
29pub struct MouseState {
30    pub left_button: bool,
31    pub right_button: bool,
32    pub middle_button: bool,
33    pub four_button: bool,
34    pub five_button: bool,
35}
36
37pub struct MouseSettings {
38    pub invert_x: bool,
39    pub invert_y: bool,
40    pub invert_wheel: bool,
41
42    pub sensitivity_multiplier: i16,
43}
44
45impl Default for MouseSettings {
46    fn default() -> Self {
47        MouseSettings {
48            invert_x: false,
49            invert_y: false,
50            invert_wheel: false,
51            sensitivity_multiplier: 1,
52        }
53    }
54}
55
56#[derive(Default)]
57pub struct MouseRaw {
58    pub left_button: bool,
59    pub right_button: bool,
60    pub middle_button: bool,
61    pub four_button: bool,
62    pub five_button: bool,
63
64    pub relative_x: i16,
65    pub relative_y: i16,
66    pub relative_wheel: i16,
67}
68
69pub fn attempt_read(mouse: &mut Mouse, gadget_writer: &mut BufWriter<&mut File>) -> Result<(), Error> {
70    const BUFFER_LENGTH: usize = 4;
71    let mut mouse_buffer = [0u8; BUFFER_LENGTH];
72
73    let mouse_read_length = mouse.mouse_device_file.read(&mut mouse_buffer)?;
74
75    if mouse_read_length >= BUFFER_LENGTH {
76        let left_button = mouse_buffer[0] & 0x1 > 0;
77        let right_button = mouse_buffer[0] & 0x2 > 0;
78        let middle_button = mouse_buffer[0] & 0x4 > 0;
79
80        let mut mouse_four = false;
81        let mut mouse_five = false;
82
83        // https://isdaman.com/alsos/hardware/mouse/ps2interface.htm
84        if mouse.side_buttons {
85            mouse_four = mouse_buffer[3] & 0x10 > 0;
86            mouse_five = mouse_buffer[3] & 0x20 > 0;
87        }
88
89        let mut relative_y = -i8::from_be_bytes(mouse_buffer[2].to_be_bytes()) as i16;
90        let mut relative_x = i8::from_be_bytes(mouse_buffer[1].to_be_bytes()) as i16;
91
92        let mut relative_wheel = match mouse.side_buttons {
93            true => {
94                let mut z = ((mouse_buffer[3] & 0x8) | (mouse_buffer[3] & 0x4) | (mouse_buffer[3] & 0x2) | (mouse_buffer[3] & 0x1)) as i8;
95
96                if mouse_buffer[3] & 0x8 > 0 {
97                    z = (z << 4) >> 4
98                }
99
100                -i8::from_be_bytes(z.to_be_bytes()) as i16
101            },
102            false => -i8::from_be_bytes(mouse_buffer[3].to_be_bytes()) as i16
103        };
104
105        if mouse.mouse_settings.invert_x {
106            relative_x *= -1;
107        }
108
109        if mouse.mouse_settings.invert_y {
110            relative_y *= -1;
111        }
112
113        if mouse.mouse_settings.invert_wheel {
114            relative_wheel *= -1;
115        }
116
117        relative_x *= mouse.mouse_settings.sensitivity_multiplier;
118        relative_y *= mouse.mouse_settings.sensitivity_multiplier;
119
120        let raw_mouse = MouseRaw {
121            left_button,
122            right_button,
123            middle_button,
124            four_button: mouse_four,
125            five_button: mouse_five,
126            relative_x,
127            relative_y,
128            relative_wheel,
129        };
130
131        return push_mouse_event(raw_mouse, Some(mouse), gadget_writer);
132    }
133
134    Ok(())
135}
136
137pub fn push_mouse_event(raw_data: MouseRaw, mouse: Option<&mut Mouse>, gadget_writer: &mut BufWriter<&mut File>) -> Result<(), Error> {
138    if let Some(mouse) = mouse {
139        let new_state = MouseState {
140            left_button: raw_data.left_button,
141            right_button: raw_data.right_button,
142            middle_button: raw_data.middle_button,
143            four_button: raw_data.four_button,
144            five_button: raw_data.five_button,
145        };
146        mouse.mouse_state = new_state;
147    }
148
149    hid::write_mouse(&raw_data, gadget_writer)
150}
151
152pub fn check_mouses(mouse_inputs: &Vec<HidMouse>, mouse_interfaces: &'static mut Lazy<Vec<Mouse>>) {
153    for mouse_input in mouse_inputs {
154        if mouse_interfaces.iter().any(|mouse| mouse.mouse_path == mouse_input.mouse_path) {
155            thread::sleep(Duration::from_millis(1));
156            continue;
157        }
158
159        let mouse_path = Path::new(&mouse_input.mouse_path);
160        if Path::exists(mouse_path) {
161            let mouse = match OpenOptions::new()
162                .write(true)
163                .read(true)
164                .open(mouse_path)
165            {
166                Ok(result) => result,
167                Err(_) => continue,
168            };
169
170            let mut mouse_interface = Mouse {
171                mouse_data_buffer: Vec::new(),
172                mouse_state: MouseState::default(),
173                mouse_device_file: mouse,
174                mouse_settings: MouseSettings::default(),
175                mouse_path: mouse_input.mouse_path.clone(),
176                side_buttons: mouse_input.mouse_side_buttons
177            };
178
179            // https://wiki.osdev.org/PS/2_Mouse#Mouse_Extensions
180            let mut mouse_feature: [u8; 6] = [0xf3, 200, 0xf3, 100, 0xf3, 80];
181            if mouse_input.mouse_side_buttons {
182                mouse_feature = [0xf3, 200, 0xf3, 200, 0xf3, 80];
183            }
184
185            _ = write_feature(&mut mouse_interface, mouse_feature);
186
187            if let Some(poll_rate) = mouse_input.mouse_poll_rate {
188                _ = write_poll_rate(&mut mouse_interface, poll_rate);
189            }
190
191            mouse_interfaces.push(mouse_interface);
192        }
193    }
194}
195
196pub fn write_feature(mouse: &mut Mouse, feature: [u8; 6]) -> Result<(), Error> {
197    if mouse.mouse_device_file.write_all(&feature).is_err() {
198        return Err(Error::new(
199            ErrorKind::Other,
200            String::from("Failed write magic scroll feature to mouse!"),
201        ));
202    }
203
204    Ok(())
205}
206
207pub fn write_poll_rate(mouse: &mut Mouse, poll_rate: i32) -> Result<(), Error> {
208    let mut poll_rate_packet: Vec<u8> = Vec::new();
209    poll_rate_packet.push(0xf3);
210    poll_rate_packet.append(&mut poll_rate.to_be_bytes().to_vec());
211
212    if mouse.mouse_device_file.write_all(&poll_rate_packet).is_err() {
213        return Err(Error::new(
214            ErrorKind::Other,
215            String::from("Failed to set poll rate to mouse! (Defaulting to 125 hz or last mouse profile)"),
216        ));
217    }
218
219    Ok(())
220}