mouse: Make pointer warp emulation via relative mode available to all platforms

Move the Wayland pointer warp emulation code up to the SDL mouse layer, and activate it when a client attempts to warp a hidden mouse cursor when the hint is set.

testrelative adds the ability to test the warp emulation activation/deactivation with the --warp parameter and 'c' key for toggling cursor visibility.
This commit is contained in:
Frank Praznik
2024-07-24 17:43:02 -04:00
parent 92667e3066
commit 66eb2ea443
8 changed files with 212 additions and 122 deletions

View File

@@ -12,6 +12,7 @@
/* Simple program: Test relative mouse motion */
#include <SDL3/SDL_test.h>
#include <SDL3/SDL_test_common.h>
#include <SDL3/SDL_main.h>
@@ -21,16 +22,47 @@
static SDLTest_CommonState *state;
static int i, done;
static float mouseX, mouseY;
static SDL_FRect rect;
static SDL_Event event;
static SDL_bool warp;
static void DrawRects(SDL_Renderer *renderer)
{
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
rect.x = mouseX;
rect.y = mouseY;
SDL_RenderFillRect(renderer, &rect);
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
if (SDL_GetRelativeMouseMode()) {
SDLTest_DrawString(renderer, 0.f, 0.f, "Relative Mode: Enabled");
} else {
SDLTest_DrawString(renderer, 0.f, 0.f, "Relative Mode: Disabled");
}
}
static void CenterMouse()
{
/* Warp the mouse back to the center of the window with input focus to use the
* center point for calculating future motion deltas.
*
* NOTE: DO NOT DO THIS IN REAL APPS/GAMES!
*
* This is an outdated method of handling relative pointer motion, and
* may not work properly, if at all, on some platforms. It is here *only*
* for testing the warp emulation code path internal to SDL.
*
* Relative mouse mode should be used instead!
*/
SDL_Window *window = SDL_GetKeyboardFocus();
if (window) {
int w, h;
float cx, cy;
SDL_GetWindowSize(window, &w, &h);
cx = (float)w / 2.f;
cy = (float)h / 2.f;
SDL_WarpMouseInWindow(window, cx, cy);
}
}
static void loop(void)
@@ -39,21 +71,46 @@ static void loop(void)
while (SDL_PollEvent(&event)) {
SDLTest_CommonEvent(state, &event, &done);
switch (event.type) {
case SDL_EVENT_WINDOW_FOCUS_GAINED:
if (warp) {
/* This should activate relative mode for warp emulation, unless disabled via a hint. */
CenterMouse();
}
break;
case SDL_EVENT_KEY_DOWN:
if (event.key.key == SDLK_C) {
/* If warp emulation is active, showing the cursor should turn
* relative mode off, and it should re-activate after a warp
* when hidden again.
*/
if (SDL_CursorVisible()) {
SDL_HideCursor();
} else {
SDL_ShowCursor();
}
}
break;
case SDL_EVENT_MOUSE_MOTION:
{
mouseX += event.motion.xrel;
mouseY += event.motion.yrel;
rect.x += event.motion.xrel;
rect.y += event.motion.yrel;
if (warp) {
CenterMouse();
}
} break;
default:
break;
}
}
for (i = 0; i < state->num_windows; ++i) {
SDL_Rect viewport;
SDL_Renderer *renderer = state->renderers[i];
if (state->windows[i] == NULL) {
continue;
}
SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF);
SDL_RenderClear(renderer);
@@ -85,7 +142,6 @@ static void loop(void)
int main(int argc, char *argv[])
{
/* Enable standard application logging */
SDL_SetLogPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
@@ -96,8 +152,27 @@ int main(int argc, char *argv[])
}
/* Parse commandline */
if (!SDLTest_CommonDefaultArgs(state, argc, argv)) {
return 1;
for (i = 1; i < argc;) {
int consumed;
consumed = SDLTest_CommonArg(state, i);
if (consumed == 0) {
consumed = -1;
if (SDL_strcasecmp(argv[i], "--warp") == 0) {
warp = SDL_TRUE;
consumed = 1;
}
}
if (consumed < 0) {
static const char *options[] = {
"[--warp]",
NULL
};
SDLTest_CommonLogUsage(state, argv[0], options);
return 1;
}
i += consumed;
}
if (!SDLTest_CommonInit(state)) {
@@ -112,8 +187,17 @@ int main(int argc, char *argv[])
SDL_RenderClear(renderer);
}
if (SDL_SetRelativeMouseMode(SDL_TRUE) < 0) {
return 3;
/* If warp mode is activated, the cursor will be repeatedly warped back to
* the center of the window to simulate the behavior of older games. The cursor
* is initially hidden in this case to trigger the warp emulation unless it has
* been explicitly disabled via a hint.
*
* Otherwise, try to activate relative mode.
*/
if (warp) {
SDL_HideCursor();
} else if (SDL_SetRelativeMouseMode(SDL_TRUE) < 0) {
return 3; /* Relative mode failed, just exit. */
}
rect.x = DEFAULT_WINDOW_WIDTH / 2;