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

I have a Logitech G500 gaming mouse running at full DPI 5700.

I am trying to write a program in C ++ that accurately measures the horizontal movement of the mouse in physical units, i.e. centimeters or inches.

I use the Windows API and the Windows input via the WM_INPUT message to get the raw motion changes with the mouse.

Then I assume that 1 unit of movement reported via WM_INPUT is 1 / 5700th of an inch, and when I track the pure movement of the mouse, I thought I could do a simple calculation to give a pure physical movement:

distance (inches) = total_movement_from_wminput / dpi; // dpi = 5700 in this case

Unfortunately, the calculation does not seem accurate. I can say from the physical measurement only on the mouse pad that for about 6 inches of mouse movement, the calculation gives a value of about 5 and a half inches (loss of battle by 1/2 inch).

Where am I mistaken? I set my mouse to 5700DPI in the control panel, can its actual DPI be less than this? Is my assumption of 1 units of change using WM_INPUT equal to 1 / dpi inches of physical movement?

Does anyone have any ideas on how I could get this to be exact? Thanks!

+2
c ++ dpi winapi distance raw-input
source share
1 answer

Mark

It seems that the problem may be that you move the mouse faster than the Windows WM_INPUT event handles it. For example, suppose a mouse moves 2 pixels in one frame. You will have a loss of 1 / 5700th of an inch (in your case), because for the processed "strong" WM_INPUT event you are moving two .

To fix this, you should check how many pixels the mouse moves each time a WM_INPUT message is sent to the program. What you need to do is make the RAWINPUTDEVICE variable and set the structure so that it has mouse information.

The following code registers RAWINPUTDEVICE , so it can be used in 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]); 

The code below uses the Rid variable, which determines how many pixels the mouse has moved since the last 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; } 

Please note that this code is the same code that was specified in msdn on this topic (link below).

Now you can have some global variable that has the x and y position (in pixels) of the mouse. Then you simply divide these variables by DPI, and you have the number of inches offset from each time you set global variables to 0.


A very simple way would be to handle the WM_MOUSEMOVE event. This makes it easy to get the exact position of the mouse (in pixels, of course). Using this, you can subtract this from the pixel values ​​of the original location.

Example:

DPI = 5700.

Starting position = (100px, 300px).

Position after 3 seconds = (500 pixels, 400 pixels).

Number of inches moved in these 3 seconds = ((500px - 100px) / 5700 inches (400px - 300px) / 5700 inches)

General rule : the number of inches moved after S seconds = (inital_pixels_x - final_pixels_x) / DPI inches

horizontal, (initial_pixels_y - final_pixels_y) / DPI inches vertically

Here final_pixels_x is the x-position of the mouse after s seconds, and final_pixels y is the y-position after s seconds.


To summarize what you did wrong, you mistakenly assumed that each WM_INPUT event means that the mouse passed 1 pixel.

If for some reason I misunderstood this question, and you know that you are already getting the correct number of pixels moved, leave a comment and I will do my best to try to correct my answer. However, I would still recommend using WM_MOUSEMOVE instead of WM_INPUT , as it is specifically designed for the mouse, and it uses “pointer acceleration”, which you can read about at the bottom of the link.

Thanks for asking your question, tcs08

Msdn code and mouse input explanation with WM_INPUT

Msdn code and explanation for mouse input with WM_MOUSEMOVE

+2
source share

All Articles