From 5ff42438e36e98c9d72ac70f5f5ce4599b96d3d2 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
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 ec324f96bf6..25383b1a72a 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 0e6de72b019..2e88ee71459 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 b7fb9fd5bde..7b020447a9b 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;