Hotkey for a console application

Started by
6 comments, last by NisseBosseLasse 14 years, 10 months ago
Hello, I am trying to monitor a specific key combination in order to perform some tasks in my console application (from within the console application, I want to listen to a specific hotkey stroke, even if the console application doesn't have the focus). I am using (trying to use!) a keyboard hook for that. This is what I have so far, but the hook seems to be non-operational somehow: Hook function:

LRESULT keyboardHook(INT nCode,WPARAM wParam,LPARAM lParam)
{
	std::cout << "HOOK!!\n";
	return(CallNextHookEx(hhook, nCode, wParam, lParam));
}

Hook initialization:

	hhook = SetWindowsHookEx(WH_KEYBOARD_LL,(HOOKPROC)keyboardHook,::GetModuleHandle(NULL),0);

The hhook pointer is non-NULL which makes me think the hook was installed correctly. However the keyboardHook function doesn't print anything. What am I doing wrong?
Advertisement
Maybe you can use RegisterHotKey, and listen to WM_HOTKEY-notifications?
Thanks NisseBosseLasse,

Actually I also tried that with following code:

		MSG aMessage;		while (true)		{			if (PeekMessage(&aMessage,GetConsoleWindow(),0,0,PM_NOREMOVE)==0)				break;			if (aMessage.message==WM_HOTKEY)			{				PeekMessage(&aMessage,GetConsoleWindow(),0,0,PM_REMOVE);				std::cout << "HOTKEY!!!\n";				break;			}			std::cout << "MESSAGE!!!\n";			TranslateMessage(&aMessage);			DispatchMessage(&aMessage);		}


But it seems I cannot intercept messages to the console somehow (PeekMessage always returns 0)

EDIT: from what I read, it seems that console messages cannot be intercepted..
You don't need to peek into that window for retrieving that message (I believe) - just use NULL instead of GetConsoleWindow().

Here's an example I wrote (using Unicode-character set, Windows subsystem). It allocates a console, registers a hotkey (CTRL+B), and goes into its message loop.
Switch to any other window and press CTRL+B. Text will pop up in the console window (as well as a message box, but that's just because we don't want the console window to disappear since the program ends when CTRL+B is pressed).
#define WIN32_LEAN_AND_MEAN#include <windows.h>#include <string>using std::wstring;void ConPrint(const wstring &text){	const wstring text_nl = text + L"\n";	DWORD written = 0;	WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),		text_nl.c_str(),		text_nl.length(),		&written,		NULL);}int __stdcall WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show){	// Start up	AllocConsole();	ConPrint(L"--- Start up ---");	// Register hot key (CTRL+B in this case)	if (RegisterHotKey(NULL, 1, MOD_CONTROL, 'B'))	{		ConPrint(L"Hotkey registration succeeded.");	}	else	{		ConPrint(L"Hotkey registration failed, exiting...");		MessageBox(NULL,			L"Pressing OK will close the console...",			L"Hotkey example", 			MB_OK | MB_ICONINFORMATION);		FreeConsole();		return -1;	}	// Main loop	MSG msg = {0};	while (GetMessage(&msg, NULL, 0, 0) != 0)	{		TranslateMessage(&msg);		DispatchMessage(&msg);		// We got a hotkey message!		if (msg.message == WM_HOTKEY)		{			ConPrint(L"Nice, CTRL+B pressed! Exiting...");			break;		}		else if (msg.message == WM_QUIT)		{			break;		}	}	// Clean up	ConPrint(L"--- Closing ---");	UnregisterHotKey(NULL, 1);		MessageBox(NULL,		L"Pressing OK will close the console...",		L"Hotkey example",		MB_OK | MB_ICONINFORMATION);	FreeConsole();	return 0;}
Thanks again NisseBosseLasse,

I tried your example and the same thing happens (or doesn't happen!): I can't get any message with "GetMessage" or "PeekMessage". The only difference is that I am using the default console (i.e. I created a console project).
Did you replace GetConsoleWindow() with NULL? I.e.

PeekMessage(&aMessage, NULL, 0, 0, PM_NOREMOVE);
Actually, yes, here is what I have:

		RegisterHotKey(NULL,1,MOD_WIN,'a');		MSG aMessage;		while (true)		{			if (PeekMessage(&aMessage,NULL,0,0,PM_NOREMOVE)==0)				break;			if (aMessage.message==WM_HOTKEY)			{				PeekMessage(&aMessage,NULL,0,0,PM_REMOVE);				std::cout << "HOTKEY!!!\n";				break;			}			std::cout << "MESSAGE!!!\n";			TranslateMessage(&aMessage);			DispatchMessage(&aMessage);		}
Ok, I've tested your code and believe there two potential pitfalls here:
1) the use of PeekMessage isn't right
2) you're not checking the result code from RegisterHotKey()

I rewrote your code slightly and ended up with this:
MSG aMessage = {0};PeekMessage(&aMessage, NULL, 0, 0, PM_NOREMOVE);while (aMessage.message != WM_QUIT){	if (PeekMessage(&aMessage, NULL, 0, 0, PM_REMOVE) != 0)	{		switch (aMessage.message)		{			case WM_HOTKEY:				ConPrint(L"Hotkey!");				break;			default:				break;		}	}	else	{		// Do other stuff not related to messages	}}


This works, but then I noticed your register MOD_WIN + 'a' as your hotkey (I've used CTRL+B all the time). When I changed to MOD_WIN, I got an error from RegisterHotKey (zero as result).
MSDN states:
Quote:
MOD_WIN
Either WINDOWS key was held down. These keys are labeled with the Microsoft Windows logo. Keyboard shortcuts that involve the WINDOWS key are reserved for use by the operating system.

GetLastError returned code 1409: "Hot key is already registered."
So you can't register hotkeys with the Windows-key.


Nevermind, it was mine code that was faulty! I registered MOD_WIN + 'b', which was taken. But MOD_WIN + 'a' actually works :)

This topic is closed to new replies.

Advertisement