使用 Windows 钩子的 C++ 自定义热键

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8698616/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 18:46:35  来源:igfitidea点击:

C++ Custom hot keys using windows hooks

c++windowshook

提问by user781439

I want to make some custom hot keys where in any program I can bring up different programs with certain key combinations. I researched how to do hooks and was given this example.

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

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;
}

Rather than a message box, as I want this to run in the background, I tried using loops but nothing I have tried successfully behaves like the messagebox. Any ideas?

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

采纳答案by ybungalobill

Don't use windows hooks unless you absolutely need to. In your case you can install a hotkey by calling the RegisterHotKeyfunction, which is much simpler since you don't need to develop interprocess communication (that is between your DLL with the hook procedure and your main app).

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

回答by Software_Designer

This good code below is a Hotkey app that sits in the background listening for the CTRL-ykey combination, and you can modify or add any more key combinations to the app. Use CTRL-qto exit the app when hidden.

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

If you wish to fully hide the console window, then un-comment this line in main() : //ShowWindow(FindWindowA("ConsoleWindowClass", NULL), false). Enjoy.

如果你想完全隐藏控制台窗口,然后取消注释在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;
}

Full code listing:

完整代码清单:

#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;

}

回答by Motes

"This hook is called in the context of the thread that installed it. The call is made by sending a message to the thread that installed the hook. Therefore, the thread that installed the hook must have a message loop." - LowLevelKeyboardProc MSDN

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

You need to create an invisible window.

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

回答by Some programmer dude

I'm not sure, but instead of a normal empty infinite loop, you might need to have a complete message loop. Especially if you use the RegisterHotKey function as suggested by ybungalobill.

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