src/video/quartz/SDL_QuartzEvents.m
author Sam Lantinga <slouken@libsdl.org>
Fri, 20 Aug 2004 22:35:23 +0000
changeset 934 af585d6efec8
parent 898 f221cadd6eda
child 1050 8e1815fd9777
permissions -rw-r--r--
Date: Thu, 17 Jun 2004 11:38:51 -0700 (PDT)
From: Eric Wing <ewing2121@yahoo.com>
Subject: New OS X patch (was Re: [SDL] Bug with inverted mouse coordinates in

I have a new patch for OS X I would like to submit.
First, it appears no further action has been taken on
my fix from Apple on the OpenGL windowed mode mouse
inversion problem. The fix would reunify the code, and
no longer require case checking for which version of
the OS you are running. This is probably a good fix
because the behavior with the old code could change
again with future versions of the OS, so those fixes
are included in this new patch.

But in addition, when I was at Apple, I asked them
about the ability to distinguish between the modifier
keys on the left and right sides of the keyboard (e.g.
Left Shift, Right Shift, Left/Right Alt, L/R Cmd, L/R
Ctrl). They told me that starting with Panther, the OS
began supporting this feature. This has always been a
source of annoyance for me when bringing a program
that comes from Windows or Linux to OS X when the
keybindings happened to need distinguishable left-side
and right-side keys. So the rest of the patch I am
submitting contains new code to support this feature
on Panther (and presumably later versions of the OS).

So after removing the OS version checks for the mouse
inversion problem, I reused the OS version checks to
activate the Left/Right detection of modifier keys. If
you are running Panther (or above), the new code will
attempt to distinguish between sides. For the older
OS's, the code path reverts to the original code.

I've tested with Panther on a G4 Cube, G5 dual
processor, and Powerbook Rev C. The Cube and G5
keyboards demonstrated the ability to distinguish
between sides. The Powerbook seems to only have
left-side keys, but the patch was still able to handle
it by producing the same results as before the patch.

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