src/video/cocoa/SDL_cocoamouse.m
author Sam Lantinga <slouken@libsdl.org>
Sun, 02 Feb 2014 00:53:27 -0800
changeset 8149 681eb46b8ac4
parent 8093 b43765095a6f
child 8232 8976fb30952f
permissions -rw-r--r--
Fixed bug 2374 - Update copyright for 2014...

Is it that time already??
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 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_internal.h"
    22 
    23 #if SDL_VIDEO_DRIVER_COCOA
    24 
    25 #include "SDL_assert.h"
    26 #include "SDL_events.h"
    27 #include "SDL_cocoamouse.h"
    28 #include "SDL_cocoamousetap.h"
    29 
    30 #include "../../events/SDL_mouse_c.h"
    31 
    32 @implementation NSCursor (InvisibleCursor)
    33 + (NSCursor *)invisibleCursor
    34 {
    35     static NSCursor *invisibleCursor = NULL;
    36     if (!invisibleCursor) {
    37         /* RAW 16x16 transparent GIF */
    38         static unsigned char cursorBytes[] = {
    39             0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x10, 0x00, 0x10, 0x00, 0x80,
    40             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0xF9, 0x04,
    41             0x01, 0x00, 0x00, 0x01, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x10,
    42             0x00, 0x10, 0x00, 0x00, 0x02, 0x0E, 0x8C, 0x8F, 0xA9, 0xCB, 0xED,
    43             0x0F, 0xA3, 0x9C, 0xB4, 0xDA, 0x8B, 0xB3, 0x3E, 0x05, 0x00, 0x3B
    44         };
    45 
    46         NSData *cursorData = [NSData dataWithBytesNoCopy:&cursorBytes[0]
    47                                                   length:sizeof(cursorBytes)
    48                                             freeWhenDone:NO];
    49         NSImage *cursorImage = [[[NSImage alloc] initWithData:cursorData] autorelease];
    50         invisibleCursor = [[NSCursor alloc] initWithImage:cursorImage
    51                                                   hotSpot:NSZeroPoint];
    52     }
    53 
    54     return invisibleCursor;
    55 }
    56 @end
    57 
    58 
    59 static SDL_Cursor *
    60 Cocoa_CreateDefaultCursor()
    61 {
    62     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    63     NSCursor *nscursor;
    64     SDL_Cursor *cursor = NULL;
    65 
    66     nscursor = [NSCursor arrowCursor];
    67 
    68     if (nscursor) {
    69         cursor = SDL_calloc(1, sizeof(*cursor));
    70         if (cursor) {
    71             cursor->driverdata = nscursor;
    72             [nscursor retain];
    73         }
    74     }
    75 
    76     [pool release];
    77 
    78     return cursor;
    79 }
    80 
    81 static SDL_Cursor *
    82 Cocoa_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
    83 {
    84     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    85     NSImage *nsimage;
    86     NSCursor *nscursor = NULL;
    87     SDL_Cursor *cursor = NULL;
    88 
    89     nsimage = Cocoa_CreateImage(surface);
    90     if (nsimage) {
    91         nscursor = [[NSCursor alloc] initWithImage: nsimage hotSpot: NSMakePoint(hot_x, hot_y)];
    92     }
    93 
    94     if (nscursor) {
    95         cursor = SDL_calloc(1, sizeof(*cursor));
    96         if (cursor) {
    97             cursor->driverdata = nscursor;
    98         } else {
    99             [nscursor release];
   100         }
   101     }
   102 
   103     [pool release];
   104 
   105     return cursor;
   106 }
   107 
   108 static SDL_Cursor *
   109 Cocoa_CreateSystemCursor(SDL_SystemCursor id)
   110 {
   111     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   112     NSCursor *nscursor = NULL;
   113     SDL_Cursor *cursor = NULL;
   114 
   115     switch(id)
   116     {
   117     case SDL_SYSTEM_CURSOR_ARROW:
   118         nscursor = [NSCursor arrowCursor];
   119         break;
   120     case SDL_SYSTEM_CURSOR_IBEAM:
   121         nscursor = [NSCursor IBeamCursor];
   122         break;
   123     case SDL_SYSTEM_CURSOR_WAIT:
   124         nscursor = [NSCursor arrowCursor];
   125         break;
   126     case SDL_SYSTEM_CURSOR_CROSSHAIR:
   127         nscursor = [NSCursor crosshairCursor];
   128         break;
   129     case SDL_SYSTEM_CURSOR_WAITARROW:
   130         nscursor = [NSCursor arrowCursor];
   131         break;
   132     case SDL_SYSTEM_CURSOR_SIZENWSE:
   133     case SDL_SYSTEM_CURSOR_SIZENESW:
   134         nscursor = [NSCursor closedHandCursor];
   135         break;
   136     case SDL_SYSTEM_CURSOR_SIZEWE:
   137         nscursor = [NSCursor resizeLeftRightCursor];
   138         break;
   139     case SDL_SYSTEM_CURSOR_SIZENS:
   140         nscursor = [NSCursor resizeUpDownCursor];
   141         break;
   142     case SDL_SYSTEM_CURSOR_SIZEALL:
   143         nscursor = [NSCursor closedHandCursor];
   144         break;
   145     case SDL_SYSTEM_CURSOR_NO:
   146         nscursor = [NSCursor operationNotAllowedCursor];
   147         break;
   148     case SDL_SYSTEM_CURSOR_HAND:
   149         nscursor = [NSCursor pointingHandCursor];
   150         break;
   151     default:
   152         SDL_assert(!"Unknown system cursor");
   153         return NULL;
   154     }
   155 
   156     if (nscursor) {
   157         cursor = SDL_calloc(1, sizeof(*cursor));
   158         if (cursor) {
   159             /* We'll free it later, so retain it here */
   160             [nscursor retain];
   161             cursor->driverdata = nscursor;
   162         }
   163     }
   164 
   165     [pool release];
   166 
   167     return cursor;
   168 }
   169 
   170 static void
   171 Cocoa_FreeCursor(SDL_Cursor * cursor)
   172 {
   173     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   174     NSCursor *nscursor = (NSCursor *)cursor->driverdata;
   175 
   176     [nscursor release];
   177     SDL_free(cursor);
   178 
   179     [pool release];
   180 }
   181 
   182 static int
   183 Cocoa_ShowCursor(SDL_Cursor * cursor)
   184 {
   185     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   186 
   187     SDL_VideoDevice *device = SDL_GetVideoDevice();
   188     SDL_Window *window = (device ? device->windows : NULL);
   189     for (; window != NULL; window = window->next) {
   190         SDL_WindowData *driverdata = (SDL_WindowData *)window->driverdata;
   191         if (driverdata) {
   192             [driverdata->nswindow performSelectorOnMainThread:@selector(invalidateCursorRectsForView:)
   193                                                    withObject:[driverdata->nswindow contentView]
   194                                                 waitUntilDone:NO];
   195         }
   196     }
   197 
   198     [pool release];
   199 
   200     return 0;
   201 }
   202 
   203 static void
   204 Cocoa_WarpMouse(SDL_Window * window, int x, int y)
   205 {
   206     SDL_Mouse *mouse = SDL_GetMouse();
   207     CGPoint point = CGPointMake(x + (float)window->x, y + (float)window->y);
   208 
   209     {
   210         /* This makes Cocoa_HandleMouseEvent ignore this delta in the next
   211          * movement event.
   212          */
   213         SDL_MouseData *driverdata = (SDL_MouseData*)mouse->driverdata;
   214         NSPoint location =  [NSEvent mouseLocation];
   215         driverdata->deltaXOffset = location.x - point.x;
   216         driverdata->deltaYOffset = point.y - location.y;
   217     }
   218 
   219     /* According to the docs, this was deprecated in 10.6, but it's still
   220      * around. The substitute requires a CGEventSource, but I'm not entirely
   221      * sure how we'd procure the right one for this event.
   222      */
   223     CGSetLocalEventsSuppressionInterval(0.0);
   224     CGWarpMouseCursorPosition(point);
   225     CGSetLocalEventsSuppressionInterval(0.25);
   226 
   227     if (!mouse->relative_mode) {
   228         /* CGWarpMouseCursorPosition doesn't generate a window event, unlike our
   229          * other implementations' APIs.
   230          */
   231         SDL_SendMouseMotion(mouse->focus, mouse->mouseID, 0, x, y);
   232     }
   233 }
   234 
   235 static int
   236 Cocoa_SetRelativeMouseMode(SDL_bool enabled)
   237 {
   238     CGError result;
   239 
   240     if (enabled) {
   241         result = CGAssociateMouseAndMouseCursorPosition(NO);
   242     } else {
   243         result = CGAssociateMouseAndMouseCursorPosition(YES);
   244     }
   245     if (result != kCGErrorSuccess) {
   246         return SDL_SetError("CGAssociateMouseAndMouseCursorPosition() failed");
   247     }
   248     return 0;
   249 }
   250 
   251 void
   252 Cocoa_InitMouse(_THIS)
   253 {
   254     SDL_Mouse *mouse = SDL_GetMouse();
   255 
   256     mouse->driverdata = SDL_calloc(1, sizeof(SDL_MouseData));
   257 
   258     mouse->CreateCursor = Cocoa_CreateCursor;
   259     mouse->CreateSystemCursor = Cocoa_CreateSystemCursor;
   260     mouse->ShowCursor = Cocoa_ShowCursor;
   261     mouse->FreeCursor = Cocoa_FreeCursor;
   262     mouse->WarpMouse = Cocoa_WarpMouse;
   263     mouse->SetRelativeMouseMode = Cocoa_SetRelativeMouseMode;
   264 
   265     SDL_SetDefaultCursor(Cocoa_CreateDefaultCursor());
   266 
   267     Cocoa_InitMouseEventTap(mouse->driverdata);
   268 }
   269 
   270 void
   271 Cocoa_HandleMouseEvent(_THIS, NSEvent *event)
   272 {
   273     SDL_Mouse *mouse = SDL_GetMouse();
   274 
   275     if (mouse->relative_mode &&
   276         ([event type] == NSMouseMoved ||
   277          [event type] == NSLeftMouseDragged ||
   278          [event type] == NSRightMouseDragged ||
   279          [event type] == NSOtherMouseDragged)) {
   280         SDL_MouseData *driverdata = (SDL_MouseData*)mouse->driverdata;
   281         float x = [event deltaX] + driverdata->deltaXOffset;
   282         float y = [event deltaY] + driverdata->deltaYOffset;
   283         driverdata->deltaXOffset = driverdata->deltaYOffset = 0;
   284 
   285         SDL_SendMouseMotion(mouse->focus, mouse->mouseID, 1, (int)x, (int)y);
   286     }
   287 }
   288 
   289 void
   290 Cocoa_HandleMouseWheel(SDL_Window *window, NSEvent *event)
   291 {
   292     SDL_Mouse *mouse = SDL_GetMouse();
   293 
   294     float x = [event deltaX];
   295     float y = [event deltaY];
   296 
   297     if (x > 0) {
   298         x += 0.9f;
   299     } else if (x < 0) {
   300         x -= 0.9f;
   301     }
   302     if (y > 0) {
   303         y += 0.9f;
   304     } else if (y < 0) {
   305         y -= 0.9f;
   306     }
   307     SDL_SendMouseWheel(window, mouse->mouseID, (int)x, (int)y);
   308 }
   309 
   310 void
   311 Cocoa_QuitMouse(_THIS)
   312 {
   313     SDL_Mouse *mouse = SDL_GetMouse();
   314     if (mouse) {
   315         if (mouse->driverdata) {
   316             Cocoa_QuitMouseEventTap(((SDL_MouseData*)mouse->driverdata));
   317         }
   318 
   319         SDL_free(mouse->driverdata);
   320     }
   321 }
   322 
   323 #endif /* SDL_VIDEO_DRIVER_COCOA */
   324 
   325 /* vi: set ts=4 sw=4 expandtab: */