From a86eabc1f054cb52e0ee9bd499b45366af8ad6b5 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Fri, 18 Apr 2025 18:48:28 +1000 Subject: [PATCH] Win32RawInputSource: Fix handling of absolute positioned devices Maybe? Works in VMware now, I don't have any actual tablets. --- src/util/input_manager.cpp | 4 +- src/util/input_manager.h | 2 +- src/util/win32_raw_input_source.cpp | 67 +++++++++++++++++++++++------ 3 files changed, 56 insertions(+), 17 deletions(-) diff --git a/src/util/input_manager.cpp b/src/util/input_manager.cpp index 33c88adac..f6df56009 100644 --- a/src/util/input_manager.cpp +++ b/src/util/input_manager.cpp @@ -1283,9 +1283,9 @@ std::pair InputManager::GetPointerAbsolutePosition(u32 index) s_host_pointer_positions[index][static_cast(InputPointerAxis::Y)]); } -void InputManager::UpdatePointerAbsolutePosition(u32 index, float x, float y) +void InputManager::UpdatePointerAbsolutePosition(u32 index, float x, float y, bool raw_input) { - if (index >= MAX_POINTER_DEVICES || s_relative_mouse_mode_active) [[unlikely]] + if (index >= MAX_POINTER_DEVICES || (s_relative_mouse_mode_active && !raw_input)) [[unlikely]] return; const float dx = x - std::exchange(s_host_pointer_positions[index][static_cast(InputPointerAxis::X)], x); diff --git a/src/util/input_manager.h b/src/util/input_manager.h index 9cb1474f3..35a35aede 100644 --- a/src/util/input_manager.h +++ b/src/util/input_manager.h @@ -348,7 +348,7 @@ u32 GetPointerCount(); std::pair GetPointerAbsolutePosition(u32 index); /// Updates absolute pointer position. Can call from UI thread, use when the host only reports absolute coordinates. -void UpdatePointerAbsolutePosition(u32 index, float x, float y); +void UpdatePointerAbsolutePosition(u32 index, float x, float y, bool raw_input = false); /// Resets the accumulated pointer movement. Use when pointer tracking was interrupted. void ResetPointerRelativeDelta(u32 index); diff --git a/src/util/win32_raw_input_source.cpp b/src/util/win32_raw_input_source.cpp index a49bf0bbc..ca69d72ee 100644 --- a/src/util/win32_raw_input_source.cpp +++ b/src/util/win32_raw_input_source.cpp @@ -3,6 +3,9 @@ #include "win32_raw_input_source.h" #include "input_manager.h" +#include "platform_misc.h" + +#include "core/gpu_thread.h" #include "common/assert.h" #include "common/error.h" @@ -313,16 +316,6 @@ bool Win32RawInputSource::ProcessRawInputEvent(const RAWINPUT* event) const RAWMOUSE& rm = event->data.mouse; - s32 dx = rm.lLastX; - s32 dy = rm.lLastY; - - // handle absolute positioned devices - if ((rm.usFlags & MOUSE_MOVE_ABSOLUTE) == MOUSE_MOVE_ABSOLUTE) - { - dx -= std::exchange(dx, state.last_x); - dy -= std::exchange(dy, state.last_y); - } - unsigned long button_mask = (rm.usButtonFlags & (rm.usButtonFlags ^ std::exchange(state.button_state, rm.usButtonFlags))) & ALL_BUTTON_MASKS; @@ -341,10 +334,56 @@ bool Win32RawInputSource::ProcessRawInputEvent(const RAWINPUT* event) button_mask &= ~(1u << bit_index); } - if (dx != 0) - InputManager::UpdatePointerRelativeDelta(pointer_index, InputPointerAxis::X, static_cast(dx), true); - if (dy != 0) - InputManager::UpdatePointerRelativeDelta(pointer_index, InputPointerAxis::Y, static_cast(dy), true); + // handle absolute positioned devices + if ((rm.usFlags & MOUSE_MOVE_ABSOLUTE) == MOUSE_MOVE_ABSOLUTE) + { + // https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-rawmouse#remarks + RECT rect; + if (rm.usFlags & MOUSE_VIRTUAL_DESKTOP) + { + rect.left = GetSystemMetrics(SM_XVIRTUALSCREEN); + rect.top = GetSystemMetrics(SM_YVIRTUALSCREEN); + rect.right = GetSystemMetrics(SM_CXVIRTUALSCREEN); + rect.bottom = GetSystemMetrics(SM_CYVIRTUALSCREEN); + } + else + { + rect.left = 0; + rect.top = 0; + rect.right = GetSystemMetrics(SM_CXSCREEN); + rect.bottom = GetSystemMetrics(SM_CYSCREEN); + } + + int absolute_x = MulDiv(rm.lLastX, rect.right, USHRT_MAX) + rect.left; + int absolute_y = MulDiv(rm.lLastY, rect.bottom, USHRT_MAX) + rect.top; + + // This is truely awful. But for something that isn't used much, it's the easiest way to get the render rect... + const WindowInfo& render_wi = GPUThread::GetRenderWindowInfo(); + if (render_wi.type == WindowInfo::Type::Win32 && + GetWindowRect(static_cast(render_wi.window_handle), &rect)) + { + absolute_x -= rect.left; + absolute_y -= rect.top; + } + + InputManager::UpdatePointerAbsolutePosition(pointer_index, static_cast(absolute_x), + static_cast(absolute_y), true); + } + else + { + // relative is easy + if (rm.lLastX != 0) + { + InputManager::UpdatePointerRelativeDelta(pointer_index, InputPointerAxis::X, static_cast(rm.lLastX), + true); + } + + if (rm.lLastY != 0) + { + InputManager::UpdatePointerRelativeDelta(pointer_index, InputPointerAxis::Y, static_cast(rm.lLastY), + true); + } + } return true; }