user781439
user781439

Reputation: 257

C++ Custom hot keys using windows hooks

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?

Upvotes: 4

Views: 7098

Answers (4)

Software_Designer
Software_Designer

Reputation: 8587

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

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

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;

}

Upvotes: 7

Motomotes
Motomotes

Reputation: 4237

"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

You need to create an invisible window.

Upvotes: 1

Some programmer dude
Some programmer dude

Reputation: 409166

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.

Upvotes: 0

Yakov Galka
Yakov Galka

Reputation: 72469

Don't use windows hooks unless you absolutely need to. In your case you can install a hotkey by calling the RegisterHotKey function, 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).

Upvotes: 3

Related Questions