SDL
SDL copied to clipboard
SDL3: SDL_EVENT_MOUSE_MOTION relative movement stops at screen borders
With SDL_SetWindowMouseGrab enabled (and mouse cursor disabled), the invisible mouse cursor will sooner or later hit a screen border. While this should be no problem when checking only the relative mouse movements, the relative movements reported by SDL_EVENT_MOUSE_MOTION are stopping in SDL 3 then too. This is different to SDL 2, where the absolute positions stop at the screen border too, but the relative positions continue to provide the movement values.
E.g. if you have a 800 pixel wide screen, you eventually get 799 as x position. If you move the mouse further right in SDL 2, xrel will continue to return values > 0, while in SDL 3 xrel will be 0.
Windows 10 x64, Direct 3D and OpenGL, SDL 3.2.14
Does SDL_SetWindowRelativeMouseMode fit your use case?
* Set relative mouse mode for a window.
*
* While the window has focus and relative mouse mode is enabled, the cursor
* is hidden, the mouse position is constrained to the window, and SDL will
* report continuous relative mouse motion even if the mouse is at the edge of
* the window.
*
* If you'd like to keep the mouse position fixed while in relative mode you
* can use SDL_SetWindowMouseRect(). If you'd like the cursor to be at a
* specific location when relative mode ends, you should use
* SDL_WarpMouseInWindow() before disabling relative mode.
Thanks. That does the trick. Somehow.
The bug is gone, but the mouse feels sluggish and not precise now. What's happening here? Is the OS suddenly kicking in?
Should I open a new issue for this? (it was much better with SDL 2)
I did some more testing and it seems that with SDL_SetWindowRelativeMouseMode enabled, the mouse ignores the OS settings. Is there a way to combine both? As it was in SDL 2?
If tried SDL_HINT_MOUSE_RELATIVE_SYSTEM_SCALE but the cursor still behaves different.
I did some more testing and it seems that with SDL_SetWindowRelativeMouseMode enabled, the mouse ignores the OS settings. Is there a way to combine both? As it was in SDL 2?
If tried SDL_HINT_MOUSE_RELATIVE_SYSTEM_SCALE but the cursor still behaves different.
That should work. Can you describe how the cursor behaves differently? Adding @expikr for visibility.
minimal test app
#define SDL_MAIN_USE_CALLBACKS
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <windows.h>
static char debug_string[32];
static bool system_scale_enabled;
typedef struct {
SDL_Window *window;
SDL_Renderer *renderer;
} AppState;
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
AppState *as = SDL_calloc(1, sizeof(AppState));
if (!as) {
return SDL_APP_FAILURE;
} else {
*appstate = as;
}
if (!SDL_Init(SDL_INIT_VIDEO)) {
return SDL_APP_FAILURE;
}
if (!SDL_CreateWindowAndRenderer("mouse test", 640, 480, SDL_WINDOW_FULLSCREEN, &as->window, &as->renderer)) {
return SDL_APP_FAILURE;
}
SDL_SetHintWithPriority(SDL_HINT_MOUSE_RELATIVE_CURSOR_VISIBLE, "1", SDL_HINT_OVERRIDE);
SDL_SetHintWithPriority(SDL_HINT_MOUSE_RELATIVE_MODE_CENTER, "0", SDL_HINT_OVERRIDE);
SDL_SetHintWithPriority(SDL_HINT_MOUSE_RELATIVE_SYSTEM_SCALE, "1", SDL_HINT_OVERRIDE);
system_scale_enabled = true;
SDL_SetWindowRelativeMouseMode(as->window, true);
{
int x0, y0;
float x, y;
SDL_GetGlobalMouseState(&x, &y);
SDL_GetWindowPosition(as->window, &x0, &y0);
SDL_WarpMouseInWindow(as->window, x-(float)x0, y-(float)y0);
}
debug_string[0] = 0;
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
AppState *as = appstate;
int i;
switch (event->type) {
case SDL_EVENT_QUIT:
return SDL_APP_SUCCESS;
break;
case SDL_EVENT_KEY_UP: {
SDL_Keycode sym = event->key.key;
if (sym == SDLK_ESCAPE) return SDL_APP_SUCCESS;
if (sym == SDLK_R) {
system_scale_enabled = !system_scale_enabled;
SDL_SetHintWithPriority(SDL_HINT_MOUSE_RELATIVE_SYSTEM_SCALE, system_scale_enabled ? "1" : "0", SDL_HINT_OVERRIDE);
int x0, y0;
float x, y;
SDL_GetGlobalMouseState(&x, &y);
SDL_GetWindowPosition(as->window, &x0, &y0);
SDL_WarpMouseInWindow(as->window, x-(float)x0, y-(float)y0);
};
break;
}
}
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppIterate(void *appstate)
{
AppState *as = appstate;
static Uint64 accu = 0;
static Uint64 last = 0;
static Uint64 past = 0;
Uint64 now = SDL_GetTicksNS();
Uint64 dt_ns = now - past;
{
int w, h;
float x, y;
SDL_Renderer *renderer = as->renderer;
SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderDebugText(renderer, 0, 0, debug_string);
SDL_GetRenderOutputSize(renderer, &w, &h);
SDL_GetMouseState(&x, &y);
if (!system_scale_enabled) SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
SDL_RenderLine(renderer, x, 0, x, h);
SDL_RenderLine(renderer, 0, y, w, y);
SDL_RenderPresent(renderer);
}
if (now - last > 999999999) {
last = now;
SDL_snprintf(debug_string, sizeof(debug_string), "%" SDL_PRIu64 " fps", accu);
accu = 0;
}
past = now;
accu += 1;
Uint64 elapsed = SDL_GetTicksNS() - now;
if (elapsed < 999999) {
SDL_DelayNS(999999 - elapsed);
}
return SDL_APP_CONTINUE;
}
void SDL_AppQuit(void *appstate, SDL_AppResult result)
{
SDL_free(appstate);
}
@thrust26, if you run the test app @expikr wrote above, you'll see a white crosshair that should match the system cursor as you move around. That's relative mode with SDL_HINT_MOUSE_RELATIVE_SYSTEM_SCALE enabled. If you press 'R', the crosshair will turn red, and SDL_HINT_MOUSE_RELATIVE_SYSTEM_SCALE will be off, and you can compare the difference.
Thanks, that seems to work identical. With and without grabbed mouse, with and without visible cursor, red or not.
Hm... I will have to compare with our code...
What mouse setting are you using?
I am now using the settings from the demo. The mouse movement is fine, but we are back to the original problem. With mouse grab enabled, the mouse seems to hit invisible barriers at varying positions. You can overcome these barriers by moving the mouse into opposite directions. It seems that the mouse behaves as it is inside a differently positioned window. Note: Windowed mode.
I tried to adapt the test code, but that doesn't work. In windowed mode one or both lines disappear. With and without SDL_HINT_MOUSE_RELATIVE_SYSTEM_SCALE enabled.
Is the issue that setting both relative mouse mode and grabbing the mouse together causes this issue? In this case are you still getting relative motion in the mouse events? If not, can you adapt the example above to show the problem?
I am still experimenting. Got the demo working as expected, but our own code behaves differently, even with the same mouse settings applied.
Could it be due to the input processing? We are using SDL_PollEvent and then react to SDL_EVENT_MOUSE_MOTION. This is used because we also use the mouse movement (relative positions) to emulate digital input. And working well in SDL2.
Your code seems to do no event handling, and instead just repositions the mouse at an absolute position each frame(or so). That's something completely different, right?
BTW: I don't get the description of SDL_HINT_MOUSE_RELATIVE_MODE_CENTER:
* A variable controlling whether relative mouse mode constrains the mouse to
* the center of the window.
*
* Constraining to the center of the window works better for FPS games and
* when the application is running over RDP. Constraining to the whole window
* works better for 2D games and increases the chance that the mouse will be
* in the correct position when using high DPI mice.
What sense does a mouse constraint to the center of a window make? Then you cannot move it anymore. 😕
You shouldn’t set any of the hints in the demo above, they’re just used to make it easier to see what the mouse is doing.
Ah, until now I thought the hints (or some of them) were supposed to make the difference.
Anyway, the problem is probably the event polling. I suppose if the demo gets rewritten that way, it will show the problem too. Currently my time is quite limited, else I would do that now.
Ok, I changed the source code to point out problem.
#define SDL_MAIN_USE_CALLBACKS
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <windows.h>
#include <iostream>
#include <iomanip>
static char debug_string[32];
static bool system_scale_enabled;
static bool grab;
static float mouseX, mouseY;
typedef struct {
SDL_Window *window;
SDL_Renderer *renderer;
} AppState;
void draw(void* appstate, float x, float y);
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
AppState *as = static_cast<AppState*>(SDL_calloc(1, sizeof(AppState)));
if (!as) {
return SDL_APP_FAILURE;
} else {
*appstate = as;
}
if (!SDL_Init(SDL_INIT_VIDEO)) {
return SDL_APP_FAILURE;
}
if (!SDL_CreateWindowAndRenderer("mouse test", 640, 480, 0, &as->window, &as->renderer)) {
return SDL_APP_FAILURE;
}
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
SDL_SetHintWithPriority(SDL_HINT_MOUSE_RELATIVE_CURSOR_VISIBLE, "0", SDL_HINT_OVERRIDE);
SDL_SetHintWithPriority(SDL_HINT_MOUSE_RELATIVE_MODE_CENTER, "0", SDL_HINT_OVERRIDE); // ???
SDL_SetHintWithPriority(SDL_HINT_MOUSE_RELATIVE_SYSTEM_SCALE, "1", SDL_HINT_OVERRIDE);
system_scale_enabled = false;
grab = false;
SDL_SetWindowRelativeMouseMode(as->window, system_scale_enabled);
SDL_SetWindowMouseGrab(as->window, grab);
SDL_HideCursor();
{
SDL_GetMouseState(&mouseX, &mouseY);
SDL_WarpMouseInWindow(as->window, mouseX, mouseY);
}
debug_string[0] = 0;
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
AppState *as = static_cast<AppState*>(appstate);
int i;
switch (event->type) {
case SDL_EVENT_QUIT:
return SDL_APP_SUCCESS;
break;
case SDL_EVENT_KEY_UP: {
SDL_Keycode sym = event->key.key;
if (sym == SDLK_ESCAPE) return SDL_APP_SUCCESS;
if (sym == SDLK_R) {
system_scale_enabled = !system_scale_enabled;
SDL_SetHintWithPriority(SDL_HINT_MOUSE_RELATIVE_SYSTEM_SCALE, system_scale_enabled ? "1" : "0", SDL_HINT_OVERRIDE);
};
if (sym == SDLK_G) {
grab = !grab;
SDL_SetWindowMouseGrab(as->window, grab);
}
break;
}
case SDL_EVENT_MOUSE_MOTION:
// this does not work, because xrel, yrel stay 0 outside the window (different to SDL2):
mouseX += event->motion.xrel;
mouseY += event->motion.yrel;
std::cout << std::setw(4) << event->motion.xrel << std::setw(5) << event->motion.yrel << std::endl;
draw(appstate, mouseX, mouseY);
break;
}
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppIterate(void *appstate)
{
// this works:
//float x, y;
//SDL_GetMouseState(&x, &y);
//draw(appstate, x, y);
return SDL_APP_CONTINUE;
}
void draw(void *appstate, float x, float y)
{
AppState *as = static_cast<AppState*>(appstate);
static Uint64 accu = 0;
static Uint64 last = 0;
static Uint64 past = 0;
Uint64 now = SDL_GetTicksNS();
Uint64 dt_ns = now - past;
{
int w, h;
SDL_Renderer *renderer = as->renderer;
SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderClear(renderer);
SDL_RenderDebugText(renderer, 0, 0, debug_string);
SDL_GetRenderOutputSize(renderer, &w, &h);
if (system_scale_enabled) {
if(!grab)
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); // S && !G = white
else
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255); // S && G = green
} else {
if(!grab)
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); // !S && !G = red
else
SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255); // !S && G = blue
}
SDL_RenderLine(renderer, x, 0, x, h);
SDL_RenderLine(renderer, 0, y, w, y);
SDL_RenderPresent(renderer);
}
if (now - last > 999999999) {
last = now;
SDL_snprintf(debug_string, sizeof(debug_string), "%" SDL_PRIu64 " fps", accu);
accu = 0;
}
past = now;
accu += 1;
Uint64 elapsed = SDL_GetTicksNS() - now;
if (elapsed < 999999) {
SDL_DelayNS(999999 - elapsed);
}
}
void SDL_AppQuit(void *appstate, SDL_AppResult result)
{
SDL_free(appstate);
}
This now uses relative mouse motions. Press G to switch mouse grabbing. But neither R or G or any combination make a difference.
If you move around the mouse, also outside the window, you will notice the barriers I described. In the console you can see that motion.xrel/yrel become 0 then. Using SDL2 they continued to provide values.
Your code never enables relative mode, so of course it will be stopped by the screen border, because non-relative mode uses the OS cursor motion instead of raw motion, and the OS cursor is clipped to the screen border.
Regardless, you are missing the point of the demo. I was asking you what mouse settings you were using in the OS, it's completely unrelated to the SDL hints above. I asked because you said that the mouse motion behaves differently as though the operating system mouse setting is ignored, so I wrote the above test demo so that you can check if the white crosshair is staying with the cursor or not, even when you alter the operating system mouse setting.
Here's the same demo adapted to using SDL events instead of fetching the state from SDL:
#define SDL_MAIN_USE_CALLBACKS
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <ntdef.h>
static char debug_string[32];
static bool system_scale_enabled;
static float mouseX;
static float mouseY;
typedef struct {
SDL_Window *window;
SDL_Renderer *renderer;
} AppState;
void syncMouse(SDL_Window *window) {
int x0, y0;
float x, y;
SDL_GetGlobalMouseState(&x, &y);
SDL_GetWindowPosition(window, &x0, &y0);
mouseX = x-(float)x0;
mouseY = y-(float)y0;
SDL_WarpMouseInWindow(window, mouseX, mouseY);
}
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
AppState *as = SDL_calloc(1, sizeof(AppState));
if (!as) {
return SDL_APP_FAILURE;
} else {
*appstate = as;
}
if (!SDL_Init(SDL_INIT_VIDEO)) {
return SDL_APP_FAILURE;
}
if (!SDL_CreateWindowAndRenderer("mouse test", 640, 480, 0, &as->window, &as->renderer)) {
return SDL_APP_FAILURE;
}
SDL_SetHintWithPriority(SDL_HINT_MOUSE_RELATIVE_CURSOR_VISIBLE, "1", SDL_HINT_OVERRIDE);
SDL_SetHintWithPriority(SDL_HINT_MOUSE_RELATIVE_MODE_CENTER, "0", SDL_HINT_OVERRIDE);
SDL_SetHintWithPriority(SDL_HINT_MOUSE_RELATIVE_SYSTEM_SCALE, "1", SDL_HINT_OVERRIDE);
system_scale_enabled = true;
SDL_SetWindowRelativeMouseMode(as->window, true);
syncMouse(as->window);
debug_string[0] = 0;
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
AppState *as = appstate;
int i;
switch (event->type) {
case SDL_EVENT_QUIT:
return SDL_APP_SUCCESS;
break;
case SDL_EVENT_KEY_UP: {
SDL_Keycode sym = event->key.key;
if (sym == SDLK_ESCAPE) return SDL_APP_SUCCESS;
if (sym == SDLK_R) {
system_scale_enabled = !system_scale_enabled;
SDL_SetHintWithPriority(SDL_HINT_MOUSE_RELATIVE_SYSTEM_SCALE, system_scale_enabled ? "1" : "0", SDL_HINT_OVERRIDE);
syncMouse(as->window);
};
break;
}
case SDL_EVENT_MOUSE_MOTION:
mouseX += event->motion.xrel;
mouseY += event->motion.yrel;
mouseX = SDL_max(0, SDL_min(mouseX, 640));
mouseY = SDL_max(0, SDL_min(mouseY, 480));
break;
}
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppIterate(void *appstate)
{
AppState *as = appstate;
static Uint64 accu = 0;
static Uint64 last = 0;
static Uint64 past = 0;
Uint64 now = SDL_GetTicksNS();
Uint64 dt_ns = now - past;
{
int w, h;
SDL_Renderer *renderer = as->renderer;
SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderDebugText(renderer, 0, 0, debug_string);
SDL_GetRenderOutputSize(renderer, &w, &h);
if (!system_scale_enabled) SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
SDL_RenderLine(renderer, mouseX, 0, mouseX, h);
SDL_RenderLine(renderer, 0, mouseY, w, mouseY);
SDL_RenderPresent(renderer);
}
if (now - last > 999999999) {
last = now;
SDL_snprintf(debug_string, sizeof(debug_string), "%" SDL_PRIu64 " fps", accu);
accu = 0;
}
past = now;
accu += 1;
Uint64 elapsed = SDL_GetTicksNS() - now;
if (elapsed < 999999) {
SDL_DelayNS(999999 - elapsed);
}
return SDL_APP_CONTINUE;
}
void SDL_AppQuit(void *appstate, SDL_AppResult result)
{
SDL_free(appstate);
}
also @slouken I suspect that what he's attempting to ask for here is essentially #7674, since he wants to continue receiving hardware relative motion independent of the actual OS cursor motion. What's the timeline for 3.4.0? I can try to unearth and refactor the reverted rawevent PR before 3.4.0 is locked in, just want to know how soon I'd need to start thinking about it.
3.4 is soft-locked at this point. raw events can be considered for 3.6, but let's see what's actually needed here.
Your code never enables relative mode, so of course it will be stopped by the screen border, because non-relative mode uses the OS cursor motion instead of raw motion, and the OS cursor is clipped to the screen border.
Sorry, I confused that with SDL_HINT_MOUSE_RELATIVE_SYSTEM_SCALE.
Regardless, you are missing the point of the demo. I was asking you what mouse settings you were using in the OS, it's completely unrelated to the SDL hints above. I asked because you said that the mouse motion behaves differently as though the operating system mouse setting is ignored, so I wrote the above test demo so that you can check if the white crosshair is staying with the cursor or not, even when you alter the operating system mouse setting.
Here they are:
I thought about these before, but changing speed and disabling acceleration made no difference.
Here's the same demo adapted to using SDL events instead of fetching the state from SDL:
The problem with SDL_SetWindowRelativeMouseMode enabled is, that while I can move the lines as expected, it also grabs the mouse pointer and limits its cursor to the window. Using SDL_SetWindowMouseGrab makes no difference then???
So I replaced SDL_SetWindowMouseGrab with SDL_SetWindowRelativeMouseMode in our application. Now grabbing the mouse works as expected. But, now it again moves much slower while SDL_SetWindowRelativeMouseMode is enabled.
It tried the same with your code and here the opposite is true, it moves faster with SDL_SetWindowRelativeMouseMode enabled. I have no idea why it is once faster and once slower (I suppose Windows mouse acceleration plays a role here), but the key point is, that the speeds differ. Which must not happen.
Does that make sense?
also @slouken I suspect that what he's attempting to ask for here is essentially #7674, since he wants to continue receiving hardware relative motion independent of the actual OS cursor motion.
I am not 100% sure if I get your point. But it seems to be correct. Basically it should work like it used to work in SDL2, where I could move the mouse with identical speed and effect (== same events created) with and without limiting its movement to the application window. Currently either I am too stupid to make it work like that or there is a regression.
I'm having difficulty parsing your description of the behaviour. Can you explicitly state what object/subject you are referring to instead of using pronouns?
I'm having difficulty parsing your description of the behaviour. Can you explicitly state what object/subject you are referring to instead of using pronouns?
Sorry, I don't get you. English is not my first language and I was always terrible with grammar. How can I describe it differently?
I'm not able to reproduce the issue you described.
I ran SDL3 testsprite with the --info event_motion command line parameter to print out mouse motion, then pressed Ctrl+G to grab the mouse, then Ctrl+R to enter relative mode, and I continued to get relative mouse motion at the window border.
Here's a minimal test program to demonstrate:
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
int main(int argc, char* argv[])
{
bool done = false;
SDL_Window *window = SDL_CreateWindow("Relative motion test", 800, 600, 0);
SDL_SetWindowRelativeMouseMode(window, true);
// This grab isn't necessary, just here to replicate the original bug description
SDL_SetWindowMouseGrab(window, true);
while (!done) {
SDL_Event ev;
while (SDL_PollEvent(&ev)) {
switch (ev.type) {
case SDL_EVENT_MOUSE_MOTION:
SDL_Log("Mouse motion: %g,%g, relative: %g,%g", ev.motion.x, ev.motion.y, ev.motion.xrel, ev.motion.yrel);
break;
case SDL_EVENT_KEY_UP:
if (ev.key.key == SDLK_ESCAPE) {
done = true;
}
break;
default:
break;
}
}
}
return 0;
}
My problem is the difference of mouse speed with and with SDL_SetWindowRelativeMouseMode enabled. Try to switch these while in your demo.
Try this:
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
int main(int argc, char* argv[])
{
bool done = false;
SDL_Window *window = SDL_CreateWindow("Relative motion test", 800, 600, 0);
SDL_SetWindowRelativeMouseMode(window, true);
// Make sure the relative mouse motion uses the same scale as the system mouse cursor
SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_SYSTEM_SCALE, "1");
// Do floating point accumulation in SDL instead of the application
SDL_SetHint("SDL_MOUSE_INTEGER_MODE", "1");
// This grab isn't necessary, just here to replicate the original bug description
//SDL_SetWindowMouseGrab(window, true);
while (!done) {
SDL_Event ev;
while (SDL_PollEvent(&ev)) {
switch (ev.type) {
case SDL_EVENT_MOUSE_MOTION:
SDL_Log("Mouse motion: %g,%g, relative: %g,%g", ev.motion.x, ev.motion.y, ev.motion.xrel, ev.motion.yrel);
break;
case SDL_EVENT_KEY_UP:
switch (ev.key.key) {
case SDLK_R:
SDL_SetWindowRelativeMouseMode(window, !SDL_GetWindowRelativeMouseMode(window));
break;
case SDLK_ESCAPE:
done = true;
break;
}
break;
default:
break;
}
}
}
return 0;
}
Either I can move the mouse outside the window, but then relative movement stops. Or I cannot move the mouse outside the window, but relative movement is still created, when I continue to move it.
The first one is the problem.
I'm not sure how SDL2 provided the functionality you're asking for. Can you provide a minimal SDL2 program that works the way you want?
I'm not sure how SDL2 provided the functionality you're asking for. Can you provide a minimal SDL2 program that works the way you want?
Forget what I said in my last post, use the last by one. Sorry. 😒
The input stops when the mouse is moved outside the window in our SDL2 version too. The difference is in the movement speed having the mouse restricted to the window or not. When restricted (grabbed) it moves slower in SDL3. That last source code with only text output is not useful here. But the one I posted is useful.
To remind myself for the future: Either the mouse moves slower when grabbed. Or its movement often stops before reaching the window borders (at varying positions). I can only fix one of the problems.
With my example above, the mouse should not move slower when grabbed, at least on Windows. Did you test it? https://github.com/libsdl-org/SDL/issues/13151#issuecomment-3236946643
I cannot see a the cursor when grabbed, so it is hard to tell. And the mouse coordinates are nowhere used as input like it was with the lines. Maybe you can adapt a previous demo or tell me what is the significant change in your code.
I cannot see a the cursor when grabbed, so it is hard to tell. And the mouse coordinates are nowhere used as input like it was with the lines. Maybe you can adapt a previous demo or tell me what is the significant change in your code.
Try this:
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
int main(int argc, char* argv[])
{
bool done = false;
SDL_Window *window;
SDL_Renderer *renderer;
float x = 0, y = 0;
SDL_CreateWindowAndRenderer("Relative motion test", 800, 600, 0, &window, &renderer);
SDL_SetWindowRelativeMouseMode(window, true);
// Make sure the relative mouse motion uses the same scale as the system mouse cursor
SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_SYSTEM_SCALE, "1");
// Do floating point accumulation in SDL instead of the application
SDL_SetHint("SDL_MOUSE_INTEGER_MODE", "1");
// This grab isn't necessary, just here to replicate the original bug description
//SDL_SetWindowMouseGrab(window, true);
while (!done) {
SDL_Event ev;
while (SDL_PollEvent(&ev)) {
switch (ev.type) {
case SDL_EVENT_MOUSE_MOTION:
x = ev.motion.x;
y = ev.motion.y;
SDL_Log("Mouse motion: %g,%g, relative: %g,%g", ev.motion.x, ev.motion.y, ev.motion.xrel, ev.motion.yrel);
break;
case SDL_EVENT_KEY_UP:
switch (ev.key.key) {
case SDLK_R:
SDL_SetWindowRelativeMouseMode(window, !SDL_GetWindowRelativeMouseMode(window));
break;
case SDLK_ESCAPE:
done = true;
break;
}
break;
default:
break;
}
}
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderLine(renderer, x - 16, y, x + 16, y);
SDL_RenderLine(renderer, x, y - 16, x, y + 16);
SDL_RenderPresent(renderer);
SDL_Delay(10);
}
return 0;
}
That looks good. 👍
What makes the difference? SDL_MOUSE_INTEGER_MODE does not appear to be the case.