Windows截获系统鼠标消息转发到指定窗口

发布于:2025-02-10 ⋅ 阅读:(32) ⋅ 点赞:(0)

注册输入设备,截获系统底层的设备消息

先看关键代码:


RAWINPUTDEVICE rids[1];
rids[0].usUsagePage = HID_USAGE_PAGE_GENERIC; //0x01
rids[0].usUsage = HID_USAGE_GENERIC_MOUSE; //0x02
rids[0].dwFlags = RIDEV_INPUTSINK; //0x00000100
rids[0].hwndTarget = win->hwnd;
RegisterRawInputDevices(rids, 1, sizeof(rids[0]));

这段代码中,RegisterRawInputDevices 方法用于让程序注册一个或多个输入设备(代码中仅注册了一个),以便应用程序可以直接接收来自这些设备的原始输入数据。

参数RAWINPUTDEVICE的属性usUsagePage的值为HID_USAGE_PAGE_GENERIC,表示通用输入设备。

dwFlags属性的值为HID_USAGE_GENERIC_MOUSE,表示鼠标设备。

dwFlags属性的值为RIDEV_INPUTSINK ,表示原始输入设备的输入将发送到指定的目标窗口,而不是默认的窗口。这意味着即使目标窗口没有被激活,它仍然可以接收输入。

hwndTarget属性的值为目标窗口的句柄。

处理截获到的消息

如下代码所示:


LRESULT CALLBACK processMsg(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  if (uMsg != WM_INPUT) {
      return CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam);
  }
  UINT dwSize = sizeof(RAWINPUT);
  static BYTE lpb[sizeof(RAWINPUT)];
  GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER));
  auto raw = (RAWINPUT*)lpb;
  if (raw->header.dwType == RIM_TYPEMOUSE){
    RAWMOUSE rawMouse = raw->data.mouse;
    if (rawMouse.usButtonFlags == RI_MOUSE_WHEEL)
    {
       //鼠标滚轮消息
      return 0;
    }
    switch (rawMouse.ulButtons)
    {
        case RI_MOUSE_LEFT_BUTTON_DOWN:
        {
           //鼠标左键按下消息 
          return 0;               
        }
        case RI_MOUSE_LEFT_BUTTON_UP:
        {
             //鼠标左键弹起消息;
            return 0;
        }
        default:
        {
             //鼠标移动消息
            return 0;
        }
    }
  }
  return CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam);
}

截获到的消息都是 WM_INPUT 消息,其他消息我们就交由窗口的原有消息处理函数处理了。

截获到的消息数据存储在lParam中,我们通过GetRawInputData方法把这些数据提取到一个RAWINPUT类型的对象中。

由于我们只截获了鼠标消息,所以又从RAWINPUT对象中提取了RAWMOUSE类型的对象,我们只处理鼠标消息。

当这个RAWMOUSE对象的usButtonFlags属性值为RI_MOUSE_WHEEL时,表示鼠标滚轮消息。

这个对象的ulButtons属性的值代表着鼠标消息的其他类型,比如鼠标左键按下:RI_MOUSE_LEFT_BUTTON_DOWN,鼠标左键弹起:RI_MOUSE_LEFT_BUTTON_UP等。

如果窗口是你自己的,此时你就可以执行具体的方法了,如果窗口不是你自己的,你还可以把这些消息发送给目标窗口。如下代码所示:


auto lParam = MAKELPARAM(point.x, point.y);
PostMessage(win->hwnd, WM_LBUTTONUP, MK_LBUTTON, lParam);

当然,鼠标消息要注意处理鼠标的坐标呦(你希望得到绝对坐标还是相对坐标呢?)