1 use std::{
2     mem::{self, size_of},
3     ptr,
4 };
5 
6 use winapi::{
7     ctypes::wchar_t,
8     shared::{
9         hidusage::{HID_USAGE_GENERIC_KEYBOARD, HID_USAGE_GENERIC_MOUSE, HID_USAGE_PAGE_GENERIC},
10         minwindef::{TRUE, UINT, USHORT},
11         windef::HWND,
12     },
13     um::{
14         winnt::HANDLE,
15         winuser::{
16             self, HRAWINPUT, RAWINPUT, RAWINPUTDEVICE, RAWINPUTDEVICELIST, RAWINPUTHEADER,
17             RIDEV_DEVNOTIFY, RIDEV_INPUTSINK, RIDI_DEVICEINFO, RIDI_DEVICENAME, RID_DEVICE_INFO,
18             RID_DEVICE_INFO_HID, RID_DEVICE_INFO_KEYBOARD, RID_DEVICE_INFO_MOUSE, RID_INPUT,
19             RIM_TYPEHID, RIM_TYPEKEYBOARD, RIM_TYPEMOUSE,
20         },
21     },
22 };
23 
24 use crate::{event::ElementState, platform_impl::platform::util};
25 
26 #[allow(dead_code)]
get_raw_input_device_list() -> Option<Vec<RAWINPUTDEVICELIST>>27 pub fn get_raw_input_device_list() -> Option<Vec<RAWINPUTDEVICELIST>> {
28     let list_size = size_of::<RAWINPUTDEVICELIST>() as UINT;
29 
30     let mut num_devices = 0;
31     let status =
32         unsafe { winuser::GetRawInputDeviceList(ptr::null_mut(), &mut num_devices, list_size) };
33 
34     if status == UINT::max_value() {
35         return None;
36     }
37 
38     let mut buffer = Vec::with_capacity(num_devices as _);
39 
40     let num_stored = unsafe {
41         winuser::GetRawInputDeviceList(buffer.as_ptr() as _, &mut num_devices, list_size)
42     };
43 
44     if num_stored == UINT::max_value() {
45         return None;
46     }
47 
48     debug_assert_eq!(num_devices, num_stored);
49 
50     unsafe { buffer.set_len(num_devices as _) };
51 
52     Some(buffer)
53 }
54 
55 #[allow(dead_code)]
56 pub enum RawDeviceInfo {
57     Mouse(RID_DEVICE_INFO_MOUSE),
58     Keyboard(RID_DEVICE_INFO_KEYBOARD),
59     Hid(RID_DEVICE_INFO_HID),
60 }
61 
62 impl From<RID_DEVICE_INFO> for RawDeviceInfo {
from(info: RID_DEVICE_INFO) -> Self63     fn from(info: RID_DEVICE_INFO) -> Self {
64         unsafe {
65             match info.dwType {
66                 RIM_TYPEMOUSE => RawDeviceInfo::Mouse(*info.u.mouse()),
67                 RIM_TYPEKEYBOARD => RawDeviceInfo::Keyboard(*info.u.keyboard()),
68                 RIM_TYPEHID => RawDeviceInfo::Hid(*info.u.hid()),
69                 _ => unreachable!(),
70             }
71         }
72     }
73 }
74 
75 #[allow(dead_code)]
get_raw_input_device_info(handle: HANDLE) -> Option<RawDeviceInfo>76 pub fn get_raw_input_device_info(handle: HANDLE) -> Option<RawDeviceInfo> {
77     let mut info: RID_DEVICE_INFO = unsafe { mem::zeroed() };
78     let info_size = size_of::<RID_DEVICE_INFO>() as UINT;
79 
80     info.cbSize = info_size;
81 
82     let mut minimum_size = 0;
83     let status = unsafe {
84         winuser::GetRawInputDeviceInfoW(
85             handle,
86             RIDI_DEVICEINFO,
87             &mut info as *mut _ as _,
88             &mut minimum_size,
89         )
90     };
91 
92     if status == UINT::max_value() || status == 0 {
93         return None;
94     }
95 
96     debug_assert_eq!(info_size, status);
97 
98     Some(info.into())
99 }
100 
get_raw_input_device_name(handle: HANDLE) -> Option<String>101 pub fn get_raw_input_device_name(handle: HANDLE) -> Option<String> {
102     let mut minimum_size = 0;
103     let status = unsafe {
104         winuser::GetRawInputDeviceInfoW(handle, RIDI_DEVICENAME, ptr::null_mut(), &mut minimum_size)
105     };
106 
107     if status != 0 {
108         return None;
109     }
110 
111     let mut name: Vec<wchar_t> = Vec::with_capacity(minimum_size as _);
112 
113     let status = unsafe {
114         winuser::GetRawInputDeviceInfoW(
115             handle,
116             RIDI_DEVICENAME,
117             name.as_ptr() as _,
118             &mut minimum_size,
119         )
120     };
121 
122     if status == UINT::max_value() || status == 0 {
123         return None;
124     }
125 
126     debug_assert_eq!(minimum_size, status);
127 
128     unsafe { name.set_len(minimum_size as _) };
129 
130     Some(util::wchar_to_string(&name))
131 }
132 
register_raw_input_devices(devices: &[RAWINPUTDEVICE]) -> bool133 pub fn register_raw_input_devices(devices: &[RAWINPUTDEVICE]) -> bool {
134     let device_size = size_of::<RAWINPUTDEVICE>() as UINT;
135 
136     let success = unsafe {
137         winuser::RegisterRawInputDevices(devices.as_ptr() as _, devices.len() as _, device_size)
138     };
139 
140     success == TRUE
141 }
142 
register_all_mice_and_keyboards_for_raw_input(window_handle: HWND) -> bool143 pub fn register_all_mice_and_keyboards_for_raw_input(window_handle: HWND) -> bool {
144     // RIDEV_DEVNOTIFY: receive hotplug events
145     // RIDEV_INPUTSINK: receive events even if we're not in the foreground
146     let flags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK;
147 
148     let devices: [RAWINPUTDEVICE; 2] = [
149         RAWINPUTDEVICE {
150             usUsagePage: HID_USAGE_PAGE_GENERIC,
151             usUsage: HID_USAGE_GENERIC_MOUSE,
152             dwFlags: flags,
153             hwndTarget: window_handle,
154         },
155         RAWINPUTDEVICE {
156             usUsagePage: HID_USAGE_PAGE_GENERIC,
157             usUsage: HID_USAGE_GENERIC_KEYBOARD,
158             dwFlags: flags,
159             hwndTarget: window_handle,
160         },
161     ];
162 
163     register_raw_input_devices(&devices)
164 }
165 
get_raw_input_data(handle: HRAWINPUT) -> Option<RAWINPUT>166 pub fn get_raw_input_data(handle: HRAWINPUT) -> Option<RAWINPUT> {
167     let mut data: RAWINPUT = unsafe { mem::zeroed() };
168     let mut data_size = size_of::<RAWINPUT>() as UINT;
169     let header_size = size_of::<RAWINPUTHEADER>() as UINT;
170 
171     let status = unsafe {
172         winuser::GetRawInputData(
173             handle,
174             RID_INPUT,
175             &mut data as *mut _ as _,
176             &mut data_size,
177             header_size,
178         )
179     };
180 
181     if status == UINT::max_value() || status == 0 {
182         return None;
183     }
184 
185     Some(data)
186 }
187 
button_flags_to_element_state( button_flags: USHORT, down_flag: USHORT, up_flag: USHORT, ) -> Option<ElementState>188 fn button_flags_to_element_state(
189     button_flags: USHORT,
190     down_flag: USHORT,
191     up_flag: USHORT,
192 ) -> Option<ElementState> {
193     // We assume the same button won't be simultaneously pressed and released.
194     if util::has_flag(button_flags, down_flag) {
195         Some(ElementState::Pressed)
196     } else if util::has_flag(button_flags, up_flag) {
197         Some(ElementState::Released)
198     } else {
199         None
200     }
201 }
202 
get_raw_mouse_button_state(button_flags: USHORT) -> [Option<ElementState>; 3]203 pub fn get_raw_mouse_button_state(button_flags: USHORT) -> [Option<ElementState>; 3] {
204     [
205         button_flags_to_element_state(
206             button_flags,
207             winuser::RI_MOUSE_LEFT_BUTTON_DOWN,
208             winuser::RI_MOUSE_LEFT_BUTTON_UP,
209         ),
210         button_flags_to_element_state(
211             button_flags,
212             winuser::RI_MOUSE_MIDDLE_BUTTON_DOWN,
213             winuser::RI_MOUSE_MIDDLE_BUTTON_UP,
214         ),
215         button_flags_to_element_state(
216             button_flags,
217             winuser::RI_MOUSE_RIGHT_BUTTON_DOWN,
218             winuser::RI_MOUSE_RIGHT_BUTTON_UP,
219         ),
220     ]
221 }
222