SDL2: drain event queue every frame + relative mouse mode during gameplay (#49)

This commit is contained in:
Julian
2026-10-02 20:47:47 +02:00
committed by GitHub
parent d4d588a199
commit a26fff4af5
2 changed files with 83 additions and 8 deletions
+26 -4
View File
@@ -890,6 +890,11 @@ CMouseControllerState CMousePointerStateHelper::GetMouseSetUp()
return state;
}
#ifdef LIBRW_SDL2
bool _InputMouseIsRelative(void);
void _InputConsumeMouseRelative(int *dx, int *dy);
#endif
void CPad::UpdateMouse()
{
#if defined RW_D3D9 || defined RWLIBS
@@ -942,8 +947,13 @@ void CPad::UpdateMouse()
double xpos = 1.0f, ypos;
glfwGetCursorPos(PSGLOBAL(window), &xpos, &ypos);
#endif
if (xpos == 0.f)
return;
#ifdef LIBRW_SDL2
if (!_InputMouseIsRelative() && xpos == 0)
return;
#else
if (xpos == 0.f)
return;
#endif
int32 signX = 1;
int32 signy = 1;
@@ -958,8 +968,20 @@ void CPad::UpdateMouse()
PCTempMouseControllerState.Clear();
PCTempMouseControllerState.x = (float)(signX * (xpos - PSGLOBAL(lastMousePos.x)));
PCTempMouseControllerState.y = (float)(signy * (ypos - PSGLOBAL(lastMousePos.y)));
#ifdef LIBRW_SDL2
if (_InputMouseIsRelative()) {
// true relative deltas from the motion events; polled positions are
// confined and stall at window/monitor edges
int dx, dy;
_InputConsumeMouseRelative(&dx, &dy);
PCTempMouseControllerState.x = (float)(signX * dx);
PCTempMouseControllerState.y = (float)(signy * dy);
} else
#endif
{
PCTempMouseControllerState.x = (float)(signX * (xpos - PSGLOBAL(lastMousePos.x)));
PCTempMouseControllerState.y = (float)(signy * (ypos - PSGLOBAL(lastMousePos.y)));
}
#ifdef LIBRW_SDL2
PCTempMouseControllerState.LMB = !!(mouseState & SDL_BUTTON(1));
PCTempMouseControllerState.RMB = !!(mouseState & SDL_BUTTON(3));
+57 -4
View File
@@ -784,6 +784,24 @@ bool _InputMouseNeedsExclusive()
return false;
}
// Relative mouse support: the game derives deltas from polled positions,
// but confined positions stall at window/monitor edges. Accumulate the true
// deltas from the motion events instead; the game consumes them once per frame.
static bool mouseRelativeMode = false;
static int mouseRelX = 0, mouseRelY = 0;
bool _InputMouseIsRelative(void)
{
return mouseRelativeMode;
}
void _InputConsumeMouseRelative(int *dx, int *dy)
{
*dx = mouseRelX;
*dy = mouseRelY;
mouseRelX = mouseRelY = 0;
}
void psPostRWinit(void)
{
RwVideoMode vm;
@@ -1268,9 +1286,12 @@ cursorEnterCB(int entered) {
PSGLOBAL(cursorIsInWindow) = !!entered;
}
void
windowFocusCB(int focused) {
void windowFocusCB(int focused) {
WindowFocused = !!focused;
if (!focused) {
// deltas accumulated while unfocused must not fire on refocus
mouseRelX = mouseRelY = 0;
}
}
void
@@ -1281,14 +1302,18 @@ windowIconifyCB(int iconified) {
void inputEventHandler() {
SDL_Event event;
if (SDL_PollEvent(&event)) {
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_KEYDOWN: /* fall-through */
case SDL_KEYUP:
keypressCB(event.key.keysym.sym, event.type, 0);
break;
case SDL_MOUSEMOTION: cursorCB(event.motion.x, event.motion.y); break;
case SDL_MOUSEMOTION:
cursorCB(event.motion.x, event.motion.y);
mouseRelX += event.motion.xrel;
mouseRelY += event.motion.yrel;
break;
case SDL_MOUSEWHEEL: scrollCB(event.wheel.x, event.wheel.y); break;
// note that SDL_CONTROLLERDEVICEADDED/REMOVED exists, but it did not work for me
@@ -1313,6 +1338,34 @@ void inputEventHandler() {
break;
}
}
// Grab the mouse during gameplay (GLFW_CURSOR_DISABLED equivalent):
// relative motion + pointer confinement, so the hidden cursor can't
// wander off to another monitor or stall at the window edge.
// The frontend needs absolute positions, so keep it free there.
bool wantRelative = gGameState == GS_PLAYING_GAME &&
!FrontEndMenuManager.m_bMenuActive && !WindowIconified;
if (wantRelative != mouseRelativeMode) {
if (SDL_SetRelativeMouseMode(wantRelative ? SDL_TRUE : SDL_FALSE) == 0) {
mouseRelativeMode = wantRelative;
mouseRelX = mouseRelY = 0;
if (wantRelative) {
PSGLOBAL(cursorIsInWindow) = true;
} else {
int x, y;
SDL_GetMouseState(&x, &y);
PSGLOBAL(lastMousePos.x) = x;
PSGLOBAL(lastMousePos.y) = y;
}
} else {
// switch failed: never leave the menu with a grabbed pointer and
// garbage coordinates — release the grab and fall back to polling
SDL_SetWindowGrab(PSGLOBAL(window), SDL_FALSE);
SDL_ShowCursor(SDL_DISABLE);
mouseRelativeMode = false;
}
}
}
/*