I'm attempting to use the Win32 Raw Input API to collect raw mouse data with higher precision, but I can't seem to make sense of the documentation and samples at all for GetRawInputBuffer
.
While my mouse is hovering over the window, nothing seems to happen. I only seem to get buffered data when I click or release on the title bar of the window and even then I mostly get 0 movement values and never receive mouse button changes. I've followed samples as closely as possible and have had little luck searching online.
Below is the the Window Procedure and Main for a heavily simplified example bearing the issue.
LRESULT CALLBACK MessageHandler(HWND WindowHandle, UINT Message, WPARAM wParameter, LPARAM lParameter)
{
switch(Message)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
break;
case WM_CLOSE:
{
DestroyWindow(WindowHandle);
return 0;
}
break;
case WM_INPUT:
{
UINT RawInputSize;
UINT Result;
Result = GetRawInputBuffer(NULL, &(RawInputSize), sizeof(RAWINPUTHEADER));
if(Result == -1)
{
DWORD ErrorCode = GetLastError();
std::cout << "GetRawInputBuffer returned error code" << ErrorCode << std::endl;
}
else if(Result == 0 && RawInputSize != 0)
{
UINT AllocatedBufferByteCount = RawInputSize * 16;
RAWINPUT* RawInputBuffer = reinterpret_cast<RAWINPUT*>(malloc(AllocatedBufferByteCount));
UINT AllocatedBufferByteCountTwo = AllocatedBufferByteCount;
Result = GetRawInputBuffer(RawInputBuffer, &(AllocatedBufferByteCountTwo), sizeof(RAWINPUTHEADER));
if(Result == -1)
{
DWORD ErrorCode = GetLastError();
std::cout << "GetRawInputBuffer returned error code" << ErrorCode << std::endl;
}
else if(Result != 0)
{
UINT RawInputCount = Result;
DWORD MouseDeltaX = 0;
DWORD MouseDeltaY = 0;
bool ButtonsPressed[2] = {false, false};
RAWINPUT* RawInput = RawInputBuffer;
for(unsigned int i = 0; i < RawInputCount; ++i)
{
switch(RawInput->header.dwType)
{
// Raw mouse movement data for high-resolution mice.
case RIM_TYPEMOUSE:
{
MouseDeltaX += RawInput->data.mouse.lLastX;
MouseDeltaY += RawInput->data.mouse.lLastY;
ButtonsPressed[0] = ((RawInput->data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN) == RI_MOUSE_LEFT_BUTTON_DOWN);
ButtonsPressed[1] = ((RawInput->data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN) == RI_MOUSE_RIGHT_BUTTON_DOWN);
}
break;
}
RawInput = NEXTRAWINPUTBLOCK(RawInput);
}
DefRawInputProc(&(RawInputBuffer), RawInputCount, sizeof(RAWINPUTHEADER));
std::cout << "Mouse moved (" << MouseDeltaX << ", " << MouseDeltaY << ")." << std::endl;
if(ButtonsPressed[0])
{
std::cout << "LMB pressed." << std::endl;
}
if(ButtonsPressed[1])
{
std::cout << "RMB pressed." << std::endl;
}
}
free(RawInputBuffer);
}
return 0;
}
break;
default:
{
return DefWindowProc(WindowHandle, Message, wParameter, lParameter);
}
break;
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
// Initialize window strings.
wchar_t WindowClassName[] = L"DominionWindowClass";
wchar_t WindowCaption[] = L"Test Window";
// Create the window class.
WNDCLASSEX WindowClass;
WindowClass.cbSize = sizeof(WindowClass);
WindowClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
WindowClass.lpfnWndProc = &(MessageHandler);
WindowClass.cbClsExtra = 0;
WindowClass.cbWndExtra = 0;
WindowClass.hInstance = hInstance;
WindowClass.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
WindowClass.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);
WindowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WindowClass.hbrBackground = NULL;
WindowClass.lpszMenuName = NULL;
WindowClass.lpszClassName = WindowClassName;
// Register window class.
RegisterClassEx(&WindowClass);
// Setup window style flags.
DWORD WindowStyles = WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU;
DWORD ExWindowStyles = WS_EX_APPWINDOW;
// Setup window rectangle area.
RECT WindowArea;
WindowArea.left = 0;
WindowArea.top = 0;
WindowArea.right = 1024;
WindowArea.bottom = 768;
AdjustWindowRectEx(&(WindowArea), WindowStyles, false, ExWindowStyles);
// Window creation.
HWND WindowHandle = CreateWindowEx(ExWindowStyles, WindowClass.lpszClassName, WindowCaption, WindowStyles, CW_USEDEFAULT, CW_USEDEFAULT, (WindowArea.right - WindowArea.left), (WindowArea.bottom - WindowArea.top), NULL, NULL, hInstance, NULL);
// Display the window.
ShowWindow(WindowHandle, SW_SHOWDEFAULT);
UpdateWindow(WindowHandle);
// Register devices for raw input.
const unsigned int RawInputDeviceCount = 1;
RAWINPUTDEVICE RawInputDevices[RawInputDeviceCount];
memset(RawInputDevices, 0, RawInputDeviceCount * sizeof(RAWINPUTDEVICE));
RAWINPUTDEVICE* MouseRawInputDevice;
MouseRawInputDevice = RawInputDevices;
MouseRawInputDevice->usUsagePage = 1;
MouseRawInputDevice->usUsage = 2;
MouseRawInputDevice->hwndTarget = WindowHandle;
BOOL SuccessfullyRegisteredInput = RegisterRawInputDevices(RawInputDevices, RawInputDeviceCount, sizeof(RAWINPUTDEVICE));
// Core loop.
MSG Message;
for(;;)
{
while(PeekMessage(&Message, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&Message);
DispatchMessage(&Message);
if(Message.message == WM_QUIT)
{
break;
}
}
if(Message.message == WM_QUIT)
{
break;
}
}
// Unregister devices for raw input.
memset(RawInputDevices, 0, RawInputDeviceCount * sizeof(RAWINPUTDEVICE));
MouseRawInputDevice = RawInputDevices;
MouseRawInputDevice->usUsagePage = 1;
MouseRawInputDevice->usUsage = 2;
MouseRawInputDevice->dwFlags = RIDEV_REMOVE;
MouseRawInputDevice->hwndTarget = NULL;
BOOL SuccessfullyUnregisteredInput = RegisterRawInputDevices(RawInputDevices, RawInputDeviceCount, sizeof(RAWINPUTDEVICE));
return Message.wParam;
}
I can't think of a simpler way to experiment with the Raw Input API. Thoughts?
Long late answer, but GetRawInputBuffer
seems to be used for polling outside of the message processing loop. Use GetRawInputData
within WM_INPUT
handling or use GetRawInputBuffer
outside the message processing loop.