You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++如何获取鼠标原始移动输入而非光标位置(Windows10环境)

Windows 10 环境下C++原始鼠标输入移动检测实现

使用Windows原生Raw Input API即可实现需求,该API直接从输入设备驱动层获取鼠标上报的相对位移数据,完全不受屏幕边界、程序锁定光标逻辑的影响,适配你提到的两类光标检测失效场景。

核心实现逻辑

  • 第一步:向系统注册鼠标类型的原始输入设备,指定接收原始输入消息的窗口句柄
  • 第二步:截获窗口的WM_INPUT消息,这是系统投递原始输入数据的标准消息
  • 第三步:解析消息中携带的原始鼠标数据,提取X/Y轴的相对位移增量,根据增量正负判断移动方向

注意:Windows系统中鼠标坐标系Y轴向下为正,因此Y轴增量为负代表鼠标向上移动,Y轴增量为正代表向下移动;X轴向右为正,X轴增量为负代表向左移动。

完整可运行代码

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

// 保存控制台原窗口过程指针
WNDPROC originalConsoleProc = nullptr;

// 自定义窗口过程,用于截获WM_INPUT消息
LRESULT CALLBACK RawInputProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    if (msg == WM_INPUT)
    {
        UINT dataSize = 0;
        // 先获取原始输入数据的大小
        GetRawInputData((HRAWINPUT)lParam, RID_INPUT, nullptr, &dataSize, sizeof(RAWINPUTHEADER));
        if (dataSize > 0)
        {
            // 分配缓冲区存储数据
            LPBYTE buffer = new BYTE[dataSize];
            if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, buffer, &dataSize, sizeof(RAWINPUTHEADER)) == dataSize)
            {
                RAWINPUT* rawData = (RAWINPUT*)buffer;
                // 判断是否为鼠标输入
                if (rawData->header.dwType == RIM_TYPEMOUSE)
                {
                    RAWMOUSE mouseData = rawData->data.mouse;
                    // 判断是否为相对移动事件
                    if (mouseData.usFlags & MOUSE_MOVE_RELATIVE)
                    {
                        LONG deltaX = mouseData.lLastX;
                        LONG deltaY = mouseData.lLastY;
                        
                        // 可根据需求调整阈值过滤鼠标微抖动
                        const LONG MOVE_THRESHOLD = 1;
                        if (abs(deltaY) >= MOVE_THRESHOLD)
                        {
                            if (deltaY < 0)
                            {
                                std::cout << "the mouse is moving up\n";
                            }
                            else
                            {
                                std::cout << "the mouse is moving down\n";
                            }
                        }
                        if (abs(deltaX) >= MOVE_THRESHOLD)
                        {
                            if (deltaX < 0)
                            {
                                std::cout << "the mouse is moving left\n";
                            }
                            else
                            {
                                std::cout << "the mouse is moving right\n";
                            }
                        }
                    }
                }
            }
            delete[] buffer;
        }
    }
    // 调用原窗口过程保证其他消息正常处理
    return CallWindowProc(originalConsoleProc, hwnd, msg, wParam, lParam);
}

int main()
{
    // 获取当前控制台窗口句柄
    HWND consoleHwnd = GetConsoleWindow();
    if (!consoleHwnd)
    {
        std::cerr << "获取控制台窗口句柄失败\n";
        return 1;
    }

    // 子类化控制台窗口,替换窗口过程以接收WM_INPUT
    originalConsoleProc = (WNDPROC)SetWindowLongPtr(consoleHwnd, GWLP_WNDPROC, (LONG_PTR)RawInputProc);

    // 注册鼠标原始输入设备
    RAWINPUTDEVICE rid;
    rid.usUsagePage = 0x01;  // 通用桌面设备类
    rid.usUsage = 0x02;      // 鼠标设备
    rid.dwFlags = RIDEV_INPUTSINK | RIDEV_NOLEGACY; // 即使窗口不在前台也接收消息,屏蔽legacy鼠标消息
    rid.hwndTarget = consoleHwnd;

    if (!RegisterRawInputDevices(&rid, 1, sizeof(RAWINPUTDEVICE)))
    {
        std::cerr << "注册原始输入设备失败,错误码:" << GetLastError() << "\n";
        return 1;
    }

    std::cout << "原始鼠标输入检测已启动,移动鼠标查看输出...\n";

    // 标准消息循环
    MSG msg;
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}

编译注意事项

  • 编译时需要链接user32.lib库,Visual Studio环境下默认会链接该库,MinGW环境如果出现链接错误可手动添加链接参数-luser32
  • 代码中MOVE_THRESHOLD为移动判定阈值,可根据实际需求调整,数值越大越不容易被鼠标微小抖动触发,数值越小检测灵敏度越高
  • 该实现获取的相对位移不受光标位置、屏幕边界、程序锁定光标逻辑影响,只要鼠标物理移动就会正常上报位移增量

内容的提问来源于stack exchange,提问作者EukkMaru

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 02:15:32