Windows 11 PeekMessage() not returning WM_KEYDOWN message

Hi. I'm having trouble with PeekMessage(). I use PeekMessage() in a loop inside my WM_PAINT procedure to consume messages generated during a long computation process, and to allow the user to abort the process by pressing ESCAPE. Here is a snippet of my code...

Code:
... Create several threads to do some lengthy work
        // Wait for all threads to terminate.
        for (;;)
        {
            // Wait for up to fifty milliseconds.
            if (WaitForMultipleObjects(Threads, phThreadArray, TRUE, 50) == WAIT_OBJECT_0) break;
            
            // Update the user about progress.
            int Slice = wq->getSlices();
            int iPercent = (int)((Slices - Slice) * 100.f / Slices + 0.5f);
            StringCchPrintf(szProgress, 100, _T("Slice: %d of %d (%d%%)"), Slices - Slice, Slices, iPercent);
            SetBkColor(dc, RGB(240, 240, 240));
            TextOut(dc, 16, 16, szProgress, lstrlen(szProgress));
            TextOut(dc, 16, 40, _T("Press ESC to abort"), 19);

            // Flush the message queue and check for abort request.
            MSG msg;
            if (!PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE)) continue; // Case of no message.
            TCHAR sz[50];
            StringCchPrintf(sz, 50, _T("%08x   %016x\n"), msg.message, msg.wParam);
            OutputDebugString(sz);
            if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE) bAbort = true;
        }
... Clean up and display results

I used OutputDebugString() to display the message code and wparam values. I never get a WM_KEYDOWN message (0x0100). I should, when I press ESCAPE during the lengthy execution. Any ideas? Thanks.
 
From your given code snippet, it seems like you're doing quite a bit in your WM_PAINT handling - including performing long computations and initiating multiple threads which, whilst possible, isn't generally advised.

However, I understand that this situation may require it, and I'll focus on the issue mentioned: PeekMessage() does not return WM_KEYDOWN (0x0100) in your debug output. There could be a few reasons for this:

1. **Message Loop Issue**: The most common reason is that the input messages(i.e., WM_KEYDOWN and WM_KEYUP) are being dispatched to the other part of your application.

Instead of `PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE)` which only checks messages for your concrete window, you could try changing this to `PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)` (NULL implies messages for any window belonging to the current thread), which checks all the thread's messages.

2. **Priority of Messages**: WM_PAINT is a low priority message. Windows ignores WM_PAINT message if there are other messages in the message queue for a particular application. And since you are running a loop for lengthy computations and thread waits inside WM_PAINT, there are chances that your WM_KEYDOWN is being overridden. You might want to reconsider this design approach.

3. **Keyboard Issue**: Check if ESCAPE key is working fine. Try with some other key for confirmation.

4. **Thread Issue**: You mentioned you're using threads. Depending on how this is implemented, there can be issues between threads and the Windows message pump which might cause messages to be lost.

Make sure your approach to threading in this case does not interfere with the message loop. If you're not very certain, you could try posting a minimum reproduction case so we can understand more fully where the issue may be coming from.

Let me know if these suggestions help.
 
From your given code snippet, it seems like you're doing quite a bit in your WM_PAINT handling - including performing long computations and initiating multiple threads which, whilst possible, isn't generally advised.

However, I understand that this situation may require it, and I'll focus on the issue mentioned: PeekMessage() does not return WM_KEYDOWN (0x0100) in your debug output. There could be a few reasons for this:

1. **Message Loop Issue**: The most common reason is that the input messages(i.e., WM_KEYDOWN and WM_KEYUP) are being dispatched to the other part of your application.

Instead of `PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE)` which only checks messages for your concrete window, you could try changing this to `PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)` (NULL implies messages for any window belonging to the current thread), which checks all the thread's messages.

2. **Priority of Messages**: WM_PAINT is a low priority message. Windows ignores WM_PAINT message if there are other messages in the message queue for a particular application. And since you are running a loop for lengthy computations and thread waits inside WM_PAINT, there are chances that your WM_KEYDOWN is being overridden. You might want to reconsider this design approach.

3. **Keyboard Issue**: Check if ESCAPE key is working fine. Try with some other key for confirmation.

4. **Thread Issue**: You mentioned you're using threads. Depending on how this is implemented, there can be issues between threads and the Windows message pump which might cause messages to be lost.

Make sure your approach to threading in this case does not interfere with the message loop. If you're not very certain, you could try posting a minimum reproduction case so we can understand more fully where the issue may be coming from.

Let me know if these suggestions help.
"ChatGPT"

1. I tried PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) and that did not help.

2. I could understand that, if the priority of WM_PAINT vs WM_KEYDOWN were reversed. If this were the issue, I would expect that WM_KEYDOWN would have priority over WM_PAINT. Besides, I have another program that checks for ESCAPE inside WM_PAINT and that program works fine. (Yes, I will compare and see if there is any remedy with the other paradigm. The other program does not use threads, so the wait loop is different.)

3. ESCAPE is working fine. I also checked with several other keys. I never get a WM_KEYDOWN message.

4. My threads don't do any GUI work at all. They only compute the pixels for the Mandelbrot set, using a memory based bitmap. After the wait loop is done, I BITBLT the bitmap to the DC for the window using SetDIBitsToDevice(). I do this in the main program thread.

My approach to threading is simple. I call CreateThread() 12 times, after filling a FIFO with slices to work on. The threads are initially stalled, waiting on a mutex to proceed. I release the mutex, and the threads take off. Then I enter the wait loop shown above.

I will review your suggestions. I will post new snippets if I need to. Again, thank you.
 
"ChatGPT"

1. I tried PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) and that did not help.

2. I could understand that, if the priority of WM_PAINT vs WM_KEYDOWN were reversed. If this were the issue, I would expect that WM_KEYDOWN would have priority over WM_PAINT. Besides, I have another program that checks for ESCAPE inside WM_PAINT and that program works fine. (Yes, I will compare and see if there is any remedy with the other paradigm. The other program does not use threads, so the wait loop is different.)

3. ESCAPE is working fine. I also checked with several other keys. I never get a WM_KEYDOWN message.

4. My threads don't do any GUI work at all. They only compute the pixels for the Mandelbrot set, using a memory based bitmap. After the wait loop is done, I BITBLT the bitmap to the DC for the window using SetDIBitsToDevice(). I do this in the main program thread.

My approach to threading is simple. I call CreateThread() 12 times, after filling a FIFO with slices to work on. The threads are initially stalled, waiting on a mutex to proceed. I release the mutex, and the threads take off. Then I enter the wait loop shown above.

I will review your suggestions. I will post new snippets if I need to. Again, thank you.
From the detailed explanation you provided, your threading model seems quite clear-cut and your outlined approach seems reasonable.

However, given the state of your problem, I have another couple of suggestions that might help to narrow down the issue:

1. **Correct Message Constants**: Just for sanity's check, you can look into VK_ESCAPE constant and WM_KEYDOWN message to check they are correct. VK_ESCAPE should be 0x1B and WM_KEYDOWN should be 0x0100.

2. **Keyboard Message Translation**: Generally, it's recommended to call `TranslateMessage` as well because some keyboard message translations need to happen.
```
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
}
```
3. **Check Message Queue State**: To better understand the current state of your message queue, refer to the GetMessage function. This function retrieves a message from the calling thread's message queue. The function dispatches incoming sent messages until a posted message is available for retrieval. This behavior can help you to debug your issue as well.

4. **Message Filtering**: When using `PeekMessage()`, you might require a more specific filter, say from WM_KEYFIRST to WM_KEYLAST, instead of 0, 0 which gets all windows messages.
Here is how you could tweak your existing code:
```cpp
if(PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
{
// Print / Handle message
}
```
5. **Collisions with System Level HotKeys**: Ensure that there are no collisions with system level hotkeys. For instance, does the keycode you're using conflict with any system-wide hotkeys?

Furthermore, could your application be losing focus for any reason, which might result in the WM_KEYDOWN events not being sent to it?

Hopefully, these suggestions will help you to isolate the problem you’re facing. If you should still have problems, please provide any new information you might find.
 
"ChatGPT"

1. I checked. VK_ESCAPE is 0x1B and WM_KEYDOWN is 0x0100.

2. I tried TranslateMessage(). It did not help. Besides, the docs say that TranslateMessage() directly sends the translated messages to the Windows Procedure.

3. I don't think GetMessage() would work. It does not return until there is a message. Besides, I think that would result in a deadlock situation as I'm already in a WM_PAINT handler.

4. I used WM_KEYFIRST, WM_KEYLAST in another program. It resulted in the Windows Display Manager marking my application as "non-responsive". Since I use 0,0 I remove all messages, and then filter with "if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE) bAbort = true;"

5. I don't think there is any conflict with System Level Hotkeys. I only use ESCAPE, without any Ctrl, Alt, or Shift modifier.

6. I don't think I have a focus problem. I thought about that and tried clicking on the window and then on the modeless dialog box berfore pressing ESCAPE. That did not change anything.

I still have some research to do. I'll do that and get back to you. Thank you.
 
This problem has been resolved. The solution involved replacing "PeekMessage(&msg, hWnd, WM_KEYFIRST, 0, 0, PM_REMOVE)" with "PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)". The reason I did not think it was the solution before was that I was also throwing an access exception (in a different part of my code) and I was confused as to it's source. Thank you.
 
Last edited:
Back
Top