【发布时间】:2021-02-03 19:33:27
【问题描述】:
我有一个打开 SDL 窗口的 SDL2 程序。在main 中,我为鼠标事件创建了一个钩子
hMSHook = SetWindowsHookEx(WH_MOUSE_LL, MouseProc, NULL, NULL);
在main 之外我有自定义鼠标事件处理程序
HHOOK hMSHook;
int xPosAbsolute = 0;
int yPosAbsolute = 0;
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HC_ACTION)
{
auto &ms = *(const MOUSEHOOKSTRUCT *)lParam;
if (wParam == WM_MOUSEMOVE)
{
xPosAbsolute = ms.pt.x;
yPosAbsolute = ms.pt.y;
}
}
return CallNextHookEx(hMSHook, nCode, wParam, lParam);
}
当窗口处于焦点时,鼠标坐标xPosAbsolute 和yPosAbsolute 会随着鼠标移动而正确更新。但是,如果另一个窗口获得焦点,这些变量将停止更新。
我的问题是,我如何让SetWindowsHookEx() 在我的窗口未聚焦时继续接收WH_MOUSE_LL 事件?
编辑:
实际上,事实证明,SetWindowsHookEx 仅在窗口焦点丢失到另一个以管理员身份启动的窗口时才停止接收事件更新,而该程序的 SDL2 窗口以普通用户身份启动。一旦当前程序也以管理员身份启动,所有更新都会继续进来(使用上面的代码),即使窗口焦点丢失。所以结果证明这不是问题。
【问题讨论】:
-
对于低级挂钩,
SetWindowsHookEx()的hMod参数应该为 NULL,而不是hInstance。SetWindowsHookEx()文档甚至指出:“hMod 参数必须设置为 NULL [...] 如果挂钩过程在与当前进程关联的代码内。” -
话虽如此,请考虑使用Raw Input API 而不是
SetWindowsHookEx()。LowLevelMouseProc()文档甚至指出:“在应用程序需要使用低级挂钩的大多数情况下,它应该监控原始输入。” -
@RemyLebeau 感谢您指出这一点。我在我的代码和上面的问题中解决了这个问题。不幸的是,当窗口焦点丢失时
SetWindowsHookEx()未接收事件的问题仍然存在。 -
安装钩子的线程是否有消息循环?低级别的钩子事件在安装线程中运行(这就是为什么 Raw Input 在钩子其他应用时效率更高的原因),因此线程需要有消息处理。
-
@RemyLebeau 它没有,因为
GetMessage是阻塞的,而有一个循环来执行其他功能。我不确定如何将两者合并...不幸的是,我对原始输入不够熟悉,无法让它做同样的事情。