win32: account for mouse wheel speed setting
Also adds a method to toggle this behavior during runtime.
This commit is contained in:
parent
b13b39aa0b
commit
317d62fb93
5 changed files with 96 additions and 18 deletions
|
|
@ -42,22 +42,23 @@ use windows_sys::Win32::UI::Input::{
|
|||
use windows_sys::Win32::UI::WindowsAndMessaging::{
|
||||
CreateWindowExW, DefWindowProcW, DestroyWindow, DispatchMessageW, GetClientRect, GetCursorPos,
|
||||
GetMenu, LoadCursorW, MsgWaitForMultipleObjectsEx, PeekMessageW, PostMessageW,
|
||||
RegisterClassExW, RegisterWindowMessageA, SetCursor, SetWindowPos, TranslateMessage,
|
||||
CREATESTRUCTW, GWL_STYLE, GWL_USERDATA, HTCAPTION, HTCLIENT, MINMAXINFO, MNC_CLOSE, MSG,
|
||||
MWMO_INPUTAVAILABLE, NCCALCSIZE_PARAMS, PM_REMOVE, PT_TOUCH, QS_ALLINPUT, RI_MOUSE_HWHEEL,
|
||||
RI_MOUSE_WHEEL, SC_MINIMIZE, SC_RESTORE, SIZE_MAXIMIZED, SWP_NOACTIVATE, SWP_NOMOVE,
|
||||
SWP_NOSIZE, SWP_NOZORDER, WHEEL_DELTA, WINDOWPOS, WMSZ_BOTTOM, WMSZ_BOTTOMLEFT,
|
||||
WMSZ_BOTTOMRIGHT, WMSZ_LEFT, WMSZ_RIGHT, WMSZ_TOP, WMSZ_TOPLEFT, WMSZ_TOPRIGHT,
|
||||
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_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_SIZING, 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,
|
||||
RegisterClassExW, RegisterWindowMessageA, SetCursor, SetWindowPos, SystemParametersInfoW,
|
||||
TranslateMessage, CREATESTRUCTW, GWL_STYLE, GWL_USERDATA, HTCAPTION, HTCLIENT, MINMAXINFO,
|
||||
MNC_CLOSE, MSG, MWMO_INPUTAVAILABLE, NCCALCSIZE_PARAMS, PM_REMOVE, PT_TOUCH, QS_ALLINPUT,
|
||||
RI_MOUSE_HWHEEL, RI_MOUSE_WHEEL, SC_MINIMIZE, SC_RESTORE, SIZE_MAXIMIZED,
|
||||
SPI_GETWHEELSCROLLCHARS, SPI_GETWHEELSCROLLLINES, SWP_NOACTIVATE, SWP_NOMOVE, SWP_NOSIZE,
|
||||
SWP_NOZORDER, WHEEL_DELTA, WINDOWPOS, WMSZ_BOTTOM, WMSZ_BOTTOMLEFT, WMSZ_BOTTOMRIGHT,
|
||||
WMSZ_LEFT, WMSZ_RIGHT, WMSZ_TOP, WMSZ_TOPLEFT, WMSZ_TOPRIGHT, 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_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_SIZING, 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,
|
||||
};
|
||||
use winit_core::application::ApplicationHandler;
|
||||
use winit_core::cursor::{CustomCursor, CustomCursorSource};
|
||||
|
|
@ -92,6 +93,13 @@ use crate::window::{InitData, Window};
|
|||
use crate::window_state::{CursorFlags, ImeState, WindowFlags, WindowState};
|
||||
use crate::{raw_input, util};
|
||||
|
||||
// This is defined in `winuser.h` as a macro that expands to `UINT_MAX`
|
||||
const WHEEL_PAGESCROLL: u32 = u32::MAX;
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfoa#:~:text=SPI_GETWHEELSCROLLLINES
|
||||
const DEFAULT_SCROLL_LINES_PER_WHEEL_DELTA: isize = 3;
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfoa#:~:text=SPI_GETWHEELSCROLLCHARS
|
||||
const DEFAULT_SCROLL_CHARACTERS_PER_WHEEL_DELTA: isize = 3;
|
||||
|
||||
pub(crate) struct WindowData {
|
||||
pub window_state: Arc<Mutex<WindowState>>,
|
||||
pub event_loop_runner: Rc<EventLoopRunner>,
|
||||
|
|
@ -1636,9 +1644,26 @@ unsafe fn public_window_callback_inner(
|
|||
|
||||
update_modifiers(window, userdata);
|
||||
|
||||
let scroll_lines_multiplier = if userdata.window_state_lock().use_system_wheel_speed {
|
||||
let mut scroll_lines = DEFAULT_SCROLL_LINES_PER_WHEEL_DELTA;
|
||||
let _ = SystemParametersInfoW(
|
||||
SPI_GETWHEELSCROLLLINES,
|
||||
0,
|
||||
&mut scroll_lines as *mut isize as *mut c_void,
|
||||
0,
|
||||
);
|
||||
if scroll_lines as u32 == WHEEL_PAGESCROLL {
|
||||
// TODO: figure out how to handle page scrolls
|
||||
scroll_lines = DEFAULT_SCROLL_LINES_PER_WHEEL_DELTA;
|
||||
}
|
||||
scroll_lines
|
||||
} else {
|
||||
1
|
||||
};
|
||||
|
||||
userdata.send_window_event(window, WindowEvent::MouseWheel {
|
||||
device_id: None,
|
||||
delta: LineDelta(0.0, value),
|
||||
delta: LineDelta(0.0, value * scroll_lines_multiplier as f32),
|
||||
phase: TouchPhase::Moved,
|
||||
});
|
||||
|
||||
|
|
@ -1653,9 +1678,23 @@ unsafe fn public_window_callback_inner(
|
|||
|
||||
update_modifiers(window, userdata);
|
||||
|
||||
let scroll_characters_multiplier =
|
||||
if userdata.window_state_lock().use_system_wheel_speed {
|
||||
let mut scroll_characters = DEFAULT_SCROLL_CHARACTERS_PER_WHEEL_DELTA;
|
||||
let _ = SystemParametersInfoW(
|
||||
SPI_GETWHEELSCROLLCHARS,
|
||||
0,
|
||||
&mut scroll_characters as *mut isize as *mut c_void,
|
||||
0,
|
||||
);
|
||||
scroll_characters
|
||||
} else {
|
||||
1
|
||||
};
|
||||
|
||||
userdata.send_window_event(window, WindowEvent::MouseWheel {
|
||||
device_id: None,
|
||||
delta: LineDelta(value, 0.0),
|
||||
delta: LineDelta(value * scroll_characters_multiplier as f32, 0.0),
|
||||
phase: TouchPhase::Moved,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -285,6 +285,15 @@ pub trait WindowExtWindows {
|
|||
/// Supported starting with Windows 11 Build 22000.
|
||||
fn set_corner_preference(&self, preference: CornerPreference);
|
||||
|
||||
/// Sets if the reported [`winit_core::event::WindowEvent::MouseWheel`] event
|
||||
/// should account for scroll speed system settings.
|
||||
///
|
||||
/// The default scroll speed on Windows is 3 lines/characters per scroll,
|
||||
/// this will be 1 if you set it to false.
|
||||
///
|
||||
/// The default is `true`.
|
||||
fn set_use_system_scroll_speed(&self, should_use: bool);
|
||||
|
||||
/// Get the raw window handle for this [`Window`] without checking for thread affinity.
|
||||
///
|
||||
/// Window handles in Win32 have a property called "thread affinity" that ties them to their
|
||||
|
|
@ -398,6 +407,11 @@ impl WindowExtWindows for dyn CoreWindow + '_ {
|
|||
window.set_corner_preference(preference)
|
||||
}
|
||||
|
||||
fn set_use_system_scroll_speed(&self, should_use: bool) {
|
||||
let window = self.cast_ref::<Window>().unwrap();
|
||||
window.set_use_system_scroll_speed(should_use)
|
||||
}
|
||||
|
||||
unsafe fn window_handle_any_thread(
|
||||
&self,
|
||||
) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError> {
|
||||
|
|
@ -459,6 +473,7 @@ pub struct WindowAttributesWindows {
|
|||
pub(crate) title_background_color: Option<Color>,
|
||||
pub(crate) title_text_color: Option<Color>,
|
||||
pub(crate) corner_preference: Option<CornerPreference>,
|
||||
pub(crate) use_system_wheel_speed: bool,
|
||||
}
|
||||
|
||||
impl Default for WindowAttributesWindows {
|
||||
|
|
@ -478,6 +493,7 @@ impl Default for WindowAttributesWindows {
|
|||
title_background_color: None,
|
||||
title_text_color: None,
|
||||
corner_preference: None,
|
||||
use_system_wheel_speed: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -610,6 +626,18 @@ impl WindowAttributesWindows {
|
|||
self.corner_preference = Some(corners);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets if the reported [`winit_core::event::WindowEvent::MouseWheel`] event
|
||||
/// should account for scroll speed system settings.
|
||||
///
|
||||
/// The default scroll speed on Windows is 3 lines/characters per scroll,
|
||||
/// this will be 1 if you set it to false.
|
||||
///
|
||||
/// The default is `true`.
|
||||
pub fn with_use_system_scroll_speed(mut self, should_use: bool) -> Self {
|
||||
self.use_system_wheel_speed = should_use;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl PlatformWindowAttributes for WindowAttributesWindows {
|
||||
|
|
|
|||
|
|
@ -344,6 +344,11 @@ impl Window {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_use_system_scroll_speed(&self, should_use: bool) {
|
||||
self.window_state_lock().use_system_wheel_speed = should_use;
|
||||
}
|
||||
|
||||
fn set_icon(&self, mut new_icon: Icon, icon_type: IconType) {
|
||||
if let Some(icon) = new_icon.cast_ref::<RgbaIcon>() {
|
||||
let icon = match WinIcon::from_rgba(icon) {
|
||||
|
|
@ -1303,6 +1308,7 @@ impl InitData<'_> {
|
|||
win.set_skip_taskbar(self.win_attributes.skip_taskbar);
|
||||
win.set_window_icon(self.attributes.window_icon.clone());
|
||||
win.set_taskbar_icon(self.win_attributes.taskbar_icon.clone());
|
||||
win.set_use_system_scroll_speed(self.win_attributes.use_system_wheel_speed);
|
||||
|
||||
let attributes = self.attributes.clone();
|
||||
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@ pub(crate) struct WindowState {
|
|||
pub dragging: bool,
|
||||
|
||||
pub skip_taskbar: bool,
|
||||
|
||||
pub use_system_wheel_speed: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
@ -187,6 +189,8 @@ impl WindowState {
|
|||
dragging: false,
|
||||
|
||||
skip_taskbar: false,
|
||||
|
||||
use_system_wheel_speed: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -256,3 +256,4 @@ changelog entry.
|
|||
- On macOS, fixed redundant `SurfaceResized` event at window creation.
|
||||
- On macOS, don't panic on monitors with unknown bit-depths.
|
||||
- On macOS, fixed crash when closing the window on macOS 26+.
|
||||
- On Windows, account for mouse wheel lines per scroll setting for `WindowEvent::MouseWheel`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue