From f44b31313028cadcc2f3f2014e7f06e5921129d7 Mon Sep 17 00:00:00 2001 From: Markus Siglreithmaier Date: Fri, 22 Dec 2023 18:42:17 +0100 Subject: [PATCH] On Windows, refactor dynamic function definitions and raw input keyboard handling (#3286) --- src/platform_impl/windows/dpi.rs | 6 +- src/platform_impl/windows/event_loop.rs | 190 ++++-------------------- src/platform_impl/windows/raw_input.rs | 120 ++++++++++++++- src/platform_impl/windows/util.rs | 41 ++++- 4 files changed, 185 insertions(+), 172 deletions(-) diff --git a/src/platform_impl/windows/dpi.rs b/src/platform_impl/windows/dpi.rs index 0ff980a227..c4ed08a6db 100644 --- a/src/platform_impl/windows/dpi.rs +++ b/src/platform_impl/windows/dpi.rs @@ -9,8 +9,8 @@ use windows_sys::Win32::{ }, UI::{ HiDpi::{ - DPI_AWARENESS_CONTEXT, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE, MDT_EFFECTIVE_DPI, - PROCESS_PER_MONITOR_DPI_AWARE, + DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2, + MDT_EFFECTIVE_DPI, PROCESS_PER_MONITOR_DPI_AWARE, }, WindowsAndMessaging::IsProcessDPIAware, }, @@ -21,8 +21,6 @@ use crate::platform_impl::platform::util::{ SET_PROCESS_DPI_AWARENESS, SET_PROCESS_DPI_AWARENESS_CONTEXT, }; -const DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2: DPI_AWARENESS_CONTEXT = -4; - pub fn become_dpi_aware() { static ENABLE_DPI_AWARENESS: Once = Once::new(); ENABLE_DPI_AWARENESS.call_once(|| { diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index d4263920af..949e4155e2 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -21,7 +21,7 @@ use once_cell::sync::Lazy; use windows_sys::Win32::{ Devices::HumanInterfaceDevice::MOUSE_MOVE_RELATIVE, - Foundation::{BOOL, HANDLE, HWND, LPARAM, LRESULT, POINT, RECT, WPARAM}, + Foundation::{HWND, LPARAM, LRESULT, POINT, RECT, WPARAM}, Graphics::Gdi::{ GetMonitorInfoW, MonitorFromRect, MonitorFromWindow, RedrawWindow, ScreenToClient, ValidateRect, MONITORINFO, MONITOR_DEFAULTTONULL, RDW_INTERNALPAINT, SC_SCREENSAVE, @@ -35,13 +35,9 @@ use windows_sys::Win32::{ Input::{ Ime::{GCS_COMPSTR, GCS_RESULTSTR, ISC_SHOWUICOMPOSITIONWINDOW}, KeyboardAndMouse::{ - MapVirtualKeyW, ReleaseCapture, SetCapture, TrackMouseEvent, MAPVK_VK_TO_VSC_EX, - TME_LEAVE, TRACKMOUSEEVENT, VK_NUMLOCK, VK_SHIFT, - }, - Pointer::{ - POINTER_FLAG_DOWN, POINTER_FLAG_UP, POINTER_FLAG_UPDATE, POINTER_INFO, - POINTER_PEN_INFO, POINTER_TOUCH_INFO, + ReleaseCapture, SetCapture, TrackMouseEvent, TME_LEAVE, TRACKMOUSEEVENT, }, + Pointer::{POINTER_FLAG_DOWN, POINTER_FLAG_UP, POINTER_FLAG_UPDATE}, Touch::{ CloseTouchInputHandle, GetTouchInputInfo, TOUCHEVENTF_DOWN, TOUCHEVENTF_MOVE, TOUCHEVENTF_UP, TOUCHINPUT, @@ -54,20 +50,19 @@ use windows_sys::Win32::{ RegisterClassExW, RegisterWindowMessageA, SetCursor, SetTimer, SetWindowPos, TranslateMessage, CREATESTRUCTW, GIDC_ARRIVAL, GIDC_REMOVAL, GWL_STYLE, GWL_USERDATA, HTCAPTION, HTCLIENT, MINMAXINFO, MNC_CLOSE, MSG, NCCALCSIZE_PARAMS, PM_REMOVE, PT_PEN, - PT_TOUCH, RI_KEY_E0, RI_KEY_E1, RI_MOUSE_HWHEEL, RI_MOUSE_WHEEL, SC_MINIMIZE, - SC_RESTORE, SIZE_MAXIMIZED, SWP_NOACTIVATE, SWP_NOMOVE, SWP_NOSIZE, SWP_NOZORDER, - WHEEL_DELTA, WINDOWPOS, WM_CAPTURECHANGED, WM_CLOSE, WM_CREATE, WM_DESTROY, - WM_DPICHANGED, WM_ENTERSIZEMOVE, WM_EXITSIZEMOVE, WM_GETMINMAXINFO, WM_IME_COMPOSITION, - WM_IME_ENDCOMPOSITION, WM_IME_SETCONTEXT, WM_IME_STARTCOMPOSITION, WM_INPUT, - WM_INPUT_DEVICE_CHANGE, WM_KEYDOWN, WM_KEYUP, WM_KILLFOCUS, WM_LBUTTONDOWN, - WM_LBUTTONUP, WM_MBUTTONDOWN, WM_MBUTTONUP, WM_MENUCHAR, WM_MOUSEHWHEEL, WM_MOUSEMOVE, - WM_MOUSEWHEEL, WM_NCACTIVATE, WM_NCCALCSIZE, WM_NCCREATE, WM_NCDESTROY, - WM_NCLBUTTONDOWN, WM_PAINT, WM_POINTERDOWN, WM_POINTERUP, WM_POINTERUPDATE, - WM_RBUTTONDOWN, WM_RBUTTONUP, WM_SETCURSOR, WM_SETFOCUS, WM_SETTINGCHANGE, WM_SIZE, - WM_SYSCOMMAND, WM_SYSKEYDOWN, WM_SYSKEYUP, WM_TOUCH, WM_WINDOWPOSCHANGED, - WM_WINDOWPOSCHANGING, WM_XBUTTONDOWN, WM_XBUTTONUP, WNDCLASSEXW, WS_EX_LAYERED, - WS_EX_NOACTIVATE, WS_EX_TOOLWINDOW, WS_EX_TRANSPARENT, WS_OVERLAPPED, WS_POPUP, - WS_VISIBLE, + PT_TOUCH, RI_MOUSE_HWHEEL, RI_MOUSE_WHEEL, SC_MINIMIZE, SC_RESTORE, SIZE_MAXIMIZED, + SWP_NOACTIVATE, SWP_NOMOVE, SWP_NOSIZE, SWP_NOZORDER, WHEEL_DELTA, WINDOWPOS, + WM_CAPTURECHANGED, WM_CLOSE, WM_CREATE, WM_DESTROY, WM_DPICHANGED, WM_ENTERSIZEMOVE, + WM_EXITSIZEMOVE, WM_GETMINMAXINFO, WM_IME_COMPOSITION, WM_IME_ENDCOMPOSITION, + WM_IME_SETCONTEXT, WM_IME_STARTCOMPOSITION, WM_INPUT, WM_INPUT_DEVICE_CHANGE, + WM_KEYDOWN, WM_KEYUP, WM_KILLFOCUS, WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDOWN, + WM_MBUTTONUP, WM_MENUCHAR, WM_MOUSEHWHEEL, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_NCACTIVATE, + WM_NCCALCSIZE, WM_NCCREATE, WM_NCDESTROY, WM_NCLBUTTONDOWN, WM_PAINT, WM_POINTERDOWN, + WM_POINTERUP, WM_POINTERUPDATE, WM_RBUTTONDOWN, WM_RBUTTONUP, WM_SETCURSOR, + WM_SETFOCUS, WM_SETTINGCHANGE, WM_SIZE, WM_SYSCOMMAND, WM_SYSKEYDOWN, WM_SYSKEYUP, + WM_TOUCH, WM_WINDOWPOSCHANGED, WM_WINDOWPOSCHANGING, WM_XBUTTONDOWN, WM_XBUTTONUP, + WNDCLASSEXW, WS_EX_LAYERED, WS_EX_NOACTIVATE, WS_EX_TOOLWINDOW, WS_EX_TRANSPARENT, + WS_OVERLAPPED, WS_POPUP, WS_VISIBLE, }, }, }; @@ -80,8 +75,8 @@ use crate::{ WindowEvent, }, event_loop::{ControlFlow, DeviceEvents, EventLoopClosed, EventLoopWindowTarget as RootELW}, - keyboard::{KeyCode, ModifiersState, PhysicalKey}, - platform::{pump_events::PumpStatus, scancode::PhysicalKeyExtScancode}, + keyboard::ModifiersState, + platform::pump_events::PumpStatus, platform_impl::platform::{ dark_mode::try_theme, dpi::{become_dpi_aware, dpi_to_scale_factor}, @@ -103,37 +98,6 @@ use self::runner::RunnerState; use super::window::set_skip_taskbar; -type GetPointerFrameInfoHistory = unsafe extern "system" fn( - pointerId: u32, - entriesCount: *mut u32, - pointerCount: *mut u32, - pointerInfo: *mut POINTER_INFO, -) -> BOOL; - -type SkipPointerFrameMessages = unsafe extern "system" fn(pointerId: u32) -> BOOL; -type GetPointerDeviceRects = unsafe extern "system" fn( - device: HANDLE, - pointerDeviceRect: *mut RECT, - displayRect: *mut RECT, -) -> BOOL; - -type GetPointerTouchInfo = - unsafe extern "system" fn(pointerId: u32, touchInfo: *mut POINTER_TOUCH_INFO) -> BOOL; - -type GetPointerPenInfo = - unsafe extern "system" fn(pointId: u32, penInfo: *mut POINTER_PEN_INFO) -> BOOL; - -static GET_POINTER_FRAME_INFO_HISTORY: Lazy> = - Lazy::new(|| get_function!("user32.dll", GetPointerFrameInfoHistory)); -static SKIP_POINTER_FRAME_MESSAGES: Lazy> = - Lazy::new(|| get_function!("user32.dll", SkipPointerFrameMessages)); -static GET_POINTER_DEVICE_RECTS: Lazy> = - Lazy::new(|| get_function!("user32.dll", GetPointerDeviceRects)); -static GET_POINTER_TOUCH_INFO: Lazy> = - Lazy::new(|| get_function!("user32.dll", GetPointerTouchInfo)); -static GET_POINTER_PEN_INFO: Lazy> = - Lazy::new(|| get_function!("user32.dll", GetPointerPenInfo)); - pub(crate) struct WindowData { pub window_state: Arc>, pub event_loop_runner: EventLoopRunnerShared, @@ -1831,9 +1795,9 @@ unsafe fn public_window_callback_inner( Some(SkipPointerFrameMessages), Some(GetPointerDeviceRects), ) = ( - *GET_POINTER_FRAME_INFO_HISTORY, - *SKIP_POINTER_FRAME_MESSAGES, - *GET_POINTER_DEVICE_RECTS, + *util::GET_POINTER_FRAME_INFO_HISTORY, + *util::SKIP_POINTER_FRAME_MESSAGES, + *util::GET_POINTER_DEVICE_RECTS, ) { let pointer_id = super::loword(wparam as u32) as u32; let mut entries_count = 0u32; @@ -1915,7 +1879,7 @@ unsafe fn public_window_callback_inner( let force = match pointer_info.pointerType { PT_TOUCH => { let mut touch_info = mem::MaybeUninit::uninit(); - GET_POINTER_TOUCH_INFO.and_then(|GetPointerTouchInfo| { + util::GET_POINTER_TOUCH_INFO.and_then(|GetPointerTouchInfo| { match unsafe { GetPointerTouchInfo( pointer_info.pointerId, @@ -1931,7 +1895,7 @@ unsafe fn public_window_callback_inner( } PT_PEN => { let mut pen_info = mem::MaybeUninit::uninit(); - GET_POINTER_PEN_INFO.and_then(|GetPointerPenInfo| { + util::GET_POINTER_PEN_INFO.and_then(|GetPointerPenInfo| { match unsafe { GetPointerPenInfo(pointer_info.pointerId, pen_info.as_mut_ptr()) } { @@ -2493,105 +2457,17 @@ unsafe fn handle_raw_input(userdata: &ThreadMsgTargetData, data: return; } - let state = if pressed { Pressed } else { Released }; - let extension = { - if util::has_flag(keyboard.Flags, RI_KEY_E0 as _) { - 0xE000 - } else if util::has_flag(keyboard.Flags, RI_KEY_E1 as _) { - 0xE100 - } else { - 0x0000 - } - }; - let scancode = if keyboard.MakeCode == 0 { - // In some cases (often with media keys) the device reports a scancode of 0 but a - // valid virtual key. In these cases we obtain the scancode from the virtual key. - unsafe { MapVirtualKeyW(keyboard.VKey as u32, MAPVK_VK_TO_VSC_EX) as u16 } - } else { - keyboard.MakeCode | extension - }; - if scancode == 0xE11D || scancode == 0xE02A { - // At the hardware (or driver?) level, pressing the Pause key is equivalent to pressing - // Ctrl+NumLock. - // This equvalence means that if the user presses Pause, the keyboard will emit two - // subsequent keypresses: - // 1, 0xE11D - Which is a left Ctrl (0x1D) with an extension flag (0xE100) - // 2, 0x0045 - Which on its own can be interpreted as Pause - // - // There's another combination which isn't quite an equivalence: - // PrtSc used to be Shift+Asterisk. This means that on some keyboards, presssing - // PrtSc (print screen) produces the following sequence: - // 1, 0xE02A - Which is a left shift (0x2A) with an extension flag (0xE000) - // 2, 0xE037 - Which is a numpad multiply (0x37) with an exteion flag (0xE000). This on - // its own it can be interpreted as PrtSc - // - // For this reason, if we encounter the first keypress, we simply ignore it, trusting - // that there's going to be another event coming, from which we can extract the - // appropriate key. - // For more on this, read the article by Raymond Chen, titled: - // "Why does Ctrl+ScrollLock cancel dialogs?" - // https://devblogs.microsoft.com/oldnewthing/20080211-00/?p=23503 - return; - } - let physical_key = if keyboard.VKey == VK_NUMLOCK { - // Historically, the NumLock and the Pause key were one and the same physical key. - // The user could trigger Pause by pressing Ctrl+NumLock. - // Now these are often physically separate and the two keys can be differentiated by - // checking the extension flag of the scancode. NumLock is 0xE045, Pause is 0x0045. - // - // However in this event, both keys are reported as 0x0045 even on modern hardware. - // Therefore we use the virtual key instead to determine whether it's a NumLock and - // set the KeyCode accordingly. - // - // For more on this, read the article by Raymond Chen, titled: - // "Why does Ctrl+ScrollLock cancel dialogs?" - // https://devblogs.microsoft.com/oldnewthing/20080211-00/?p=23503 - PhysicalKey::Code(KeyCode::NumLock) - } else { - PhysicalKey::from_scancode(scancode as u32) - }; - if keyboard.VKey == VK_SHIFT { - if let PhysicalKey::Code(code) = physical_key { - match code { - KeyCode::NumpadDecimal - | KeyCode::Numpad0 - | KeyCode::Numpad1 - | KeyCode::Numpad2 - | KeyCode::Numpad3 - | KeyCode::Numpad4 - | KeyCode::Numpad5 - | KeyCode::Numpad6 - | KeyCode::Numpad7 - | KeyCode::Numpad8 - | KeyCode::Numpad9 => { - // On Windows, holding the Shift key makes numpad keys behave as if NumLock - // wasn't active. The way this is exposed to applications by the system is that - // the application receives a fake key release event for the shift key at the - // moment when the numpad key is pressed, just before receiving the numpad key - // as well. - // - // The issue is that in the raw device event (here), the fake shift release - // event reports the numpad key as the scancode. Unfortunately, the event doesn't - // have any information to tell whether it's the left shift or the right shift - // that needs to get the fake release (or press) event so we don't forward this - // event to the application at all. - // - // For more on this, read the article by Raymond Chen, titled: - // "The shift key overrides NumLock" - // https://devblogs.microsoft.com/oldnewthing/20040906-00/?p=37953 - return; - } - _ => (), - } - } + if let Some(physical_key) = raw_input::get_keyboard_physical_key(keyboard) { + let state = if pressed { Pressed } else { Released }; + + userdata.send_event(Event::DeviceEvent { + device_id, + event: Key(RawKeyEvent { + physical_key, + state, + }), + }); } - userdata.send_event(Event::DeviceEvent { - device_id, - event: Key(RawKeyEvent { - physical_key, - state, - }), - }); } } diff --git a/src/platform_impl/windows/raw_input.rs b/src/platform_impl/windows/raw_input.rs index eeec93e719..897b2a29b1 100644 --- a/src/platform_impl/windows/raw_input.rs +++ b/src/platform_impl/windows/raw_input.rs @@ -11,21 +11,29 @@ use windows_sys::Win32::{ UI::{ Input::{ GetRawInputData, GetRawInputDeviceInfoW, GetRawInputDeviceList, + KeyboardAndMouse::{MapVirtualKeyW, MAPVK_VK_TO_VSC_EX, VK_NUMLOCK, VK_SHIFT}, RegisterRawInputDevices, HRAWINPUT, RAWINPUT, RAWINPUTDEVICE, RAWINPUTDEVICELIST, - RAWINPUTHEADER, RIDEV_DEVNOTIFY, RIDEV_INPUTSINK, RIDEV_REMOVE, 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, + RAWINPUTHEADER, RAWKEYBOARD, RIDEV_DEVNOTIFY, RIDEV_INPUTSINK, RIDEV_REMOVE, + 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, }, WindowsAndMessaging::{ - RI_MOUSE_BUTTON_1_DOWN, RI_MOUSE_BUTTON_1_UP, RI_MOUSE_BUTTON_2_DOWN, - RI_MOUSE_BUTTON_2_UP, RI_MOUSE_BUTTON_3_DOWN, RI_MOUSE_BUTTON_3_UP, - RI_MOUSE_BUTTON_4_DOWN, RI_MOUSE_BUTTON_4_UP, RI_MOUSE_BUTTON_5_DOWN, - RI_MOUSE_BUTTON_5_UP, + RI_KEY_E0, RI_KEY_E1, RI_MOUSE_BUTTON_1_DOWN, RI_MOUSE_BUTTON_1_UP, + RI_MOUSE_BUTTON_2_DOWN, RI_MOUSE_BUTTON_2_UP, RI_MOUSE_BUTTON_3_DOWN, + RI_MOUSE_BUTTON_3_UP, RI_MOUSE_BUTTON_4_DOWN, RI_MOUSE_BUTTON_4_UP, + RI_MOUSE_BUTTON_5_DOWN, RI_MOUSE_BUTTON_5_UP, }, }, }; -use crate::{event::ElementState, event_loop::DeviceEvents, platform_impl::platform::util}; +use crate::{ + event::ElementState, + event_loop::DeviceEvents, + keyboard::{KeyCode, PhysicalKey}, + platform::scancode::PhysicalKeyExtScancode, + platform_impl::platform::util, +}; #[allow(dead_code)] pub fn get_raw_input_device_list() -> Option> { @@ -220,3 +228,99 @@ pub fn get_raw_mouse_button_state(button_flags: u32) -> [Option; 5 button_flags_to_element_state(button_flags, RI_MOUSE_BUTTON_5_DOWN, RI_MOUSE_BUTTON_5_UP), ] } + +pub fn get_keyboard_physical_key(keyboard: RAWKEYBOARD) -> Option { + let extension = { + if util::has_flag(keyboard.Flags, RI_KEY_E0 as _) { + 0xE000 + } else if util::has_flag(keyboard.Flags, RI_KEY_E1 as _) { + 0xE100 + } else { + 0x0000 + } + }; + let scancode = if keyboard.MakeCode == 0 { + // In some cases (often with media keys) the device reports a scancode of 0 but a + // valid virtual key. In these cases we obtain the scancode from the virtual key. + unsafe { MapVirtualKeyW(keyboard.VKey as u32, MAPVK_VK_TO_VSC_EX) as u16 } + } else { + keyboard.MakeCode | extension + }; + if scancode == 0xE11D || scancode == 0xE02A { + // At the hardware (or driver?) level, pressing the Pause key is equivalent to pressing + // Ctrl+NumLock. + // This equvalence means that if the user presses Pause, the keyboard will emit two + // subsequent keypresses: + // 1, 0xE11D - Which is a left Ctrl (0x1D) with an extension flag (0xE100) + // 2, 0x0045 - Which on its own can be interpreted as Pause + // + // There's another combination which isn't quite an equivalence: + // PrtSc used to be Shift+Asterisk. This means that on some keyboards, presssing + // PrtSc (print screen) produces the following sequence: + // 1, 0xE02A - Which is a left shift (0x2A) with an extension flag (0xE000) + // 2, 0xE037 - Which is a numpad multiply (0x37) with an exteion flag (0xE000). This on + // its own it can be interpreted as PrtSc + // + // For this reason, if we encounter the first keypress, we simply ignore it, trusting + // that there's going to be another event coming, from which we can extract the + // appropriate key. + // For more on this, read the article by Raymond Chen, titled: + // "Why does Ctrl+ScrollLock cancel dialogs?" + // https://devblogs.microsoft.com/oldnewthing/20080211-00/?p=23503 + return None; + } + let physical_key = if keyboard.VKey == VK_NUMLOCK { + // Historically, the NumLock and the Pause key were one and the same physical key. + // The user could trigger Pause by pressing Ctrl+NumLock. + // Now these are often physically separate and the two keys can be differentiated by + // checking the extension flag of the scancode. NumLock is 0xE045, Pause is 0x0045. + // + // However in this event, both keys are reported as 0x0045 even on modern hardware. + // Therefore we use the virtual key instead to determine whether it's a NumLock and + // set the KeyCode accordingly. + // + // For more on this, read the article by Raymond Chen, titled: + // "Why does Ctrl+ScrollLock cancel dialogs?" + // https://devblogs.microsoft.com/oldnewthing/20080211-00/?p=23503 + PhysicalKey::Code(KeyCode::NumLock) + } else { + PhysicalKey::from_scancode(scancode as u32) + }; + if keyboard.VKey == VK_SHIFT { + if let PhysicalKey::Code(code) = physical_key { + match code { + KeyCode::NumpadDecimal + | KeyCode::Numpad0 + | KeyCode::Numpad1 + | KeyCode::Numpad2 + | KeyCode::Numpad3 + | KeyCode::Numpad4 + | KeyCode::Numpad5 + | KeyCode::Numpad6 + | KeyCode::Numpad7 + | KeyCode::Numpad8 + | KeyCode::Numpad9 => { + // On Windows, holding the Shift key makes numpad keys behave as if NumLock + // wasn't active. The way this is exposed to applications by the system is that + // the application receives a fake key release event for the shift key at the + // moment when the numpad key is pressed, just before receiving the numpad key + // as well. + // + // The issue is that in the raw device event (here), the fake shift release + // event reports the numpad key as the scancode. Unfortunately, the event doesn't + // have any information to tell whether it's the left shift or the right shift + // that needs to get the fake release (or press) event so we don't forward this + // event to the application at all. + // + // For more on this, read the article by Raymond Chen, titled: + // "The shift key overrides NumLock" + // https://devblogs.microsoft.com/oldnewthing/20040906-00/?p=37953 + return None; + } + _ => (), + } + } + } + + Some(physical_key) +} diff --git a/src/platform_impl/windows/util.rs b/src/platform_impl/windows/util.rs index 355b366a19..66e6be0980 100644 --- a/src/platform_impl/windows/util.rs +++ b/src/platform_impl/windows/util.rs @@ -13,7 +13,7 @@ use once_cell::sync::Lazy; use windows_sys::{ core::{HRESULT, PCWSTR}, Win32::{ - Foundation::{BOOL, HMODULE, HWND, RECT}, + Foundation::{BOOL, HANDLE, HMODULE, HWND, RECT}, Graphics::Gdi::{ClientToScreen, HMONITOR}, System::{ LibraryLoader::{GetProcAddress, LoadLibraryA}, @@ -21,7 +21,10 @@ use windows_sys::{ }, UI::{ HiDpi::{DPI_AWARENESS_CONTEXT, MONITOR_DPI_TYPE, PROCESS_DPI_AWARENESS}, - Input::KeyboardAndMouse::GetActiveWindow, + Input::{ + KeyboardAndMouse::GetActiveWindow, + Pointer::{POINTER_INFO, POINTER_PEN_INFO, POINTER_TOUCH_INFO}, + }, WindowsAndMessaging::{ ClipCursor, GetClientRect, GetClipCursor, GetSystemMetrics, GetWindowPlacement, GetWindowRect, IsIconic, ShowCursor, IDC_APPSTARTING, IDC_ARROW, IDC_CROSS, @@ -191,7 +194,9 @@ pub(crate) fn to_windows_cursor(cursor: CursorIcon) -> PCWSTR { } } -// Helper function to dynamically load function pointer. +// Helper function to dynamically load function pointer as some functions +// may not be available on all Windows platforms supported by winit. +// // `library` and `function` must be zero-terminated. pub(super) fn get_function_impl(library: &str, function: &str) -> Option<*const c_void> { assert_eq!(library.chars().last(), Some('\0')); @@ -237,6 +242,26 @@ pub type AdjustWindowRectExForDpi = unsafe extern "system" fn( dpi: u32, ) -> BOOL; +pub type GetPointerFrameInfoHistory = unsafe extern "system" fn( + pointerId: u32, + entriesCount: *mut u32, + pointerCount: *mut u32, + pointerInfo: *mut POINTER_INFO, +) -> BOOL; + +pub type SkipPointerFrameMessages = unsafe extern "system" fn(pointerId: u32) -> BOOL; +pub type GetPointerDeviceRects = unsafe extern "system" fn( + device: HANDLE, + pointerDeviceRect: *mut RECT, + displayRect: *mut RECT, +) -> BOOL; + +pub type GetPointerTouchInfo = + unsafe extern "system" fn(pointerId: u32, touchInfo: *mut POINTER_TOUCH_INFO) -> BOOL; + +pub type GetPointerPenInfo = + unsafe extern "system" fn(pointId: u32, penInfo: *mut POINTER_PEN_INFO) -> BOOL; + pub static GET_DPI_FOR_WINDOW: Lazy> = Lazy::new(|| get_function!("user32.dll", GetDpiForWindow)); pub static ADJUST_WINDOW_RECT_EX_FOR_DPI: Lazy> = @@ -251,3 +276,13 @@ pub static SET_PROCESS_DPI_AWARENESS: Lazy> = Lazy::new(|| get_function!("shcore.dll", SetProcessDpiAwareness)); pub static SET_PROCESS_DPI_AWARE: Lazy> = Lazy::new(|| get_function!("user32.dll", SetProcessDPIAware)); +pub static GET_POINTER_FRAME_INFO_HISTORY: Lazy> = + Lazy::new(|| get_function!("user32.dll", GetPointerFrameInfoHistory)); +pub static SKIP_POINTER_FRAME_MESSAGES: Lazy> = + Lazy::new(|| get_function!("user32.dll", SkipPointerFrameMessages)); +pub static GET_POINTER_DEVICE_RECTS: Lazy> = + Lazy::new(|| get_function!("user32.dll", GetPointerDeviceRects)); +pub static GET_POINTER_TOUCH_INFO: Lazy> = + Lazy::new(|| get_function!("user32.dll", GetPointerTouchInfo)); +pub static GET_POINTER_PEN_INFO: Lazy> = + Lazy::new(|| get_function!("user32.dll", GetPointerPenInfo));