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.
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"
slouken@1931
    27
#include "SDL_cocoavideo.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@7113
   196
    /* According to the docs, this was deprecated in 10.6, but it's still
jorgen@7113
   197
     * around. The substitute requires a CGEventSource, but I'm not entirely
jorgen@7113
   198
     * sure how we'd procure the right one for this event.
jorgen@7113
   199
     */
jorgen@7113
   200
    CGSetLocalEventsSuppressionInterval(0.0);
slouken@5376
   201
    CGWarpMouseCursorPosition(point);
jorgen@7113
   202
    CGSetLocalEventsSuppressionInterval(0.25);
jorgen@7106
   203
jorgen@7106
   204
    /* CGWarpMouseCursorPosition doesn't generate a window event, unlike our
jorgen@7106
   205
     * other implementations' APIs.
jorgen@7106
   206
     */
jorgen@7106
   207
    SDL_SendMouseMotion(mouse->focus, mouse->mouseID, 0, x, y);
slouken@5376
   208
}
slouken@5376
   209
slouken@5406
   210
static int
slouken@5406
   211
Cocoa_SetRelativeMouseMode(SDL_bool enabled)
slouken@5406
   212
{
slouken@5406
   213
    CGError result;
slouken@5406
   214
slouken@5406
   215
    if (enabled) {
slouken@5406
   216
        result = CGAssociateMouseAndMouseCursorPosition(NO);
slouken@5406
   217
    } else {
slouken@5406
   218
        result = CGAssociateMouseAndMouseCursorPosition(YES);
slouken@5406
   219
    }
slouken@5406
   220
    if (result != kCGErrorSuccess) {
icculus@7037
   221
        return SDL_SetError("CGAssociateMouseAndMouseCursorPosition() failed");
slouken@5406
   222
    }
slouken@5406
   223
    return 0;
slouken@5406
   224
}
slouken@5406
   225
slouken@1931
   226
void
slouken@1931
   227
Cocoa_InitMouse(_THIS)
slouken@1931
   228
{
slouken@5376
   229
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@5376
   230
slouken@5376
   231
    mouse->CreateCursor = Cocoa_CreateCursor;
slouken@6676
   232
    mouse->CreateSystemCursor = Cocoa_CreateSystemCursor;
slouken@5376
   233
    mouse->ShowCursor = Cocoa_ShowCursor;
slouken@5406
   234
    mouse->FreeCursor = Cocoa_FreeCursor;
slouken@5376
   235
    mouse->WarpMouse = Cocoa_WarpMouse;
slouken@5406
   236
    mouse->SetRelativeMouseMode = Cocoa_SetRelativeMouseMode;
slouken@5376
   237
slouken@5405
   238
    SDL_SetDefaultCursor(Cocoa_CreateDefaultCursor());
slouken@1931
   239
}
slouken@1931
   240
slouken@3517
   241
void
slouken@3517
   242
Cocoa_HandleMouseEvent(_THIS, NSEvent *event)
slouken@3517
   243
{
slouken@5406
   244
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@5406
   245
slouken@5477
   246
    if (mouse->relative_mode &&
slouken@5477
   247
        ([event type] == NSMouseMoved ||
slouken@5477
   248
         [event type] == NSLeftMouseDragged ||
slouken@5477
   249
         [event type] == NSRightMouseDragged ||
slouken@5477
   250
         [event type] == NSOtherMouseDragged)) {
slouken@5406
   251
        float x = [event deltaX];
slouken@5406
   252
        float y = [event deltaY];
slouken@6950
   253
        SDL_SendMouseMotion(mouse->focus, mouse->mouseID, 1, (int)x, (int)y);
slouken@5406
   254
    }
slouken@3517
   255
}
slouken@3517
   256
slouken@1931
   257
void
gzjjgod@5057
   258
Cocoa_HandleMouseWheel(SDL_Window *window, NSEvent *event)
gzjjgod@5057
   259
{
slouken@6950
   260
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@6950
   261
gzjjgod@5057
   262
    float x = [event deltaX];
gzjjgod@5057
   263
    float y = [event deltaY];
gzjjgod@5057
   264
gzjjgod@5057
   265
    if (x > 0) {
gzjjgod@5057
   266
        x += 0.9f;
gzjjgod@5057
   267
    } else if (x < 0) {
gzjjgod@5057
   268
        x -= 0.9f;
gzjjgod@5057
   269
    }
gzjjgod@5057
   270
    if (y > 0) {
gzjjgod@5057
   271
        y += 0.9f;
gzjjgod@5057
   272
    } else if (y < 0) {
gzjjgod@5057
   273
        y -= 0.9f;
gzjjgod@5057
   274
    }
slouken@6950
   275
    SDL_SendMouseWheel(window, mouse->mouseID, (int)x, (int)y);
gzjjgod@5057
   276
}
gzjjgod@5057
   277
slouken@5058
   278
void
slouken@5058
   279
Cocoa_QuitMouse(_THIS)
slouken@5058
   280
{
slouken@5058
   281
}
slouken@5058
   282
slouken@6044
   283
#endif /* SDL_VIDEO_DRIVER_COCOA */
slouken@6044
   284
slouken@1931
   285
/* vi: set ts=4 sw=4 expandtab: */