Sign in to follow this  
floatingwoods

Hotkey for a console application

Recommended Posts

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?

Share this post


Link to post
Share on other sites
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..

Share this post


Link to post
Share on other sites
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;
}

Share this post


Link to post
Share on other sites
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).

Share this post


Link to post
Share on other sites
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);
}



Share this post


Link to post
Share on other sites
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:

[i]MOD_WIN[i]
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 :)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this