Skip to content

Commit

Permalink
Fixed mouse click count for relative mode and multiple mice
Browse files Browse the repository at this point in the history
We'll track the click count separately for each input source, and the click distance is calculated using a point on an infinite plane that is pushed around by mouse motion deltas, unclamped by the window edge.
  • Loading branch information
slouken committed Dec 24, 2024
1 parent ed75d9d commit 483e79b
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 31 deletions.
42 changes: 22 additions & 20 deletions src/events/SDL_mouse.c
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ void SDL_RemoveMouse(SDL_MouseID mouseID, bool send_event)
for (int i = 0; i < mouse->num_sources; ++i) {
SDL_MouseInputSource *source = &mouse->sources[i];
if (source->mouseID == mouseID) {
SDL_free(source->clickstate);
if (i != mouse->num_sources - 1) {
SDL_memcpy(&mouse->sources[i], &mouse->sources[i + 1], (mouse->num_sources - i - 1) * sizeof(mouse->sources[i]));
}
Expand Down Expand Up @@ -728,6 +729,9 @@ static void SDL_PrivateSendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL
// Use unclamped values if we're getting events outside the window
mouse->last_x = relative ? mouse->x : x;
mouse->last_y = relative ? mouse->y : y;

mouse->click_motion_x += xrel;
mouse->click_motion_y += yrel;
}

// Move the mouse cursor, if needed
Expand Down Expand Up @@ -795,29 +799,29 @@ static SDL_MouseInputSource *GetMouseInputSource(SDL_Mouse *mouse, SDL_MouseID m
mouse->sources = sources;
++mouse->num_sources;
source = &sources[mouse->num_sources - 1];
SDL_zerop(source);
source->mouseID = mouseID;
source->buttonstate = 0;
return source;
}
return NULL;
}

static SDL_MouseClickState *GetMouseClickState(SDL_Mouse *mouse, Uint8 button)
static SDL_MouseClickState *GetMouseClickState(SDL_MouseInputSource *source, Uint8 button)
{
if (button >= mouse->num_clickstates) {
if (button >= source->num_clickstates) {
int i, count = button + 1;
SDL_MouseClickState *clickstate = (SDL_MouseClickState *)SDL_realloc(mouse->clickstate, count * sizeof(*mouse->clickstate));
SDL_MouseClickState *clickstate = (SDL_MouseClickState *)SDL_realloc(source->clickstate, count * sizeof(*source->clickstate));
if (!clickstate) {
return NULL;
}
mouse->clickstate = clickstate;
source->clickstate = clickstate;

for (i = mouse->num_clickstates; i < count; ++i) {
SDL_zero(mouse->clickstate[i]);
for (i = source->num_clickstates; i < count; ++i) {
SDL_zero(source->clickstate[i]);
}
mouse->num_clickstates = count;
source->num_clickstates = count;
}
return &mouse->clickstate[button];
return &source->clickstate[button];
}

static void SDL_PrivateSendMouseButton(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, Uint8 button, bool down, int clicks)
Expand Down Expand Up @@ -882,19 +886,19 @@ static void SDL_PrivateSendMouseButton(Uint64 timestamp, SDL_Window *window, SDL
source->buttonstate = buttonstate;

if (clicks < 0) {
SDL_MouseClickState *clickstate = GetMouseClickState(mouse, button);
SDL_MouseClickState *clickstate = GetMouseClickState(source, button);
if (clickstate) {
if (down) {
Uint64 now = SDL_GetTicks();

if (now >= (clickstate->last_timestamp + mouse->double_click_time) ||
SDL_fabs((double)mouse->x - clickstate->last_x) > mouse->double_click_radius ||
SDL_fabs((double)mouse->y - clickstate->last_y) > mouse->double_click_radius) {
SDL_fabs(mouse->click_motion_x - clickstate->click_motion_x) > mouse->double_click_radius ||
SDL_fabs(mouse->click_motion_y - clickstate->click_motion_y) > mouse->double_click_radius) {
clickstate->click_count = 0;
}
clickstate->last_timestamp = now;
clickstate->last_x = mouse->x;
clickstate->last_y = mouse->y;
clickstate->click_motion_x = mouse->click_motion_x;
clickstate->click_motion_y = mouse->click_motion_y;
if (clickstate->click_count < 255) {
++clickstate->click_count;
}
Expand Down Expand Up @@ -1001,17 +1005,15 @@ void SDL_QuitMouse(void)
mouse->cur_cursor = NULL;

if (mouse->sources) {
for (int i = 0; i < mouse->num_sources; ++i) {
SDL_MouseInputSource *source = &mouse->sources[i];
SDL_free(source->clickstate);
}
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_RemoveHintCallback(SDL_HINT_MOUSE_DOUBLE_CLICK_TIME,
SDL_MouseDoubleClickTimeChanged, mouse);

Expand Down
25 changes: 14 additions & 11 deletions src/events/SDL_mouse_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,22 @@ struct SDL_Cursor

typedef struct
{
SDL_MouseID mouseID;
Uint32 buttonstate;
} SDL_MouseInputSource;

typedef struct
{
float last_x, last_y;
Uint64 last_timestamp;
double click_motion_x;
double click_motion_y;
Uint8 click_count;
} SDL_MouseClickState;

typedef struct
{
SDL_MouseID mouseID;
Uint32 buttonstate;

// Data for double-click tracking
int num_clickstates;
SDL_MouseClickState *clickstate;
} SDL_MouseInputSource;

typedef struct
{
// Create a cursor from a surface
Expand Down Expand Up @@ -93,6 +98,8 @@ typedef struct
float x_accu;
float y_accu;
float last_x, last_y; // the last reported x and y coordinates
double click_motion_x;
double click_motion_y;
bool has_position;
bool relative_mode;
bool relative_mode_warp_motion;
Expand Down Expand Up @@ -123,10 +130,6 @@ typedef struct
int num_sources;
SDL_MouseInputSource *sources;

// Data for double-click tracking
int num_clickstates;
SDL_MouseClickState *clickstate;

SDL_Cursor *cursors;
SDL_Cursor *def_cursor;
SDL_Cursor *cur_cursor;
Expand Down

0 comments on commit 483e79b

Please sign in to comment.