From 746928350f9f011c85331020f133d703b80305d9 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Mon, 23 Dec 2013 12:17:52 -0800 Subject: [PATCH] Added support for double-clicks, through a new "clicks" field in the mouse button event. --- include/SDL_events.h | 2 +- src/events/SDL_mouse.c | 54 ++++++++++++++++++++++++++++ src/events/SDL_mouse_c.h | 14 ++++++++ src/test/SDL_test_common.c | 8 ++--- src/video/windows/SDL_windowsmouse.c | 2 ++ 5 files changed, 75 insertions(+), 5 deletions(-) diff --git a/include/SDL_events.h b/include/SDL_events.h index c08903073a9b1..81ff4dd564740 100644 --- a/include/SDL_events.h +++ b/include/SDL_events.h @@ -239,8 +239,8 @@ typedef struct SDL_MouseButtonEvent Uint32 which; /**< The mouse instance id, or SDL_TOUCH_MOUSEID */ Uint8 button; /**< The mouse button index */ Uint8 state; /**< ::SDL_PRESSED or ::SDL_RELEASED */ + Uint8 clicks; /**< 1 for single-click, 2 for double-click, etc. */ Uint8 padding1; - Uint8 padding2; Sint32 x; /**< X coordinate, relative to window */ Sint32 y; /**< Y coordinate, relative to window */ } SDL_MouseButtonEvent; diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c index 0bb0b184df889..742802a755a01 100644 --- a/src/events/SDL_mouse.c +++ b/src/events/SDL_mouse.c @@ -23,6 +23,7 @@ /* General mouse handling code for SDL */ #include "SDL_assert.h" +#include "SDL_timer.h" #include "SDL_events.h" #include "SDL_events_c.h" #include "default_cursor.h" @@ -32,6 +33,8 @@ /* The mouse state */ static SDL_Mouse SDL_mouse; +static Uint32 SDL_double_click_time = 500; +static int SDL_double_click_radius = 1; static int SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y); @@ -64,6 +67,12 @@ SDL_GetMouse(void) return &SDL_mouse; } +void +SDL_SetDoubleClickTime(Uint32 interval) +{ + SDL_double_click_time = interval; +} + SDL_Window * SDL_GetMouseFocus(void) { @@ -272,6 +281,23 @@ SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relativ return posted; } +static SDL_MouseClickState *GetMouseClickState(SDL_Mouse *mouse, Uint8 button) +{ + if (button >= mouse->num_clickstates) { + int i, count = button + 1; + mouse->clickstate = (SDL_MouseClickState *)SDL_realloc(mouse->clickstate, count * sizeof(*mouse->clickstate)); + if (!mouse->clickstate) { + return NULL; + } + + for (i = mouse->num_clickstates; i < count; ++i) { + SDL_zero(mouse->clickstate[i]); + } + mouse->num_clickstates = count; + } + return &mouse->clickstate[button]; +} + int SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button) { @@ -279,6 +305,8 @@ SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 int posted; Uint32 type; Uint32 buttonstate = mouse->buttonstate; + SDL_MouseClickState *clickstate = GetMouseClickState(mouse, button); + Uint8 click_count; /* Figure out which event to perform */ switch (state) { @@ -306,6 +334,27 @@ SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 } mouse->buttonstate = buttonstate; + if (clickstate) { + if (state == SDL_PRESSED) { + Uint32 now = SDL_GetTicks(); + + if (SDL_TICKS_PASSED(now, clickstate->last_timestamp + SDL_double_click_time) || + SDL_abs(mouse->x - clickstate->last_x) > SDL_double_click_radius || + SDL_abs(mouse->y - clickstate->last_y) > SDL_double_click_radius) { + clickstate->click_count = 0; + } + clickstate->last_timestamp = now; + clickstate->last_x = mouse->x; + clickstate->last_y = mouse->y; + if (clickstate->click_count < 255) { + ++clickstate->click_count; + } + } + click_count = clickstate->click_count; + } else { + click_count = 1; + } + /* Post the event, if desired */ posted = 0; if (SDL_GetEventState(type) == SDL_ENABLE) { @@ -315,6 +364,7 @@ SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 event.button.which = mouseID; event.button.state = state; event.button.button = button; + event.button.clicks = click_count; event.button.x = mouse->x; event.button.y = mouse->y; posted = (SDL_PushEvent(&event) > 0); @@ -376,6 +426,10 @@ SDL_MouseQuit(void) mouse->FreeCursor(mouse->def_cursor); } + if (mouse->clickstate) { + SDL_free(mouse->clickstate); + } + SDL_zerop(mouse); } diff --git a/src/events/SDL_mouse_c.h b/src/events/SDL_mouse_c.h index a8faa2e17f46a..fd34c66f87d00 100644 --- a/src/events/SDL_mouse_c.h +++ b/src/events/SDL_mouse_c.h @@ -33,6 +33,13 @@ struct SDL_Cursor void *driverdata; }; +typedef struct +{ + int last_x, last_y; + Uint32 last_timestamp; + Uint8 click_count; +} SDL_MouseClickState; + typedef struct { /* Create a cursor from a surface */ @@ -69,6 +76,10 @@ typedef struct /* the x and y coordinates when relative mode was activated */ int original_x, original_y; + /* Data for double-click tracking */ + int num_clickstates; + SDL_MouseClickState *clickstate; + SDL_Cursor *cursors; SDL_Cursor *def_cursor; SDL_Cursor *cur_cursor; @@ -85,6 +96,9 @@ extern int SDL_MouseInit(void); /* Get the mouse state structure */ SDL_Mouse *SDL_GetMouse(void); +/* Set the default double-click interval */ +extern void SDL_SetDoubleClickTime(Uint32 interval); + /* Set the default mouse cursor */ extern void SDL_SetDefaultCursor(SDL_Cursor * cursor); diff --git a/src/test/SDL_test_common.c b/src/test/SDL_test_common.c index 3b4d3323fc33b..ee65b3f0cc94b 100644 --- a/src/test/SDL_test_common.c +++ b/src/test/SDL_test_common.c @@ -1042,13 +1042,13 @@ SDLTest_PrintEvent(SDL_Event * event) event->motion.windowID); break; case SDL_MOUSEBUTTONDOWN: - fprintf(stderr, "Mouse: button %d pressed at %d,%d in window %d", - event->button.button, event->button.x, event->button.y, + fprintf(stderr, "Mouse: button %d pressed at %d,%d with click count %d in window %d", + event->button.button, event->button.x, event->button.y, event->button.clicks, event->button.windowID); break; case SDL_MOUSEBUTTONUP: - fprintf(stderr, "Mouse: button %d released at %d,%d in window %d", - event->button.button, event->button.x, event->button.y, + fprintf(stderr, "Mouse: button %d released at %d,%d with click count %d in window %d", + event->button.button, event->button.x, event->button.y, event->button.clicks, event->button.windowID); break; case SDL_MOUSEWHEEL: diff --git a/src/video/windows/SDL_windowsmouse.c b/src/video/windows/SDL_windowsmouse.c index f75b8dad335d9..2298dc89a8bf6 100644 --- a/src/video/windows/SDL_windowsmouse.c +++ b/src/video/windows/SDL_windowsmouse.c @@ -250,6 +250,8 @@ WIN_InitMouse(_THIS) mouse->SetRelativeMouseMode = WIN_SetRelativeMouseMode; SDL_SetDefaultCursor(WIN_CreateDefaultCursor()); + + SDL_SetDoubleClickTime(GetDoubleClickTime()); } void