| Summary: | Mouse location jumps after entering and leaving invisible grab | ||
|---|---|---|---|
| Product: | SDL | Reporter: | Christian Walther <cwalther> |
| Component: | events | Assignee: | Ryan C. Gordon <icculus> |
| Status: | RESOLVED WONTFIX | QA Contact: | Sam Lantinga <slouken> |
| Severity: | normal | ||
| Priority: | P2 | Keywords: | target-1.2.14 |
| Version: | HG 1.2 | ||
| Hardware: | PowerPC | ||
| OS: | All | ||
| Attachments: |
test case
proposed patch |
||
|
Description
Christian Walther
2006-10-08 16:03:28 UTC
Created attachment 167 [details]
test case
This is my generic mouse test program that can be used to reproduce the issue. Press V to hide the cursor, then G to grab or ungrab, move the mouse, and observe the orange dot that marks SDL's mouse position.
Created attachment 171 [details]
proposed patch
OK, here's a more detailed description of the misbehavior I'm seeing, on 10.4.8 with SDL SVN and on 10.3.9 with SDL 1.2.9:
- On the first mouse move after entering invisible grab, the SDL mouse position sometimes makes a jump (that I'm unable to exactly predict yet, but I'll leave it at that). In particular, this happens the first time after the application started, and after moving the window. This happens in both windowed and fullscreen mode.
- On the first mouse move after leaving invisible grab, the SDL mouse position jumps to the center of the window. This only happens in windowed mode.
- When grabbing while the cursor is hidden, but outside of the window (and therefore visible), the cursor jumps to the center of the window and stays visible, only when the mouse moves the first time it is hidden.
"Entering invisible grab" means either grabbing while the cursor is hidden, or hiding the cursor while grabbed, and conversely for "leaving invisible grab".
The attached patch fixes these three issues. In addition, it simplifies things a bit by removing the use of the CGGetLastMouseDelta() function. I'm not sure why this was used in the first place, as using [event deltaX|Y] in all cases works just as well here. It may have been working around a bug on 10.0 or something. Tested on 10.2.8, 10.3.9, 10.4.8 (PPC).
There are still some things wrong with grabbing (at least according to my understanding of how it should work), but I don't feel like fixing these right now. I found that things aren't any better on Windows and Linux, meaning that I can't use seamless grabbing and ungrabbing in my application anyway.
Wait - put this on hold for the moment. It appears that my patch isn't as mature as I thought. It works in my test application, but not in my "real" application: there, the big jump after entering invisible grab often comes not in the first mouse moved event (that I discard), but in the second. Have to investigate... I don't really understand this problem, and I'm giving up here. The explanation that seemed obvious is that because grabbing happens outside of the event stream, occasionally a mouse-moved event that was generated before grabbing is handled after grabbing (and therefore wrongly dropped with my patch, while the next event, which should have been dropped, is accepted). However, the problem persists if I try to remedy this by coupling grabbing to the event stream. I changed QZ_ChangeGrabState() to only post a custom event ("grab request") to the Cocoa event queue, and moved the actual grabbing into QZ_PumpEvents(). This didn't change behavior at all: often, the first mouse event after grabbing still seemed to originate from before the grab, only the second event contained the jump caused by grabbing. It seems as if at the time the "grab request" is inserted into the event queue, the older mouse event isn't there yet.
A preliminary workaround I found is calling SDL_PumpEvents() right before SDL_WM_GrabInput(). This made the problem very infrequent (though I still observed it once or twice), both with my original patch and with the additional "deferred grab" change. This also turned out to be the difference between the test application and the "real" application: In the former, the event loop spins very fast, while in the latter a lot of things happened between the last call to SDL_PumpEvents() and the call to SDL_WM_GrabInput() (almost a complete run loop cycle, ~16ms).
By the way, this is because many platforms implement the grabbed hidden mouse relative mode by warping the mouse to the middle of the window and then calculating deltas from that position. The real fix for this is to warp the mouse to the "current" mouse location and then flush mouse motion events until that motion event arrives and the mouse position is synchronized. Offhand this would have to be implemented for X11, GDI, Quartz, BWindow, possibly more. Patches accepted! *grin* Bumping some bugs' priorities to P1 for consideration before the 1.2.12 release (though some may not be resolved for 1.2.12). --ryan. It's not likely that this will be fixed for SDL 1.2.12, but if anyone wants to submit patches, feel free. :) Tagging this bug with "target-1.2.14" so we can try to resolve it for SDL 1.2.14. Please note that we may choose to resolve it as WONTFIX. This tag is largely so we have a comprehensive wishlist of bugs to examine for 1.2.14 (and so we can close bugs that we'll never fix, rather than have them live forever in Bugzilla). --ryan. This hasn't been updated in a couple years. Please reopen this if it's still active in 1.3. |