From dfb834d3d4d06c9529d7577127d65b88a9ffc52d Mon Sep 17 00:00:00 2001 From: Sam Lantinga 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 | 84 +++++++++++++++++++++++++++------------- src/events/SDL_mouse_c.h | 11 +++++- 2 files changed, 67 insertions(+), 28 deletions(-) diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c index 45fb092f7..9d2ea9a65 100644 --- a/src/events/SDL_mouse.c +++ b/src/events/SDL_mouse.c @@ -177,6 +177,17 @@ SDL_GetMouse(void) return &SDL_mouse; } +static Uint32 GetButtonState(SDL_Mouse *mouse) +{ + int i; + Uint32 buttonstate = 0; + + for (i = 0; i < mouse->num_sources; ++i) { + buttonstate |= mouse->sources[i].buttonstate; + } + return buttonstate; +} + SDL_Window * SDL_GetMouseFocus(void) { @@ -185,25 +196,6 @@ SDL_GetMouseFocus(void) return mouse->focus; } -#if 0 -void -SDL_ResetMouse(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); -} -#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 9c4c62816..0915c3731 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;