From dfb834d3d4d06c9529d7577127d65b88a9ffc52d Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Wed, 10 Nov 2021 13:41:44 -0800
Subject: [PATCH] Track button state for each mouse input source separately
This way we'll get button down and up events for each mouseID
individually.
Fixes https://github.com/libsdl-org/SDL/issues/4518
---
src/events/SDL_mouse.c | 82 +++++++++++++++++++++++++++-------------
src/events/SDL_mouse_c.h | 11 +++++-
2 files changed, 66 insertions(+), 27 deletions(-)
diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c
index 45fb092f76..9d2ea9a65d 100644
--- a/src/events/SDL_mouse.c
+++ b/src/events/SDL_mouse.c
@@ -177,32 +177,24 @@ SDL_GetMouse(void)
return &SDL_mouse;
}
-SDL_Window *
-SDL_GetMouseFocus(void)
+static Uint32 GetButtonState(SDL_Mouse *mouse)
{
- SDL_Mouse *mouse = SDL_GetMouse();
+ int i;
+ Uint32 buttonstate = 0;
- return mouse->focus;
+ for (i = 0; i < mouse->num_sources; ++i) {
+ buttonstate |= mouse->sources[i].buttonstate;
+ }
+ return buttonstate;
}
-#if 0
-void
-SDL_ResetMouse(void)
+SDL_Window *
+SDL_GetMouseFocus(void)
{
SDL_Mouse *mouse = SDL_GetMouse();
- Uint8 i;
-#ifdef DEBUG_MOUSE
- printf("Resetting mouse\n");
-#endif
- for (i = 1; i <= sizeof(mouse->buttonstate)*8; ++i) {
- if (mouse->buttonstate & SDL_BUTTON(i)) {
- SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, i);
- }
- }
- SDL_assert(mouse->buttonstate == 0);
+ return mouse->focus;
}
-#endif
void
SDL_SetMouseFocus(SDL_Window * window)
@@ -299,7 +291,7 @@ SDL_SendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int
{
if (window && !relative) {
SDL_Mouse *mouse = SDL_GetMouse();
- if (!SDL_UpdateMouseFocus(window, x, y, mouse->buttonstate, (mouseID == SDL_TOUCH_MOUSEID) ? SDL_FALSE : SDL_TRUE)) {
+ if (!SDL_UpdateMouseFocus(window, x, y, GetButtonState(mouse), (mouseID == SDL_TOUCH_MOUSEID) ? SDL_FALSE : SDL_TRUE)) {
return 0;
}
}
@@ -399,7 +391,7 @@ SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relativ
}
/* Ignore relative motion positioning the first touch */
- if (mouseID == SDL_TOUCH_MOUSEID && !mouse->buttonstate) {
+ if (mouseID == SDL_TOUCH_MOUSEID && !GetButtonState(mouse)) {
xrel = 0;
yrel = 0;
}
@@ -473,7 +465,7 @@ SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relativ
event.motion.which = mouseID;
/* Set us pending (or clear during a normal mouse movement event) as having triggered */
mouse->was_touch_mouse_events = (mouseID == SDL_TOUCH_MOUSEID)? SDL_TRUE : SDL_FALSE;
- event.motion.state = mouse->buttonstate;
+ event.motion.state = GetButtonState(mouse);
event.motion.x = mouse->x;
event.motion.y = mouse->y;
event.motion.xrel = xrel;
@@ -491,6 +483,30 @@ SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relativ
return posted;
}
+static SDL_MouseInputSource *GetMouseInputSource(SDL_Mouse *mouse, SDL_MouseID mouseID)
+{
+ SDL_MouseInputSource *source, *sources;
+ int i;
+
+ for (i = 0; i < mouse->num_sources; ++i) {
+ source = &mouse->sources[i];
+ if (source->mouseID == mouseID) {
+ return source;
+ }
+ }
+
+ sources = (SDL_MouseInputSource *)SDL_realloc(mouse->sources, (mouse->num_sources + 1)*sizeof(*mouse->sources));
+ if (sources) {
+ mouse->sources = sources;
+ ++mouse->num_sources;
+ source = &sources[mouse->num_sources - 1];
+ source->mouseID = mouseID;
+ source->buttonstate = 0;
+ return source;
+ }
+ return NULL;
+}
+
static SDL_MouseClickState *GetMouseClickState(SDL_Mouse *mouse, Uint8 button)
{
if (button >= mouse->num_clickstates) {
@@ -515,7 +531,14 @@ SDL_PrivateSendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state
SDL_Mouse *mouse = SDL_GetMouse();
int posted;
Uint32 type;
- Uint32 buttonstate = mouse->buttonstate;
+ Uint32 buttonstate;
+ SDL_MouseInputSource *source;
+
+ source = GetMouseInputSource(mouse, mouseID);
+ if (!source) {
+ return 0;
+ }
+ buttonstate = source->buttonstate;
/* SDL_HINT_MOUSE_TOUCH_EVENTS: controlling whether mouse events should generate synthetic touch events */
if (mouse->mouse_touch_events) {
@@ -560,11 +583,11 @@ SDL_PrivateSendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state
SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate, SDL_TRUE);
}
- if (buttonstate == mouse->buttonstate) {
+ if (buttonstate == source->buttonstate) {
/* Ignore this event, no state change */
return 0;
}
- mouse->buttonstate = buttonstate;
+ source->buttonstate = buttonstate;
if (clicks < 0) {
SDL_MouseClickState *clickstate = GetMouseClickState(mouse, button);
@@ -722,10 +745,17 @@ SDL_MouseQuit(void)
mouse->def_cursor = NULL;
}
+ if (mouse->sources) {
+ SDL_free(mouse->sources);
+ mouse->sources = NULL;
+ }
+ mouse->num_sources = 0;
+
if (mouse->clickstate) {
SDL_free(mouse->clickstate);
mouse->clickstate = NULL;
}
+ mouse->num_clickstates = 0;
SDL_DelHintCallback(SDL_HINT_MOUSE_NORMAL_SPEED_SCALE,
SDL_MouseNormalSpeedScaleChanged, mouse);
@@ -745,7 +775,7 @@ SDL_GetMouseState(int *x, int *y)
if (y) {
*y = mouse->y;
}
- return mouse->buttonstate;
+ return GetButtonState(mouse);
}
Uint32
@@ -761,7 +791,7 @@ SDL_GetRelativeMouseState(int *x, int *y)
}
mouse->xdelta = 0;
mouse->ydelta = 0;
- return mouse->buttonstate;
+ return GetButtonState(mouse);
}
Uint32
diff --git a/src/events/SDL_mouse_c.h b/src/events/SDL_mouse_c.h
index 9c4c62816d..0915c37313 100644
--- a/src/events/SDL_mouse_c.h
+++ b/src/events/SDL_mouse_c.h
@@ -33,6 +33,12 @@ struct SDL_Cursor
void *driverdata;
};
+typedef struct
+{
+ SDL_MouseID mouseID;
+ Uint32 buttonstate;
+} SDL_MouseInputSource;
+
typedef struct
{
int last_x, last_y;
@@ -82,7 +88,6 @@ typedef struct
int last_x, last_y; /* the last reported x and y coordinates */
float accumulated_wheel_x;
float accumulated_wheel_y;
- Uint32 buttonstate;
SDL_bool has_position;
SDL_bool relative_mode;
SDL_bool relative_mode_warp;
@@ -96,6 +101,10 @@ typedef struct
SDL_bool mouse_touch_events;
SDL_bool was_touch_mouse_events; /* Was a touch-mouse event pending? */
+ /* Data for input source state */
+ int num_sources;
+ SDL_MouseInputSource *sources;
+
/* Data for double-click tracking */
int num_clickstates;
SDL_MouseClickState *clickstate;