我正在尝试使用 Win32 Raw Input API 以更高的精度收集原始鼠标数据,但我似乎根本无法理解GetRawInputBuffer
.
当我的鼠标悬停在窗口上时,似乎什么也没发生。当我在窗口的标题栏上单击或释放时,我似乎只获得缓冲数据,即使这样,我也大多获得 0 移动值并且从未收到鼠标按钮更改。我已经尽可能地密切关注样本,并且在网上搜索时运气不佳。
下面是一个非常简化的示例的窗口过程和主要问题。
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;
}
我想不出更简单的方法来试验原始输入 API。想法?