src/video/cocoa/SDL_cocoamouse.m
author Jørgen P. Tjernø <jorgen@valvesoftware.com>
Thu, 25 Apr 2013 18:40:22 -0700
changeset 7113 7b4b596b3cfb
parent 7106 31f8acac196b
child 7114 02b2fe147478
permissions -rw-r--r--
Mac: Don't supress mousemoves after warp.

By default, synthesizing events supresses real events for a quarter
second. This makes for some wonky behavior.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 #if SDL_VIDEO_DRIVER_COCOA
    24 
    25 #include "SDL_assert.h"
    26 #include "SDL_events.h"
    27 #include "SDL_cocoavideo.h"
    28 
    29 #include "../../events/SDL_mouse_c.h"
    30 
    31 
    32 static SDL_Cursor *
    33 Cocoa_CreateDefaultCursor()
    34 {
    35     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    36     NSCursor *nscursor;
    37     SDL_Cursor *cursor = NULL;
    38 
    39     nscursor = [NSCursor arrowCursor];
    40 
    41     if (nscursor) {
    42         cursor = SDL_calloc(1, sizeof(*cursor));
    43         if (cursor) {
    44             cursor->driverdata = nscursor;
    45             [nscursor retain];
    46         }
    47     }
    48 
    49     [pool release];
    50 
    51     return cursor;
    52 }
    53 
    54 static SDL_Cursor *
    55 Cocoa_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
    56 {
    57     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    58     NSImage *nsimage;
    59     NSCursor *nscursor = NULL;
    60     SDL_Cursor *cursor = NULL;
    61 
    62     nsimage = Cocoa_CreateImage(surface);
    63     if (nsimage) {
    64         nscursor = [[NSCursor alloc] initWithImage: nsimage hotSpot: NSMakePoint(hot_x, hot_y)];
    65     }
    66 
    67     if (nscursor) {
    68         cursor = SDL_calloc(1, sizeof(*cursor));
    69         if (cursor) {
    70             cursor->driverdata = nscursor;
    71         }
    72     }
    73 
    74     [pool release];
    75 
    76     return cursor;
    77 }
    78 
    79 static SDL_Cursor *
    80 Cocoa_CreateSystemCursor(SDL_SystemCursor id)
    81 {
    82     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    83     NSCursor *nscursor = NULL;
    84     SDL_Cursor *cursor = NULL;
    85 
    86     switch(id)
    87     {
    88     case SDL_SYSTEM_CURSOR_ARROW:
    89         nscursor = [NSCursor arrowCursor];
    90         break;
    91     case SDL_SYSTEM_CURSOR_IBEAM:
    92         nscursor = [NSCursor IBeamCursor];
    93         break;
    94     case SDL_SYSTEM_CURSOR_WAIT:
    95         nscursor = [NSCursor arrowCursor];
    96         break;
    97     case SDL_SYSTEM_CURSOR_CROSSHAIR:
    98         nscursor = [NSCursor crosshairCursor];
    99         break;
   100     case SDL_SYSTEM_CURSOR_WAITARROW:
   101         nscursor = [NSCursor arrowCursor];
   102         break;
   103     case SDL_SYSTEM_CURSOR_SIZENWSE:
   104     case SDL_SYSTEM_CURSOR_SIZENESW:
   105         nscursor = [NSCursor closedHandCursor];
   106         break;
   107     case SDL_SYSTEM_CURSOR_SIZEWE:
   108         nscursor = [NSCursor resizeLeftRightCursor];
   109         break;
   110     case SDL_SYSTEM_CURSOR_SIZENS:
   111         nscursor = [NSCursor resizeUpDownCursor];
   112         break;
   113     case SDL_SYSTEM_CURSOR_SIZEALL:
   114         nscursor = [NSCursor closedHandCursor];
   115         break;
   116     case SDL_SYSTEM_CURSOR_NO:
   117         nscursor = [NSCursor operationNotAllowedCursor];
   118         break;
   119     case SDL_SYSTEM_CURSOR_HAND:
   120         nscursor = [NSCursor pointingHandCursor];
   121         break;
   122     default:
   123         SDL_assert(!"Unknown system cursor");
   124         return NULL;
   125     }
   126 
   127     if (nscursor) {
   128         cursor = SDL_calloc(1, sizeof(*cursor));
   129         if (cursor) {
   130             // We'll free it later, so retain it here
   131             [nscursor retain];
   132             cursor->driverdata = nscursor;
   133         }
   134     }
   135 
   136     [pool release];
   137 
   138     return cursor;
   139 }
   140 
   141 static void
   142 Cocoa_FreeCursor(SDL_Cursor * cursor)
   143 {
   144     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   145     NSCursor *nscursor = (NSCursor *)cursor->driverdata;
   146 
   147     [nscursor release];
   148     SDL_free(cursor);
   149 
   150     [pool release];
   151 }
   152 
   153 static int
   154 Cocoa_ShowCursor(SDL_Cursor * cursor)
   155 {
   156 	/* We need to track the previous state because hide and unhide calls need to
   157 	 * be matched, but ShowCursor calls don't.
   158 	 */
   159 	static SDL_bool isShown = SDL_TRUE;
   160     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   161 
   162     if (cursor) {
   163         NSCursor *nscursor = (NSCursor *)cursor->driverdata;
   164 
   165         /* We're possibly executing from an event handler where this operation
   166          * is unsupported. This will execute it in the main Cocoa event loop
   167          * after this returns.
   168          */
   169         [nscursor performSelectorOnMainThread:@selector(set)
   170                                    withObject:nil
   171                                 waitUntilDone:NO];
   172 
   173 		if (!isShown) {
   174 			[NSCursor unhide];
   175 			isShown = SDL_TRUE;
   176 		}
   177 	} else if (isShown) {
   178 		[NSCursor hide];
   179 		isShown = SDL_FALSE;
   180     }
   181 
   182     [pool release];
   183 
   184     return 0;
   185 }
   186 
   187 static void
   188 Cocoa_WarpMouse(SDL_Window * window, int x, int y)
   189 {
   190     SDL_Mouse *mouse = SDL_GetMouse();
   191     CGPoint point;
   192 
   193     point.x = (float)window->x + x;
   194     point.y = (float)window->y + y;
   195 
   196     /* According to the docs, this was deprecated in 10.6, but it's still
   197      * around. The substitute requires a CGEventSource, but I'm not entirely
   198      * sure how we'd procure the right one for this event.
   199      */
   200     CGSetLocalEventsSuppressionInterval(0.0);
   201     CGWarpMouseCursorPosition(point);
   202     CGSetLocalEventsSuppressionInterval(0.25);
   203 
   204     /* CGWarpMouseCursorPosition doesn't generate a window event, unlike our
   205      * other implementations' APIs.
   206      */
   207     SDL_SendMouseMotion(mouse->focus, mouse->mouseID, 0, x, y);
   208 }
   209 
   210 static int
   211 Cocoa_SetRelativeMouseMode(SDL_bool enabled)
   212 {
   213     CGError result;
   214 
   215     if (enabled) {
   216         result = CGAssociateMouseAndMouseCursorPosition(NO);
   217     } else {
   218         result = CGAssociateMouseAndMouseCursorPosition(YES);
   219     }
   220     if (result != kCGErrorSuccess) {
   221         return SDL_SetError("CGAssociateMouseAndMouseCursorPosition() failed");
   222     }
   223     return 0;
   224 }
   225 
   226 void
   227 Cocoa_InitMouse(_THIS)
   228 {
   229     SDL_Mouse *mouse = SDL_GetMouse();
   230 
   231     mouse->CreateCursor = Cocoa_CreateCursor;
   232     mouse->CreateSystemCursor = Cocoa_CreateSystemCursor;
   233     mouse->ShowCursor = Cocoa_ShowCursor;
   234     mouse->FreeCursor = Cocoa_FreeCursor;
   235     mouse->WarpMouse = Cocoa_WarpMouse;
   236     mouse->SetRelativeMouseMode = Cocoa_SetRelativeMouseMode;
   237 
   238     SDL_SetDefaultCursor(Cocoa_CreateDefaultCursor());
   239 }
   240 
   241 void
   242 Cocoa_HandleMouseEvent(_THIS, NSEvent *event)
   243 {
   244     SDL_Mouse *mouse = SDL_GetMouse();
   245 
   246     if (mouse->relative_mode &&
   247         ([event type] == NSMouseMoved ||
   248          [event type] == NSLeftMouseDragged ||
   249          [event type] == NSRightMouseDragged ||
   250          [event type] == NSOtherMouseDragged)) {
   251         float x = [event deltaX];
   252         float y = [event deltaY];
   253         SDL_SendMouseMotion(mouse->focus, mouse->mouseID, 1, (int)x, (int)y);
   254     }
   255 }
   256 
   257 void
   258 Cocoa_HandleMouseWheel(SDL_Window *window, NSEvent *event)
   259 {
   260     SDL_Mouse *mouse = SDL_GetMouse();
   261 
   262     float x = [event deltaX];
   263     float y = [event deltaY];
   264 
   265     if (x > 0) {
   266         x += 0.9f;
   267     } else if (x < 0) {
   268         x -= 0.9f;
   269     }
   270     if (y > 0) {
   271         y += 0.9f;
   272     } else if (y < 0) {
   273         y -= 0.9f;
   274     }
   275     SDL_SendMouseWheel(window, mouse->mouseID, (int)x, (int)y);
   276 }
   277 
   278 void
   279 Cocoa_QuitMouse(_THIS)
   280 {
   281 }
   282 
   283 #endif /* SDL_VIDEO_DRIVER_COCOA */
   284 
   285 /* vi: set ts=4 sw=4 expandtab: */