Added a hint to capture the mouse when mouse buttons are pressed, defaulting on

Fixes https://github.com/libsdl-org/SDL/issues/5301
This commit is contained in:
Sam Lantinga 2022-03-17 17:39:46 -07:00
parent 09b8152fae
commit 5ff42438e3
3 changed files with 58 additions and 14 deletions

View File

@ -969,6 +969,19 @@ extern "C" {
*/ */
#define SDL_HINT_MOUSE_TOUCH_EVENTS "SDL_MOUSE_TOUCH_EVENTS" #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. * \brief Tell SDL not to catch the SIGINT or SIGTERM signals.
* *

View File

@ -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 */ /* Public functions */
int int
SDL_MouseInit(void) SDL_MouseInit(void)
@ -153,6 +169,9 @@ SDL_MouseInit(void)
SDL_AddHintCallback(SDL_HINT_MOUSE_TOUCH_EVENTS, SDL_AddHintCallback(SDL_HINT_MOUSE_TOUCH_EVENTS,
SDL_MouseTouchEventsChanged, mouse); 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->was_touch_mouse_events = SDL_FALSE; /* no touch to mouse movement event pending */
mouse->cursor_shown = SDL_TRUE; 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) { if (!inWindow) {
#endif
if (window == mouse->focus) { if (window == mouse->focus) {
#ifdef DEBUG_MOUSE #ifdef DEBUG_MOUSE
SDL_Log("Mouse left window, synthesizing move & focus lost event\n"); SDL_Log("Mouse left window, synthesizing move & focus lost event\n");
@ -534,6 +540,7 @@ SDL_PrivateSendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state
Uint32 type; Uint32 type;
Uint32 buttonstate; Uint32 buttonstate;
SDL_MouseInputSource *source; SDL_MouseInputSource *source;
SDL_bool had_buttons_pressed = (SDL_GetMouseState(NULL, NULL) ? SDL_TRUE : SDL_FALSE);
source = GetMouseInputSource(mouse, mouseID); source = GetMouseInputSource(mouse, mouseID);
if (!source) { if (!source) {
@ -634,6 +641,14 @@ SDL_PrivateSendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state
SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate, SDL_TRUE); 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; return posted;
} }
@ -758,11 +773,26 @@ SDL_MouseQuit(void)
} }
mouse->num_clickstates = 0; 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_DelHintCallback(SDL_HINT_MOUSE_NORMAL_SPEED_SCALE,
SDL_MouseNormalSpeedScaleChanged, mouse); SDL_MouseNormalSpeedScaleChanged, mouse);
SDL_DelHintCallback(SDL_HINT_MOUSE_RELATIVE_SPEED_SCALE, SDL_DelHintCallback(SDL_HINT_MOUSE_RELATIVE_SPEED_SCALE,
SDL_MouseRelativeSpeedScaleChanged, mouse); 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 Uint32

View File

@ -100,6 +100,7 @@ typedef struct
SDL_bool touch_mouse_events; SDL_bool touch_mouse_events;
SDL_bool mouse_touch_events; SDL_bool mouse_touch_events;
SDL_bool was_touch_mouse_events; /* Was a touch-mouse event pending? */ SDL_bool was_touch_mouse_events; /* Was a touch-mouse event pending? */
SDL_bool auto_capture;
/* Data for input source state */ /* Data for input source state */
int num_sources; int num_sources;