Skip to content

Commit

Permalink
Added a hint to capture the mouse when mouse buttons are pressed, def…
Browse files Browse the repository at this point in the history
…aulting on

Fixes #5301
  • Loading branch information
slouken committed Mar 18, 2022
1 parent 09b8152 commit 5ff4243
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 14 deletions.
13 changes: 13 additions & 0 deletions include/SDL_hints.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down
58 changes: 44 additions & 14 deletions src/events/SDL_mouse.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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;
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/events/SDL_mouse_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 5ff4243

Please sign in to comment.