From b861efde14f093864396bf04acb4f3ae1cf4569d Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Thu, 5 Jun 2014 00:03:33 -0400 Subject: [PATCH] Implemented SDL_GetAbsoluteMouseState(). X11 only for now, but this should be doable on every platform, I think. --- include/SDL_mouse.h | 25 +++++++++++++++++++++++ src/dynapi/SDL_dynapi_overrides.h | 1 + src/dynapi/SDL_dynapi_procs.h | 1 + src/events/SDL_mouse.c | 24 ++++++++++++++++++++++ src/events/SDL_mouse_c.h | 3 +++ src/test/SDL_test_common.c | 13 ++++++++++++ src/video/x11/SDL_x11mouse.c | 34 +++++++++++++++++++++++++++++++ 7 files changed, 101 insertions(+) diff --git a/include/SDL_mouse.h b/include/SDL_mouse.h index 571754ad2f9ee..fdb68f04047f2 100644 --- a/include/SDL_mouse.h +++ b/include/SDL_mouse.h @@ -77,6 +77,31 @@ extern DECLSPEC SDL_Window * SDLCALL SDL_GetMouseFocus(void); */ extern DECLSPEC Uint32 SDLCALL SDL_GetMouseState(int *x, int *y); +/** + * \brief Get the current state of the mouse, in relation to the desktop + * + * This works just like SDL_GetMouseState(), but the coordinates will be + * reported relative to the top-left of the desktop. This can be useful if + * you need to track the mouse outside of a specific window and + * SDL_CaptureMouse() doesn't fit your needs. For example, it could be + * useful if you need to track the mouse while dragging a window, where + * coordinates relative to a window might not be in sync at all times. + * + * \note SDL_GetMouseState() returns the mouse position as SDL understands + * it from the last pump of the event queue. This function, however, + * queries the OS for the current mouse position, and as such, might + * be a slightly less efficient function. Unless you know what you're + * doing and have a good reason to use this function, you probably want + * SDL_GetMouseState() instead. + * + * \param x Returns the current X coord, relative to the desktop. Can be NULL. + * \param y Returns the current Y coord, relative to the desktop. Can be NULL. + * \return The current button state as a bitmask, which can be tested using the SDL_BUTTON(X) macros. + * + * \sa SDL_GetMouseState + */ +extern DECLSPEC Uint32 SDLCALL SDL_GetAbsoluteMouseState(int *x, int *y); + /** * \brief Retrieve the relative state of the mouse. * diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index ce11175292f13..aa996399e34c2 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -581,3 +581,4 @@ #define SDL_WinRTRunApp SDL_WinRTRunApp_REAL #define SDL_CaptureMouse SDL_CaptureMouse_REAL #define SDL_SetWindowHitTest SDL_SetWindowHitTest_REAL +#define SDL_GetAbsoluteMouseState SDL_GetAbsoluteMouseState_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index ba78b98ad424b..1df1222572c42 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -614,3 +614,4 @@ SDL_DYNAPI_PROC(int,SDL_WinRTRunApp,(int a, char **b, void *c),(a,b,c),return) #endif SDL_DYNAPI_PROC(int,SDL_CaptureMouse,(SDL_bool a),(a),return) SDL_DYNAPI_PROC(int,SDL_SetWindowHitTest,(SDL_Window *a, SDL_HitTest b, void *c),(a,b,c),return) +SDL_DYNAPI_PROC(Uint32,SDL_GetAbsoluteMouseState,(int *a, int *b),(a,b),return) diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c index 757c63490ff56..970cc78c1a621 100644 --- a/src/events/SDL_mouse.c +++ b/src/events/SDL_mouse.c @@ -469,6 +469,30 @@ SDL_GetRelativeMouseState(int *x, int *y) return mouse->buttonstate; } +Uint32 +SDL_GetAbsoluteMouseState(int *x, int *y) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + int tmpx, tmpy; + + /* make sure these are never NULL for the backend implementations... */ + if (!x) { + x = &tmpx; + } + if (!y) { + y = &tmpy; + } + + *x = *y = 0; + + if (!mouse->GetAbsoluteMouseState) { + SDL_assert(0 && "This should really be implemented for every target."); + return 0; + } + + return mouse->GetAbsoluteMouseState(x, y); +} + void SDL_WarpMouseInWindow(SDL_Window * window, int x, int y) { diff --git a/src/events/SDL_mouse_c.h b/src/events/SDL_mouse_c.h index 34cd259e60393..70b3ec0b303cc 100644 --- a/src/events/SDL_mouse_c.h +++ b/src/events/SDL_mouse_c.h @@ -66,6 +66,9 @@ typedef struct /* Set mouse capture */ int (*CaptureMouse) (SDL_Window * window); + /* Get absolute mouse coordinates. (x) and (y) are never NULL and set to zero before call. */ + Uint32 (*GetAbsoluteMouseState) (int *x, int *y); + /* Data common to all mice */ SDL_MouseID mouseID; SDL_Window *focus; diff --git a/src/test/SDL_test_common.c b/src/test/SDL_test_common.c index 2c4cabc7c57cd..fa6c1fea94d1e 100644 --- a/src/test/SDL_test_common.c +++ b/src/test/SDL_test_common.c @@ -1488,6 +1488,19 @@ SDLTest_CommonEvent(SDLTest_CommonState * state, SDL_Event * event, int *done) } } break; + case SDLK_a: + if (withControl) { + /* Ctrl-A reports absolute mouse position. */ + int x, y; + const Uint32 mask = SDL_GetAbsoluteMouseState(&x, &y); + SDL_Log("ABSOLUTE MOUSE: (%d, %d)%s%s%s%s%s\n", x, y, + (mask & SDL_BUTTON_LMASK) ? " [LBUTTON]" : "", + (mask & SDL_BUTTON_MMASK) ? " [MBUTTON]" : "", + (mask & SDL_BUTTON_RMASK) ? " [RBUTTON]" : "", + (mask & SDL_BUTTON_X1MASK) ? " [X2BUTTON]" : "", + (mask & SDL_BUTTON_X2MASK) ? " [X2BUTTON]" : ""); + } + break; case SDLK_0: if (withControl) { SDL_Window *window = SDL_GetWindowFromID(event->key.windowID); diff --git a/src/video/x11/SDL_x11mouse.c b/src/video/x11/SDL_x11mouse.c index 74dc8789c4c9f..7386da5fb9ced 100644 --- a/src/video/x11/SDL_x11mouse.c +++ b/src/video/x11/SDL_x11mouse.c @@ -353,6 +353,39 @@ X11_CaptureMouse(SDL_Window *window) return 0; } +static Uint32 +X11_GetAbsoluteMouseState(int *x, int *y) +{ + Display *display = GetDisplay(); + const int num_screens = SDL_GetNumVideoDisplays(); + int i; + + /* !!! FIXME: should we XSync() here first? */ + + for (i = 0; i < num_screens; i++) { + SDL_DisplayData *data = (SDL_DisplayData *) SDL_GetDisplayDriverData(i); + if (data != NULL) { + Window root, child; + int rootx, rooty, winx, winy; + unsigned int mask; + if (X11_XQueryPointer(display, RootWindow(display, data->screen), &root, &child, &rootx, &rooty, &winx, &winy, &mask)) { + Uint32 retval = 0; + retval |= (mask & Button1Mask) ? SDL_BUTTON_LMASK : 0; + retval |= (mask & Button2Mask) ? SDL_BUTTON_MMASK : 0; + retval |= (mask & Button3Mask) ? SDL_BUTTON_RMASK : 0; + *x = data->x + rootx; + *y = data->y + rooty; + return retval; + } + } + } + + SDL_assert(0 && "The pointer wasn't on any X11 screen?!"); + + return 0; +} + + void X11_InitMouse(_THIS) { @@ -365,6 +398,7 @@ X11_InitMouse(_THIS) mouse->WarpMouse = X11_WarpMouse; mouse->SetRelativeMouseMode = X11_SetRelativeMouseMode; mouse->CaptureMouse = X11_CaptureMouse; + mouse->GetAbsoluteMouseState = X11_GetAbsoluteMouseState; SDL_SetDefaultCursor(X11_CreateDefaultCursor()); }