use std::{ mem::{self, size_of}, ptr, }; use winapi::{ ctypes::wchar_t, shared::{ hidusage::{HID_USAGE_GENERIC_KEYBOARD, HID_USAGE_GENERIC_MOUSE, HID_USAGE_PAGE_GENERIC}, minwindef::{TRUE, UINT, USHORT}, windef::HWND, }, um::{ winnt::HANDLE, winuser::{ self, HRAWINPUT, RAWINPUT, RAWINPUTDEVICE, RAWINPUTDEVICELIST, RAWINPUTHEADER, RIDEV_DEVNOTIFY, RIDEV_INPUTSINK, RIDI_DEVICEINFO, RIDI_DEVICENAME, RID_DEVICE_INFO, RID_DEVICE_INFO_HID, RID_DEVICE_INFO_KEYBOARD, RID_DEVICE_INFO_MOUSE, RID_INPUT, RIM_TYPEHID, RIM_TYPEKEYBOARD, RIM_TYPEMOUSE, }, }, }; use crate::{event::ElementState, platform_impl::platform::util}; #[allow(dead_code)] pub fn get_raw_input_device_list() -> Option> { let list_size = size_of::() as UINT; let mut num_devices = 0; let status = unsafe { winuser::GetRawInputDeviceList(ptr::null_mut(), &mut num_devices, list_size) }; if status == UINT::max_value() { return None; } let mut buffer = Vec::with_capacity(num_devices as _); let num_stored = unsafe { winuser::GetRawInputDeviceList(buffer.as_ptr() as _, &mut num_devices, list_size) }; if num_stored == UINT::max_value() { return None; } debug_assert_eq!(num_devices, num_stored); unsafe { buffer.set_len(num_devices as _) }; Some(buffer) } #[allow(dead_code)] pub enum RawDeviceInfo { Mouse(RID_DEVICE_INFO_MOUSE), Keyboard(RID_DEVICE_INFO_KEYBOARD), Hid(RID_DEVICE_INFO_HID), } impl From for RawDeviceInfo { fn from(info: RID_DEVICE_INFO) -> Self { unsafe { match info.dwType { RIM_TYPEMOUSE => RawDeviceInfo::Mouse(*info.u.mouse()), RIM_TYPEKEYBOARD => RawDeviceInfo::Keyboard(*info.u.keyboard()), RIM_TYPEHID => RawDeviceInfo::Hid(*info.u.hid()), _ => unreachable!(), } } } } #[allow(dead_code)] pub fn get_raw_input_device_info(handle: HANDLE) -> Option { let mut info: RID_DEVICE_INFO = unsafe { mem::zeroed() }; let info_size = size_of::() as UINT; info.cbSize = info_size; let mut minimum_size = 0; let status = unsafe { winuser::GetRawInputDeviceInfoW( handle, RIDI_DEVICEINFO, &mut info as *mut _ as _, &mut minimum_size, ) }; if status == UINT::max_value() || status == 0 { return None; } debug_assert_eq!(info_size, status); Some(info.into()) } pub fn get_raw_input_device_name(handle: HANDLE) -> Option { let mut minimum_size = 0; let status = unsafe { winuser::GetRawInputDeviceInfoW(handle, RIDI_DEVICENAME, ptr::null_mut(), &mut minimum_size) }; if status != 0 { return None; } let mut name: Vec = Vec::with_capacity(minimum_size as _); let status = unsafe { winuser::GetRawInputDeviceInfoW( handle, RIDI_DEVICENAME, name.as_ptr() as _, &mut minimum_size, ) }; if status == UINT::max_value() || status == 0 { return None; } debug_assert_eq!(minimum_size, status); unsafe { name.set_len(minimum_size as _) }; Some(util::wchar_to_string(&name)) } pub fn register_raw_input_devices(devices: &[RAWINPUTDEVICE]) -> bool { let device_size = size_of::() as UINT; let success = unsafe { winuser::RegisterRawInputDevices(devices.as_ptr() as _, devices.len() as _, device_size) }; success == TRUE } pub fn register_all_mice_and_keyboards_for_raw_input(window_handle: HWND) -> bool { // RIDEV_DEVNOTIFY: receive hotplug events // RIDEV_INPUTSINK: receive events even if we're not in the foreground let flags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK; let devices: [RAWINPUTDEVICE; 2] = [ RAWINPUTDEVICE { usUsagePage: HID_USAGE_PAGE_GENERIC, usUsage: HID_USAGE_GENERIC_MOUSE, dwFlags: flags, hwndTarget: window_handle, }, RAWINPUTDEVICE { usUsagePage: HID_USAGE_PAGE_GENERIC, usUsage: HID_USAGE_GENERIC_KEYBOARD, dwFlags: flags, hwndTarget: window_handle, }, ]; register_raw_input_devices(&devices) } pub fn get_raw_input_data(handle: HRAWINPUT) -> Option { let mut data: RAWINPUT = unsafe { mem::zeroed() }; let mut data_size = size_of::() as UINT; let header_size = size_of::() as UINT; let status = unsafe { winuser::GetRawInputData( handle, RID_INPUT, &mut data as *mut _ as _, &mut data_size, header_size, ) }; if status == UINT::max_value() || status == 0 { return None; } Some(data) } fn button_flags_to_element_state( button_flags: USHORT, down_flag: USHORT, up_flag: USHORT, ) -> Option { // We assume the same button won't be simultaneously pressed and released. if util::has_flag(button_flags, down_flag) { Some(ElementState::Pressed) } else if util::has_flag(button_flags, up_flag) { Some(ElementState::Released) } else { None } } pub fn get_raw_mouse_button_state(button_flags: USHORT) -> [Option; 3] { [ button_flags_to_element_state( button_flags, winuser::RI_MOUSE_LEFT_BUTTON_DOWN, winuser::RI_MOUSE_LEFT_BUTTON_UP, ), button_flags_to_element_state( button_flags, winuser::RI_MOUSE_MIDDLE_BUTTON_DOWN, winuser::RI_MOUSE_MIDDLE_BUTTON_UP, ), button_flags_to_element_state( button_flags, winuser::RI_MOUSE_RIGHT_BUTTON_DOWN, winuser::RI_MOUSE_RIGHT_BUTTON_UP, ), ] }