src/video/cocoa/SDL_cocoamouse.m
author Jørgen P. Tjernø <jorgen@valvesoftware.com>
Thu, 25 Apr 2013 18:40:29 -0700
changeset 7114 02b2fe147478
parent 7113 7b4b596b3cfb
child 7158 ff52fba70795
permissions -rw-r--r--
Mac: Fix relative mode message after gaining focus.

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