Фон:
Я использую WM_MOUSEMOVE
а также WM_KEYDOWN
/WM_KEYUP
сообщения для ввода с клавиатуры и мыши соответственно большую часть моего времени разрабатывались с использованием Windows API. Однако недавно я начал реализовывать класс ввода, который обрабатывает ввод, используя RAWINPUT
и WM_INPUT
сообщение вместо
Реализация клавиатуры работает безупречно благодаря этому сайт
Однако теперь я обратил свое внимание на реализацию движений мыши. Из моего понимания, WM_INPUT
генерирует дельты движения мыши, а не координаты пространства клиента при работе с мышью.
Проблема заключается в том, что я также хотел бы сохранить координаты указателя мыши в пространстве клиента и в пространстве экрана, и в идеале я хотел бы сделать это без необходимости перехвата WM_MOUSEMOVE
сообщение или использование GetCursorPos()
/ScreenToClient()
функции, если это возможно, из-за моего (вероятно, необоснованного) страха перед проблемами производительности.
Мои исследования в RAWINPUT
привели меня Вот в котором говорится о деталях мыши:
Обратите внимание, что возвращаемые значения не являются значениями экранного пространства, как вы получаете из сообщения WM_MOUSEMOVE. Это необработанные данные, которые мы получаем, поэтому значения необходимо интерпретировать.
Это заставило меня поверить, что было возможно интерпретировать данные, вычисляя начальную позицию курсора мыши, используя первоначальный вызов. GetCursorPos()
затем для каждого события перемещения мыши, обнаруженного WM_INPUT
добавьте дельты, полученные из WM_INPUT
сообщение в исходную позицию курсора, предпринимая шаги, чтобы убедиться, что позиция остается в пределах границ экрана. Например, что-то вроде этого (обратите внимание, что это не будет компилироваться, поскольку оно содержит выдержки из моего класса, но этого должно быть достаточно, чтобы дать обзор того, что я делаю в настоящее время)
// Somewhere in class header
RECT m_screenMouseBounds;
POINT m_mouseDelta;
POINT m_mouseScreenPosition;
POINT m_mouseScreenPositionGETCURSOR;
RAWMOUSE m_rawMouse;
// ...
// Somewhere during class initialisation
GetCursorPos(&m_mouseScreenPosition); // Get initial mouse cursor position
// Determine maximum and minimum boundaires of current display
m_screenMouseBounds.right = GetSystemMetrics(SM_CXSCREEN);
m_screenMouseBounds.bottom = GetSystemMetrics(SM_CYSCREEN);
m_screenMouseBounds.top = 0;
m_screenMouseBounds.left = 0;
// Prepare the devices for registering
RAWINPUTDEVICE theInputDevices[2];
// 0 = keyboard
theInputDevices[0].usUsagePage = 0x01;
theInputDevices[0].usUsage = 0x06;
theInputDevices[0].dwFlags = RIDEV_NOLEGACY;
theInputDevices[0].hwndTarget = theWindowToHandle;
// 1 = mouse
theInputDevices[1].usUsagePage = 0x01;
theInputDevices[1].usUsage = 0x02;
theInputDevices[1].dwFlags = 0; // RIDEV_NOLEGACY
theInputDevices[1].hwndTarget = theWindowToHandle;
// Register each device with raw input
if(RegisterRawInputDevices(theInputDevices,2,sizeof(RAWINPUTDEVICE))==FALSE)
{
// throw exception
return false;
}
// ...
// In the WM_INPUT processing function with parameters : (WPARAM wParam, LPARAM lParam)
char inputBuffer[sizeof(RAWINPUT)] = {};
UINT inputBufferSize = sizeof(RAWINPUT);
GetRawInputData(reinterpret_cast<HRAWINPUT>(lParam), RID_INPUT, inputBuffer, &inputBufferSize, sizeof(RAWINPUTHEADER));
RAWINPUT* rawData = reinterpret_cast<RAWINPUT*>(inputBuffer);
if(rawData->header.dwType == RIM_TYPEMOUSE)
{
m_rawMouse = rawData->data.mouse;
// Add the movement deltas acquired from the WM_INPUT message
m_mouseDelta.x = m_rawMouse.lLastX;
m_mouseDelta.y = m_rawMouse.lLastY;
// Update the screen position using the delta values (Does not work as expected!)
m_mouseScreenPosition.x += m_mouseDelta.x;
m_mouseScreenPosition.y += m_mouseDelta.y;
// Ensure mouse coords are within the screens boundaries
if (m_mouseScreenPosition.x < m_screenMouseBounds.left)
{
m_mouseScreenPosition.x = m_screenMouseBounds.left;
}
if (m_mouseScreenPosition.x > m_screenMouseBounds.right)
{
m_mouseScreenPosition.x = m_screenMouseBounds.right;
}
if (m_mouseScreenPosition.y < m_screenMouseBounds.top)
{
m_mouseScreenPosition.y = m_screenMouseBounds.top;
}
if (m_mouseScreenPosition.y > m_screenMouseBounds.bottom)
{
m_mouseScreenPosition.y = m_screenMouseBounds.bottom;
}
// Double check to make sure that the screen position coordinates calculated
// above match the screen coordinates as determined by Windows
// using GetCursorPos() (Hint: They don't! :( )
GetCursorPos(&m_mouseScreenPositionGETCURSOR);
TCHAR s[256];
swprintf(s, L"MouseDX: %ld MouseDY: %ld\n", m_mouseDelta.x, m_mouseDelta.y);
OutputDebugString(s);
swprintf(s, L"MouseX(Screen(WM_INPUT)): %ld MouseY(Screen(WM_INPUT)): %ld\n", m_mouseScreenPosition.x, m_mouseScreenPosition.y);
OutputDebugString(s);
swprintf(s, L"MouseX(Screen(GetCursorPos)): %ld MouseY(Screen(GetCursorPos)): %ld\n", m_mouseScreenPositionGETCURSOR.x, m_mouseScreenPositionGETCURSOR.y);
OutputDebugString(s);
}
Проблема заключается в значениях, приобретенных для m_mouseScreenPosition
с помощью этого метода отличаются от m_mouseScreenPositionGETCURSOR
которые получены через функцию WINAPI GetCursorPos()
,
В итоге
Я предполагаю, что мой общий набор вопросов:
Какие ценности lLastX
а также lLastY
из RAWMOUSE
структура связана с? связаны ли они с координатами экрана / клиентскими координатами, т.е. возвращаемые значения имеют отношение 1: 1 к пикселям на экране, или они вообще не связаны с дисплеем и скорее связаны с деталями мыши (чувствительностью и т. д.) и поэтому не являются 1 : 1 отношение к пикселям?
Если ответ на 1 относится к мыши, а не к отображению координат: можно ли определить фактические координаты экрана указателя мыши исключительно с помощью WM_INPUT
? или мне придется либо ловить WM_MOUSEMOVE
сообщения и / или использовать GetCursorPos () для определения координат курсоров в пространстве клиента и на экране?
Если ответ на 2 — мне нужно будет использовать WM_MOUSEMOVE
/GetCursorPos()
: Есть ли проблемы с производительностью, о которых мне следует знать, если я в конечном итоге использую RAWINPUT
так же как WM_MOUSEMOVE
/GetCursorPos()
? Или мои опасения по поводу производительности необоснованны?
Если вам удалось это сделать, я благодарен вам, и я ценю любую помощь или информацию, которую вы можете мне дать. Спасибо!
«Обратите внимание, что возвращаемые значения не являются значениями экранного пространства, как вы получаете из сообщения WM_MOUSEMOVE. Это необработанные данные, которые мы получаем, поэтому значения должны интерпретироваться. Значения, как правило, относятся к последней позиции и, следовательно, указывают на движение. можете проверить usFlags в структуре RAWMOUSE. » Получил это от Toymaker, который я всегда нахожу потрясающим. Вот
RAWINPUT предназначен только для получения относительного ввода. Вот почему его сырье. Если вы действительно не хотите использовать GetCursorPos, просто используйте WM_MOUSEMOVE и проверьте параметры l / w.
Я никогда не делал тесты производительности для GetCursorPos (), но я немного читал об этом для своих собственных проектов, и я никогда не видел никаких возражений против этого. Вызов GetCursorPos, независимо от того, используете ли вы RAWINPUT, один раз за кадр или каждое обновление, несомненно, будет незначительным. Я использовал его для вращающихся камер, и он всегда работал нормально.
Других решений пока нет …