我正在尝试使用原始输入法获取鼠标位置。在 RAWMOUSE 结构中,我总是获取 MOUSE_MOVE_RELATIVE 作为 usFlags 值,这意味着我获取最后鼠标位置的相对值。但我想要鼠标的绝对位置。如何从原始输入中获取鼠标的绝对位置值?
[很奇怪看到一个 9 年前未解答的问题成为 google 搜索结果的热门,所以我会提供一个答案..迟做总比不做好!]
在原始输入 API 级别,您将获得鼠标设备的原始水平/垂直移动——鼠标在硬件级别报告的内容。
根据文档(我尚未验证),这些增量 X/Y 值尚未由桌面鼠标速度/加速/减速设置处理。因此,即使您从已知的绝对位置开始跟踪增量,您也会很快偏离 Windows 在屏幕上定位鼠标光标的位置。
文档中不清楚的是报告这些相对 X/Y 值的单位或比例。如果能以某种方式标准化那就太好了,但我怀疑这取决于鼠标的 DPI 分辨率。 (我会找一个可调节 DPI 的鼠标来测试,如果没有人先编辑我,我会报告回来。)
编辑/更新:我拿到了具有可调节 DPI 的鼠标..做了一些粗略的测试,足以确认 lLastX/Y 值的粗略比例似乎与硬件 DPI 相匹配..例如。鼠标处于 1200 dpi 模式时,从左向右物理移动 1 英寸,生成 lLastX 值的净和 ~= 1200。
RAWMOUSE
具有与 Windows 从鼠标硬件接收的完全相同的值(可能是 HID USB/蓝牙或 i8042 PS/2 鼠标等)。通常鼠标发送相对移动,但有些可以发送绝对移动 - 例如触摸屏、RDP 鼠标(耶!)。
因此,如果您需要绝对鼠标位置(例如游戏菜单),您可以使用 GetCursorPos API 来获取 Windows 渲染的光标在屏幕上的坐标。
但它与
MOUSE_MOVE_ABSOLUTE
中带有 RAWMOUSE
标志发送的内容不同。
MOUSE_MOVE_ABSOLUTE
是设备空间(而不是屏幕空间)中 0..65535 范围内的鼠标移动。这是一些如何将其转换为屏幕空间的代码:
if (raw->mouse.usFlags & MOUSE_MOVE_ABSOLUTE)
{
RECT rect;
if (raw->mouse.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 absoluteX = MulDiv(raw->mouse.lLastX, rect.right, 65535) + rect.left;
int absoluteY = MulDiv(raw->mouse.lLastY, rect.bottom, 65535) + rect.top;
...
}
else if (raw->mouse.lLastX != 0 || raw->mouse.lLastY != 0)
{
int relativeX = raw->mouse.lLastX;
int relativeY = raw->mouse.lLastY;
...
}