Coordinates from mouse low level hook messages are not mapped the same way than WM_MOUSEMOVE or GetCursorPos. This causes problems on programs that make use of both values to calculate mouse movement, like the wine DirectInput implementation.
I'm marking this as a draft since I was not able to find a way to write a test for this. I'm able to easily reproduce it on Proton, because it creates a scaled full screen window, on Wine this doesn't happen so the coordinates are not required to be mapped to a scaled window.
Edit: I didn't realize that modesetting emulation was an experimental option! So, I was able to reproduce the bug by enabling it.
-- v2: win32u: Map raw coordinates to virtual screen in low-level hooks.
From: Santino Mazza smazza@codeweavers.com
--- dlls/win32u/message.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 2a824dbdab3..7cdec243189 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2948,8 +2948,13 @@ int peek_message( MSG *msg, const struct peek_message_filter *filter ) } else if (info.msg.message == WH_MOUSE_LL && size >= sizeof(msg_data->hardware)) { + RECT rect = {info.msg.pt.x, info.msg.pt.y, info.msg.pt.x, info.msg.pt.y}; MSLLHOOKSTRUCT hook;
+ rect = map_rect_raw_to_virt( rect, 0 ); + info.msg.pt.x = rect.left; + info.msg.pt.y = rect.top; + hook.pt = info.msg.pt; hook.mouseData = info.msg.lParam; hook.flags = msg_data->hardware.flags;
On Thu Aug 14 14:53:57 2025 +0000, Santino Mazza wrote:
I did more testing on Windows, WH_MOUSE_LL messages are not DPI scaled. So I suppose, instead of `get_thread_dpi`, I should just put 0 so it doesn't do any DPI scaling? Also, because WH_MOUSE_LL is not DPI scaled, I think there are still going to be issues on the way mouse movement is currently calculated by DirectInput. How would we write a test for this? On Windows I can just increase the scaling of the display in the settings, but I'm not sure how to do it programmatically.
Yeah I don't think we have tests that change DPI dynamically. Maybe it's just a matter of setting the LogPixels registry setting, but it's probably a whole can of worms.
This seems to match what MSDN says at least. The dinput worker thread will need to be made per-monitor aware too for it to work correctly.