C++ 当窗口焦点丢失时,SetWindowsHookEx停止接收WH_MOUSE_LL事件

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

我有一个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, 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()
阻塞的原因。