Throttle beginDragAutoRepeat() on Windows


#1

I have an issue where if 1000s of objects are selected, beginDragAutoRepeat() sends me mouseDrag messages faster than I can process them, causing my app to be processing mouse drag messages for minutes after mouse button is released. Is there any way to throttle beginDragAutoRepeat(0 so I don’t get messages faster than I can process them?


#2

Hmm, it uses a Timer and AsyncUpdater to invoke the callbacks, so if a callback blocks the message thread, it should delay any further timer callbacks and not queue them up… Can’t really see how it’d get stuck like that, but if you can find a place where hacking it fixes it, let me know.


#3

It’s only a problem on Windows, I made a simple demo app that reproduces the problem, code is here:

You should click and drag anywhere on main window, and the pink dot should follow the mouse with a 250 ms delay. Works on macOS, on Windows it immediately locks up.


#4

I’d recommend the following changes, they will stop the app from locking up. However the screen still won’t repaint during the drag operation, not sure if there is any way around that. I think the issue is that on Windows, WM_MOUSEMOVE and WM_PAINT aren’t real messages, they just get generated and stuffed into the message queue whenever the queue is empty and the dirty flag is set. The two asyncUpdaters are keeping the message queue full, so mouse handling and repainting never happens. I figured a way to force the mouse updates to happen, but not sure about the repaint.


#5

Hmm. Those changes wouldn’t work. The first one would mean that sequences of queued mouse-movements would probably all be delivered with the same coordinates. And the second one would break multi-touch behaviour.

What if it was to throttle or cancel the async update calls somehow? It’s tricky though because if I understand right, you really only want it to behave differently if a callback starts taking too long?


#6

getScreenPosition() actually queries the mouse position, so it will provide the current mouse position. If I didn’t do that, then the mouse position would never change.

Is there anyway to get the current modifiers of a specific mouse input source? I didn’t see one.

Maybe the 2nd one could be changed to:

if (mi->isDragging() && ModifierKeys::getCurrentModifiersRealtime().isAnyMouseButtonDown())

That should break the deadlock


#7

Yeah, that might work, I guess. Will have a tinker around and see what I can do.


#8

Does it work for you if in the timerCallback it forces an update of the position, e.g.

            mi->triggerFakeMove();
            mi->lastScreenPos = mi->getScreenPosition();

?

I’m just keen to avoid messing with the way the fake moves work under circumstances other than the auto-repeat mode


#9

Yes, that updates the mouse position

Still trying to figure out a way to get the screen to repaint.