src/video/quartz/SDL_QuartzEvents.m
author Sam Lantinga
Sun, 22 Jun 2014 11:08:33 -0700
branchSDL-1.2
changeset 8911 606600f0f6d7
parent 6150 5f0b3693ab60
permissions -rw-r--r--
Fixed bug 2560 - Crash on any input

Alex Marshall

On all of my OSX machines running 10.9 (I posted OS as Mac OS X (All) due to there not being a 10.9 selection), I get a crash on any input using SDL 1.2. I've had this issue in both HG 1.2 and final release 1.2 on the website.

Today I got around to trying to fix it; commenting out the two uses of 'field_edit' in src/video/quartz/SQL_QuartzEvents.m fixes the crash and doesn't cause any side effects as far as I can tell.
slouken@47
     1
/*
slouken@390
     2
    SDL - Simple DirectMedia Layer
slouken@6137
     3
    Copyright (C) 1997-2012  Sam Lantinga
slouken@47
     4
slouken@390
     5
    This library is free software; you can redistribute it and/or
slouken@390
     6
    modify it under the terms of the GNU Library General Public
slouken@390
     7
    License as published by the Free Software Foundation; either
slouken@390
     8
    version 2 of the License, or (at your option) any later version.
slouken@47
     9
slouken@390
    10
    This library is distributed in the hope that it will be useful,
slouken@390
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@390
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@390
    13
    Library General Public License for more details.
slouken@47
    14
slouken@390
    15
    You should have received a copy of the GNU Library General Public
slouken@390
    16
    License along with this library; if not, write to the Free
slouken@390
    17
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
slouken@47
    18
slouken@390
    19
    Sam Lantinga
slouken@390
    20
    slouken@libsdl.org
slouken@47
    21
*/
slouken@1403
    22
#include "SDL_config.h"
slouken@761
    23
slouken@761
    24
#include "SDL_QuartzVideo.h"
slouken@4070
    25
#include "SDL_QuartzWM.h"
slouken@761
    26
slouken@1487
    27
#include <IOKit/IOMessage.h> /* For wake from sleep detection */
slouken@1487
    28
#include <IOKit/pwr_mgt/IOPMLib.h> /* For wake from sleep detection */
slouken@47
    29
#include "SDL_QuartzKeys.h"
slouken@47
    30
slouken@4244
    31
/*
slouken@4244
    32
 * On Leopard, this is missing from the 64-bit headers
slouken@4244
    33
 */
slouken@4251
    34
#if defined(__LP64__) && !defined(__POWER__)
slouken@4251
    35
/*
slouken@4251
    36
 * Workaround for a bug in the 10.5 SDK: By accident, OSService.h does
slouken@4251
    37
 * not include Power.h at all when compiling in 64bit mode. This has
slouken@4251
    38
 * been fixed in 10.6, but for 10.5, we manually define UsrActivity
slouken@4251
    39
 * to ensure compilation works.
slouken@4251
    40
 */
slouken@4244
    41
#define UsrActivity 1
slouken@4244
    42
#endif
slouken@4244
    43
slouken@934
    44
/* 
slouken@934
    45
 * In Panther, this header defines device dependent masks for 
slouken@934
    46
 * right side keys. These definitions only exist in Panther, but
slouken@934
    47
 * the header seems to exist at least in Jaguar and probably earlier
slouken@934
    48
 * versions of the OS, so this should't break anything.
slouken@934
    49
 */
slouken@934
    50
#include <IOKit/hidsystem/IOLLEvent.h>
slouken@934
    51
/* 
slouken@934
    52
 * These are not defined before Panther. To keep the code compiling
slouken@934
    53
 * on systems without these, I will define if they don't exist.
slouken@934
    54
 */
slouken@934
    55
#ifndef NX_DEVICERCTLKEYMASK
slouken@934
    56
    #define NX_DEVICELCTLKEYMASK    0x00000001
slouken@934
    57
#endif
slouken@934
    58
#ifndef NX_DEVICELSHIFTKEYMASK
slouken@934
    59
    #define NX_DEVICELSHIFTKEYMASK  0x00000002
slouken@934
    60
#endif
slouken@934
    61
#ifndef NX_DEVICERSHIFTKEYMASK
slouken@934
    62
    #define NX_DEVICERSHIFTKEYMASK  0x00000004
slouken@934
    63
#endif
slouken@934
    64
#ifndef NX_DEVICELCMDKEYMASK
slouken@934
    65
    #define NX_DEVICELCMDKEYMASK    0x00000008
slouken@934
    66
#endif
slouken@934
    67
#ifndef NX_DEVICERCMDKEYMASK
slouken@934
    68
    #define NX_DEVICERCMDKEYMASK    0x00000010
slouken@934
    69
#endif
slouken@934
    70
#ifndef NX_DEVICELALTKEYMASK
slouken@934
    71
    #define NX_DEVICELALTKEYMASK    0x00000020
slouken@934
    72
#endif
slouken@934
    73
#ifndef NX_DEVICERALTKEYMASK
slouken@934
    74
    #define NX_DEVICERALTKEYMASK    0x00000040
slouken@934
    75
#endif
slouken@934
    76
#ifndef NX_DEVICERCTLKEYMASK
slouken@934
    77
    #define NX_DEVICERCTLKEYMASK    0x00002000
slouken@934
    78
#endif
slouken@934
    79
slouken@761
    80
void     QZ_InitOSKeymap (_THIS) {
icculus@5628
    81
    BOOL saw_layout = NO;
slouken@390
    82
    UInt32 state;
slouken@390
    83
    UInt32 value;
icculus@5628
    84
    Uint16 i;
slouken@390
    85
    int world = SDLK_WORLD_0;
slouken@390
    86
slouken@390
    87
    for ( i=0; i<SDL_TABLESIZE(keymap); ++i )
slouken@390
    88
        keymap[i] = SDLK_UNKNOWN;
slouken@47
    89
slouken@390
    90
    /* This keymap is almost exactly the same as the OS 9 one */
slouken@390
    91
    keymap[QZ_ESCAPE] = SDLK_ESCAPE;
slouken@390
    92
    keymap[QZ_F1] = SDLK_F1;
slouken@390
    93
    keymap[QZ_F2] = SDLK_F2;
slouken@390
    94
    keymap[QZ_F3] = SDLK_F3;
slouken@390
    95
    keymap[QZ_F4] = SDLK_F4;
slouken@390
    96
    keymap[QZ_F5] = SDLK_F5;
slouken@390
    97
    keymap[QZ_F6] = SDLK_F6;
slouken@390
    98
    keymap[QZ_F7] = SDLK_F7;
slouken@390
    99
    keymap[QZ_F8] = SDLK_F8;
slouken@390
   100
    keymap[QZ_F9] = SDLK_F9;
slouken@390
   101
    keymap[QZ_F10] = SDLK_F10;
slouken@390
   102
    keymap[QZ_F11] = SDLK_F11;
slouken@390
   103
    keymap[QZ_F12] = SDLK_F12;
icculus@3914
   104
    keymap[QZ_F13] = SDLK_F13;
icculus@3914
   105
    keymap[QZ_F14] = SDLK_F14;
icculus@3914
   106
    keymap[QZ_F15] = SDLK_F15;
icculus@3914
   107
/*
slouken@390
   108
    keymap[QZ_PRINT] = SDLK_PRINT;
slouken@390
   109
    keymap[QZ_SCROLLOCK] = SDLK_SCROLLOCK;
slouken@390
   110
    keymap[QZ_PAUSE] = SDLK_PAUSE;
icculus@3914
   111
*/
slouken@390
   112
    keymap[QZ_POWER] = SDLK_POWER;
slouken@390
   113
    keymap[QZ_BACKQUOTE] = SDLK_BACKQUOTE;
slouken@390
   114
    keymap[QZ_1] = SDLK_1;
slouken@390
   115
    keymap[QZ_2] = SDLK_2;
slouken@390
   116
    keymap[QZ_3] = SDLK_3;
slouken@390
   117
    keymap[QZ_4] = SDLK_4;
slouken@390
   118
    keymap[QZ_5] = SDLK_5;
slouken@390
   119
    keymap[QZ_6] = SDLK_6;
slouken@390
   120
    keymap[QZ_7] = SDLK_7;
slouken@390
   121
    keymap[QZ_8] = SDLK_8;
slouken@390
   122
    keymap[QZ_9] = SDLK_9;
slouken@390
   123
    keymap[QZ_0] = SDLK_0;
slouken@390
   124
    keymap[QZ_MINUS] = SDLK_MINUS;
slouken@390
   125
    keymap[QZ_EQUALS] = SDLK_EQUALS;
slouken@390
   126
    keymap[QZ_BACKSPACE] = SDLK_BACKSPACE;
slouken@390
   127
    keymap[QZ_INSERT] = SDLK_INSERT;
slouken@390
   128
    keymap[QZ_HOME] = SDLK_HOME;
slouken@390
   129
    keymap[QZ_PAGEUP] = SDLK_PAGEUP;
slouken@390
   130
    keymap[QZ_NUMLOCK] = SDLK_NUMLOCK;
slouken@390
   131
    keymap[QZ_KP_EQUALS] = SDLK_KP_EQUALS;
slouken@390
   132
    keymap[QZ_KP_DIVIDE] = SDLK_KP_DIVIDE;
slouken@390
   133
    keymap[QZ_KP_MULTIPLY] = SDLK_KP_MULTIPLY;
slouken@390
   134
    keymap[QZ_TAB] = SDLK_TAB;
slouken@390
   135
    keymap[QZ_q] = SDLK_q;
slouken@390
   136
    keymap[QZ_w] = SDLK_w;
slouken@390
   137
    keymap[QZ_e] = SDLK_e;
slouken@390
   138
    keymap[QZ_r] = SDLK_r;
slouken@390
   139
    keymap[QZ_t] = SDLK_t;
slouken@390
   140
    keymap[QZ_y] = SDLK_y;
slouken@390
   141
    keymap[QZ_u] = SDLK_u;
slouken@390
   142
    keymap[QZ_i] = SDLK_i;
slouken@390
   143
    keymap[QZ_o] = SDLK_o;
slouken@390
   144
    keymap[QZ_p] = SDLK_p;
slouken@390
   145
    keymap[QZ_LEFTBRACKET] = SDLK_LEFTBRACKET;
slouken@390
   146
    keymap[QZ_RIGHTBRACKET] = SDLK_RIGHTBRACKET;
slouken@390
   147
    keymap[QZ_BACKSLASH] = SDLK_BACKSLASH;
slouken@390
   148
    keymap[QZ_DELETE] = SDLK_DELETE;
slouken@390
   149
    keymap[QZ_END] = SDLK_END;
slouken@390
   150
    keymap[QZ_PAGEDOWN] = SDLK_PAGEDOWN;
slouken@390
   151
    keymap[QZ_KP7] = SDLK_KP7;
slouken@390
   152
    keymap[QZ_KP8] = SDLK_KP8;
slouken@390
   153
    keymap[QZ_KP9] = SDLK_KP9;
slouken@390
   154
    keymap[QZ_KP_MINUS] = SDLK_KP_MINUS;
slouken@390
   155
    keymap[QZ_CAPSLOCK] = SDLK_CAPSLOCK;
slouken@390
   156
    keymap[QZ_a] = SDLK_a;
slouken@390
   157
    keymap[QZ_s] = SDLK_s;
slouken@390
   158
    keymap[QZ_d] = SDLK_d;
slouken@390
   159
    keymap[QZ_f] = SDLK_f;
slouken@390
   160
    keymap[QZ_g] = SDLK_g;
slouken@390
   161
    keymap[QZ_h] = SDLK_h;
slouken@390
   162
    keymap[QZ_j] = SDLK_j;
slouken@390
   163
    keymap[QZ_k] = SDLK_k;
slouken@390
   164
    keymap[QZ_l] = SDLK_l;
slouken@390
   165
    keymap[QZ_SEMICOLON] = SDLK_SEMICOLON;
slouken@390
   166
    keymap[QZ_QUOTE] = SDLK_QUOTE;
slouken@390
   167
    keymap[QZ_RETURN] = SDLK_RETURN;
slouken@390
   168
    keymap[QZ_KP4] = SDLK_KP4;
slouken@390
   169
    keymap[QZ_KP5] = SDLK_KP5;
slouken@390
   170
    keymap[QZ_KP6] = SDLK_KP6;
slouken@390
   171
    keymap[QZ_KP_PLUS] = SDLK_KP_PLUS;
slouken@390
   172
    keymap[QZ_LSHIFT] = SDLK_LSHIFT;
slouken@934
   173
    keymap[QZ_RSHIFT] = SDLK_RSHIFT;
slouken@390
   174
    keymap[QZ_z] = SDLK_z;
slouken@390
   175
    keymap[QZ_x] = SDLK_x;
slouken@390
   176
    keymap[QZ_c] = SDLK_c;
slouken@390
   177
    keymap[QZ_v] = SDLK_v;
slouken@390
   178
    keymap[QZ_b] = SDLK_b;
slouken@390
   179
    keymap[QZ_n] = SDLK_n;
slouken@390
   180
    keymap[QZ_m] = SDLK_m;
slouken@390
   181
    keymap[QZ_COMMA] = SDLK_COMMA;
slouken@390
   182
    keymap[QZ_PERIOD] = SDLK_PERIOD;
slouken@390
   183
    keymap[QZ_SLASH] = SDLK_SLASH;
slouken@390
   184
    keymap[QZ_UP] = SDLK_UP;
slouken@390
   185
    keymap[QZ_KP1] = SDLK_KP1;
slouken@390
   186
    keymap[QZ_KP2] = SDLK_KP2;
slouken@390
   187
    keymap[QZ_KP3] = SDLK_KP3;
slouken@390
   188
    keymap[QZ_KP_ENTER] = SDLK_KP_ENTER;
slouken@390
   189
    keymap[QZ_LCTRL] = SDLK_LCTRL;
slouken@390
   190
    keymap[QZ_LALT] = SDLK_LALT;
slouken@390
   191
    keymap[QZ_LMETA] = SDLK_LMETA;
slouken@934
   192
    keymap[QZ_RCTRL] = SDLK_RCTRL;
slouken@934
   193
    keymap[QZ_RALT] = SDLK_RALT;
slouken@934
   194
    keymap[QZ_RMETA] = SDLK_RMETA;
slouken@390
   195
    keymap[QZ_SPACE] = SDLK_SPACE;
slouken@390
   196
    keymap[QZ_LEFT] = SDLK_LEFT;
slouken@390
   197
    keymap[QZ_DOWN] = SDLK_DOWN;
slouken@390
   198
    keymap[QZ_RIGHT] = SDLK_RIGHT;
slouken@390
   199
    keymap[QZ_KP0] = SDLK_KP0;
slouken@390
   200
    keymap[QZ_KP_PERIOD] = SDLK_KP_PERIOD;
slouken@390
   201
    keymap[QZ_IBOOK_ENTER] = SDLK_KP_ENTER;
slouken@390
   202
    keymap[QZ_IBOOK_RIGHT] = SDLK_RIGHT;
slouken@390
   203
    keymap[QZ_IBOOK_DOWN] = SDLK_DOWN;
slouken@390
   204
    keymap[QZ_IBOOK_UP]      = SDLK_UP;
slouken@390
   205
    keymap[QZ_IBOOK_LEFT] = SDLK_LEFT;
slouken@390
   206
slouken@501
   207
    /* 
slouken@501
   208
        Up there we setup a static scancode->keysym map. However, it will not
slouken@501
   209
        work very well on international keyboard. Hence we now query MacOS
slouken@501
   210
        for its own keymap to adjust our own mapping table. However, this is
slouken@501
   211
        basically only useful for ascii char keys. This is also the reason
slouken@501
   212
        why we keep the static table, too.
slouken@390
   213
     */
slouken@390
   214
icculus@5628
   215
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= 1050)
icculus@5628
   216
    if (TISCopyCurrentKeyboardLayoutInputSource != NULL) {
icculus@5628
   217
        TISInputSourceRef src = TISCopyCurrentKeyboardLayoutInputSource();
icculus@5628
   218
        if (src != NULL) {
icculus@5628
   219
            CFDataRef data = (CFDataRef)
icculus@5628
   220
                TISGetInputSourceProperty(src,
icculus@5628
   221
                    kTISPropertyUnicodeKeyLayoutData);
icculus@5628
   222
            if (data != NULL) {
icculus@5628
   223
                const UCKeyboardLayout *layout = (const UCKeyboardLayout *)
icculus@5628
   224
                    CFDataGetBytePtr(data);
icculus@5628
   225
                if (layout != NULL) {
icculus@5628
   226
                    const UInt32 kbdtype = LMGetKbdType();
icculus@5628
   227
                    saw_layout = YES;
icculus@5628
   228
icculus@5628
   229
                    /* Loop over all 127 possible scan codes */
icculus@5628
   230
                    for (i = 0; i < 0x7F; i++) {
icculus@5628
   231
                        UniChar buf[16];
icculus@5628
   232
                        UniCharCount count = 0;
icculus@5628
   233
icculus@5628
   234
                        /* We pretend a clean start to begin with (i.e. no dead keys active */
icculus@5628
   235
                        state = 0;
icculus@5628
   236
icculus@5628
   237
                        if (UCKeyTranslate(layout, i, kUCKeyActionDown, 0, kbdtype,
icculus@5628
   238
                                           0, &state, 16, &count, buf) != noErr) {
icculus@5628
   239
                            continue;
icculus@5628
   240
                        }
icculus@5628
   241
icculus@5628
   242
                        /* If the state become 0, it was a dead key. We need to
icculus@5628
   243
                           translate again, passing in the new state, to get
icculus@5628
   244
                           the actual key value */
icculus@5628
   245
                        if (state != 0) {
icculus@5628
   246
                            if (UCKeyTranslate(layout, i, kUCKeyActionDown, 0, kbdtype,
icculus@5628
   247
                                               0, &state, 16, &count, buf) != noErr) {
icculus@5628
   248
                                continue;
icculus@5628
   249
                            }
icculus@5628
   250
                        }
icculus@5628
   251
icculus@5628
   252
                        if (count != 1) {
icculus@5628
   253
                            continue;  /* no multi-char. Use SDL 1.3 instead. :) */
icculus@5628
   254
                        }
icculus@5628
   255
icculus@5628
   256
                        value = (UInt32) buf[0];
icculus@5628
   257
                        if (value >= 128) {
icculus@5628
   258
                            /* Some non-ASCII char, map it to SDLK_WORLD_* */
icculus@5628
   259
                            if (world < 0xFF) {
icculus@5628
   260
                                keymap[i] = world++;
icculus@5628
   261
                            }
icculus@5628
   262
                        } else if (value >= 32) {     /* non-control ASCII char */
icculus@5628
   263
                            keymap[i] = value;
icculus@5628
   264
                        }
icculus@5628
   265
                    }
icculus@5628
   266
                }
icculus@5628
   267
            }
icculus@5628
   268
            CFRelease(src);
icculus@5628
   269
        }
icculus@5628
   270
    }
icculus@5628
   271
#endif
icculus@5628
   272
icculus@5628
   273
#if (MAC_OS_X_VERSION_MIN_REQUIRED < 1050)
icculus@5628
   274
    if (!saw_layout) {
icculus@5628
   275
        /* Get a pointer to the systems cached KCHR */
icculus@5984
   276
        const void *KCHRPtr = (const void *)GetScriptManagerVariable(smKCHRCache);
icculus@5628
   277
        if (KCHRPtr)
slouken@390
   278
        {
icculus@5628
   279
            /* Loop over all 127 possible scan codes */
icculus@5628
   280
            for (i = 0; i < 0x7F; i++)
icculus@5628
   281
            {
icculus@5628
   282
                /* We pretend a clean start to begin with (i.e. no dead keys active */
icculus@5628
   283
                state = 0;
slouken@390
   284
icculus@5628
   285
                /* Now translate the key code to a key value */
slouken@390
   286
                value = KeyTranslate(KCHRPtr, i, &state) & 0xff;
slouken@390
   287
icculus@5628
   288
                /* If the state become 0, it was a dead key. We need to translate again,
icculus@5628
   289
                    passing in the new state, to get the actual key value */
icculus@5628
   290
                if (state != 0)
icculus@5628
   291
                    value = KeyTranslate(KCHRPtr, i, &state) & 0xff;
icculus@5628
   292
icculus@5628
   293
                /* Now we should have an ascii value, or 0. Try to figure out to which SDL symbol it maps */
icculus@5628
   294
                if (value >= 128) {     /* Some non-ASCII char, map it to SDLK_WORLD_* */
icculus@5628
   295
                    if (world < 0xFF) {
icculus@5628
   296
                        keymap[i] = world++;
icculus@5628
   297
                    }
icculus@5628
   298
                } else if (value >= 32) {     /* non-control ASCII char */
icculus@5628
   299
                    keymap[i] = value;
icculus@5628
   300
                }
icculus@5628
   301
            }
slouken@390
   302
        }
slouken@390
   303
    }
icculus@5628
   304
#endif
slouken@390
   305
slouken@501
   306
    /* 
slouken@501
   307
        The keypad codes are re-setup here, because the loop above cannot
slouken@501
   308
        distinguish between a key on the keypad and a regular key. We maybe
slouken@501
   309
        could get around this problem in another fashion: NSEvent's flags
slouken@501
   310
        include a "NSNumericPadKeyMask" bit; we could check that and modify
slouken@501
   311
        the symbol we return on the fly. However, this flag seems to exhibit
slouken@501
   312
        some weird behaviour related to the num lock key
slouken@501
   313
    */
slouken@390
   314
    keymap[QZ_KP0] = SDLK_KP0;
slouken@390
   315
    keymap[QZ_KP1] = SDLK_KP1;
slouken@390
   316
    keymap[QZ_KP2] = SDLK_KP2;
slouken@390
   317
    keymap[QZ_KP3] = SDLK_KP3;
slouken@390
   318
    keymap[QZ_KP4] = SDLK_KP4;
slouken@390
   319
    keymap[QZ_KP5] = SDLK_KP5;
slouken@390
   320
    keymap[QZ_KP6] = SDLK_KP6;
slouken@390
   321
    keymap[QZ_KP7] = SDLK_KP7;
slouken@390
   322
    keymap[QZ_KP8] = SDLK_KP8;
slouken@390
   323
    keymap[QZ_KP9] = SDLK_KP9;
slouken@390
   324
    keymap[QZ_KP_MINUS] = SDLK_KP_MINUS;
slouken@390
   325
    keymap[QZ_KP_PLUS] = SDLK_KP_PLUS;
slouken@390
   326
    keymap[QZ_KP_PERIOD] = SDLK_KP_PERIOD;
slouken@390
   327
    keymap[QZ_KP_EQUALS] = SDLK_KP_EQUALS;
slouken@390
   328
    keymap[QZ_KP_DIVIDE] = SDLK_KP_DIVIDE;
slouken@390
   329
    keymap[QZ_KP_MULTIPLY] = SDLK_KP_MULTIPLY;
slouken@390
   330
    keymap[QZ_KP_ENTER] = SDLK_KP_ENTER;
slouken@47
   331
}
slouken@47
   332
slouken@501
   333
static void QZ_DoKey (_THIS, int state, NSEvent *event) {
slouken@47
   334
slouken@4130
   335
    NSString *chars = NULL;
slouken@4049
   336
    unsigned int i, numChars;
slouken@390
   337
    SDL_keysym key;
slouken@561
   338
    
slouken@501
   339
    /* 
slouken@561
   340
        A key event can contain multiple characters,
slouken@561
   341
        or no characters at all. In most cases, it
slouken@561
   342
        will contain a single character. If it contains
slouken@561
   343
        0 characters, we'll use 0 as the unicode. If it
slouken@561
   344
        contains multiple characters, we'll use 0 as
slouken@561
   345
        the scancode/keysym.
slouken@501
   346
    */
slouken@4049
   347
    if (SDL_TranslateUNICODE && state == SDL_PRESSED) {
slouken@8911
   348
/*        [field_edit interpretKeyEvents:[NSArray arrayWithObject:event]]; */
slouken@1876
   349
        chars = [ event characters ];
slouken@1876
   350
        numChars = [ chars length ];
slouken@8911
   351
/*
slouken@4093
   352
        if (numChars > 0)
slouken@8911
   353
            [field_edit setString:@""];*/
slouken@1876
   354
    } else {
slouken@1876
   355
        numChars = 0;
slouken@1876
   356
    }
slouken@561
   357
slouken@1876
   358
    if (numChars == 0) {
slouken@1876
   359
      
slouken@1876
   360
        key.scancode = [ event keyCode ];
slouken@1876
   361
        key.sym      = keymap [ key.scancode ];
slouken@1876
   362
        key.unicode  = 0;
slouken@1876
   363
        key.mod      = KMOD_NONE;
slouken@1876
   364
slouken@1876
   365
        SDL_PrivateKeyboard (state, &key);
slouken@1876
   366
    }
slouken@4049
   367
    else if (numChars >= 1) {
slouken@390
   368
slouken@390
   369
        key.scancode = [ event keyCode ];
slouken@561
   370
        key.sym      = keymap [ key.scancode ];
slouken@561
   371
        key.unicode  = [ chars characterAtIndex:0 ];
slouken@561
   372
        key.mod      = KMOD_NONE;
slouken@561
   373
slouken@561
   374
        SDL_PrivateKeyboard (state, &key);
slouken@561
   375
      
slouken@4049
   376
        for (i = 1; i < numChars; i++) {
slouken@561
   377
slouken@561
   378
            key.scancode = 0;
slouken@561
   379
            key.sym      = 0;
slouken@561
   380
            key.unicode  = [ chars characterAtIndex:i];
slouken@561
   381
            key.mod      = KMOD_NONE;
slouken@561
   382
slouken@561
   383
            SDL_PrivateKeyboard (state, &key);
slouken@561
   384
        }
slouken@561
   385
    }
slouken@683
   386
    
slouken@1338
   387
    if (SDL_getenv ("SDL_ENABLEAPPEVENTS"))
slouken@683
   388
        [ NSApp sendEvent:event ];
slouken@47
   389
}
slouken@47
   390
slouken@934
   391
/* This is the original behavior, before support was added for 
slouken@934
   392
 * differentiating between left and right versions of the keys.
slouken@934
   393
 */
slouken@934
   394
static void QZ_DoUnsidedModifiers (_THIS, unsigned int newMods) {
slouken@47
   395
slouken@664
   396
    const int mapping[] = { SDLK_CAPSLOCK, SDLK_LSHIFT, SDLK_LCTRL, SDLK_LALT, SDLK_LMETA };
slouken@390
   397
slouken@390
   398
    int i;
slouken@390
   399
    int bit;
slouken@390
   400
    SDL_keysym key;
slouken@816
   401
    
slouken@664
   402
    key.scancode    = 0;
slouken@390
   403
    key.sym         = SDLK_UNKNOWN;
slouken@390
   404
    key.unicode     = 0;
slouken@390
   405
    key.mod         = KMOD_NONE;
slouken@390
   406
slouken@390
   407
    /* Iterate through the bits, testing each against the current modifiers */
slouken@390
   408
    for (i = 0, bit = NSAlphaShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) {
slouken@390
   409
slouken@390
   410
        unsigned int currentMask, newMask;
slouken@390
   411
slouken@501
   412
        currentMask = current_mods & bit;
slouken@501
   413
        newMask     = newMods & bit;
slouken@47
   414
slouken@390
   415
        if ( currentMask &&
slouken@390
   416
             currentMask != newMask ) {     /* modifier up event */
slouken@47
   417
slouken@390
   418
             key.sym = mapping[i];
slouken@390
   419
             /* If this was Caps Lock, we need some additional voodoo to make SDL happy */
slouken@390
   420
             if (bit == NSAlphaShiftKeyMask)
slouken@761
   421
                  SDL_PrivateKeyboard (SDL_PRESSED, &key);
slouken@390
   422
             SDL_PrivateKeyboard (SDL_RELEASED, &key);
slouken@390
   423
        }
slouken@390
   424
        else if ( newMask &&
slouken@390
   425
                  currentMask != newMask ) {     /* modifier down event */
slouken@390
   426
        
slouken@390
   427
             key.sym = mapping[i];
slouken@390
   428
             SDL_PrivateKeyboard (SDL_PRESSED, &key);
slouken@390
   429
             /* If this was Caps Lock, we need some additional voodoo to make SDL happy */
slouken@390
   430
             if (bit == NSAlphaShiftKeyMask)
slouken@390
   431
                  SDL_PrivateKeyboard (SDL_RELEASED, &key);
slouken@390
   432
        }
slouken@390
   433
    }
slouken@934
   434
}
slouken@390
   435
slouken@934
   436
/* This is a helper function for QZ_HandleModifierSide. This 
slouken@934
   437
 * function reverts back to behavior before the distinction between
slouken@934
   438
 * sides was made.
slouken@934
   439
 */
slouken@934
   440
static void QZ_HandleNonDeviceModifier ( _THIS, unsigned int device_independent_mask, unsigned int newMods, unsigned int key_sym) {
slouken@934
   441
    unsigned int currentMask, newMask;
slouken@934
   442
    SDL_keysym key;
slouken@934
   443
    
slouken@934
   444
    key.scancode    = 0;
slouken@934
   445
    key.sym         = key_sym;
slouken@934
   446
    key.unicode     = 0;
slouken@934
   447
    key.mod         = KMOD_NONE;
slouken@934
   448
    
slouken@934
   449
    /* Isolate just the bits we care about in the depedent bits so we can 
slouken@934
   450
     * figure out what changed
slouken@934
   451
     */ 
slouken@934
   452
    currentMask = current_mods & device_independent_mask;
slouken@934
   453
    newMask     = newMods & device_independent_mask;
slouken@934
   454
    
slouken@934
   455
    if ( currentMask &&
slouken@934
   456
         currentMask != newMask ) {     /* modifier up event */
slouken@934
   457
         SDL_PrivateKeyboard (SDL_RELEASED, &key);
slouken@934
   458
    }
slouken@934
   459
    else if ( newMask &&
slouken@934
   460
          currentMask != newMask ) {     /* modifier down event */
slouken@934
   461
          SDL_PrivateKeyboard (SDL_PRESSED, &key);
slouken@934
   462
    }
slouken@934
   463
}
slouken@934
   464
slouken@934
   465
/* This is a helper function for QZ_HandleModifierSide. 
slouken@934
   466
 * This function sets the actual SDL_PrivateKeyboard event.
slouken@934
   467
 */
slouken@934
   468
static void QZ_HandleModifierOneSide ( _THIS, unsigned int newMods,
slouken@934
   469
                                       unsigned int key_sym, 
slouken@934
   470
                                       unsigned int sided_device_dependent_mask ) {
slouken@934
   471
    
slouken@934
   472
    SDL_keysym key;
slouken@934
   473
    unsigned int current_dep_mask, new_dep_mask;
slouken@934
   474
    
slouken@934
   475
    key.scancode    = 0;
slouken@934
   476
    key.sym         = key_sym;
slouken@934
   477
    key.unicode     = 0;
slouken@934
   478
    key.mod         = KMOD_NONE;
slouken@934
   479
    
slouken@934
   480
    /* Isolate just the bits we care about in the depedent bits so we can 
slouken@934
   481
     * figure out what changed
slouken@934
   482
     */ 
slouken@934
   483
    current_dep_mask = current_mods & sided_device_dependent_mask;
slouken@934
   484
    new_dep_mask     = newMods & sided_device_dependent_mask;
slouken@934
   485
    
slouken@934
   486
    /* We now know that this side bit flipped. But we don't know if
slouken@934
   487
     * it went pressed to released or released to pressed, so we must 
slouken@934
   488
     * find out which it is.
slouken@934
   489
     */
slouken@934
   490
    if( new_dep_mask &&
slouken@934
   491
        current_dep_mask != new_dep_mask ) { 
slouken@934
   492
        /* Modifier down event */
slouken@934
   493
        SDL_PrivateKeyboard (SDL_PRESSED, &key);
slouken@934
   494
    }
slouken@934
   495
    else /* Modifier up event */ {
slouken@934
   496
        SDL_PrivateKeyboard (SDL_RELEASED, &key);
slouken@934
   497
    }
slouken@934
   498
}
slouken@934
   499
slouken@934
   500
/* This is a helper function for QZ_DoSidedModifiers.
slouken@934
   501
 * This function will figure out if the modifier key is the left or right side, 
slouken@934
   502
 * e.g. left-shift vs right-shift. 
slouken@934
   503
 */
slouken@934
   504
static void QZ_HandleModifierSide ( _THIS, int device_independent_mask, 
slouken@934
   505
                                    unsigned int newMods, 
slouken@934
   506
                                    unsigned int left_key_sym, 
slouken@934
   507
                                    unsigned int right_key_sym,
slouken@934
   508
                                    unsigned int left_device_dependent_mask, 
slouken@934
   509
                                    unsigned int right_device_dependent_mask ) {
slouken@934
   510
    unsigned int device_dependent_mask = 0;
slouken@934
   511
    unsigned int diff_mod = 0;
slouken@934
   512
    
slouken@934
   513
    device_dependent_mask = left_device_dependent_mask | right_device_dependent_mask;
slouken@934
   514
    /* On the basis that the device independent mask is set, but there are 
slouken@934
   515
     * no device dependent flags set, we'll assume that we can't detect this 
slouken@934
   516
     * keyboard and revert to the unsided behavior.
slouken@934
   517
     */
slouken@934
   518
    if ( (device_dependent_mask & newMods) == 0 ) {
slouken@934
   519
        /* Revert to the old behavior */
slouken@934
   520
        QZ_HandleNonDeviceModifier ( this, device_independent_mask, newMods, left_key_sym );
slouken@934
   521
        return;
slouken@934
   522
    }
slouken@934
   523
        
slouken@934
   524
    /* XOR the previous state against the new state to see if there's a change */
slouken@934
   525
    diff_mod = (device_dependent_mask & current_mods)
slouken@934
   526
        ^ (device_dependent_mask & newMods);
slouken@934
   527
slouken@934
   528
    if ( diff_mod ) {
slouken@934
   529
        /* A change in state was found. Isolate the left and right bits 
slouken@934
   530
         * to handle them separately just in case the values can simulataneously
slouken@934
   531
         * change or if the bits don't both exist.
slouken@934
   532
         */
slouken@934
   533
        if ( left_device_dependent_mask & diff_mod ) {
slouken@934
   534
            QZ_HandleModifierOneSide ( this, newMods, left_key_sym, left_device_dependent_mask );
slouken@934
   535
        }
slouken@934
   536
        if ( right_device_dependent_mask & diff_mod ) {
slouken@934
   537
            QZ_HandleModifierOneSide ( this, newMods, right_key_sym, right_device_dependent_mask );
slouken@934
   538
        }
slouken@934
   539
    }
slouken@934
   540
}
slouken@934
   541
   
slouken@934
   542
/* This is a helper function for QZ_DoSidedModifiers.
slouken@934
   543
 * This function will release a key press in the case that 
slouken@934
   544
 * it is clear that the modifier has been released (i.e. one side 
slouken@934
   545
 * can't still be down).
slouken@934
   546
 */
slouken@934
   547
static void QZ_ReleaseModifierSide ( _THIS, 
slouken@934
   548
                                     unsigned int device_independent_mask, 
slouken@934
   549
                                     unsigned int newMods,
slouken@934
   550
                                     unsigned int left_key_sym, 
slouken@934
   551
                                     unsigned int right_key_sym,
slouken@934
   552
                                     unsigned int left_device_dependent_mask, 
slouken@934
   553
                                     unsigned int right_device_dependent_mask ) {
slouken@934
   554
    unsigned int device_dependent_mask = 0;
slouken@934
   555
    SDL_keysym key;
slouken@934
   556
    
slouken@934
   557
    key.scancode    = 0;
slouken@934
   558
    key.sym         = SDLK_UNKNOWN;
slouken@934
   559
    key.unicode     = 0;
slouken@934
   560
    key.mod         = KMOD_NONE;
slouken@934
   561
    
slouken@934
   562
    device_dependent_mask = left_device_dependent_mask | right_device_dependent_mask;
slouken@934
   563
    /* On the basis that the device independent mask is set, but there are 
slouken@934
   564
     * no device dependent flags set, we'll assume that we can't detect this 
slouken@934
   565
     * keyboard and revert to the unsided behavior.
slouken@934
   566
     */
slouken@934
   567
    if ( (device_dependent_mask & current_mods) == 0 ) {
slouken@934
   568
        /* In this case, we can't detect the keyboard, so use the left side 
slouken@934
   569
         * to represent both, and release it. 
slouken@934
   570
         */
slouken@934
   571
        key.sym = left_key_sym;
slouken@934
   572
        SDL_PrivateKeyboard (SDL_RELEASED, &key);
slouken@934
   573
slouken@934
   574
        return;
slouken@934
   575
    }
slouken@934
   576
        
slouken@934
   577
        
slouken@934
   578
    /* 
slouken@934
   579
     * This could have been done in an if-else case because at this point,
slouken@934
   580
     * we know that all keys have been released when calling this function. 
slouken@934
   581
     * But I'm being paranoid so I want to handle each separately,
slouken@934
   582
     * so I hope this doesn't cause other problems.
slouken@934
   583
     */
slouken@934
   584
    if ( left_device_dependent_mask & current_mods ) {
slouken@934
   585
        key.sym = left_key_sym;
slouken@934
   586
        SDL_PrivateKeyboard (SDL_RELEASED, &key);
slouken@934
   587
    }
slouken@934
   588
    if ( right_device_dependent_mask & current_mods ) {
slouken@934
   589
        key.sym = right_key_sym;
slouken@934
   590
        SDL_PrivateKeyboard (SDL_RELEASED, &key);
slouken@934
   591
    }
slouken@934
   592
}
slouken@934
   593
slouken@934
   594
/* This is a helper function for QZ_DoSidedModifiers.
slouken@934
   595
 * This function handles the CapsLock case.
slouken@934
   596
 */
slouken@934
   597
static void QZ_HandleCapsLock (_THIS, unsigned int newMods) {
slouken@934
   598
    unsigned int currentMask, newMask;
slouken@934
   599
    SDL_keysym key;
slouken@934
   600
    
slouken@934
   601
    key.scancode    = 0;
slouken@934
   602
    key.sym         = SDLK_CAPSLOCK;
slouken@934
   603
    key.unicode     = 0;
slouken@934
   604
    key.mod         = KMOD_NONE;
slouken@934
   605
    
slouken@934
   606
    currentMask = current_mods & NSAlphaShiftKeyMask;
slouken@934
   607
    newMask     = newMods & NSAlphaShiftKeyMask;
slouken@934
   608
slouken@934
   609
    if ( currentMask &&
slouken@934
   610
         currentMask != newMask ) {     /* modifier up event */
slouken@934
   611
         /* If this was Caps Lock, we need some additional voodoo to make SDL happy */
slouken@934
   612
         SDL_PrivateKeyboard (SDL_PRESSED, &key);
slouken@934
   613
         SDL_PrivateKeyboard (SDL_RELEASED, &key);
slouken@934
   614
    }
slouken@934
   615
    else if ( newMask &&
slouken@934
   616
              currentMask != newMask ) {     /* modifier down event */
slouken@934
   617
        /* If this was Caps Lock, we need some additional voodoo to make SDL happy */
slouken@934
   618
        SDL_PrivateKeyboard (SDL_PRESSED, &key);
slouken@934
   619
        SDL_PrivateKeyboard (SDL_RELEASED, &key);
slouken@934
   620
    }
slouken@934
   621
}
slouken@934
   622
slouken@934
   623
/* This function will handle the modifier keys and also determine the 
slouken@934
   624
 * correct side of the key.
slouken@934
   625
 */
slouken@934
   626
static void QZ_DoSidedModifiers (_THIS, unsigned int newMods) {
slouken@934
   627
	/* Set up arrays for the key syms for the left and right side. */
slouken@934
   628
    const unsigned int left_mapping[]  = { SDLK_LSHIFT, SDLK_LCTRL, SDLK_LALT, SDLK_LMETA };
slouken@934
   629
    const unsigned int right_mapping[] = { SDLK_RSHIFT, SDLK_RCTRL, SDLK_RALT, SDLK_RMETA };
slouken@934
   630
	/* Set up arrays for the device dependent masks with indices that 
slouken@934
   631
     * correspond to the _mapping arrays 
slouken@934
   632
     */
slouken@934
   633
    const unsigned int left_device_mapping[]  = { NX_DEVICELSHIFTKEYMASK, NX_DEVICELCTLKEYMASK, NX_DEVICELALTKEYMASK, NX_DEVICELCMDKEYMASK };
slouken@934
   634
    const unsigned int right_device_mapping[] = { NX_DEVICERSHIFTKEYMASK, NX_DEVICERCTLKEYMASK, NX_DEVICERALTKEYMASK, NX_DEVICERCMDKEYMASK };
slouken@934
   635
slouken@934
   636
    unsigned int i;
slouken@934
   637
    unsigned int bit;
slouken@934
   638
    
slouken@934
   639
    /* Handle CAPSLOCK separately because it doesn't have a left/right side */
slouken@934
   640
    QZ_HandleCapsLock ( this, newMods );
slouken@934
   641
        
slouken@934
   642
    /* Iterate through the bits, testing each against the current modifiers */
slouken@934
   643
    for (i = 0, bit = NSShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) {
slouken@934
   644
		
slouken@934
   645
        unsigned int currentMask, newMask;
slouken@934
   646
		
slouken@934
   647
        currentMask = current_mods & bit;
slouken@934
   648
        newMask     = newMods & bit;
slouken@934
   649
		
slouken@934
   650
        /* If the bit is set, we must always examine it because the left
slouken@934
   651
         * and right side keys may alternate or both may be pressed.
slouken@934
   652
         */
slouken@934
   653
        if ( newMask ) {
slouken@934
   654
            QZ_HandleModifierSide ( this, bit, newMods, 
slouken@934
   655
                                       left_mapping[i],
slouken@934
   656
                                       right_mapping[i],
slouken@934
   657
                                       left_device_mapping[i],
slouken@934
   658
                                       right_device_mapping[i] );
slouken@934
   659
        }
slouken@934
   660
        /* If the state changed from pressed to unpressed, we must examine
slouken@934
   661
            * the device dependent bits to release the correct keys.
slouken@934
   662
            */
slouken@934
   663
        else if ( currentMask &&
slouken@934
   664
                  currentMask != newMask ) { /* modifier up event */
slouken@934
   665
                  QZ_ReleaseModifierSide ( this, bit, newMods,
slouken@934
   666
                                           left_mapping[i],
slouken@934
   667
                                           right_mapping[i],
slouken@934
   668
                                           left_device_mapping[i],
slouken@934
   669
                                           right_device_mapping[i] );
slouken@934
   670
        }
slouken@934
   671
    }
slouken@934
   672
}
slouken@934
   673
slouken@934
   674
/* This function is called to handle the modifiers.
slouken@934
   675
 * It will try to distinguish between the left side and right side 
slouken@934
   676
 * of the keyboard for those modifiers that qualify if the 
slouken@934
   677
 * operating system version supports it. Otherwise, the code 
slouken@934
   678
 * will not try to make the distinction.
slouken@934
   679
 */
slouken@934
   680
static void QZ_DoModifiers (_THIS, unsigned int newMods) {
slouken@934
   681
	
slouken@934
   682
    if (current_mods == newMods)
slouken@934
   683
    	return;
slouken@934
   684
    
slouken@934
   685
    /* 
slouken@934
   686
     * Starting with Panther (10.3.0), the ability to distinguish between 
slouken@934
   687
     * left side and right side modifiers is available.
slouken@934
   688
     */
slouken@934
   689
    if( system_version >= 0x1030 ) {
slouken@934
   690
        QZ_DoSidedModifiers (this, newMods);
slouken@934
   691
    }
slouken@934
   692
    else {
slouken@934
   693
        QZ_DoUnsidedModifiers (this, newMods);
slouken@934
   694
    }
slouken@934
   695
    
slouken@501
   696
    current_mods = newMods;
slouken@47
   697
}
slouken@47
   698
slouken@782
   699
static void QZ_GetMouseLocation (_THIS, NSPoint *p) {
slouken@782
   700
    *p = [ NSEvent mouseLocation ]; /* global coordinates */
slouken@782
   701
    if (qz_window)
slouken@782
   702
        QZ_PrivateGlobalToLocal (this, p);
slouken@782
   703
    QZ_PrivateCocoaToSDL (this, p);
slouken@782
   704
}
slouken@782
   705
slouken@1629
   706
void QZ_DoActivate (_THIS) {
slouken@1629
   707
slouken@4070
   708
    SDL_PrivateAppActive (1, SDL_APPINPUTFOCUS | (QZ_IsMouseInWindow (this) ? SDL_APPMOUSEFOCUS : 0));
slouken@4066
   709
slouken@4070
   710
    QZ_UpdateCursor(this);
slouken@172
   711
icculus@563
   712
    /* Regrab input, only if it was previously grabbed */
icculus@563
   713
    if ( current_grab_mode == SDL_GRAB_ON ) {
icculus@563
   714
        
icculus@563
   715
        /* Restore cursor location if input was grabbed */
icculus@563
   716
        QZ_PrivateWarpCursor (this, cursor_loc.x, cursor_loc.y);
icculus@563
   717
        QZ_ChangeGrabState (this, QZ_ENABLE_GRAB);
slouken@390
   718
    }
icculus@1560
   719
    else {
icculus@1560
   720
        /* Update SDL's mouse location */
icculus@1560
   721
        NSPoint p;
icculus@1560
   722
        QZ_GetMouseLocation (this, &p);
icculus@1560
   723
        SDL_PrivateMouseMotion (0, 0, p.x, p.y);
icculus@1560
   724
    }
icculus@6150
   725
icculus@6150
   726
    QZ_UpdateCursor(this);
slouken@47
   727
}
slouken@47
   728
slouken@1629
   729
void QZ_DoDeactivate (_THIS) {
slouken@1629
   730
    
slouken@1629
   731
    SDL_PrivateAppActive (0, SDL_APPINPUTFOCUS | SDL_APPMOUSEFOCUS);
slouken@390
   732
icculus@563
   733
    /* Get the current cursor location, for restore on activate */
slouken@782
   734
    QZ_GetMouseLocation (this, &cursor_loc);
icculus@563
   735
    
icculus@563
   736
    /* Reassociate mouse and cursor */
icculus@563
   737
    CGAssociateMouseAndMouseCursorPosition (1);
slouken@172
   738
slouken@4070
   739
    QZ_UpdateCursor(this);
slouken@47
   740
}
slouken@47
   741
slouken@555
   742
void QZ_SleepNotificationHandler (void * refcon,
slouken@555
   743
                                  io_service_t service,
slouken@555
   744
                                  natural_t messageType,
slouken@555
   745
                                  void * messageArgument )
slouken@555
   746
{
slouken@555
   747
     SDL_VideoDevice *this = (SDL_VideoDevice*)refcon;
slouken@555
   748
     
slouken@555
   749
     switch(messageType)
slouken@555
   750
     {
slouken@555
   751
         case kIOMessageSystemWillSleep:
icculus@563
   752
             IOAllowPowerChange(power_connection, (long) messageArgument);
slouken@555
   753
             break;
slouken@555
   754
         case kIOMessageCanSystemSleep:
icculus@563
   755
             IOAllowPowerChange(power_connection, (long) messageArgument);
slouken@555
   756
             break;
slouken@555
   757
         case kIOMessageSystemHasPoweredOn:
slouken@761
   758
            /* awake */
slouken@555
   759
            SDL_PrivateExpose();
slouken@555
   760
            break;
slouken@555
   761
     }
slouken@555
   762
}
slouken@555
   763
slouken@761
   764
void QZ_RegisterForSleepNotifications (_THIS)
slouken@555
   765
{
slouken@555
   766
     CFRunLoopSourceRef rls;
slouken@555
   767
     IONotificationPortRef thePortRef;
slouken@555
   768
     io_object_t notifier;
slouken@555
   769
icculus@563
   770
     power_connection = IORegisterForSystemPower (this, &thePortRef, QZ_SleepNotificationHandler, &notifier);
slouken@555
   771
icculus@563
   772
     if (power_connection == 0)
slouken@555
   773
         NSLog(@"SDL: QZ_SleepNotificationHandler() IORegisterForSystemPower failed.");
slouken@555
   774
slouken@555
   775
     rls = IONotificationPortGetRunLoopSource (thePortRef);
slouken@555
   776
     CFRunLoopAddSource (CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
slouken@555
   777
     CFRelease (rls);
slouken@555
   778
}
slouken@555
   779
icculus@624
   780
slouken@1487
   781
/* Try to map Quartz mouse buttons to SDL's lingo... */
icculus@624
   782
static int QZ_OtherMouseButtonToSDL(int button)
icculus@624
   783
{
icculus@624
   784
    switch (button)
icculus@624
   785
    {
icculus@624
   786
        case 0:
slouken@1487
   787
            return(SDL_BUTTON_LEFT);   /* 1 */
icculus@624
   788
        case 1:
slouken@1487
   789
            return(SDL_BUTTON_RIGHT);  /* 3 */
icculus@624
   790
        case 2:
slouken@1487
   791
            return(SDL_BUTTON_MIDDLE); /* 2 */
icculus@624
   792
    }
icculus@624
   793
slouken@1487
   794
    /* >= 3: skip 4 & 5, since those are the SDL mousewheel buttons. */
icculus@624
   795
    return(button + 3);
icculus@624
   796
}
icculus@624
   797
icculus@624
   798
slouken@761
   799
void QZ_PumpEvents (_THIS)
slouken@158
   800
{
icculus@5628
   801
    int32_t dx, dy;
slouken@390
   802
slouken@390
   803
    NSDate *distantPast;
slouken@390
   804
    NSEvent *event;
slouken@390
   805
    NSRect winRect;
slouken@390
   806
    NSAutoreleasePool *pool;
slouken@390
   807
icculus@1213
   808
    if (!SDL_VideoSurface)
icculus@1213
   809
        return;  /* don't do anything if there's no screen surface. */
icculus@1213
   810
icculus@619
   811
    /* Update activity every five seconds to prevent screensaver. --ryan. */
icculus@3936
   812
    if (!allow_screensaver) {
slouken@4139
   813
        static Uint32 screensaverTicks;
slouken@4139
   814
        Uint32 nowTicks = SDL_GetTicks();
icculus@3936
   815
        if ((nowTicks - screensaverTicks) > 5000)
icculus@3936
   816
        {
icculus@3936
   817
            UpdateSystemActivity(UsrActivity);
icculus@3936
   818
            screensaverTicks = nowTicks;
icculus@3936
   819
        }
icculus@619
   820
    }
icculus@619
   821
slouken@390
   822
    pool = [ [ NSAutoreleasePool alloc ] init ];
slouken@390
   823
    distantPast = [ NSDate distantPast ];
slouken@390
   824
slouken@390
   825
    winRect = NSMakeRect (0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h);
slouken@435
   826
    
icculus@3952
   827
    /* while grabbed, accumulate all mouse moved events into one SDL mouse event */
slouken@390
   828
    dx = 0;
slouken@390
   829
    dy = 0;
slouken@390
   830
    
slouken@390
   831
    do {
slouken@390
   832
    
slouken@390
   833
        /* Poll for an event. This will not block */
slouken@390
   834
        event = [ NSApp nextEventMatchingMask:NSAnyEventMask
slouken@390
   835
                                    untilDate:distantPast
slouken@390
   836
                                    inMode: NSDefaultRunLoopMode dequeue:YES ];
slouken@390
   837
        if (event != nil) {
slouken@390
   838
icculus@624
   839
            int button;
slouken@390
   840
            unsigned int type;
icculus@563
   841
            BOOL isInGameWin;
icculus@563
   842
            
icculus@563
   843
            #define DO_MOUSE_DOWN(button) do {                                               \
slouken@1629
   844
                            if ( SDL_GetAppState() & SDL_APPMOUSEFOCUS ) {                   \
slouken@1629
   845
                                SDL_PrivateMouseButton (SDL_PRESSED, button, 0, 0);          \
slouken@1629
   846
                                expect_mouse_up |= 1<<button;                                \
slouken@390
   847
                            }                                                                \
slouken@390
   848
                            [ NSApp sendEvent:event ];                                       \
slouken@390
   849
            } while(0)
slouken@390
   850
            
icculus@563
   851
            #define DO_MOUSE_UP(button) do {                                            \
icculus@563
   852
                            if ( expect_mouse_up & (1<<button) ) {                      \
icculus@563
   853
                                SDL_PrivateMouseButton (SDL_RELEASED, button, 0, 0);    \
icculus@563
   854
                                expect_mouse_up &= ~(1<<button);                        \
icculus@563
   855
                            }                                                           \
icculus@563
   856
                            [ NSApp sendEvent:event ];                                  \
slouken@390
   857
            } while(0)
slouken@390
   858
            
slouken@390
   859
            type = [ event type ];
slouken@779
   860
            isInGameWin = QZ_IsMouseInWindow (this);
slouken@782
   861
slouken@816
   862
            QZ_DoModifiers(this, [ event modifierFlags ] );
slouken@816
   863
slouken@390
   864
            switch (type) {
slouken@390
   865
                case NSLeftMouseDown:
slouken@1338
   866
                    if ( SDL_getenv("SDL_HAS3BUTTONMOUSE") ) {
icculus@563
   867
                        DO_MOUSE_DOWN (SDL_BUTTON_LEFT);
slouken@511
   868
                    } else {
slouken@4230
   869
                        if ( NSCommandKeyMask & current_mods ) {
icculus@563
   870
                            last_virtual_button = SDL_BUTTON_RIGHT;
icculus@563
   871
                            DO_MOUSE_DOWN (SDL_BUTTON_RIGHT);
slouken@511
   872
                        }
slouken@511
   873
                        else if ( NSAlternateKeyMask & current_mods ) {
icculus@563
   874
                            last_virtual_button = SDL_BUTTON_MIDDLE;
icculus@563
   875
                            DO_MOUSE_DOWN (SDL_BUTTON_MIDDLE);
slouken@511
   876
                        }
slouken@511
   877
                        else {
icculus@563
   878
                            DO_MOUSE_DOWN (SDL_BUTTON_LEFT);
slouken@511
   879
                        }
slouken@390
   880
                    }
slouken@390
   881
                    break;
icculus@624
   882
slouken@390
   883
                case NSLeftMouseUp:
slouken@390
   884
                    if ( last_virtual_button != 0 ) {
icculus@563
   885
                        DO_MOUSE_UP (last_virtual_button);
slouken@390
   886
                        last_virtual_button = 0;
slouken@390
   887
                    }
slouken@390
   888
                    else {
icculus@563
   889
                        DO_MOUSE_UP (SDL_BUTTON_LEFT);
slouken@390
   890
                    }
slouken@390
   891
                    break;
icculus@624
   892
icculus@624
   893
                case NSOtherMouseDown:
icculus@624
   894
                case NSRightMouseDown:
icculus@624
   895
                    button = QZ_OtherMouseButtonToSDL([ event buttonNumber ]);
icculus@624
   896
                    DO_MOUSE_DOWN (button);
icculus@624
   897
                    break;
icculus@624
   898
icculus@624
   899
                case NSOtherMouseUp:
icculus@624
   900
                case NSRightMouseUp:
icculus@624
   901
                    button = QZ_OtherMouseButtonToSDL([ event buttonNumber ]);
icculus@624
   902
                    DO_MOUSE_UP (button);
icculus@624
   903
                    break;
icculus@624
   904
slouken@390
   905
                case NSSystemDefined:
slouken@501
   906
                    /*
slouken@501
   907
                        Future: up to 32 "mouse" buttons can be handled.
slouken@501
   908
                        if ([event subtype] == 7) {
slouken@501
   909
                            unsigned int buttons;
slouken@501
   910
                            buttons = [ event data2 ];
slouken@501
   911
                    */
slouken@390
   912
                    break;
slouken@390
   913
                case NSLeftMouseDragged:
slouken@390
   914
                case NSRightMouseDragged:
slouken@435
   915
                case NSOtherMouseDragged: /* usually middle mouse dragged */
slouken@898
   916
                case NSMouseMoved:
icculus@563
   917
                    if ( grab_state == QZ_INVISIBLE_GRAB ) {
slouken@272
   918
                
slouken@501
   919
                        /*
icculus@563
   920
                            If input is grabbed+hidden, the cursor doesn't move,
slouken@501
   921
                            so we have to call the lowlevel window server
slouken@501
   922
                            function. This is less accurate but works OK.                         
slouken@501
   923
                        */
icculus@5628
   924
                        int32_t dx1, dy1;
slouken@390
   925
                        CGGetLastMouseDelta (&dx1, &dy1);
slouken@390
   926
                        dx += dx1;
slouken@390
   927
                        dy += dy1;
slouken@390
   928
                    }
icculus@3952
   929
                    else {
slouken@435
   930
                        
slouken@501
   931
                        /*
icculus@3952
   932
                            Get the absolute mouse location. This is not the
icculus@3952
   933
                            mouse location after the currently processed event,
icculus@3952
   934
                            but the *current* mouse location, i.e. after all
icculus@3952
   935
                            pending events. This means that if there are
icculus@3952
   936
                            multiple mouse moved events in the queue, we make
icculus@3952
   937
                            multiple identical calls to SDL_PrivateMouseMotion(),
icculus@3952
   938
                            but that's no problem since the latter only
icculus@3952
   939
                            generates SDL events for nonzero movements. In my
icculus@3952
   940
                            experience on PBG4/10.4.8, this rarely happens anyway.
slouken@501
   941
                        */
slouken@782
   942
                        NSPoint p;
slouken@782
   943
                        QZ_GetMouseLocation (this, &p);
slouken@454
   944
                        SDL_PrivateMouseMotion (0, 0, p.x, p.y);
slouken@435
   945
                    }
icculus@563
   946
                    
icculus@563
   947
                    /* 
icculus@563
   948
                        Handle grab input+cursor visible by warping the cursor back
icculus@563
   949
                        into the game window. This still generates a mouse moved event,
icculus@563
   950
                        but not as a result of the warp (so it's in the right direction).
icculus@563
   951
                    */
slouken@4066
   952
                    if ( grab_state == QZ_VISIBLE_GRAB && !isInGameWin ) {
icculus@563
   953
                       
slouken@782
   954
                        NSPoint p;
slouken@782
   955
                        QZ_GetMouseLocation (this, &p);
icculus@563
   956
icculus@563
   957
                        if ( p.x < 0.0 ) 
icculus@563
   958
                            p.x = 0.0;
icculus@563
   959
                        
icculus@563
   960
                        if ( p.y < 0.0 ) 
icculus@563
   961
                            p.y = 0.0;
icculus@563
   962
                        
icculus@563
   963
                        if ( p.x >= winRect.size.width ) 
icculus@563
   964
                            p.x = winRect.size.width-1;
icculus@563
   965
                        
icculus@563
   966
                        if ( p.y >= winRect.size.height ) 
icculus@563
   967
                            p.y = winRect.size.height-1;
icculus@563
   968
                        
icculus@563
   969
                        QZ_PrivateWarpCursor (this, p.x, p.y);
icculus@563
   970
                    }
slouken@631
   971
                    else
slouken@631
   972
                    if ( !isInGameWin && (SDL_GetAppState() & SDL_APPMOUSEFOCUS) ) {
slouken@631
   973
                    
slouken@631
   974
                        SDL_PrivateAppActive (0, SDL_APPMOUSEFOCUS);
slouken@4070
   975
icculus@1212
   976
                        if (grab_state == QZ_INVISIBLE_GRAB)
icculus@1212
   977
                            /*The cursor has left the window even though it is
icculus@1212
   978
                              disassociated from the mouse (and therefore
icculus@1212
   979
                              shouldn't move): this can happen with Wacom
icculus@1212
   980
                              tablets, and it effectively breaks the grab, since
icculus@1212
   981
                              mouse down events now go to background
icculus@1212
   982
                              applications. The only possibility to avoid this
icculus@1212
   983
                              seems to be talking to the tablet driver
icculus@1212
   984
                              (AppleEvents) to constrain its mapped area to the
icculus@1212
   985
                              window, which may not be worth the effort. For
icculus@1212
   986
                              now, handle the condition more gracefully than
icculus@1212
   987
                              before by reassociating cursor and mouse until the
icculus@1212
   988
                              cursor enters the window again, making it obvious
icculus@1212
   989
                              to the user that the grab is broken.*/
icculus@1212
   990
                            CGAssociateMouseAndMouseCursorPosition (1);
slouken@4066
   991
slouken@4070
   992
                        QZ_UpdateCursor(this);
slouken@631
   993
                    }
slouken@631
   994
                    else
slouken@1629
   995
                    if ( isInGameWin && (SDL_GetAppState() & (SDL_APPMOUSEFOCUS | SDL_APPINPUTFOCUS)) == SDL_APPINPUTFOCUS ) {
slouken@631
   996
                    
slouken@631
   997
                        SDL_PrivateAppActive (1, SDL_APPMOUSEFOCUS);
slouken@4066
   998
slouken@4070
   999
                        QZ_UpdateCursor(this);
slouken@4066
  1000
icculus@1212
  1001
                        if (grab_state == QZ_INVISIBLE_GRAB) { /*see comment above*/
icculus@1212
  1002
                            QZ_PrivateWarpCursor (this, SDL_VideoSurface->w / 2, SDL_VideoSurface->h / 2);
icculus@1212
  1003
                            CGAssociateMouseAndMouseCursorPosition (0);
icculus@1212
  1004
                        }
slouken@631
  1005
                    }
slouken@390
  1006
                    break;
slouken@390
  1007
                case NSScrollWheel:
icculus@563
  1008
                    if ( isInGameWin ) {
icculus@1050
  1009
                        float dy, dx;
slouken@502
  1010
                        Uint8 button;
slouken@390
  1011
                        dy = [ event deltaY ];
icculus@1050
  1012
                        dx = [ event deltaX ];
slouken@4101
  1013
                        if ( dy > 0.0 ) /* Scroll up */
slouken@4011
  1014
                            button = SDL_BUTTON_WHEELUP;
slouken@4101
  1015
                        else if ( dy < 0.0 ) /* Scroll down */
slouken@4011
  1016
                            button = SDL_BUTTON_WHEELDOWN;
slouken@4101
  1017
                        else
slouken@4101
  1018
                            break; /* Horizontal scroll */
slouken@4011
  1019
                        /* For now, wheel is sent as a quick down+up */
slouken@4011
  1020
                        SDL_PrivateMouseButton (SDL_PRESSED, button, 0, 0);
slouken@4011
  1021
                        SDL_PrivateMouseButton (SDL_RELEASED, button, 0, 0);
slouken@272
  1022
                    }
slouken@390
  1023
                    break;
slouken@390
  1024
                case NSKeyUp:
slouken@501
  1025
                    QZ_DoKey (this, SDL_RELEASED, event);
slouken@390
  1026
                    break;
slouken@390
  1027
                case NSKeyDown:
slouken@501
  1028
                    QZ_DoKey (this, SDL_PRESSED, event);
slouken@390
  1029
                    break;
slouken@390
  1030
                case NSFlagsChanged:
slouken@390
  1031
                    break;
slouken@4072
  1032
                case NSAppKitDefined:
slouken@4072
  1033
                    [ NSApp sendEvent:event ];
slouken@4072
  1034
                    if ([ event subtype ] == NSApplicationActivatedEventType && (mode_flags & SDL_FULLSCREEN)) {
slouken@4072
  1035
                        /* the default handling of this event seems to reset any cursor set by [NSCursor set] (used by SDL_SetCursor() in fullscreen mode) to the default system arrow cursor */
slouken@4072
  1036
                        SDL_Cursor *sdlc = SDL_GetCursor();
slouken@4072
  1037
                        if (sdlc != NULL && sdlc->wm_cursor != NULL) {
slouken@4072
  1038
                            [ sdlc->wm_cursor->nscursor set ];
slouken@4072
  1039
                        }
slouken@4072
  1040
                    }
slouken@4072
  1041
                    break;
slouken@390
  1042
                    /* case NSApplicationDefined: break; */
slouken@390
  1043
                    /* case NSPeriodic: break; */
slouken@390
  1044
                    /* case NSCursorUpdate: break; */
slouken@390
  1045
                default:
slouken@390
  1046
                    [ NSApp sendEvent:event ];
slouken@272
  1047
            }
slouken@272
  1048
        }
slouken@390
  1049
    } while (event != nil);
slouken@390
  1050
    
slouken@435
  1051
    /* handle accumulated mouse moved events */
slouken@390
  1052
    if (dx != 0 || dy != 0)
slouken@435
  1053
        SDL_PrivateMouseMotion (0, 1, dx, dy);
slouken@898
  1054
    
slouken@390
  1055
    [ pool release ];
slouken@502
  1056
}
icculus@1212
  1057
icculus@1212
  1058
void QZ_UpdateMouse (_THIS)
icculus@1212
  1059
{
icculus@1212
  1060
    NSPoint p;
icculus@1212
  1061
    QZ_GetMouseLocation (this, &p);
icculus@1212
  1062
    SDL_PrivateAppActive (QZ_IsMouseInWindow (this), SDL_APPMOUSEFOCUS);
icculus@1212
  1063
    SDL_PrivateMouseMotion (0, 0, p.x, p.y);
icculus@1212
  1064
}