C++ 当窗口焦点丢失时,SetWindowsHookEx停止接收WH_MOUSE_LL事件
我有一个SDL2程序,可以打开SDL窗口。在C++ 当窗口焦点丢失时,SetWindowsHookEx停止接收WH_MOUSE_LL事件,c++,winapi,hook,C++,Winapi,Hook,我有一个SDL2程序,可以打开SDL窗口。在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, LP
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\u MOUSE\u LL
事件
编辑:
事实证明,
SetWindowsHookEx
仅当窗口焦点丢失到以管理员身份启动的另一个窗口时,才停止接收事件更新,而此程序的SDL2窗口是以普通用户身份启动的。一旦当前程序以管理员身份启动,即使窗口焦点丢失,所有更新也会继续进入(使用上述代码)。因此,这不是问题。不需要关注,但需要持续发送消息
下面是一个带有低级钩子的迷你Win32窗口应用程序,您可以参考它。它将在与调用线程在同一桌面上运行的所有现有线程中接收WM_MOUSEMOVE消息,而不管哪个窗口保持焦点
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HC_ACTION)
{
auto& ms = *(const MOUSEHOOKSTRUCT*)lParam;
if (wParam == WM_MOUSEMOVE)
{
OutputDebugString(L"\n WM_MOUSEMOVE \n");
OutputDebugStringA(to_string(counter++).c_str());
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hWnd, message, wParam, lParam);
}
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
HHOOK hMSHook = SetWindowsHookEx(WH_MOUSE_LL, MouseProc, NULL, NULL);
WNDCLASSEXW wcex = {0};
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpfnWndProc = WndProc;
wcex.hInstance = hInstance;
wcex.lpszClassName = szWindowClass;
RegisterClassExW(&wcex);
HWND hWnd = CreateWindowW(szWindowClass, L"test", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
对于低级钩子,
SetWindowsHookEx()
的hMod
参数应该为NULL,而不是hInstance
。文档甚至声明:“如果钩子子程在与当前进程相关联的代码中,HMOD参数必须设置为NUL[…]”,也就是说,考虑使用“代替代码> SETWOWOSWOKEX())< /C>。文档甚至指出:“在大多数情况下,应用程序需要使用低级钩子,它应该监视原始输入。”@RemyLebeau感谢您指出这一点。我在我的代码和上面的问题中解决了这个问题。不幸的是,SetWindowsHookEx()
在窗口焦点丢失时未接收事件的问题仍然存在。安装挂钩的线程是否有消息循环?低级钩子事件在安装线程中运行(这就是为什么钩子其他应用程序时原始输入更有效),因此线程需要进行消息处理。@RemyLebeau没有,因为GetMessage
正在阻塞,而有一个循环来执行其他功能。我不知道如何合并这两个。。。不幸的是,我对原始输入不太熟悉,无法让它执行等效的操作。我看到这段代码创建了一个新窗口,并且有一个阻塞的主消息循环。在我的例子中,我使用SDL2创建一个窗口,为了使用SDL功能,我使用了一个不同的滚动周期更新循环。是否有方法为现有窗口设置属性,以便在焦点丢失后继续接收消息?您的代码的哪一行具体确保了该属性?@Kagaratsch因为GetMessage是阻塞的,如果当窗口失去焦点时GetMessage()
无法连续执行,如果这是真的,我们需要找到GetMessage()
阻塞的原因。