From 5ff42438e36e98c9d72ac70f5f5ce4599b96d3d2 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Thu, 17 Mar 2022 17:39:46 -0700 Subject: [PATCH] Added a hint to capture the mouse when mouse buttons are pressed, defaulting on Fixes https://github.com/libsdl-org/SDL/issues/5301 --- include/SDL_hints.h | 13 +++++++++ src/events/SDL_mouse.c | 58 ++++++++++++++++++++++++++++++---------- src/events/SDL_mouse_c.h | 1 + 3 files changed, 58 insertions(+), 14 deletions(-) diff --git a/include/SDL_hints.h b/include/SDL_hints.h index ec324f96b..25383b1a7 100644 --- a/include/SDL_hints.h +++ b/include/SDL_hints.h @@ -969,6 +969,19 @@ extern "C" { */ #define SDL_HINT_MOUSE_TOUCH_EVENTS "SDL_MOUSE_TOUCH_EVENTS" +/** + * \brief A variable controlling whether the mouse is captured while mouse buttons are pressed + * + * This variable can be set to the following values: + * "0" - The mouse is not captured while mouse buttons are pressed + * "1" - The mouse is captured while mouse buttons are pressed + * + * By default the mouse is captured while mouse buttons are pressed so if the mouse is dragged + * outside the window, the application continues to receive mouse events until the button is + * released. + */ +#define SDL_HINT_MOUSE_AUTO_CAPTURE "SDL_MOUSE_AUTO_CAPTURE" + /** * \brief Tell SDL not to catch the SIGINT or SIGTERM signals. * diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c index 0e6de72b0..2e88ee714 100644 --- a/src/events/SDL_mouse.c +++ b/src/events/SDL_mouse.c @@ -127,6 +127,22 @@ SDL_MouseTouchEventsChanged(void *userdata, const char *name, const char *oldVal } } +static void SDLCALL +SDL_MouseAutoCaptureChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_Mouse *mouse = (SDL_Mouse *)userdata; + SDL_bool auto_capture = SDL_GetStringBoolean(hint, SDL_TRUE); + + if (auto_capture != mouse->auto_capture) { + /* Turn off mouse capture if it's currently active because of button presses */ + if (!auto_capture && SDL_GetMouseState(NULL, NULL) != 0) { + SDL_CaptureMouse(SDL_FALSE); + } + + mouse->auto_capture = auto_capture; + } +} + /* Public functions */ int SDL_MouseInit(void) @@ -153,6 +169,9 @@ SDL_MouseInit(void) SDL_AddHintCallback(SDL_HINT_MOUSE_TOUCH_EVENTS, SDL_MouseTouchEventsChanged, mouse); + SDL_AddHintCallback(SDL_HINT_MOUSE_AUTO_CAPTURE, + SDL_MouseAutoCaptureChanged, mouse); + mouse->was_touch_mouse_events = SDL_FALSE; /* no touch to mouse movement event pending */ mouse->cursor_shown = SDL_TRUE; @@ -248,20 +267,7 @@ SDL_UpdateMouseFocus(SDL_Window * window, int x, int y, Uint32 buttonstate, SDL_ } } -/* Linux doesn't give you mouse events outside your window unless you grab - the pointer. - - Windows doesn't give you mouse events outside your window unless you call - SetCapture(). - - Both of these are slightly scary changes, so for now we'll punt and if the - mouse leaves the window you'll lose mouse focus and reset button state. -*/ -#ifdef SUPPORT_DRAG_OUTSIDE_WINDOW - if (!inWindow && !buttonstate) { -#else if (!inWindow) { -#endif if (window == mouse->focus) { #ifdef DEBUG_MOUSE SDL_Log("Mouse left window, synthesizing move & focus lost event\n"); @@ -534,7 +540,8 @@ SDL_PrivateSendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state Uint32 type; Uint32 buttonstate; SDL_MouseInputSource *source; - + SDL_bool had_buttons_pressed = (SDL_GetMouseState(NULL, NULL) ? SDL_TRUE : SDL_FALSE); + source = GetMouseInputSource(mouse, mouseID); if (!source) { return 0; @@ -634,6 +641,14 @@ SDL_PrivateSendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate, SDL_TRUE); } + /* Automatically capture the mouse while buttons are pressed */ + if (mouse->auto_capture) { + SDL_bool has_buttons_pressed = (SDL_GetMouseState(NULL, NULL) ? SDL_TRUE : SDL_FALSE); + if (has_buttons_pressed != had_buttons_pressed) { + SDL_CaptureMouse(has_buttons_pressed); + } + } + return posted; } @@ -758,11 +773,26 @@ SDL_MouseQuit(void) } mouse->num_clickstates = 0; + SDL_DelHintCallback(SDL_HINT_MOUSE_DOUBLE_CLICK_TIME, + SDL_MouseDoubleClickTimeChanged, mouse); + + SDL_DelHintCallback(SDL_HINT_MOUSE_DOUBLE_CLICK_RADIUS, + SDL_MouseDoubleClickRadiusChanged, mouse); + SDL_DelHintCallback(SDL_HINT_MOUSE_NORMAL_SPEED_SCALE, SDL_MouseNormalSpeedScaleChanged, mouse); SDL_DelHintCallback(SDL_HINT_MOUSE_RELATIVE_SPEED_SCALE, SDL_MouseRelativeSpeedScaleChanged, mouse); + + SDL_DelHintCallback(SDL_HINT_TOUCH_MOUSE_EVENTS, + SDL_TouchMouseEventsChanged, mouse); + + SDL_DelHintCallback(SDL_HINT_MOUSE_TOUCH_EVENTS, + SDL_MouseTouchEventsChanged, mouse); + + SDL_DelHintCallback(SDL_HINT_MOUSE_AUTO_CAPTURE, + SDL_MouseAutoCaptureChanged, mouse); } Uint32 diff --git a/src/events/SDL_mouse_c.h b/src/events/SDL_mouse_c.h index b7fb9fd5b..7b020447a 100644 --- a/src/events/SDL_mouse_c.h +++ b/src/events/SDL_mouse_c.h @@ -100,6 +100,7 @@ typedef struct SDL_bool touch_mouse_events; SDL_bool mouse_touch_events; SDL_bool was_touch_mouse_events; /* Was a touch-mouse event pending? */ + SDL_bool auto_capture; /* Data for input source state */ int num_sources;