如何以英寸或厘米为单位精确测量具有已知DPI的鼠标的移动

How to accurately measure mouse movement in inches or centimetres for a mouse with a known DPI

本文关键字:测量 DPI 移动 鼠标 为单位      更新时间:2023-10-16

我有一个罗技G500游戏鼠标,DPI为5700。

我正试图用c++写一个程序,准确地测量鼠标在物理单位的水平运动,即。厘米或英寸。

我通过WM_INPUT消息使用windows API和windows原始输入来从鼠标获得原始运动变化。

然后假设通过WM_INPUT报告的1个移动单位是1/5700英寸,并且当我跟踪鼠标的净运动时,我认为我可以执行一个简单的计算来产生净物理运动:

distance(inch) = total_movement_from_wminput/dpi;//dpi = 5700

不幸的是,计算似乎并不准确。我可以从我的鼠标垫上的物理测量中得知,在鼠标移动约6英寸时,计算得出的值约为5.5英寸(损失约1/2英寸)。

我哪里错了?我把鼠标的控制面板设置为5700DPI,它的实际DPI会比这个小吗?我的假设关于1单位的变化通过WM_INPUT是1/dpi英寸的物理运动不正确?

有谁知道我怎样才能使这个准确吗?谢谢!

Marc,

似乎问题可能是当你移动鼠标比Windows事件WM_INPUT处理它的速度快。例如,假设鼠标在一帧中移动了2个像素。您将损失1/5700英寸(在您的情况下),因为对于一个 WM_INPUT事件处理,您将移动两个像素。

为了解决这个问题,你应该检查每次WM_INPUT消息发送给程序时鼠标移动了多少像素。你所要做的就是创建一个RAWINPUTDEVICE 变量并设置结构体,使其具有关于鼠标的信息。

下面的代码注册RAWINPUTDEVICE,以便它可以在WM_INPUT中使用。

RAWINPUTDEVICE Rid[1];
Rid[0].usUsagePage = HID_USAGE_PAGE_GENERIC;
Rid[0].usUsage = HID_USAGE_GENERIC_MOUSE; 
Rid[0].dwFlags = RIDEV_INPUTSINK;   
Rid[0].hwndTarget = hWnd;
RegisterRawInputDevices(Rid, 1, sizeof(Rid[0]);

下面的代码实际上使用Rid变量two来确定自上次启动WM_INPUT以来鼠标移动了多少像素。

case WM_INPUT: 
{
    UINT dwSize = 40;
    static BYTE lpb[40];
    GetRawInputData((HRAWINPUT)lParam, RID_INPUT, 
                    lpb, &dwSize, sizeof(RAWINPUTHEADER));
    RAWINPUT* raw = (RAWINPUT*)lpb;
    if (raw->header.dwType == RIM_TYPEMOUSE) 
    {
        int xPosRelative = raw->data.mouse.lLastX; // Could be 1, or could be more than 1
        int yPosRelative = raw->data.mouse.lLastY; // Could be 1, or could be more than 1!
    } 
    break;
}

请注意,这段代码与msdn上关于这个主题(下面的链接)的代码相同。

您现在可以使用某种类型的全局变量,该变量具有鼠标的x位置和y位置(以像素为单位)。然后,您只需将这些变量除以DPI,就可以获得从将全局变量设置为0时开始的英寸偏移量。


一个完全更简单的方法是处理WM_MOUSEMOVE事件。它可以很容易地获得鼠标的确切位置(当然是以像素为单位)。使用这个,你可以从起始位置的像素值中减去它。

的例子:

DPI = 5700.

初始位置= (100px, 300px).

3秒后的位置= (500px, 400px).

3秒内移动的英寸数= ((500px - 100px)/5700英寸,(400px - 300px)/5700英寸)

一般规则: S秒后移动的英寸数= (inital_pixels_x - final_pixels_x)/DPI英寸数

水平,(initial_pixels_y - final_pixels_y)/DPI英寸垂直

这里,final_pixels_x是s秒后鼠标的x坐标位置,而final_pixels y是s秒后鼠标的y坐标位置。


总结一下你的错误,你错误地认为每个WM_INPUT事件意味着鼠标移动了1个像素。

如果我因为某种原因误解了这个问题,你知道你已经得到了正确的像素移动量,请留下评论,我会尽我最大的努力来修复我的答案。然而,我仍然建议使用WM_MOUSEMOVE而不是WM_INPUT,因为它是专门针对鼠标的,它适用于"指针加速"。你可以在最下面的链接上读到。

谢谢你的提问,tcs08

使用WM_INPUT

进行鼠标输入的Msdn代码和说明

使用WM_MOUSEMOVE进行鼠标输入的Msdn代码和说明