2

我正在尝试使用 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。想法?

4

2 回答 2

3

很晚的答案,但GetRawInputBuffer似乎用于在消息处理循环之外进行轮询。GetRawInputDataWM_INPUT处理内使用或在GetRawInputBuffer消息处理循环外使用。

于 2013-11-12T00:53:54.917 回答
0

我猜使用 GetRawInputBuffer() 你只能读取 HID 数据。这意味着只有 RAWINPUT 结构的数据部分中的 hid 结构被输入数据填充。我能够使用 RAWHID 的 bRawData 成员从我的键盘读取输入,但我认为那没用,因为这些值因键盘而异。所以我切换回 GetRawInputData....

于 2012-06-20T16:38:10.553 回答