diff --git a/WhatsNew.txt b/WhatsNew.txt index 2b780d09c..198ae783c 100644 --- a/WhatsNew.txt +++ b/WhatsNew.txt @@ -21,6 +21,7 @@ General: * Added SDL_bsearch(), SDL_crc16(), and SDL_utf8strnlen() to the stdlib routines * Added SDL_size_mul_overflow() and SDL_size_add_overflow() for better size overflow protection * Added SDL_ResetHint() to reset a hint to the default value +* Added the hint SDL_HINT_MOUSE_RELATIVE_WARP_MOTION to control whether mouse warping generates motion events in relative mode. This hint defaults off. * The hint SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS now defaults on * Added support for mini-gamepad mode for Nintendo Joy-Con controllers using the HIDAPI driver * Added the hint SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS to control whether Joy-Con controllers are automatically merged into a unified gamepad when using the HIDAPI driver. This hint defaults on. diff --git a/include/SDL_hints.h b/include/SDL_hints.h index 32f65c3d9..e7cddba03 100644 --- a/include/SDL_hints.h +++ b/include/SDL_hints.h @@ -1064,6 +1064,17 @@ extern "C" { */ #define SDL_HINT_MOUSE_RELATIVE_SPEED_SCALE "SDL_MOUSE_RELATIVE_SPEED_SCALE" +/** + * \brief A variable controlling whether a motion event should be generated for mouse warping in relative mode. + * + * This variable can be set to the following values: + * "0" - Warping the mouse will not generate a motion event in relative mode + * "1" - Warping the mouse will generate a motion event in relative mode + * + * By default warping the mouse will not generate motion events in relative mode. This avoids the application having to filter out large relative motion due to warping. + */ +#define SDL_HINT_MOUSE_RELATIVE_WARP_MOTION "SDL_MOUSE_RELATIVE_WARP_MOTION" + /** * \brief A variable controlling whether mouse events should generate synthetic touch events * diff --git a/include/SDL_mouse.h b/include/SDL_mouse.h index 4683e2597..a9a00bd96 100644 --- a/include/SDL_mouse.h +++ b/include/SDL_mouse.h @@ -154,7 +154,7 @@ extern DECLSPEC Uint32 SDLCALL SDL_GetRelativeMouseState(int *x, int *y); /** * Move the mouse cursor to the given position within the window. * - * This function generates a mouse motion event. + * This function generates a mouse motion event if relative mode is not enabled. If relative mode is enabled, you can force mouse events for the warp by setting the SDL_HINT_MOUSE_RELATIVE_WARP_MOTION hint. * * Note that this function will appear to succeed, but not actually move the * mouse when used over Microsoft Remote Desktop. diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c index 45dffc779..ba486eefe 100644 --- a/src/events/SDL_mouse.c +++ b/src/events/SDL_mouse.c @@ -161,6 +161,14 @@ SDL_MouseAutoCaptureChanged(void *userdata, const char *name, const char *oldVal } } +static void SDLCALL +SDL_MouseRelativeWarpMotionChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_Mouse *mouse = (SDL_Mouse *)userdata; + + mouse->relative_mode_warp_motion = SDL_GetStringBoolean(hint, SDL_FALSE); +} + /* Public functions */ int SDL_MouseInit(void) @@ -195,6 +203,9 @@ SDL_MouseInit(void) SDL_AddHintCallback(SDL_HINT_MOUSE_AUTO_CAPTURE, SDL_MouseAutoCaptureChanged, mouse); + SDL_AddHintCallback(SDL_HINT_MOUSE_RELATIVE_WARP_MOTION, + SDL_MouseRelativeWarpMotionChanged, mouse); + mouse->was_touch_mouse_events = SDL_FALSE; /* no touch to mouse movement event pending */ mouse->cursor_shown = SDL_TRUE; @@ -377,13 +388,16 @@ SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relativ if (x == center_x && y == center_y) { mouse->last_x = center_x; mouse->last_y = center_y; - return 0; - } - if (window && (window->flags & SDL_WINDOW_INPUT_FOCUS) != 0) { - if (mouse->WarpMouse) { - mouse->WarpMouse(window, center_x, center_y); - } else { - SDL_PrivateSendMouseMotion(window, mouseID, 0, center_x, center_y); + if (!mouse->relative_mode_warp_motion) { + return 0; + } + } else { + if (window && (window->flags & SDL_WINDOW_INPUT_FOCUS) != 0) { + if (mouse->WarpMouse) { + mouse->WarpMouse(window, center_x, center_y); + } else { + SDL_PrivateSendMouseMotion(window, mouseID, 0, center_x, center_y); + } } } } @@ -810,6 +824,9 @@ SDL_MouseQuit(void) SDL_DelHintCallback(SDL_HINT_MOUSE_AUTO_CAPTURE, SDL_MouseAutoCaptureChanged, mouse); + + SDL_DelHintCallback(SDL_HINT_MOUSE_RELATIVE_WARP_MOTION, + SDL_MouseRelativeWarpMotionChanged, mouse); } Uint32 @@ -883,23 +900,27 @@ SDL_PerformWarpMouseInWindow(SDL_Window *window, int x, int y, SDL_bool ignore_r return; } + /* Ignore the previous position when we warp */ + mouse->last_x = x; + mouse->last_y = y; + mouse->has_position = SDL_FALSE; + if (mouse->relative_mode && !ignore_relative_mode) { /* 2.0.22 made warping in relative mode actually functional, which * surprised many applications that weren't expecting the additional * mouse motion. * * So for now, warping in relative mode adjusts the absolution position - * but doesn't generate motion events. + * but doesn't generate motion events, unless SDL_HINT_MOUSE_RELATIVE_WARP_MOTION is set. */ - mouse->x = x; - mouse->y = y; - mouse->has_position = SDL_TRUE; - return; + if (!mouse->relative_mode_warp_motion) { + mouse->x = x; + mouse->y = y; + mouse->has_position = SDL_TRUE; + return; + } } - /* Ignore the previous position when we warp */ - mouse->has_position = SDL_FALSE; - if (mouse->WarpMouse && (!mouse->relative_mode || mouse->relative_mode_warp)) { mouse->WarpMouse(window, x, y); diff --git a/src/events/SDL_mouse_c.h b/src/events/SDL_mouse_c.h index 70c320851..6b937b5dc 100644 --- a/src/events/SDL_mouse_c.h +++ b/src/events/SDL_mouse_c.h @@ -91,6 +91,7 @@ typedef struct SDL_bool has_position; SDL_bool relative_mode; SDL_bool relative_mode_warp; + SDL_bool relative_mode_warp_motion; float normal_speed_scale; float relative_speed_scale; float scale_accum_x;