基于GetMessage的窗口中鼠标静止时GetCursorPos失效问题
问题分析与解决
问题根源
改用GetMessage()后,当没有窗口消息时,线程会被阻塞挂起,主循环停在Broadcast()环节,不会执行PhaseUpdate()和Loop()——而你的鼠标位置获取逻辑是在这两个环节调用的,所以鼠标静止(无WM_MOUSEMOVE等消息)时,根本没机会调用GetMousePosition(),自然拿不到光标位置。
之前用PeekMessage()CPU占用高,是因为它非阻塞,会持续空转循环;窗口最小化时GPU负载降低,CPU空转的占比就会显得更高。
解决方案
需要结合阻塞等待与非阻塞消息处理,让线程在无消息时也能定期唤醒,执行输入检测和渲染逻辑。推荐两种实现方式:
方案1:使用MsgWaitForMultipleObjects()优化消息循环
修改Window::Broadcast(),让线程在等待消息时可定时唤醒,保证主循环持续运行:
#include <windows.h> void Window::Broadcast() { // 等待消息或1ms超时,确保循环能定期执行 DWORD result = MsgWaitForMultipleObjects(0, NULL, FALSE, 1, QS_ALLINPUT); if (result == WAIT_OBJECT_0 + 0) { // 批量处理待处理的消息 while (PeekMessageA(&msg, hWnd, NULL, NULL, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessageA(&msg); } } // 无消息时直接返回,让主循环继续执行PhaseUpdate和Loop }
这种方式既避免了空转导致的高CPU占用,又能保证即使没有鼠标消息,主循环每秒也能执行约1000次,GetMousePosition()可以被正常调用。
方案2:优化PeekMessage()的空闲处理
如果坚持使用PeekMessage(),可以在无消息时让线程短暂休眠,让出CPU资源:
void Window::Broadcast() { if (PeekMessageA(&msg, hWnd, NULL, NULL, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessageA(&msg); } else { // 无消息时休眠1ms,减少CPU空转 Sleep(1); // 窗口最小化时可延长休眠时间,比如Sleep(10),进一步降低占用 } }
额外建议
GetMousePosition()中的lastMousePos是成员变量,若输入系统存在多线程调用场景,需确保线程安全。- 可考虑将鼠标位置更新逻辑放到
WM_MOUSEMOVE消息处理函数中,配合定时检测,既能实时响应鼠标移动,又能在静止时保持最新位置。
内容的提问来源于stack exchange,提问作者Erkan Demirci
相关产品推荐
相关产品推荐

