原始输入 - 在窗口/程序处于后台时接收 WM_INPUT

问题描述

我正在尝试通过发送到前台窗口的鼠标监视和打印 RAWINPUT,或者通常只是从鼠标中输出所有 RAWINPUT

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

Raw Input API 提到对于当前窗口在后台时收到的 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),rawdata.get(),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;
    }
}

解决方法

但我不知道如何在程序在后台时接收 WM_INPUT。

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

dwFlags
输入:DWORD

模式标志,指定如何解释 usUsagePageusUsage 提供的信息。它可以是零(默认值)或以下值之一。默认情况下,操作系统将来自具有指定顶级集合 (TLC) 的设备的原始输入发送到注册的应用程序只要它具有窗口焦点

...

RIDEV_INPUTSINK
0x00000100

如果设置,这将使调用者能够接收输入即使调用者不在前台。请注意,必须指定 hwndTarget

因此,您必须指定一个 HWND 来接收 WM_INPUT 消息,并有一个消息循环来为该窗口提供服务。

试试这个:

#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,HWND_MESSAGE,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,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    DestroyWindow(targetWindow);

    return 0;
}

LRESULT CALLBACK targetWindowProc(HWND hWnd,LPARAM lParam)
{
    switch (uMsg)
    {
        // print out the values that I need
        case WM_INPUT: {
            UINT dataSize;
            GetRawInputData(reinterpret_cast<HRAWINPUT>(lParam),RID_INPUT,&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),rawdata.data(),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);
}