问题描述
我正在尝试通过发送到前台窗口的鼠标监视和打印 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
模式标志,指定如何解释 usUsagePage
和 usUsage
提供的信息。它可以是零(默认值)或以下值之一。默认情况下,操作系统将来自具有指定顶级集合 (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);
}