src/video/quartz/SDL_QuartzEvents.m
author Sam Lantinga <slouken@libsdl.org>
Thu, 13 Apr 2006 14:17:48 +0000
changeset 1629 ef4a796e7f24
parent 1560 34b9e479047e
child 1662 782fd950bd46
child 1876 406b8325ee34
permissions -rw-r--r--
Fixed bug #55

From Christian Walther:
When writing my patch for #12, I ended up doing all sorts of changes to the way
application/window activating/deactivating is handled in the Quartz backend,
resulting in the attached patch. It does make the code a bit cleaner IMHO, but
as it might be regarded as a case of "if it ain't broken, don't fix it" I'd
like to hear other people's opinion about it. Please shout if some change
strikes you as unnecessary or wrong, and I'll explain the reasons behind it. As
far as I tested it, it does not introduce any new bugs, but I may well have
missed some.

- The most fundamental change (that triggered most of the others) is irrelevant
for the usual single-window SDL applications, it only affects the people who
are crazy enough to display other Cocoa windows alongside the SDL window (I'm
actually doing this currently, although the additional window only displays
debugging info and won't be present in the final product): Before, some things
were done on the application becoming active, some on the window becoming key,
and some on the window becoming main. Conceptually, all these actions belong to
the window becoming key, so that's what I implemented. However, since in a
single-window application these three events always happen together, the
previous implementation "ain't broken".

- This slightly changed the meaning of the SDL_APPMOUSEFOCUS flag from
SDL_GetAppState(): Before, it meant "window is main and mouse is inside window
(or mode is fullscreen)". Now, it means "window is key and mouse is inside
window (or mode is fullscreen)". It makes more sense to me that way. (See
http://developer.apple.com/documentation/Cocoa/Conceptual/WinPanel/Concepts/ChangingMainKeyWindow.html
for a discussion of what key and main windows are.) The other two flags are
unchanged: SDL_APPACTIVE = application is not hidden and window is not
minimized, SDL_APPINPUTFOCUS = window is key (or mode is fullscreen).

- As a side effect, the reorganization fixes the following two issues (and
maybe others) (but they could also be fixed in less invasive ways):

* A regression that was introduced in revision 1.42 of SDL_QuartzVideo.m
(http://libsdl.org/cgi/cvsweb.cgi/SDL12/src/video/quartz/SDL_QuartzVideo.m.diff?r1=1.41&r2=1.42)
(from half-desirable to undesirable behavior):

Situation: While in windowed mode, hide the cursor using
SDL_ShowCursor(SDL_DISABLE), move the mouse outside of the window so that the
cursor becomes visible again, and SDL_SetVideoMode() to a fullscreen mode.
What happened before revision 1.42: The cursor is visible, but becomes
invisible as soon as the mouse is moved (half-desirable).
What happens in revision 1.42 and after (including current CVS): The cursor is
visible and stays visible (undesirable).
What happens after my patch: The cursor is invisible from the beginning
(desirable).

* When the cursor is hidden and grabbed, switch away from the application using
cmd-tab (which ungrabs and makes the cursor visible), move the cursor outside
of the SDL window, then cmd-tab back to the application. In 1.2.8 and in the
current CVS, the cursor is re-grabbed, but it stays visible (immovable in the
middle of the window). With my patch, the cursor is correctly re-grabbed and
hidden. (For some reason, it still doesn't work correctly if you switch back to
the application using the dock instead of cmd-tab. I haven't been able to
figure out why. I can step over [NSCursor hide] being called in the debugger,
but it seems to have no effect.)

- The patch includes my patch for #12 (it was easier to obtain using cvs diff
that way). If you apply both of them, you will end up with 6 duplicate lines in
SDL_QuartzEvents.m.
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;
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@1338
   298
    if (SDL_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@1629
   617
void QZ_DoActivate (_THIS) {
slouken@1629
   618
slouken@1629
   619
    SDL_PrivateAppActive (1, SDL_APPINPUTFOCUS | (QZ_IsMouseInWindow (this) ? SDL_APPMOUSEFOCUS : 0));
slouken@1629
   620
    
slouken@615
   621
    /* Hide the cursor if it was hidden by SDL_ShowCursor() */
slouken@761
   622
    if (!cursor_should_be_visible)
slouken@761
   623
        QZ_HideMouse (this);
slouken@168
   624
icculus@563
   625
    /* Regrab input, only if it was previously grabbed */
icculus@563
   626
    if ( current_grab_mode == SDL_GRAB_ON ) {
icculus@563
   627
        
icculus@563
   628
        /* Restore cursor location if input was grabbed */
icculus@563
   629
        QZ_PrivateWarpCursor (this, cursor_loc.x, cursor_loc.y);
icculus@563
   630
        QZ_ChangeGrabState (this, QZ_ENABLE_GRAB);
slouken@390
   631
    }
icculus@1560
   632
    else {
icculus@1560
   633
        /* Update SDL's mouse location */
icculus@1560
   634
        NSPoint p;
icculus@1560
   635
        QZ_GetMouseLocation (this, &p);
icculus@1560
   636
        SDL_PrivateMouseMotion (0, 0, p.x, p.y);
icculus@1560
   637
    }
slouken@47
   638
}
slouken@47
   639
slouken@1629
   640
void QZ_DoDeactivate (_THIS) {
slouken@1629
   641
    
slouken@1629
   642
    SDL_PrivateAppActive (0, SDL_APPINPUTFOCUS | SDL_APPMOUSEFOCUS);
slouken@47
   643
icculus@563
   644
    /* Get the current cursor location, for restore on activate */
slouken@782
   645
    QZ_GetMouseLocation (this, &cursor_loc);
icculus@563
   646
    
icculus@563
   647
    /* Reassociate mouse and cursor */
icculus@563
   648
    CGAssociateMouseAndMouseCursorPosition (1);
slouken@390
   649
slouken@615
   650
    /* Show the cursor if it was hidden by SDL_ShowCursor() */
slouken@761
   651
    if (!cursor_should_be_visible)
slouken@761
   652
        QZ_ShowMouse (this);
slouken@47
   653
}
slouken@47
   654
slouken@555
   655
void QZ_SleepNotificationHandler (void * refcon,
slouken@555
   656
                                  io_service_t service,
slouken@555
   657
                                  natural_t messageType,
slouken@555
   658
                                  void * messageArgument )
slouken@555
   659
{
slouken@555
   660
     SDL_VideoDevice *this = (SDL_VideoDevice*)refcon;
slouken@555
   661
     
slouken@555
   662
     switch(messageType)
slouken@555
   663
     {
slouken@555
   664
         case kIOMessageSystemWillSleep:
icculus@563
   665
             IOAllowPowerChange(power_connection, (long) messageArgument);
slouken@555
   666
             break;
slouken@555
   667
         case kIOMessageCanSystemSleep:
icculus@563
   668
             IOAllowPowerChange(power_connection, (long) messageArgument);
slouken@555
   669
             break;
slouken@555
   670
         case kIOMessageSystemHasPoweredOn:
slouken@761
   671
            /* awake */
slouken@555
   672
            SDL_PrivateExpose();
slouken@555
   673
            break;
slouken@555
   674
     }
slouken@555
   675
}
slouken@555
   676
slouken@761
   677
void QZ_RegisterForSleepNotifications (_THIS)
slouken@555
   678
{
slouken@555
   679
     CFRunLoopSourceRef rls;
slouken@555
   680
     IONotificationPortRef thePortRef;
slouken@555
   681
     io_object_t notifier;
slouken@555
   682
icculus@563
   683
     power_connection = IORegisterForSystemPower (this, &thePortRef, QZ_SleepNotificationHandler, &notifier);
slouken@555
   684
icculus@563
   685
     if (power_connection == 0)
slouken@555
   686
         NSLog(@"SDL: QZ_SleepNotificationHandler() IORegisterForSystemPower failed.");
slouken@555
   687
slouken@555
   688
     rls = IONotificationPortGetRunLoopSource (thePortRef);
slouken@555
   689
     CFRunLoopAddSource (CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
slouken@555
   690
     CFRelease (rls);
slouken@555
   691
}
slouken@555
   692
icculus@624
   693
slouken@1487
   694
/* Try to map Quartz mouse buttons to SDL's lingo... */
icculus@624
   695
static int QZ_OtherMouseButtonToSDL(int button)
icculus@624
   696
{
icculus@624
   697
    switch (button)
icculus@624
   698
    {
icculus@624
   699
        case 0:
slouken@1487
   700
            return(SDL_BUTTON_LEFT);   /* 1 */
icculus@624
   701
        case 1:
slouken@1487
   702
            return(SDL_BUTTON_RIGHT);  /* 3 */
icculus@624
   703
        case 2:
slouken@1487
   704
            return(SDL_BUTTON_MIDDLE); /* 2 */
icculus@624
   705
    }
icculus@624
   706
slouken@1487
   707
    /* >= 3: skip 4 & 5, since those are the SDL mousewheel buttons. */
icculus@624
   708
    return(button + 3);
icculus@624
   709
}
icculus@624
   710
icculus@624
   711
slouken@761
   712
void QZ_PumpEvents (_THIS)
slouken@158
   713
{
slouken@1487
   714
    static Uint32 screensaverTicks = 0;
slouken@1487
   715
    Uint32 nowTicks;
slouken@435
   716
    int firstMouseEvent;
slouken@390
   717
    CGMouseDelta dx, dy;
slouken@390
   718
slouken@390
   719
    NSDate *distantPast;
slouken@390
   720
    NSEvent *event;
slouken@390
   721
    NSRect winRect;
slouken@390
   722
    NSAutoreleasePool *pool;
slouken@390
   723
icculus@1213
   724
    if (!SDL_VideoSurface)
icculus@1213
   725
        return;  /* don't do anything if there's no screen surface. */
icculus@1213
   726
icculus@619
   727
    /* Update activity every five seconds to prevent screensaver. --ryan. */
slouken@1487
   728
    nowTicks = SDL_GetTicks();
icculus@619
   729
    if ((nowTicks - screensaverTicks) > 5000)
icculus@619
   730
    {
icculus@619
   731
        UpdateSystemActivity(UsrActivity);
icculus@619
   732
        screensaverTicks = nowTicks;
icculus@619
   733
    }
icculus@619
   734
slouken@390
   735
    pool = [ [ NSAutoreleasePool alloc ] init ];
slouken@390
   736
    distantPast = [ NSDate distantPast ];
slouken@390
   737
slouken@390
   738
    winRect = NSMakeRect (0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h);
slouken@435
   739
    
slouken@435
   740
    /* send the first mouse event in absolute coordinates */
slouken@435
   741
    firstMouseEvent = 1;
slouken@435
   742
    
slouken@435
   743
    /* accumulate any additional mouse moved events into one SDL mouse event */
slouken@390
   744
    dx = 0;
slouken@390
   745
    dy = 0;
slouken@390
   746
    
slouken@390
   747
    do {
slouken@390
   748
    
slouken@390
   749
        /* Poll for an event. This will not block */
slouken@390
   750
        event = [ NSApp nextEventMatchingMask:NSAnyEventMask
slouken@390
   751
                                    untilDate:distantPast
slouken@390
   752
                                    inMode: NSDefaultRunLoopMode dequeue:YES ];
slouken@390
   753
        if (event != nil) {
slouken@390
   754
icculus@624
   755
            int button;
slouken@390
   756
            unsigned int type;
icculus@563
   757
            BOOL isInGameWin;
icculus@563
   758
            
icculus@563
   759
            #define DO_MOUSE_DOWN(button) do {                                               \
slouken@1629
   760
                            if ( SDL_GetAppState() & SDL_APPMOUSEFOCUS ) {                   \
slouken@1629
   761
                                SDL_PrivateMouseButton (SDL_PRESSED, button, 0, 0);          \
slouken@1629
   762
                                expect_mouse_up |= 1<<button;                                \
slouken@390
   763
                            }                                                                \
slouken@390
   764
                            [ NSApp sendEvent:event ];                                       \
slouken@390
   765
            } while(0)
slouken@272
   766
            
icculus@563
   767
            #define DO_MOUSE_UP(button) do {                                            \
icculus@563
   768
                            if ( expect_mouse_up & (1<<button) ) {                      \
icculus@563
   769
                                SDL_PrivateMouseButton (SDL_RELEASED, button, 0, 0);    \
icculus@563
   770
                                expect_mouse_up &= ~(1<<button);                        \
icculus@563
   771
                            }                                                           \
icculus@563
   772
                            [ NSApp sendEvent:event ];                                  \
slouken@390
   773
            } while(0)
slouken@390
   774
            
slouken@390
   775
            type = [ event type ];
slouken@779
   776
            isInGameWin = QZ_IsMouseInWindow (this);
slouken@782
   777
slouken@816
   778
            QZ_DoModifiers(this, [ event modifierFlags ] );
slouken@816
   779
slouken@390
   780
            switch (type) {
slouken@390
   781
                case NSLeftMouseDown:
slouken@1338
   782
                    if ( SDL_getenv("SDL_HAS3BUTTONMOUSE") ) {
icculus@563
   783
                        DO_MOUSE_DOWN (SDL_BUTTON_LEFT);
slouken@511
   784
                    } else {
slouken@898
   785
                        if ( NSCommandKeyMask & current_mods ) {
icculus@563
   786
                            last_virtual_button = SDL_BUTTON_RIGHT;
icculus@563
   787
                            DO_MOUSE_DOWN (SDL_BUTTON_RIGHT);
slouken@511
   788
                        }
slouken@511
   789
                        else if ( NSAlternateKeyMask & current_mods ) {
icculus@563
   790
                            last_virtual_button = SDL_BUTTON_MIDDLE;
icculus@563
   791
                            DO_MOUSE_DOWN (SDL_BUTTON_MIDDLE);
slouken@511
   792
                        }
slouken@511
   793
                        else {
icculus@563
   794
                            DO_MOUSE_DOWN (SDL_BUTTON_LEFT);
slouken@511
   795
                        }
slouken@390
   796
                    }
slouken@390
   797
                    break;
icculus@624
   798
slouken@390
   799
                case NSLeftMouseUp:
slouken@390
   800
                    if ( last_virtual_button != 0 ) {
icculus@563
   801
                        DO_MOUSE_UP (last_virtual_button);
slouken@390
   802
                        last_virtual_button = 0;
slouken@390
   803
                    }
slouken@390
   804
                    else {
icculus@563
   805
                        DO_MOUSE_UP (SDL_BUTTON_LEFT);
slouken@390
   806
                    }
slouken@390
   807
                    break;
icculus@624
   808
icculus@624
   809
                case NSOtherMouseDown:
icculus@624
   810
                case NSRightMouseDown:
icculus@624
   811
                    button = QZ_OtherMouseButtonToSDL([ event buttonNumber ]);
icculus@624
   812
                    DO_MOUSE_DOWN (button);
icculus@624
   813
                    break;
icculus@624
   814
icculus@624
   815
                case NSOtherMouseUp:
icculus@624
   816
                case NSRightMouseUp:
icculus@624
   817
                    button = QZ_OtherMouseButtonToSDL([ event buttonNumber ]);
icculus@624
   818
                    DO_MOUSE_UP (button);
icculus@624
   819
                    break;
icculus@624
   820
slouken@390
   821
                case NSSystemDefined:
slouken@501
   822
                    /*
slouken@501
   823
                        Future: up to 32 "mouse" buttons can be handled.
slouken@501
   824
                        if ([event subtype] == 7) {
slouken@501
   825
                            unsigned int buttons;
slouken@501
   826
                            buttons = [ event data2 ];
slouken@501
   827
                    */
slouken@390
   828
                    break;
slouken@390
   829
                case NSLeftMouseDragged:
slouken@390
   830
                case NSRightMouseDragged:
slouken@435
   831
                case NSOtherMouseDragged: /* usually middle mouse dragged */
slouken@898
   832
                case NSMouseMoved:
icculus@563
   833
                    if ( grab_state == QZ_INVISIBLE_GRAB ) {
slouken@272
   834
                
slouken@501
   835
                        /*
icculus@563
   836
                            If input is grabbed+hidden, the cursor doesn't move,
slouken@501
   837
                            so we have to call the lowlevel window server
slouken@501
   838
                            function. This is less accurate but works OK.                         
slouken@501
   839
                        */
slouken@390
   840
                        CGMouseDelta dx1, dy1;
slouken@390
   841
                        CGGetLastMouseDelta (&dx1, &dy1);
slouken@390
   842
                        dx += dx1;
slouken@390
   843
                        dy += dy1;
slouken@390
   844
                    }
slouken@435
   845
                    else if (firstMouseEvent) {
slouken@435
   846
                        
slouken@501
   847
                        /*
slouken@501
   848
                            Get the first mouse event in a possible
slouken@501
   849
                            sequence of mouse moved events. Since we
slouken@501
   850
                            use absolute coordinates, this serves to
slouken@501
   851
                            compensate any inaccuracy in deltas, and
slouken@501
   852
                            provides the first known mouse position,
slouken@501
   853
                            since everything after this uses deltas
slouken@501
   854
                        */
slouken@782
   855
                        NSPoint p;
slouken@782
   856
                        QZ_GetMouseLocation (this, &p);
slouken@454
   857
                        SDL_PrivateMouseMotion (0, 0, p.x, p.y);
slouken@435
   858
                        firstMouseEvent = 0;
slouken@782
   859
                   }
slouken@435
   860
                    else {
slouken@435
   861
                    
slouken@501
   862
                        /*
slouken@501
   863
                            Get the amount moved since the last drag or move event,
slouken@501
   864
                            add it on for one big move event at the end.
slouken@501
   865
                        */
slouken@501
   866
                        dx += [ event deltaX ];
slouken@501
   867
                        dy += [ event deltaY ];
slouken@435
   868
                    }
icculus@563
   869
                    
icculus@563
   870
                    /* 
icculus@563
   871
                        Handle grab input+cursor visible by warping the cursor back
icculus@563
   872
                        into the game window. This still generates a mouse moved event,
icculus@563
   873
                        but not as a result of the warp (so it's in the right direction).
icculus@563
   874
                    */
icculus@563
   875
                    if ( grab_state == QZ_VISIBLE_GRAB &&
icculus@563
   876
                         !isInGameWin ) {
icculus@563
   877
                       
slouken@782
   878
                        NSPoint p;
slouken@782
   879
                        QZ_GetMouseLocation (this, &p);
icculus@563
   880
icculus@563
   881
                        if ( p.x < 0.0 ) 
icculus@563
   882
                            p.x = 0.0;
icculus@563
   883
                        
icculus@563
   884
                        if ( p.y < 0.0 ) 
icculus@563
   885
                            p.y = 0.0;
icculus@563
   886
                        
icculus@563
   887
                        if ( p.x >= winRect.size.width ) 
icculus@563
   888
                            p.x = winRect.size.width-1;
icculus@563
   889
                        
icculus@563
   890
                        if ( p.y >= winRect.size.height ) 
icculus@563
   891
                            p.y = winRect.size.height-1;
icculus@563
   892
                        
icculus@563
   893
                        QZ_PrivateWarpCursor (this, p.x, p.y);
icculus@563
   894
                    }
slouken@631
   895
                    else
slouken@631
   896
                    if ( !isInGameWin && (SDL_GetAppState() & SDL_APPMOUSEFOCUS) ) {
slouken@631
   897
                    
slouken@631
   898
                        SDL_PrivateAppActive (0, SDL_APPMOUSEFOCUS);
icculus@1212
   899
                        if (grab_state == QZ_INVISIBLE_GRAB)
icculus@1212
   900
                            /*The cursor has left the window even though it is
icculus@1212
   901
                              disassociated from the mouse (and therefore
icculus@1212
   902
                              shouldn't move): this can happen with Wacom
icculus@1212
   903
                              tablets, and it effectively breaks the grab, since
icculus@1212
   904
                              mouse down events now go to background
icculus@1212
   905
                              applications. The only possibility to avoid this
icculus@1212
   906
                              seems to be talking to the tablet driver
icculus@1212
   907
                              (AppleEvents) to constrain its mapped area to the
icculus@1212
   908
                              window, which may not be worth the effort. For
icculus@1212
   909
                              now, handle the condition more gracefully than
icculus@1212
   910
                              before by reassociating cursor and mouse until the
icculus@1212
   911
                              cursor enters the window again, making it obvious
icculus@1212
   912
                              to the user that the grab is broken.*/
icculus@1212
   913
                            CGAssociateMouseAndMouseCursorPosition (1);
slouken@779
   914
                        if (!cursor_should_be_visible)
slouken@779
   915
                            QZ_ShowMouse (this);
slouken@631
   916
                    }
slouken@631
   917
                    else
slouken@1629
   918
                    if ( isInGameWin && (SDL_GetAppState() & (SDL_APPMOUSEFOCUS | SDL_APPINPUTFOCUS)) == SDL_APPINPUTFOCUS ) {
slouken@631
   919
                    
slouken@631
   920
                        SDL_PrivateAppActive (1, SDL_APPMOUSEFOCUS);
slouken@779
   921
                        if (!cursor_should_be_visible)
slouken@779
   922
                            QZ_HideMouse (this);
icculus@1212
   923
                        if (grab_state == QZ_INVISIBLE_GRAB) { /*see comment above*/
icculus@1212
   924
                            QZ_PrivateWarpCursor (this, SDL_VideoSurface->w / 2, SDL_VideoSurface->h / 2);
icculus@1212
   925
                            CGAssociateMouseAndMouseCursorPosition (0);
icculus@1212
   926
                        }
slouken@631
   927
                    }
slouken@390
   928
                    break;
slouken@390
   929
                case NSScrollWheel:
icculus@563
   930
                    if ( isInGameWin ) {
icculus@1050
   931
                        float dy, dx;
slouken@502
   932
                        Uint8 button;
slouken@390
   933
                        dy = [ event deltaY ];
icculus@1050
   934
                        dx = [ event deltaX ];
icculus@1050
   935
                        if ( dy > 0.0 || dx > 0.0 ) /* Scroll up */
slouken@502
   936
                            button = SDL_BUTTON_WHEELUP;
slouken@390
   937
                        else /* Scroll down */
slouken@502
   938
                            button = SDL_BUTTON_WHEELDOWN;
icculus@563
   939
                        /* For now, wheel is sent as a quick down+up */
slouken@502
   940
                        SDL_PrivateMouseButton (SDL_PRESSED, button, 0, 0);
slouken@502
   941
                        SDL_PrivateMouseButton (SDL_RELEASED, button, 0, 0);
slouken@390
   942
                    }
slouken@390
   943
                    break;
slouken@390
   944
                case NSKeyUp:
slouken@501
   945
                    QZ_DoKey (this, SDL_RELEASED, event);
slouken@390
   946
                    break;
slouken@390
   947
                case NSKeyDown:
slouken@501
   948
                    QZ_DoKey (this, SDL_PRESSED, event);
slouken@390
   949
                    break;
slouken@390
   950
                case NSFlagsChanged:
slouken@390
   951
                    break;
slouken@1629
   952
                    /* case NSAppKitDefined: break; */
slouken@390
   953
                    /* case NSApplicationDefined: break; */
slouken@390
   954
                    /* case NSPeriodic: break; */
slouken@390
   955
                    /* case NSCursorUpdate: break; */
slouken@390
   956
                default:
slouken@390
   957
                    [ NSApp sendEvent:event ];
slouken@272
   958
            }
slouken@272
   959
        }
slouken@390
   960
    } while (event != nil);
slouken@390
   961
    
slouken@435
   962
    /* handle accumulated mouse moved events */
slouken@390
   963
    if (dx != 0 || dy != 0)
slouken@435
   964
        SDL_PrivateMouseMotion (0, 1, dx, dy);
slouken@898
   965
    
slouken@390
   966
    [ pool release ];
slouken@502
   967
}
icculus@1212
   968
icculus@1212
   969
void QZ_UpdateMouse (_THIS)
icculus@1212
   970
{
icculus@1212
   971
    NSPoint p;
icculus@1212
   972
    QZ_GetMouseLocation (this, &p);
icculus@1212
   973
    SDL_PrivateAppActive (QZ_IsMouseInWindow (this), SDL_APPMOUSEFOCUS);
icculus@1212
   974
    SDL_PrivateMouseMotion (0, 0, p.x, p.y);
icculus@1212
   975
}