[rcore] [GLFW] Mouse relative, mouse position, mouse delta issues #4665
+36
−8
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Do NOT merge this
This PR is just meant to demonstrate the scope of the issue.
GLFW_CURSOR_NORMAL
) or relative cursor (GLFW_CURSOR_DISABLED
).Logs for item 1:
Note: in all cases (GLFW_CURSOR_DISABLED, GLFW_CURSOR_NORMAL, outside, inside, bottom right, top left) the first frames use a different coord plot. On
GLFW_CURSOR_DISABLED inside top left (ish)
(the last one) it appears correct, but just because the positions will "match" giving the illusion the coords are the same.GLFW_CURSOR_NORMAL outside bottom right:
GLFW_CURSOR_NORMAL outside top left:
GLFW_CURSOR_NORMAL inside bottom right (ish) of the window area:
GLFW_CURSOR_NORMAL inside top left (ish) of the window area:
GLFW_CURSOR_DISABLED outside bottom right:
GLFW_CURSOR_DISABLED outside top left:
GLFW_CURSOR_DISABLED inside bottom right (ish) of the window area:
GLFW_CURSOR_DISABLED inside top left (ish) of the window area:
In case relative cursor (
GLFW_CURSOR_DISABLED
) is enabled through aglfwSetInputMode()
call, an event (FocusIn on Linux, WM_CAPTURECHANGED | WM_SETFOCUS on Windows, NSNotification on MacOS) inside the internal polling (_glfwPollEventsX11 on Linux, _glfwPollEventsWin32 on Windows, not sure on MacOS) will trigger a disable cursor sequence (disableCursor on Linux, disableCursor on Windows, directly on MacOS), which will save the cursor, center it and call for it to be captured.This becomes a problem when trying to start the program with the cursor disabled (aka cursor relative,
GLFW_CURSOR_DISABLED
) because during those first frames the cursor will have a given position and when the cursor disabled kicks in, it will warp into a diferent position, causing cursor delta calculations to spike, making things like free cameras jolt suddenly.Trying to set the cursor position before the program main loop (e.g.: inside raylib InitPlatform) proved to be ineffective, because it may not run soon enough (sometimes missing 1 or 2 frames). And mostly because when the events (mentioned on item 2) kick in, they will force the cursor position to be "re-centered" breaking the previous position, causing the delta calculation to spike and jolting anything that depends on it.
Logs for itens 2 and 4:
With disableCursor forced call and _glfwCenterCursorInContentArea unchanged:
With disableCursor forced call and _glfwCenterCursorInContentArea commented:
A workaround for this required two steps: first it was necessary to make an early call to disableCursor(). To avoid meddling with GLFW, one can create a similar funcition to disableCursor() and call that instead (it would look like this on Linux, like this on Windows, probably similar to this on MacOS). This
raylibFixEarlyDisableCursor()
then has to be called before DisableCursor(), preferably right after InitPlatform() and would "fix" those first frames having the wrong mouse coords.Then the second part is making GLFW's internal event polling (_glfwPollEventsX11 on Linux, _glfwPollEventsWin32 on Windows, not sure on MacOS) always "re-center" because, without it, when the mouse is moved, it's moved position will not be the centered one it's supposed to be and will cause the cursor delta calculations to spike again, making things like free cameras jolt suddenly again. Also, by the comments, this apparently have an implication for glfwWaitEvents(), although I couldn't notice any problems from it while using
glfwWaitEvents()
on the tests.Yet, when I think this solves the problem I discover that the top left quadrant of the window is now broken (at least on Linux) for GLFW. For some reason, it will break the mouse coords on that quadrant alone to a point of requiring special handling just for it. Not only that, it also makes
CORE.Window.screen
sizes return wrong values. Which, makes no sense, because the lines commented only update the cursor and are there, apparently, just for performance/stability onglfwWaitEvents()
, besides, and all other changes are copies ofdisableCursor()
variants. I even double checked it with a fresh repository.It was necessary to add this to the start of raylib DisableCursor() just to handle that quadrant:
For this window quadrant:
At this point it was clear that this wasn't a viable solution and the more I kept digging, the worst it got. Maybe I just don't get how GLFW works well enough to fix this. Or maybe Linux (and/or MacOS) are broken on it on this part. Perhaps it's something really obvious that I couldn't spot, who knows.
Either way, for anyone that would like to continue debugging this issue it's confirmed to affect Linux and MacOS. The issue report is posted at #4654. A good way to debug this is directly with GLFW standalone, so raylib code won't interfere, at least on the initial testing. I've left some standalone sample tests below (including compiling instructions):
Sample tests:
Basic GLFW standalone test:
Specific GLFW standalone test:
Raylib test:
raylibFixEarlyDisableCursor()
on purpose) because I think these changes are a bad idea. I'm making it just to document everything I could find in a compact easy to check point for anyone that wants to continue to debug.@raysan5 please close this PR after you finish reading it.
@ve-nt @alexnivanov, I'm sorry guys, I really tried.