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