Faster is not always better

At the beginning I would like to clarify on details of Windows message queue. Many people believe that InvalidateRect function (or any other action that makes your window have update region) will actually post WM_PAINT message into message queue. Similarly, they believe that any mouse movement will leads to insert of WM_MOUSEMOVE (and corresponding messages like WM_HCHITTEST). But in reality, it is quite different (unless there is call to PeekMessage with PM_NOREMOVE). It is not important from processing these messages but very important to understand these details to troubleshoot any problems.

When part of window is invalidated Windows will simply set flag that indicates that window needs painting and that’s it. There is nothing inserted at message queue at all. As result, application can invalidate many different regions of window and there will be only one WM_PAINT message. This is quite clever as implementation is really fast and requires no memory.

The same applies to mouse. When you move mouse, driver notifies Windows periodically that position of mouse is changed and Windows sets global flag. When application calls one of the functions that receive messages (GetMessage, PeekMessage etc) Windows will check that flag and if it is set, it will process that message. And result is similar as with WM_PAINT – if you move mouse a lot but didn’t process messages then application will receive only one WM_MOUSEMOVE. Again, this is really simple and clever implementation that performs really well.

And messages have priority. For example: WM_PAINT have less priority than WM_MOUSEMOVE so if you move mouse before call GetMessage then WM_PAINT will never be returned. Another example: WM_TIMER has lower priority than WM_PAINT, so if there is always invalid region then GetMessage will never return WM_TIMER.

Ok, enough with explanations and let’s talk about problem.

Normally mouse reports position changes about 125 times per second and mouse resolution is not that high. So even for say 10 years old computer it should be able to process mouse message 125 times per second and will stay idle 99% of the time.

But these days there are a lot of mice with high precision and high report rate. Most of them can do 1000 reports per second. And if you move such kind of mouse then windows procedure should finish processing of mouse event in 1ms or else WM_PAINT will never be delivered because there will be new WM_MOUSEMOVE event and then another and so on. And if your application will not get WM_PAINT event than content of your window will not update or update after some delay and your application will feel laggy and unresponsive.

And tricky part that this happens only under “high mouse load”. As soon as you slow down mouse movement just little bit and everything will get back to normal. As you could imaging this is quite hard to reproduce and diagnose because there are millions of reasons why mouse event processing took over 1ms. But I hope now it will be a bit easier. And also, very often people who will try to reproduce this problem will have typical mouse and they will not able to reproduce that problem because it requires faster mouse. So, if you are developing software that heavily works with mouse, I would recommend getting that kind of mouse and put report rate as high as possible. Perhaps it is good idea to have QA to have similar mouse at least for some of the team.

I hope it helps someone.