src/video/quartz/SDL_QuartzEvents.m
author Ryan C. Gordon <icculus@icculus.org>
Wed, 14 Feb 2007 10:23:23 +0000
branchSDL-1.2
changeset 3914 4fd12011d8d6
parent 1876 406b8325ee34
child 3922 4e02435ad2be
permissions -rw-r--r--
Quartz code should use F13, F14, and F15 keys instead of PrintScreen,
ScrollLock, and Pause, since that's what's on the standard Apple keyboards
(minus the laptops, which have neither set). Ideally we'll find a better way
to distinguish this...the keys being replaced would be correct on a USB
keyboard for Windows. Sigh.

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