原始输入 - 在 window/program 处于后台时接收 WM_INPUT

Raw Input - recive WM_INPUT while window/program is in background

我正在尝试从发送到前台的鼠标监视和打印 RAWINPUT window,或者只是从鼠标发送的所有 RAWINPUT

全局钩子 LowLevelMouseProc 对我不起作用,因为它 returns MOUSEHOOKSTRUCT 没有给我 dx 和 dy。

Raw Input API提到当当前window在后台时收到WM_INPUT,wParam会被设置为RIM_INPUTSINK但我不知道程序在后台时如何接收WM_INPUT

这里有一些代码解释了我正在尝试做的事情。

int main()
{
    //regiter the monitoring device
    static bool raw_input_initialized = false;
    if (raw_input_initialized == false)
    {
        RAWINPUTDEVICE rid;

        rid.usUsagePage = 0x01; //Mouse
        rid.usUsage = 0x02;
        rid.dwFlags = 0;
        rid.hwndTarget = NULL;

        if (RegisterRawInputDevices(&rid, 1, sizeof(rid)) == FALSE)
        {
            exit(-1);
        }

        raw_input_initialized = true;
    }

    HWND targetWindow = { 0 };

    while (true)
    {
        targetWindow = GetForegroundWindow(); // get the window runing in the formost window;

        
        std::cout << targetWindow << '\n';
    }
    return 0;
}

// enterd every time there is a rawinput to ForegroundWindow, or alternatively just a rawinput in general
LRESULT CALLBACK targetWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    // print out the values that I need
    case WM_INPUT:
        UINT dataSize;
        GetRawInputData(reinterpret_cast<HRAWINPUT>(lParam), RID_INPUT, NULL, &dataSize, sizeof(RAWINPUTHEADER)); //Need to populate data size first
        std::cout << GET_RAWINPUT_CODE_WPARAM(wParam) << " code thing\n";
        if (dataSize > 0)
        {

            std::unique_ptr<BYTE[]> rawdata = std::make_unique<BYTE[]>(dataSize);

            if (GetRawInputData(reinterpret_cast<HRAWINPUT>(lParam), RID_INPUT, rawdata.get(), &dataSize, sizeof(RAWINPUTHEADER)) == dataSize)
            {
                RAWINPUT* raw = reinterpret_cast<RAWINPUT*>(rawdata.get());
                if (raw->header.dwType == RIM_TYPEMOUSE)
                {
                    std::cout << raw->data.mouse.lLastX << std::endl;
                }
            }
        }
        break;
    }
}

But I have no idea how to receive WM_INPUT while the program is in the background.

根据 RAWINPUTDEVICE 文档,您需要在注册设备时指定 RIDEV_INPUTSINK 标志:

dwFlags
Type: DWORD

Mode flag that specifies how to interpret the information provided by usUsagePage and usUsage. It can be zero (the default) or one of the following values. By default, the operating system sends raw input from devices with the specified top level collection (TLC) to the registered application as long as it has the window focus.

...

RIDEV_INPUTSINK
0x00000100

If set, this enables the caller to receive the input even when the caller is not in the foreground. Note that hwndTarget must be specified.

因此,您必须指定一个 HWND 来接收 WM_INPUT 消息,并有一个消息循环来为 window.

提供服务

试试这个:

#include <iostream>
#include <vector>
#include <Windows.h>

LRESULT CALLBACK targetWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int main()
{
    HINSTANCE hInstance = GetModuleHandle(NULL);

    WNDCLASS wc = {};
    wc.lpfnWndProc = targetWindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = TEXT("MyRawInputWnd");

    if (!RegisterClass(&wc))
        return -1;

    HWND targetWindow = CreateWindowEx(0, wc.lpszClassName, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, hInstance, NULL);
    if (!targetWindow)
        return -1;

    //register the monitoring device
    RAWINPUTDEVICE rid = {};
    rid.usUsagePage = 0x01; //Mouse
    rid.usUsage = 0x02;
    rid.dwFlags = RIDEV_INPUTSINK;
    rid.hwndTarget = targetWindow;

    if (!RegisterRawInputDevices(&rid, 1, sizeof(rid)))
        return -1;

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    DestroyWindow(targetWindow);

    return 0;
}

LRESULT CALLBACK targetWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        // print out the values that I need
        case WM_INPUT: {
            UINT dataSize;
            GetRawInputData(reinterpret_cast<HRAWINPUT>(lParam), RID_INPUT, NULL, &dataSize, sizeof(RAWINPUTHEADER)); //Need to populate data size first
            std::cout << GET_RAWINPUT_CODE_WPARAM(wParam) << " code thing\n";
            if (dataSize > 0)
            {
                std::vector<BYTE> rawdata(dataSize);

                if (GetRawInputData(reinterpret_cast<HRAWINPUT>(lParam), RID_INPUT, rawdata.data(), &dataSize, sizeof(RAWINPUTHEADER)) == dataSize)
                {
                    RAWINPUT* raw = reinterpret_cast<RAWINPUT*>(rawdata.data());
                    if (raw->header.dwType == RIM_TYPEMOUSE)
                    {
                        std::cout << raw->data.mouse.lLastX << std::endl;
                    }
                }
            }
            return 0;
        }
    }

    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}