Windows 11下Raw Input API鼠标性能远低于Windows 10的修复咨询
Windows 11下Raw Input API鼠标性能远低于Windows 10的修复咨询
我之前也踩过Win11上Raw Input鼠标刷新率骤降的坑,你的代码逻辑本身没大问题,但Win11对Raw Input的事件调度和消息合并做了针对性优化,导致单条WM_INPUT的处理方式被系统限制了。下面结合你的代码给出亲测有效的修复方案:
问题根源
Win11为了降低消息队列的资源消耗,会把短时间内的多个Raw Input鼠标事件合并成少量WM_INPUT消息投递——1000Hz的鼠标每秒产生1000次采样,合并后就只剩约128条消息,直接导致你感知到的刷新率暴跌。另外你注册设备时用的RIDEV_CAPTUREMOUSE标志,在Win11下会进一步加剧这个事件合并的行为。
具体修复步骤
1. 调整Raw Input设备注册的标志
先修改你的_RegisterRawMouse函数,移除会触发事件合并的RIDEV_CAPTUREMOUSE标志,换用更适合全局捕获的组合:
static int _RegisterRawMouse(HWND hwnd) { RAWINPUTDEVICE rid[1] = {}; rid[0].usUsagePage = 0x01; rid[0].usUsage = 0x02; // 移除RIDEV_CAPTUREMOUSE,保留RIDEV_NOLEGACY避免 legacy 消息干扰,RIDEV_INPUTSINK保证全局捕获 rid[0].dwFlags = RIDEV_NOLEGACY | RIDEV_INPUTSINK; rid[0].hwndTarget = hwnd; if (!RegisterRawInputDevices(rid, 1, sizeof(RAWINPUTDEVICE))) { return 1; } return 0; }
2. 改用缓冲读取替代单消息处理
Win11下依赖WM_INPUT逐个处理事件的方式已经不可靠,我们需要用GetRawInputBuffer批量读取设备缓冲区里的所有积压事件,绕过消息队列的投递限制。修改你的主消息循环:
首先定义一个足够容纳高频率事件的缓冲区:
#define RAW_MOUSE_BUFFER_SIZE 64 // 1000Hz下每秒1000次采样,64的缓冲区足够处理短时间积压
然后调整主循环逻辑,在处理常规消息后主动读取缓冲的鼠标事件:
MSG msg = {}; while (true) { // 先处理常规消息队列 while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) { return (int)msg.wParam; } TranslateMessage(&msg); DispatchMessage(&msg); } // 主动读取Raw Input缓冲中的所有鼠标事件 RAWINPUT rawBuffer[RAW_MOUSE_BUFFER_SIZE]; UINT bufferSize = sizeof(rawBuffer); UINT eventCount = GetRawInputBuffer(rawBuffer, &bufferSize, sizeof(RAWINPUTHEADER)); if (eventCount > 0 && eventCount != (UINT)-1) { _MouseData md = mousedata.load(); for (UINT i = 0; i < eventCount; i++) { RAWINPUT* raw = &rawBuffer[i]; if (raw->header.dwType == RIM_TYPEMOUSE) { md.dx += raw->data.mouse.lLastX; md.dy += raw->data.mouse.lLastY; md.dw += (*(short*)&raw->data.mouse.usButtonData) / WHEEL_DELTA; md.tick += 1; } } mousedata.store(md); // 调试用:printf("Total Tick: %i, Cumulative X: %i\n", md.tick, md.dx); } // 这里放置你的主循环业务逻辑(如渲染、状态更新等) }
3. 可选:优化原代码的内存分配(非核心但建议做)
你原代码在WM_INPUT里每次动态分配内存的方式,高频率下会产生内存碎片,改成预先分配的缓冲区或者栈内存会更高效,不过这不是影响刷新率的核心问题,可以后续优化。
方案原理
- 移除
RIDEV_CAPTUREMOUSE后,Win11不会再主动合并Raw Input鼠标事件,所有采样会被缓冲到设备专属队列中 GetRawInputBuffer直接从硬件缓冲区读取所有未处理事件,绕过了消息队列的投递限制,能完整获取1000Hz下的所有采样- 主动读取的方式不受Win11后台程序消息优先级的影响,即使程序在后台也能保持满刷新率
修改后你可以通过md.tick的增长速度验证:每秒应该能达到约1000次,和Win10下的表现完全一致。如果还有异常,建议检查Win11鼠标设置(关闭“提高指针精确度”),或者暂时禁用鼠标厂商的自定义驱动,用系统默认驱动测试是否是驱动层面的限制。




