Mac: Redo cursor warp handling. This fixes bugs related to getting unnaturally large xrel/yrel for SDL_MOUSEMOTION after warps and enabling / disabling relative mode. Bug: https://bugzilla.libsdl.org/show_bug.cgi?id=1836
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
diff --git a/src/video/cocoa/SDL_cocoamouse.h b/src/video/cocoa/SDL_cocoamouse.h
index a0738eb..336b840 100644
--- a/src/video/cocoa/SDL_cocoamouse.h
+++ b/src/video/cocoa/SDL_cocoamouse.h
@@ -28,11 +28,18 @@
extern void Cocoa_InitMouse(_THIS);
extern void Cocoa_HandleMouseEvent(_THIS, NSEvent * event);
extern void Cocoa_HandleMouseWheel(SDL_Window *window, NSEvent * event);
+extern void Cocoa_HandleMouseWarp(CGFloat x, CGFloat y);
extern void Cocoa_QuitMouse(_THIS);
typedef struct {
- int deltaXOffset;
- int deltaYOffset;
+ /* Wether we've seen a cursor warp since the last move event. */
+ SDL_bool seenWarp;
+ /* What location our last cursor warp was to. */
+ CGFloat lastWarpX;
+ CGFloat lastWarpY;
+ /* What location we last saw the cursor move to. */
+ CGFloat lastMoveX;
+ CGFloat lastMoveY;
void *tapdata;
} SDL_MouseData;
diff --git a/src/video/cocoa/SDL_cocoamouse.m b/src/video/cocoa/SDL_cocoamouse.m
index 12f506c..71b782c 100644
--- a/src/video/cocoa/SDL_cocoamouse.m
+++ b/src/video/cocoa/SDL_cocoamouse.m
@@ -223,16 +223,7 @@ Cocoa_WarpMouse(SDL_Window * window, int x, int y)
SDL_Mouse *mouse = SDL_GetMouse();
CGPoint point = CGPointMake(x + (float)window->x, y + (float)window->y);
- {
- /* This makes Cocoa_HandleMouseEvent ignore this delta in the next
- * movement event.
- */
- SDL_MouseData *driverdata = (SDL_MouseData*)mouse->driverdata;
- NSPoint location = [NSEvent mouseLocation];
- driverdata->deltaXOffset = location.x - point.x;
- driverdata->deltaYOffset = point.y - location.y;
- DLog("Warp to (%g, %g), offsetting next movement event by (%i, %i)", point.x, point.y, driverdata->deltaXOffset, driverdata->deltaYOffset);
- }
+ 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
@@ -285,18 +276,16 @@ Cocoa_InitMouse(_THIS)
SDL_SetDefaultCursor(Cocoa_CreateDefaultCursor());
Cocoa_InitMouseEventTap(mouse->driverdata);
+
+ SDL_MouseData *driverdata = (SDL_MouseData*)mouse->driverdata;
+ const NSPoint location = [NSEvent mouseLocation];
+ driverdata->lastMoveX = location.x;
+ driverdata->lastMoveY = location.y;
}
void
Cocoa_HandleMouseEvent(_THIS, NSEvent *event)
{
- SDL_Mouse *mouse = SDL_GetMouse();
-
- /* Non-relative movement is handled in -[Cocoa_WindowListener mouseMoved:] */
- if (!mouse->relative_mode) {
- return;
- }
-
switch ([event type])
{
case NSMouseMoved:
@@ -310,6 +299,24 @@ Cocoa_HandleMouseEvent(_THIS, NSEvent *event)
return;
}
+ SDL_Mouse *mouse = SDL_GetMouse();
+
+ SDL_MouseData *driverdata = (SDL_MouseData*)mouse->driverdata;
+ const SDL_bool seenWarp = driverdata->seenWarp;
+ driverdata->seenWarp = NO;
+
+ const NSPoint location = [NSEvent mouseLocation];
+ const CGFloat lastMoveX = driverdata->lastMoveX;
+ const CGFloat lastMoveY = driverdata->lastMoveY;
+ driverdata->lastMoveX = location.x;
+ driverdata->lastMoveY = location.y;
+ DLog("Last seen mouse: (%g, %g)", location.x, location.y);
+
+ /* Non-relative movement is handled in -[Cocoa_WindowListener mouseMoved:] */
+ if (!mouse->relative_mode) {
+ return;
+ }
+
/* Ignore events that aren't inside the client area (i.e. title bar.) */
if ([event window]) {
NSRect windowRect = [[[event window] contentView] frame];
@@ -318,16 +325,18 @@ Cocoa_HandleMouseEvent(_THIS, NSEvent *event)
}
}
- SDL_MouseData *driverdata = (SDL_MouseData*)mouse->driverdata;
- float x = [event deltaX] + driverdata->deltaXOffset;
- float y = [event deltaY] + driverdata->deltaYOffset;
- driverdata->deltaXOffset = driverdata->deltaYOffset = 0;
+ float deltaX = [event deltaX];
+ float deltaY = [event deltaY];
- if (driverdata->deltaYOffset > 0 || driverdata->deltaXOffset > 0) {
- DLog("Relative move was (%g, %g), offset to (%g, %g)", [event deltaX], [event deltaY], x, y);
+ if (seenWarp)
+ {
+ deltaX += (lastMoveX - driverdata->lastWarpX);
+ deltaY += ((CGDisplayPixelsHigh(kCGDirectMainDisplay) - lastMoveY) - driverdata->lastWarpY);
+
+ DLog("Motion was (%g, %g), offset to (%g, %g)", [event deltaX], [event deltaY], deltaX, deltaY);
}
- SDL_SendMouseMotion(mouse->focus, mouse->mouseID, 1, (int)x, (int)y);
+ SDL_SendMouseMotion(mouse->focus, mouse->mouseID, 1, (int)deltaX, (int)deltaY);
}
void
@@ -352,6 +361,20 @@ Cocoa_HandleMouseWheel(SDL_Window *window, NSEvent *event)
}
void
+Cocoa_HandleMouseWarp(CGFloat x, CGFloat y)
+{
+ /* This makes Cocoa_HandleMouseEvent ignore the delta caused by the warp,
+ * since it gets included in the next movement event.
+ */
+ SDL_MouseData *driverdata = (SDL_MouseData*)SDL_GetMouse()->driverdata;
+ driverdata->lastWarpX = x;
+ driverdata->lastWarpY = y;
+ driverdata->seenWarp = SDL_TRUE;
+
+ DLog("(%g, %g)", x, y);
+}
+
+void
Cocoa_QuitMouse(_THIS)
{
SDL_Mouse *mouse = SDL_GetMouse();
diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m
index e391ea7..c1c0caa 100644
--- a/src/video/cocoa/SDL_cocoawindow.m
+++ b/src/video/cocoa/SDL_cocoawindow.m
@@ -39,6 +39,15 @@
#include "SDL_cocoamouse.h"
#include "SDL_cocoaopengl.h"
+/* #define DEBUG_COCOAWINDOW */
+
+#ifdef DEBUG_COCOAWINDOW
+#define DLog(fmt, ...) printf("%s: " fmt "\n", __func__, ##__VA_ARGS__)
+#else
+#define DLog(...) do { } while (0)
+#endif
+
+
@interface SDLWindow : NSWindow
/* These are needed for borderless/fullscreen windows */
- (BOOL)canBecomeKeyWindow;
@@ -735,6 +744,8 @@ SetWindowStyle(SDL_Window * window, unsigned int style)
CGSetLocalEventsSuppressionInterval(0.0);
CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
CGSetLocalEventsSuppressionInterval(0.25);
+
+ Cocoa_HandleMouseWarp(cgpoint.x, cgpoint.y);
#endif
}
}
@@ -1411,6 +1422,10 @@ Cocoa_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
SDL_GetMouseState(&x, &y);
cgpoint.x = window->x + x;
cgpoint.y = window->y + y;
+
+ Cocoa_HandleMouseWarp(cgpoint.x, cgpoint.y);
+
+ DLog("Returning cursor to (%g, %g)", cgpoint.x, cgpoint.y);
CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
}