Commit 45ed5ee4945050de59a1868679e75a68d97e6977

Sam Lantinga 2014-06-04T10:55:26

Added an API function to warp the mouse cursor in global screen space: SDL_WarpMouseGlobal()

diff --git a/include/SDL_mouse.h b/include/SDL_mouse.h
index ebfd18f..69eb854 100644
--- a/include/SDL_mouse.h
+++ b/include/SDL_mouse.h
@@ -99,6 +99,16 @@ extern DECLSPEC void SDLCALL SDL_WarpMouseInWindow(SDL_Window * window,
                                                    int x, int y);
 
 /**
+ *  \brief Moves the mouse to the given position in global screen space.
+ *
+ *  \param x The x coordinate
+ *  \param y The y coordinate
+ *
+ *  \note This function generates a mouse motion event
+ */
+extern DECLSPEC void SDLCALL SDL_WarpMouseGlobal(int x, int y);
+
+/**
  *  \brief Set relative mouse mode.
  *
  *  \param enabled Whether or not to enable relative mode
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index 52b3d45..42f12a7 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -576,6 +576,7 @@
 #define SDL_GetAssertionHandler SDL_GetAssertionHandler_REAL
 #define SDL_DXGIGetOutputInfo SDL_DXGIGetOutputInfo_REAL
 #define SDL_RenderIsClipEnabled SDL_RenderIsClipEnabled_REAL
+#define SDL_WinRTRunApp SDL_WinRTRunApp_REAL
+#define SDL_WarpMouseGlobal SDL_WarpMouseGlobal_REAL
 #define SDL_WinRTGetFSPathUNICODE SDL_WinRTGetFSPathUNICODE_REAL
 #define SDL_WinRTGetFSPathUTF8 SDL_WinRTGetFSPathUTF8_REAL
-#define SDL_WinRTRunApp SDL_WinRTRunApp_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index d84a938..d39b19a 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -608,7 +608,8 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_DXGIGetOutputInfo,(int a,int *b, int *c),(a,b,c),re
 #endif
 SDL_DYNAPI_PROC(SDL_bool,SDL_RenderIsClipEnabled,(SDL_Renderer *a),(a),return)
 #ifdef __WINRT__
+SDL_DYNAPI_PROC(int,SDL_WinRTRunApp,(int a, char **b, void *c),(a,b,c),return)
 SDL_DYNAPI_PROC(const wchar_t*,SDL_WinRTGetFSPathUNICODE,(SDL_WinRT_Path a),(a),return)
 SDL_DYNAPI_PROC(const char*,SDL_WinRTGetFSPathUTF8,(SDL_WinRT_Path a),(a),return)
-SDL_DYNAPI_PROC(int,SDL_WinRTRunApp,(int a, char **b, void *c),(a,b,c),return)
 #endif
+SDL_DYNAPI_PROC(void,SDL_WarpMouseGlobal,(int a, int b),(a,b),)
diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c
index 3f82b4e..4ee6884 100644
--- a/src/events/SDL_mouse.c
+++ b/src/events/SDL_mouse.c
@@ -482,10 +482,10 @@ SDL_WarpMouseInWindow(SDL_Window * window, int x, int y)
 {
     SDL_Mouse *mouse = SDL_GetMouse();
 
-    if ( window == NULL )
+    if (window == NULL)
         window = mouse->focus;
 
-    if ( window == NULL )
+    if (window == NULL)
         return;
 
     if (mouse->WarpMouse) {
@@ -495,6 +495,16 @@ SDL_WarpMouseInWindow(SDL_Window * window, int x, int y)
     }
 }
 
+void
+SDL_WarpMouseGlobal(int x, int y)
+{
+    SDL_Mouse *mouse = SDL_GetMouse();
+
+    if (mouse->WarpMouseGlobal) {
+        mouse->WarpMouseGlobal(x, y);
+    }
+}
+
 static SDL_bool
 ShouldUseRelativeModeWarp(SDL_Mouse *mouse)
 {
diff --git a/src/events/SDL_mouse_c.h b/src/events/SDL_mouse_c.h
index e0d917c..7157a1c 100644
--- a/src/events/SDL_mouse_c.h
+++ b/src/events/SDL_mouse_c.h
@@ -57,9 +57,12 @@ typedef struct
     /* Free a window manager cursor */
     void (*FreeCursor) (SDL_Cursor * cursor);
 
-    /* Warp the mouse to (x,y) */
+    /* Warp the mouse to (x,y) within a window */
     void (*WarpMouse) (SDL_Window * window, int x, int y);
 
+    /* Warp the mouse to (x,y) in screen space */
+    void (*WarpMouseGlobal) (int x, int y);
+
     /* Set relative mode */
     int (*SetRelativeMouseMode) (SDL_bool enabled);
 
diff --git a/src/video/cocoa/SDL_cocoamouse.m b/src/video/cocoa/SDL_cocoamouse.m
index 8fc742e..54dcb1c 100644
--- a/src/video/cocoa/SDL_cocoamouse.m
+++ b/src/video/cocoa/SDL_cocoamouse.m
@@ -241,6 +241,30 @@ Cocoa_WarpMouse(SDL_Window * window, int x, int y)
     }
 }
 
+static void
+Cocoa_WarpMouseGlobal(int x, int y)
+{
+    SDL_Mouse *mouse = SDL_GetMouse();
+    CGPoint point = CGPointMake((float)x, (float)y);
+
+    Cocoa_HandleMouseWarp(point.x, point.y);
+
+    /* According to the docs, this was deprecated in 10.6, but it's still
+     * around. The substitute requires a CGEventSource, but I'm not entirely
+     * sure how we'd procure the right one for this event.
+     */
+    CGSetLocalEventsSuppressionInterval(0.0);
+    CGWarpMouseCursorPosition(point);
+    CGSetLocalEventsSuppressionInterval(0.25);
+
+    if (!mouse->relative_mode && mouse->focus) {
+        /* CGWarpMouseCursorPosition doesn't generate a window event, unlike our
+         * other implementations' APIs.
+         */
+        SDL_SendMouseMotion(mouse->focus, mouse->mouseID, 0, x - mouse->focus.x, y - mouse->focus.y);
+    }
+}
+
 static int
 Cocoa_SetRelativeMouseMode(SDL_bool enabled)
 {
@@ -295,6 +319,7 @@ Cocoa_InitMouse(_THIS)
     mouse->ShowCursor = Cocoa_ShowCursor;
     mouse->FreeCursor = Cocoa_FreeCursor;
     mouse->WarpMouse = Cocoa_WarpMouse;
+    mouse->WarpMouseGlobal = Cocoa_WarpMouseGlobal;
     mouse->SetRelativeMouseMode = Cocoa_SetRelativeMouseMode;
 
     SDL_SetDefaultCursor(Cocoa_CreateDefaultCursor());
diff --git a/src/video/mir/SDL_mirmouse.c b/src/video/mir/SDL_mirmouse.c
index def9dbd..72f4b6a 100644
--- a/src/video/mir/SDL_mirmouse.c
+++ b/src/video/mir/SDL_mirmouse.c
@@ -110,6 +110,12 @@ MIR_WarpMouse(SDL_Window* window, int x, int y)
     SDL_Unsupported();
 }
 
+static void
+MIR_WarpMouseGlobal(int x, int y)
+{
+    SDL_Unsupported();
+}
+
 static int
 MIR_SetRelativeMouseMode(SDL_bool enabled)
 {
@@ -126,6 +132,7 @@ MIR_InitMouse()
     mouse->ShowCursor           = MIR_ShowCursor;
     mouse->FreeCursor           = MIR_FreeCursor;
     mouse->WarpMouse            = MIR_WarpMouse;
+    mouse->WarpMouseGlobal      = MIR_WarpMouseGlobal;
     mouse->CreateSystemCursor   = MIR_CreateSystemCursor;
     mouse->SetRelativeMouseMode = MIR_SetRelativeMouseMode;
 
diff --git a/src/video/raspberry/SDL_rpimouse.c b/src/video/raspberry/SDL_rpimouse.c
index 718fef8..b0ba88d 100644
--- a/src/video/raspberry/SDL_rpimouse.c
+++ b/src/video/raspberry/SDL_rpimouse.c
@@ -48,6 +48,7 @@ static int RPI_ShowCursor(SDL_Cursor * cursor);
 static void RPI_MoveCursor(SDL_Cursor * cursor);
 static void RPI_FreeCursor(SDL_Cursor * cursor);
 static void RPI_WarpMouse(SDL_Window * window, int x, int y);
+static void RPI_WarpMouseGlobal(int x, int y);
 
 static SDL_Cursor *
 RPI_CreateDefaultCursor(void)
@@ -211,6 +212,13 @@ RPI_FreeCursor(SDL_Cursor * cursor)
 static void
 RPI_WarpMouse(SDL_Window * window, int x, int y)
 {
+    RPI_WarpMouseGlobal(x, y);
+}
+
+/* Warp the mouse to (x,y) */
+static void
+RPI_WarpMouseGlobal(int x, int y)
+{
     RPI_CursorData *curdata;
     DISPMANX_UPDATE_HANDLE_T update;
     int ret;
@@ -254,6 +262,7 @@ RPI_InitMouse(_THIS)
     mouse->MoveCursor = RPI_MoveCursor;
     mouse->FreeCursor = RPI_FreeCursor;
     mouse->WarpMouse = RPI_WarpMouse;
+    mouse->WarpMouseGlobal = RPI_WarpMouseGlobal;
 
     SDL_SetDefaultCursor(RPI_CreateDefaultCursor());
 }
diff --git a/src/video/wayland/SDL_waylandmouse.c b/src/video/wayland/SDL_waylandmouse.c
index 74a9f9b..8abf227 100644
--- a/src/video/wayland/SDL_waylandmouse.c
+++ b/src/video/wayland/SDL_waylandmouse.c
@@ -345,7 +345,12 @@ static void
 Wayland_WarpMouse(SDL_Window *window, int x, int y)
 {
     SDL_Unsupported();
-    return;
+}
+
+static void
+Wayland_WarpMouseGlobal(int x, int y)
+{
+    SDL_Unsupported();
 }
 
 static int
@@ -365,6 +370,7 @@ Wayland_InitMouse(void)
     mouse->ShowCursor = Wayland_ShowCursor;
     mouse->FreeCursor = Wayland_FreeCursor;
     mouse->WarpMouse = Wayland_WarpMouse;
+    mouse->WarpMouseGlobal = Wayland_WarpMouseGlobal;
     mouse->SetRelativeMouseMode = Wayland_SetRelativeMouseMode;
 
     SDL_SetDefaultCursor(Wayland_CreateDefaultCursor());
diff --git a/src/video/windows/SDL_windowsmouse.c b/src/video/windows/SDL_windowsmouse.c
index b49249d..14e99b4 100644
--- a/src/video/windows/SDL_windowsmouse.c
+++ b/src/video/windows/SDL_windowsmouse.c
@@ -198,6 +198,16 @@ WIN_WarpMouse(SDL_Window * window, int x, int y)
     SetCursorPos(pt.x, pt.y);
 }
 
+static void
+WIN_WarpMouseGlobal(int x, int y)
+{
+    POINT pt;
+
+    pt.x = x;
+    pt.y = y;
+    SetCursorPos(pt.x, pt.y);
+}
+
 static int
 WIN_SetRelativeMouseMode(SDL_bool enabled)
 {
@@ -229,6 +239,7 @@ WIN_InitMouse(_THIS)
     mouse->ShowCursor = WIN_ShowCursor;
     mouse->FreeCursor = WIN_FreeCursor;
     mouse->WarpMouse = WIN_WarpMouse;
+    mouse->WarpMouseGlobal = WIN_WarpMouseGlobal;
     mouse->SetRelativeMouseMode = WIN_SetRelativeMouseMode;
 
     SDL_SetDefaultCursor(WIN_CreateDefaultCursor());
diff --git a/src/video/x11/SDL_x11mouse.c b/src/video/x11/SDL_x11mouse.c
index 38bb866..35baa5c 100644
--- a/src/video/x11/SDL_x11mouse.c
+++ b/src/video/x11/SDL_x11mouse.c
@@ -318,6 +318,15 @@ X11_WarpMouse(SDL_Window * window, int x, int y)
     X11_XSync(display, False);
 }
 
+static void
+X11_WarpMouseGlobal(int x, int y)
+{
+    Display *display = GetDisplay();
+
+    X11_XWarpPointer(display, None, DefaultRootWindow(display), 0, 0, 0, 0, x, y);
+    X11_XSync(display, False);
+}
+
 static int
 X11_SetRelativeMouseMode(SDL_bool enabled)
 {
@@ -340,6 +349,7 @@ X11_InitMouse(_THIS)
     mouse->ShowCursor = X11_ShowCursor;
     mouse->FreeCursor = X11_FreeCursor;
     mouse->WarpMouse = X11_WarpMouse;
+    mouse->WarpMouseGlobal = X11_WarpMouseGlobal;
     mouse->SetRelativeMouseMode = X11_SetRelativeMouseMode;
 
     SDL_SetDefaultCursor(X11_CreateDefaultCursor());