【问题标题】:Low-level keyboard hook: callback not reached低级键盘挂钩:未达到回调
【发布时间】:2011-07-18 23:41:37
【问题描述】:

我正在尝试创建一段快速代码来捕获由平板电脑上的一个“热键”按钮发送的按键序列并重新编程其功能。该按钮在按下时会发送一个 LWin+LCtrl+Tab。

搜索了一段时间后,我决定尝试使用 WH_KEYBOARD_LL 挂钩,但几个小时后,我仍然无法让挂钩工作,更不用说实际功能了。

目前,我有以下内容:

// TestHook2.cpp

#include "stdafx.h"

HHOOK hook;
BOOL gotKey;
LRESULT WINAPI KeyTrap(int, WPARAM, LPARAM);
BOOL CtrlHandler(DWORD);

int _tmain(int argc, _TCHAR* argv[])
{
    SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE);
    HMODULE currentProcess = GetModuleHandle(NULL);
    hook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyTrap, currentProcess, 0);

    if (!hook) {
        printf("No hook, quitting!\n");
        return 1;
    }

    while(1) {
        if(gotKey) printf("Got Key!\n");
        gotKey = FALSE;
    }

    return 0;
}

LRESULT CALLBACK KeyTrap(int nCode, WPARAM wParam, LPARAM lParam)
{
    gotKey = TRUE;
    return  CallNextHookEx(hook, nCode, wParam, lParam);
}

BOOL CtrlHandler(DWORD fdwCtrlType)
{
    if (fdwCtrlType == CTRL_C_EVENT)
    {
        printf("Got CTRL+C, unhooking...\n");
        UnhookWindowsHookEx(hook);
    }

    return FALSE;
}

SetWindowsHookEx 返回的句柄绝对不是 NULL,但出于某种原因,无论我尝试按下多少个键,都不会调用 KeyTrap。我还尝试将回调放在 DLL 中并在运行时使用 LoadLibrary,但这也给出了完全相同的结果。

我是所有这些 Win32 编程的新手,所以这很可能是一个非常愚蠢的错误。

非常感谢!

(PS:代码在 Win7 上运行。目前无法访问实际键盘,但已尝试从屏幕键盘、远程 (RDP) 输入和平板电脑上的硬件热键生成击键。这可能是问题?)

【问题讨论】:

    标签: c++ winapi keyboard-hook


    【解决方案1】:

    问题在于您的控制台应用程序没有消息循环来处理挂钩消息。

    用以下代码替换您的 while(1) 循环,看看是否可行:

       MSG msg;
       while( GetMessage( &msg, NULL, 0, 0 ) != 0 ) 
       {
          TranslateMessage( &msg );
          DispatchMessage( &msg );
    
          if(gotKey) 
            printf("Got Key!\n");        
    
          gotKey = FALSE;
       }
    

    【讨论】:

    • 刚刚试了一下,似乎没有帮助。我以为通过将函数句柄注册到 SetWindowsHookEx,Windows 会在引发事件时直接调用该函数,这样就不需要消息循环了吗?还是我误会了什么?
    • 您误解了消息循环是低级键盘挂钩的硬性要求。当您的代码在 while(1) 循环中刻录 cpu 内核时,Windows 没有其他机制可以调用函数。
    • 根据 MSDN -“这个钩子是在安装它的线程的上下文中调用的。调用是通过向安装钩子的线程发送消息来进行的。因此,安装钩子的线程钩子必须有一个消息循环。”
    • 看来问题在于我创建了一个“Win32 控制台应用程序”,它使用 _tmain 作为入口点而不是 APIENTRY WinMain,因此应用程序没有收到任何消息。创建了一个新项目作为适当的 Win32 应用程序,现在它正在获取所有消息。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-08
    • 1970-01-01
    相关资源
    最近更新 更多