winapi - 正确使用GetRawInputBuffer

标签 winapi raw-input

我正在尝试使用 Win32 原始输入 API 以更高精度收集原始鼠标数据,但我似乎无法理解 documentation and samples对于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。想法?

最佳答案

很晚才回答,但 GetRawInputBuffer 似乎用于消息处理循环之外的轮询。在 WM_INPUT 处理中使用 GetRawInputData 或在消息处理循环之外使用 GetRawInputBuffer

关于winapi - 正确使用GetRawInputBuffer,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10866226/

相关文章:

c++ - 等待线程

python - 如何摆脱 Python raw_input() 中的正斜杠

delphi - 如何同步父/子进程执行?

c++ - 检查文件是由进程创建的还是用户使用 C++ 创建的

c++ - 如何准确测量具有已知 DPI 的鼠标的鼠标移动(以英寸或厘米为单位)

python - 如果没有有效的选择,如何返回到第一个 if 语句

r - 执行要求并包含用户提示的 R 脚本

python - 在 Python 2.7 中使用 raw_input() 读入德语变音符号

winapi - 抑制 WM_ERASEBKGND 的正确方法是什么?

c# - 为什么 C#(相当慢)和 Win32/C 之间的性能差异?