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

基于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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 21:45:35