I am writing a program which responds to the Alt+B keyboard shortcut from the user. The program keeps printing the current time and Alt+B toggles the colour of the text printed.
I try to use PeekMessage
to get the keyboard event and make the shortcut Alt+B
work. However, it doesn't work, the keyboard shortcut Alt+B has no effect.
Why is that? I am so puzzled.
The following is my code:
#include <stdio.h>
#include <windows.h>
void scta(WORD attributes)
{
SetConsoleTextAttribute (GetStdHandle(STD_OUTPUT_HANDLE), attributes);
}
void rcta(void)
{
scta(FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN);
}
void msgupd(BOOL *hotkey)
{
MSG msg={0};
if(!PeekMessage(&msg,NULL,0,0,PM_REMOVE|PM_QS_INPUT))
return;
if(msg.message == WM_HOTKEY)
{
*hotkey=!*hotkey;
if(*hotkey)
scta(FOREGROUND_GREEN | FOREGROUND_INTENSITY);
else
rcta();
}
}
int main()
{
RegisterHotKey(NULL,1,MOD_ALT|MOD_NOREPEAT,0x42);
BOOL hotkey=FALSE;
while(1)
{
msgupd(&hotkey);
SYSTEMTIME st;
GetSystemTime(&st);
printf ("\r%02d:%02d:%02d.%03d", (int)st.wHour, (int)st.wMinute, (int)st.wSecond, (int)st.wMilliseconds);
}
}
The msgupd
function probes the keyboard shortcut and updates a variable HOTKEY
, which indicates whether the printed text should be with colour.
The variable HOTKEY
is initially FALSE
, and Alt+B toggles it. However, as mentioned before, I didn't succeed in implementing this function. I don't know
why PeekMessage
doesn't work.
The scta()
function is a shortcut for SetConsoleTextAttribute
,
changing the colour of the printed text.
The rcta()
function resets the effect of scta()
.
I have tried changing PeekMessage
with GetMessage
, and I did receive a keyboard message from that. But the problem is that GetMessage
is synchronous, so my code stops printing the time text.
I think it is possible to move the time-printing part into
a new thread, so that GetMessage
would be good, but I think it is much more complex than using PeekMessage
.
UPDATE: The magic number 0x42 in RegisterHotKey
is 'b' for Alt+B.
Documents I have read:
https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-peekmessagea
https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerhotkey
Removing |PM_QS_INPUT
solves the problem.
I thought PM_QS_INPUT
includes the hotkey events but it's actually
not. In the microsoft document of PeekMessage, PM_QS_POSTMESSAGE
is defined
as (QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER) << 16
, while PM_QS_INPUT
as QS_INPUT
. That is, QS_HOTKEY and QS_INPUT are different things. The document of GetQueueStatus further illustrates that.
Therefore, by designating PM_QS_INPUT, QS_HOTKEY events are filtered 'as told'. That's why my PeekMessage failed to get the hotkey event.