SDL_MOUSEMOTION event anomaly

Under Windows WM_MOUSEMOVE messages are removed from the message queue, when
they are at the new end of the queue and a new WM_MOUSEMOVE message is
posted.
That makes sense: there is not much use in knowing where the mouse was, when
newer information is available and removing those obsolete messages prevents
latency when processing mouse moves takes longer than the time between
generation of mouse moves.
The code that I use to drag frameless windows around the screen makes
essential use of this fact. When the mouse is down, on every mouse move
event, my code calculates and sets a new position for the window. This
SetWindowPos call generates a new mouse move event.
Now when I use the same code with SDL, the Windows WM_MOUSEMOVE messages are
moved very rapidly from the Windows message queue to the SDL event queue.
That means that when I move the window around very fast, Windows does not
get a chance to remove WM_MOUSEMOVE messages, the SDL event queue is flogged
with mouse motion events and the window starts lagging behind the mouse.
I fixed this behaviour with the following code in my application:

SDL_Event event;
while ( SDL_PollEvent(&event) ) {
switch (event.type) {
case SDL_MOUSEMOTION:
if (gView) {
SDL_Event theEvent;
static sRelX = 0;
static sRelY = 0;
if (SDL_PeepEvents(&theEvent, 1, SDL_PEEKEVENT, SDL_MOUSEMOTIONMASK))
{
/* ignore the current event, a newer one is waiting */
sRelX += event.motion.xrel;
sRelY += event.motion.yrel;
} else {
event.motion.xrel += sRelX;
event.motion.yrel += sRelY;
gView->HandleMouseMove (*gView, event.motion.x, event.motion.y);
sRelX = 0;
sRelY = 0;
}
}
break;

However I think it is worth considering to do this before events are put in
the queue in the first place. Of course such a consideration should take
into account how other platforms handle mouse moves internally.

Huib-Jan

I fixed this behaviour with the following code in my application:

SDL_Event event;
while ( SDL_PollEvent(&event) ) {
switch (event.type) {
case SDL_MOUSEMOTION:
if (gView) {
SDL_Event theEvent;
static sRelX = 0;
static sRelY = 0;
if (SDL_PeepEvents(&theEvent, 1, SDL_PEEKEVENT, SDL_MOUSEMOTIONMASK))
{
/* ignore the current event, a newer one is waiting */
sRelX += event.motion.xrel;
sRelY += event.motion.yrel;
} else {
event.motion.xrel += sRelX;
event.motion.yrel += sRelY;
gView->HandleMouseMove (*gView, event.motion.x, event.motion.y);
sRelX = 0;
sRelY = 0;
}
}
break;

However I think it is worth considering to do this before events are put in
the queue in the first place. Of course such a consideration should take
into account how other platforms handle mouse moves internally.

Yes, I considered doing this at one point, but it’s not always desirable
to skip motion that has occurred in the past. A good example of when you
want all motion, is drawing a curve with a paint program.

However, if only the current state concerns you, you can just get the
current mouse position with SDL_GetMouseState()

See ya,
-Sam Lantinga, Software Engineer, Blizzard Entertainment