cwindowswinapikeyboardmessage

Windows API: Why didn't PeekMessage get the keyboard event I want here?


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


Solution

  • 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.