GetQueueStatus and the queue state
Some time ago, we learned that the
MsgWaitForMultipleObjects function waits only for new events to arrive. In particular, this means that when
MsgWaitForMultipleObjects tells you that an event has arrived, you need to process all of those events before looping back and calling
MsgWaitForMultipleObjects again, because
MsgWaitForMultipleObjects isn’t going to tell you about those old events.¹
It so happens that the
GetQueueStatus function also manipulates the queue status. Each time you call
GetQueueStatus to check a flag, that flag is marked as no longer “new” in the queue status, in the same way that
MsgWaitForMultipleObjects marks the flag as no longer “new” when it wakes up due to a queue status change.
This behavior of
GetQueueStatus is very surprising, because you don’t expect a function called “Get” to have destructive side effects.
GetQueueStatus function returns the queue status in two forms, packed into a single 32-bit integer. The low-order 16 bits contain the new queue status bits (the queue status changes since the last time you asked about them), whereas the high-order 16 bits contain the cumulative queue status bits (all the status bits, both old and new). This is explained in the “Return value” section of the documentation, but it’s something that you may read without fully comprehending the consequences.
Therefore, if you want to know if there is (say) any raw input available, either old or new, you need to write
if (HIWORD(GetQueueStatus(QS_RAWINPUT)) & QS_RAWINPUT)
And if you want to drain the raw input, you should use a
while loop to keep processing the raw input until the bit goes clear in the high word.
The fact that
GetQueueStatus is a destructive operation is one of those hidden gotchas of the window manager. This sort of atomic “test and clear” operation is common inside the window manager, so they exposed a function that let applications do it too, using the same name that the window manager used internally, so you might say that this function was named while wearing window manager colored glasses: The fact that this is a “test and clear” function is obvious if you work on the window manager, and completely surprising if you don’t.
MsgWaitForMultipleObjectsEx function lets you pass the
MWMO_ flag to mean, “Also consider old events that haven’t yet been processed.”