7

Microsoft 不建议将 DirectInput 用于键盘和鼠标输入。因此,我编写了一个输入管理器类,它使用 SetWindowsHookEx 挂钩到 WndProc 和 GetMsg。我相信钩子设置得当,尽管它们看起来是各种问题的原因。

我的 WndProc 和 GetMsg 挂钩都不会收到实际 WndProc 正在接收的任何消息。我的输入管理器从未收到它需要的 WM_INPUT、WM_BUTTON WM_MOUSEWHEEL 和 WM_KEY* 消息。

是什么赋予了?

部分标题:

namespace InputManager
{
    class CInputManager
    {
        HWND m_Window;
        HHOOK m_WndProcHook;
        HHOOK m_GetMessageHook;
        static LRESULT CALLBACK WindowsProcedureHookProcedure(int Code, WPARAM WParameter, LPARAM LParameter);
        static LRESULT CALLBACK GetMessageHookProcedure(int Code, WPARAM WParameter, LPARAM LParameter);
        static LRESULT CALLBACK MessageHandler(HWND Window, UINT Message, WPARAM wParameter, LPARAM lParameter);
    };
}

部分来源:

namespace InputManager
{
    bool CInputManager::Initialize(HWND Window)
    {
        m_Window = Window;

        // Hook into the sent messages of the target window to intercept input messages.
        m_WndProcHook = SetWindowsHookEx(WH_CALLWNDPROC, &(WindowsProcedureHookProcedure), NULL, GetCurrentThreadId());
        // Hook into the posted messages of the target window to intercept input messages.
        m_GetMessageHook = SetWindowsHookEx(WH_GETMESSAGE, &(GetMessageHookProcedure), NULL, GetCurrentThreadId());

        // Register mouse device for raw input.
        RAWINPUTDEVICE RawInputDevice;
        RawInputDevice.usUsagePage = HID_USAGE_PAGE_GENERIC; 
        RawInputDevice.usUsage = HID_USAGE_GENERIC_MOUSE; 
        RawInputDevice.dwFlags = RIDEV_INPUTSINK;   
        RawInputDevice.hwndTarget = m_Window;
        return RegisterRawInputDevices(&(RawInputDevice), 1, sizeof(RawInputDevice));
    }

    void CInputManager::Shutdown()
    {
        // Unhook from the posted messages of the target window.
        UnhookWindowsHookEx(m_GetMessageHook);
        // Unhook from the sent messages of the target window.
        UnhookWindowsHookEx(m_WndProcHook);
    }

    LRESULT CALLBACK CInputManager::WindowsProcedureHookProcedure(int nCode, WPARAM wParameter, LPARAM lParameter)
    {
        if(nCode == HC_ACTION)
        {
            // Forward to message handler.
            CWPSTRUCT* Message = reinterpret_cast<CWPSTRUCT*>(lParameter);
            MessageHandler(Message->hwnd, Message->message, Message->wParam, Message->lParam);
        }
        return CallNextHookEx(NULL, nCode, wParameter, lParameter);
    }

    LRESULT CALLBACK CInputManager::GetMessageHookProcedure(int nCode, WPARAM wParameter, LPARAM lParameter)
    {
        if(nCode == HC_ACTION)
        {
            // Forward to message handler.
            CWPSTRUCT* Message = reinterpret_cast<CWPSTRUCT*>(lParameter);
            MessageHandler(Message->hwnd, Message->message, Message->wParam, Message->lParam);
        }
        return CallNextHookEx(NULL, nCode, wParameter, lParameter);
    }
}

我不包括消息处理程序的代码,因为它由 149 行组成,其中大部分是消息类型的开关。WndProc 中收到的消息值与我的回调中的不同。

4

3 回答 3

6

我似乎无法在您的原始问题下添加评论,这是我更愿意放置的地方,但是:

从你想要做的事情来看,WH_KEYBOARD 和 WH_MOUSE 钩子不是更合适吗?

于 2011-01-27T21:59:03.867 回答
5

我在这里参加聚会已经很晚了,但是我花了很多时间来解决同样的问题,希望其他人会发现这很有用。

我的经验结论是 DispatchMessage 不会触发 WH_CALLWNDPROC 钩子。换句话说,在线程的消息队列中发布并通过消息循环(GetMessage -> DispatchMessage)的消息将不会被WH_CALLWNDPROC 捕获。它只捕获使用 SendMessage 等直接发送到窗口过程的消息。当您查看文档时,它是这样说的:

与 SetWindowsHookEx 函数一起使用的应用程序定义或库定义的回调函数。系统在调用窗口过程处理发送给线程的消息之前调用该函数。

当然,WH_GETMESSAGE 钩子的情况正好相反。它将捕获已发布的消息,但不会捕获已发送的消息。要获取所有消息,您要么必须使用这两个钩子,要么使用子类化来直接钩子窗口过程:

WNDPROC realProc;
LRESULT CALLBACK hookProc(HWND h, UINT msg, WPARAM wp, LPARAM lp)
{
  return CallWindowProc(realProc, h, msg, wp, lp);
}
...
realProc = (WNDPROC)SetWindowLongPtr(hwnd, GWL_WNDPROC, (LONG_PTR)hookProc);

此外,OP 的 GetMessage 钩子不起作用的原因可能是因为lParameter应该转换为MSG*而不是CWPSTRUCT*.

于 2011-06-19T15:59:43.660 回答
0

我曾经遇到过类似的问题。我不太确定它是什么(我认为它在 PreTranslateMessage 的某个地方被消耗了,但我不知道)但我知道我是如何发现它的:

我自己创建了其中一条消失的消息,并通过 MFC 对其进行了调试。如果我没记错的话,我只是在某个地方返回了错误的布尔值。但是,这种方法可能会为您提供实际的线索。

于 2011-03-24T21:16:54.877 回答