Как точно измерить движение мыши в дюймах или сантиметрах для мыши с известным DPI

У меня игровая мышь Logitech G500 с полным разрешением 5700 точек на дюйм.

Я пытаюсь написать программу на C ++, которая точно измеряет горизонтальное перемещение мыши в физических единицах, т.е. сантиметры или дюймы.

Я использую Windows API и Windows Raw ввод через сообщение WM_INPUT, чтобы получить необработанные изменения движения от мыши.

Затем я предполагаю, что 1 единица движения, сообщаемая через WM_INPUT, составляет 1/5700th от дюйма, и, когда я отслеживаю чистое движение мыши, я подумал, что мог бы выполнить простой расчет, чтобы получить чистое физическое движение:

расстояние (дюймы) = total_movement_from_wminput / dpi; // dpi = 5700 в этом случае

К сожалению, расчет не представляется точным. По физическим измерениям, проведенным только на моем коврике для мыши, я могу сказать, что при примерно 6 дюймах движения мыши вычисление дает значение около 5 с половиной дюймов (потеря на 1/2 дюйма).

Куда я иду не так? Я установил мышь на 5700DPI на панели управления, может ли фактический DPI быть меньше этого? Является ли мое предположение о том, что 1 единица изменения с помощью WM_INPUT составляет 1 / dpi дюймов физического движения, неверно?

У кого-нибудь есть идеи о том, как я могу сделать это, чтобы быть точным? Спасибо!

2

Решение

Марк,

Кажется, что проблема может быть, когда вы перемещаете мышь быстрее, чем событие 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 Переменная два определяет, сколько пикселей мышь переместила с момента последнего 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-position и y-position (в пикселях) мыши. Затем вы просто делите эти переменные на 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) / дюйм по вертикали

Здесь final_pixels_x — это x-позиция мыши через s секунд, а final_pixels y — это y-позиция через s секунд.


Подводя итог тому, что вы сделали неправильно, вы ошибочно предположили, что каждый WM_INPUT событие означает, что 1 пиксель был пройден мышью.

Если по какой-то причине я неправильно понял вопрос, и вы знаете, что вы уже перемещаете правильное количество пикселей, оставьте комментарий, и я сделаю все возможное, чтобы попытаться исправить мой ответ. Тем не менее, я все равно рекомендую использовать WM_MOUSEMOVE вместо WM_INPUT как это специально для мыши, и он применяет «ускорение указателя», о котором вы можете прочитать по ссылке в самом низу.

Спасибо за вопрос, tcs08

MSND-код и объяснение ввода с помощью WM_INPUT

MSND-код и пояснения для ввода с помощью WM_MOUSEMOVE

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]