【问题标题】:C++ Custom hot keys using windows hooks使用 Windows 挂钩的 C++ 自定义热键
【发布时间】:2012-01-02 07:58:03
【问题描述】:

我想制作一些自定义热键,在任何程序中我都可以使用某些组合键调出不同的程序。我研究了如何做钩子并给出了这个例子。

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
    // Set windows hook
    HHOOK keyboardHook = SetWindowsHookEx(
        WH_KEYBOARD_LL,
        keyboardHookProc,
        hInstance,
        0);
    MessageBox(NULL, "Press OK to stop hot keys", "Information", MB_OK);
    return 0;
}

而不是消息框,因为我希望它在后台运行,所以我尝试使用循环,但我成功尝试过的所有行为都不像消息框。有什么想法吗?

【问题讨论】:

    标签: c++ windows hook


    【解决方案1】:

    下面这个好代码是一个 Hotkey 应用程序,它位于后台监听 CTRL-y 组合键,您可以修改或向应用程序添加更多组合键。隐藏时使用CTRL-q退出应用。

    如果您希望完全隐藏控制台窗口,请在 main() 中取消注释此行://ShowWindow(FindWindowA("ConsoleWindowClass", NULL), false)。享受吧。

    if (CTRL_key !=0 && key == 'y' )
    {
       MessageBox(NULL, "CTRL-y was pressed\nLaunch your app here", "H O T K E Y", MB_OK); 
       CTRL_key=0;
    }
    

    完整代码清单:

    #define _WIN32_WINNT 0x0400
    #pragma comment( lib, "user32.lib" )
    
    #include <windows.h>
    #include <stdio.h>
    
    HHOOK hKeyboardHook;
    
    __declspec(dllexport) LRESULT CALLBACK KeyboardEvent (int nCode, WPARAM wParam, LPARAM lParam)
    {
        DWORD SHIFT_key=0;
        DWORD CTRL_key=0;
        DWORD ALT_key=0;
    
        if  ((nCode == HC_ACTION) &&   ((wParam == WM_SYSKEYDOWN) ||  (wParam == WM_KEYDOWN)))      
        {
            KBDLLHOOKSTRUCT hooked_key =    *((KBDLLHOOKSTRUCT*)lParam);
            DWORD dwMsg = 1;
            dwMsg += hooked_key.scanCode << 16;
            dwMsg += hooked_key.flags << 24;
            char lpszKeyName[1024] = {0};
            lpszKeyName[0] = '[';
    
            int i = GetKeyNameText(dwMsg,   (lpszKeyName+1),0xFF) + 1;
            lpszKeyName[i] = ']';
    
            int key = hooked_key.vkCode;
    
            SHIFT_key = GetAsyncKeyState(VK_SHIFT);
            CTRL_key = GetAsyncKeyState(VK_CONTROL);
            ALT_key = GetAsyncKeyState(VK_MENU);
    
            if (key >= 'A' && key <= 'Z')   
            {
    
                if  (GetAsyncKeyState(VK_SHIFT)>= 0) key +=32;
    
                if (CTRL_key !=0 && key == 'y' )
                {
                   MessageBox(NULL, "CTRL-y was pressed\nLaunch your app here", "H O T K E Y", MB_OK); 
                   CTRL_key=0;
                }
    
                if (CTRL_key !=0 && key == 'q' )
                {
                    MessageBox(NULL, "Shutting down", "H O T K E Y", MB_OK); 
                   PostQuitMessage(0);
                }
    
    
    
    
                printf("key = %c\n", key);
    
                SHIFT_key = 0;
                CTRL_key = 0;
                ALT_key = 0;
    
            }
    
            printf("lpszKeyName = %s\n",  lpszKeyName );
        }
        return CallNextHookEx(hKeyboardHook,    nCode,wParam,lParam);
    }
    
    void MessageLoop()
    {
        MSG message;
        while (GetMessage(&message,NULL,0,0)) 
        {
            TranslateMessage( &message );
            DispatchMessage( &message );
        }
    }
    
    DWORD WINAPI my_HotKey(LPVOID lpParm)
    {
        HINSTANCE hInstance = GetModuleHandle(NULL);
        if (!hInstance) hInstance = LoadLibrary((LPCSTR) lpParm); 
        if (!hInstance) return 1;
    
        hKeyboardHook = SetWindowsHookEx (  WH_KEYBOARD_LL, (HOOKPROC) KeyboardEvent,   hInstance,  NULL    );
        MessageLoop();
        UnhookWindowsHookEx(hKeyboardHook);
        return 0;
    }
    
    int main(int argc, char** argv)
    {
        HANDLE hThread;
        DWORD dwThread;
    
        hThread = CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)   my_HotKey, (LPVOID) argv[0], NULL, &dwThread);
    
        //ShowWindow(FindWindowA("ConsoleWindowClass", NULL), false);
    
        if (hThread) return WaitForSingleObject(hThread,INFINITE);
        else return 1;
    
    }
    

    【讨论】:

      【解决方案2】:

      除非绝对需要,否则不要使用 Windows 挂钩。在您的情况下,您可以通过调用RegisterHotKey function 来安装热键,这要简单得多,因为您不需要开发进程间通信(即在您的带有钩子过程的 DLL 和您的主应用程序之间)。

      【讨论】:

      • 但作为一名开发人员,我不明白为什么 MessageBox 会起作用而不是一段时间(true){}?我一定会研究 RegisterHotKey,只是出于好奇想知道。
      • @user781439:因为 MessageBox 在内部运行消息循环。
      【解决方案3】:

      “这个钩子在安装它的线程的上下文中被调用。调用是通过向安装钩子的线程发送消息来进行的。因此,安装钩子的线程必须有一个消息循环。” - LowLevelKeyboardProc MSDN

      你需要创建一个不可见的窗口。

      【讨论】:

        【解决方案4】:

        我不确定,但您可能需要一个完整的消息循环,而不是正常的空无限循环。特别是如果您按照 ybungalobill 的建议使用 RegisterHotKey 函数。

        【讨论】:

          猜你喜欢
          • 2018-12-01
          • 2010-12-07
          • 2014-08-23
          • 2020-04-07
          • 2022-01-27
          • 2021-12-07
          • 1970-01-01
          • 1970-01-01
          • 2016-08-08
          相关资源
          最近更新 更多