src/video/quartz/SDL_QuartzEvents.m
author Sam Lantinga <slouken@libsdl.org>
Sun, 20 Apr 2003 05:41:16 +0000
changeset 615 7ec821f3cbd0
parent 563 04dcaf3da918
child 619 bf816ce70144
permissions -rw-r--r--
Date: Thu, 17 Apr 2003 23:27:34 -0400
From: Darrell Walisser
Subject: Yet another OS X cursor bug

The synopsis:

1. Call SDL_ShowCursor(0);
2. Call SDL_SetVideoMode();
3. Call SDL_GetEvent();
3. Call SDL_ShowCursor(1);

The result: Sometimes the cursor doesn't come back! Ack! Oddly enough,
it does come back when mousing over the dock or clicking in the menu
bar. But that's besides the point.

The reason why this is happening is a flaw in the handling of
activation/deactivation events. The short explanation is that the
HideCursor() and ShowCursor() calls must be balanced, but if the cursor
was initially hidden, HideCursor() was called again on the activate
event - so now the next ShowCursor() fails (as does the next, and the
next, for some reason).

So, here's the patch. All it does is keep track of the
HideCursor()/ShowCursor() calls so that they will always be balanced.
slouken@47
     1
/*
slouken@390
     2
    SDL - Simple DirectMedia Layer
slouken@390
     3
    Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002    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@511
    22
#include <stdlib.h>	// For getenv()
slouken@555
    23
#include <IOKit/IOMessage.h> // For wake from sleep detection
slouken@555
    24
#include <IOKit/pwr_mgt/IOPMLib.h> // For wake from sleep detection
slouken@47
    25
#include "SDL_QuartzKeys.h"
slouken@47
    26
slouken@390
    27
static void     QZ_InitOSKeymap (_THIS) {
slouken@390
    28
    const void *KCHRPtr;
slouken@390
    29
    UInt32 state;
slouken@390
    30
    UInt32 value;
slouken@390
    31
    int i;
slouken@390
    32
    int world = SDLK_WORLD_0;
slouken@47
    33
slouken@390
    34
    for ( i=0; i<SDL_TABLESIZE(keymap); ++i )
slouken@390
    35
        keymap[i] = SDLK_UNKNOWN;
slouken@390
    36
slouken@390
    37
    /* This keymap is almost exactly the same as the OS 9 one */
slouken@390
    38
    keymap[QZ_ESCAPE] = SDLK_ESCAPE;
slouken@390
    39
    keymap[QZ_F1] = SDLK_F1;
slouken@390
    40
    keymap[QZ_F2] = SDLK_F2;
slouken@390
    41
    keymap[QZ_F3] = SDLK_F3;
slouken@390
    42
    keymap[QZ_F4] = SDLK_F4;
slouken@390
    43
    keymap[QZ_F5] = SDLK_F5;
slouken@390
    44
    keymap[QZ_F6] = SDLK_F6;
slouken@390
    45
    keymap[QZ_F7] = SDLK_F7;
slouken@390
    46
    keymap[QZ_F8] = SDLK_F8;
slouken@390
    47
    keymap[QZ_F9] = SDLK_F9;
slouken@390
    48
    keymap[QZ_F10] = SDLK_F10;
slouken@390
    49
    keymap[QZ_F11] = SDLK_F11;
slouken@390
    50
    keymap[QZ_F12] = SDLK_F12;
slouken@390
    51
    keymap[QZ_PRINT] = SDLK_PRINT;
slouken@390
    52
    keymap[QZ_SCROLLOCK] = SDLK_SCROLLOCK;
slouken@390
    53
    keymap[QZ_PAUSE] = SDLK_PAUSE;
slouken@390
    54
    keymap[QZ_POWER] = SDLK_POWER;
slouken@390
    55
    keymap[QZ_BACKQUOTE] = SDLK_BACKQUOTE;
slouken@390
    56
    keymap[QZ_1] = SDLK_1;
slouken@390
    57
    keymap[QZ_2] = SDLK_2;
slouken@390
    58
    keymap[QZ_3] = SDLK_3;
slouken@390
    59
    keymap[QZ_4] = SDLK_4;
slouken@390
    60
    keymap[QZ_5] = SDLK_5;
slouken@390
    61
    keymap[QZ_6] = SDLK_6;
slouken@390
    62
    keymap[QZ_7] = SDLK_7;
slouken@390
    63
    keymap[QZ_8] = SDLK_8;
slouken@390
    64
    keymap[QZ_9] = SDLK_9;
slouken@390
    65
    keymap[QZ_0] = SDLK_0;
slouken@390
    66
    keymap[QZ_MINUS] = SDLK_MINUS;
slouken@390
    67
    keymap[QZ_EQUALS] = SDLK_EQUALS;
slouken@390
    68
    keymap[QZ_BACKSPACE] = SDLK_BACKSPACE;
slouken@390
    69
    keymap[QZ_INSERT] = SDLK_INSERT;
slouken@390
    70
    keymap[QZ_HOME] = SDLK_HOME;
slouken@390
    71
    keymap[QZ_PAGEUP] = SDLK_PAGEUP;
slouken@390
    72
    keymap[QZ_NUMLOCK] = SDLK_NUMLOCK;
slouken@390
    73
    keymap[QZ_KP_EQUALS] = SDLK_KP_EQUALS;
slouken@390
    74
    keymap[QZ_KP_DIVIDE] = SDLK_KP_DIVIDE;
slouken@390
    75
    keymap[QZ_KP_MULTIPLY] = SDLK_KP_MULTIPLY;
slouken@390
    76
    keymap[QZ_TAB] = SDLK_TAB;
slouken@390
    77
    keymap[QZ_q] = SDLK_q;
slouken@390
    78
    keymap[QZ_w] = SDLK_w;
slouken@390
    79
    keymap[QZ_e] = SDLK_e;
slouken@390
    80
    keymap[QZ_r] = SDLK_r;
slouken@390
    81
    keymap[QZ_t] = SDLK_t;
slouken@390
    82
    keymap[QZ_y] = SDLK_y;
slouken@390
    83
    keymap[QZ_u] = SDLK_u;
slouken@390
    84
    keymap[QZ_i] = SDLK_i;
slouken@390
    85
    keymap[QZ_o] = SDLK_o;
slouken@390
    86
    keymap[QZ_p] = SDLK_p;
slouken@390
    87
    keymap[QZ_LEFTBRACKET] = SDLK_LEFTBRACKET;
slouken@390
    88
    keymap[QZ_RIGHTBRACKET] = SDLK_RIGHTBRACKET;
slouken@390
    89
    keymap[QZ_BACKSLASH] = SDLK_BACKSLASH;
slouken@390
    90
    keymap[QZ_DELETE] = SDLK_DELETE;
slouken@390
    91
    keymap[QZ_END] = SDLK_END;
slouken@390
    92
    keymap[QZ_PAGEDOWN] = SDLK_PAGEDOWN;
slouken@390
    93
    keymap[QZ_KP7] = SDLK_KP7;
slouken@390
    94
    keymap[QZ_KP8] = SDLK_KP8;
slouken@390
    95
    keymap[QZ_KP9] = SDLK_KP9;
slouken@390
    96
    keymap[QZ_KP_MINUS] = SDLK_KP_MINUS;
slouken@390
    97
    keymap[QZ_CAPSLOCK] = SDLK_CAPSLOCK;
slouken@390
    98
    keymap[QZ_a] = SDLK_a;
slouken@390
    99
    keymap[QZ_s] = SDLK_s;
slouken@390
   100
    keymap[QZ_d] = SDLK_d;
slouken@390
   101
    keymap[QZ_f] = SDLK_f;
slouken@390
   102
    keymap[QZ_g] = SDLK_g;
slouken@390
   103
    keymap[QZ_h] = SDLK_h;
slouken@390
   104
    keymap[QZ_j] = SDLK_j;
slouken@390
   105
    keymap[QZ_k] = SDLK_k;
slouken@390
   106
    keymap[QZ_l] = SDLK_l;
slouken@390
   107
    keymap[QZ_SEMICOLON] = SDLK_SEMICOLON;
slouken@390
   108
    keymap[QZ_QUOTE] = SDLK_QUOTE;
slouken@390
   109
    keymap[QZ_RETURN] = SDLK_RETURN;
slouken@390
   110
    keymap[QZ_KP4] = SDLK_KP4;
slouken@390
   111
    keymap[QZ_KP5] = SDLK_KP5;
slouken@390
   112
    keymap[QZ_KP6] = SDLK_KP6;
slouken@390
   113
    keymap[QZ_KP_PLUS] = SDLK_KP_PLUS;
slouken@390
   114
    keymap[QZ_LSHIFT] = SDLK_LSHIFT;
slouken@390
   115
    keymap[QZ_z] = SDLK_z;
slouken@390
   116
    keymap[QZ_x] = SDLK_x;
slouken@390
   117
    keymap[QZ_c] = SDLK_c;
slouken@390
   118
    keymap[QZ_v] = SDLK_v;
slouken@390
   119
    keymap[QZ_b] = SDLK_b;
slouken@390
   120
    keymap[QZ_n] = SDLK_n;
slouken@390
   121
    keymap[QZ_m] = SDLK_m;
slouken@390
   122
    keymap[QZ_COMMA] = SDLK_COMMA;
slouken@390
   123
    keymap[QZ_PERIOD] = SDLK_PERIOD;
slouken@390
   124
    keymap[QZ_SLASH] = SDLK_SLASH;
slouken@390
   125
    keymap[QZ_UP] = SDLK_UP;
slouken@390
   126
    keymap[QZ_KP1] = SDLK_KP1;
slouken@390
   127
    keymap[QZ_KP2] = SDLK_KP2;
slouken@390
   128
    keymap[QZ_KP3] = SDLK_KP3;
slouken@390
   129
    keymap[QZ_KP_ENTER] = SDLK_KP_ENTER;
slouken@390
   130
    keymap[QZ_LCTRL] = SDLK_LCTRL;
slouken@390
   131
    keymap[QZ_LALT] = SDLK_LALT;
slouken@390
   132
    keymap[QZ_LMETA] = SDLK_LMETA;
slouken@390
   133
    keymap[QZ_SPACE] = SDLK_SPACE;
slouken@390
   134
    keymap[QZ_LEFT] = SDLK_LEFT;
slouken@390
   135
    keymap[QZ_DOWN] = SDLK_DOWN;
slouken@390
   136
    keymap[QZ_RIGHT] = SDLK_RIGHT;
slouken@390
   137
    keymap[QZ_KP0] = SDLK_KP0;
slouken@390
   138
    keymap[QZ_KP_PERIOD] = SDLK_KP_PERIOD;
slouken@390
   139
    keymap[QZ_IBOOK_ENTER] = SDLK_KP_ENTER;
slouken@390
   140
    keymap[QZ_IBOOK_RIGHT] = SDLK_RIGHT;
slouken@390
   141
    keymap[QZ_IBOOK_DOWN] = SDLK_DOWN;
slouken@390
   142
    keymap[QZ_IBOOK_UP]      = SDLK_UP;
slouken@390
   143
    keymap[QZ_IBOOK_LEFT] = SDLK_LEFT;
slouken@390
   144
slouken@501
   145
    /* 
slouken@501
   146
        Up there we setup a static scancode->keysym map. However, it will not
slouken@501
   147
        work very well on international keyboard. Hence we now query MacOS
slouken@501
   148
        for its own keymap to adjust our own mapping table. However, this is
slouken@501
   149
        basically only useful for ascii char keys. This is also the reason
slouken@501
   150
        why we keep the static table, too.
slouken@390
   151
     */
slouken@390
   152
slouken@390
   153
    /* Get a pointer to the systems cached KCHR */
slouken@390
   154
    KCHRPtr = (void *)GetScriptManagerVariable(smKCHRCache);
slouken@390
   155
    if (KCHRPtr)
slouken@390
   156
    {
slouken@390
   157
        /* Loop over all 127 possible scan codes */
slouken@390
   158
        for (i = 0; i < 0x7F; i++)
slouken@390
   159
        {
slouken@390
   160
            /* We pretend a clean start to begin with (i.e. no dead keys active */
slouken@390
   161
            state = 0;
slouken@390
   162
slouken@390
   163
            /* Now translate the key code to a key value */
slouken@390
   164
            value = KeyTranslate(KCHRPtr, i, &state) & 0xff;
slouken@390
   165
slouken@390
   166
            /* If the state become 0, it was a dead key. We need to translate again,
slouken@390
   167
                passing in the new state, to get the actual key value */
slouken@390
   168
            if (state != 0)
slouken@390
   169
                value = KeyTranslate(KCHRPtr, i, &state) & 0xff;
slouken@390
   170
slouken@390
   171
            /* Now we should have an ascii value, or 0. Try to figure out to which SDL symbol it maps */
slouken@390
   172
            if (value >= 128)     /* Some non-ASCII char, map it to SDLK_WORLD_* */
slouken@390
   173
                keymap[i] = world++;
slouken@390
   174
            else if (value >= 32)     /* non-control ASCII char */
slouken@390
   175
                keymap[i] = value;
slouken@390
   176
        }
slouken@390
   177
    }
slouken@390
   178
slouken@501
   179
    /* 
slouken@501
   180
        The keypad codes are re-setup here, because the loop above cannot
slouken@501
   181
        distinguish between a key on the keypad and a regular key. We maybe
slouken@501
   182
        could get around this problem in another fashion: NSEvent's flags
slouken@501
   183
        include a "NSNumericPadKeyMask" bit; we could check that and modify
slouken@501
   184
        the symbol we return on the fly. However, this flag seems to exhibit
slouken@501
   185
        some weird behaviour related to the num lock key
slouken@501
   186
    */
slouken@390
   187
    keymap[QZ_KP0] = SDLK_KP0;
slouken@390
   188
    keymap[QZ_KP1] = SDLK_KP1;
slouken@390
   189
    keymap[QZ_KP2] = SDLK_KP2;
slouken@390
   190
    keymap[QZ_KP3] = SDLK_KP3;
slouken@390
   191
    keymap[QZ_KP4] = SDLK_KP4;
slouken@390
   192
    keymap[QZ_KP5] = SDLK_KP5;
slouken@390
   193
    keymap[QZ_KP6] = SDLK_KP6;
slouken@390
   194
    keymap[QZ_KP7] = SDLK_KP7;
slouken@390
   195
    keymap[QZ_KP8] = SDLK_KP8;
slouken@390
   196
    keymap[QZ_KP9] = SDLK_KP9;
slouken@390
   197
    keymap[QZ_KP_MINUS] = SDLK_KP_MINUS;
slouken@390
   198
    keymap[QZ_KP_PLUS] = SDLK_KP_PLUS;
slouken@390
   199
    keymap[QZ_KP_PERIOD] = SDLK_KP_PERIOD;
slouken@390
   200
    keymap[QZ_KP_EQUALS] = SDLK_KP_EQUALS;
slouken@390
   201
    keymap[QZ_KP_DIVIDE] = SDLK_KP_DIVIDE;
slouken@390
   202
    keymap[QZ_KP_MULTIPLY] = SDLK_KP_MULTIPLY;
slouken@390
   203
    keymap[QZ_KP_ENTER] = SDLK_KP_ENTER;
slouken@47
   204
}
slouken@47
   205
slouken@501
   206
static void QZ_DoKey (_THIS, int state, NSEvent *event) {
slouken@47
   207
slouken@390
   208
    NSString *chars;
slouken@561
   209
    unsigned int numChars;
slouken@390
   210
    SDL_keysym key;
slouken@561
   211
    
slouken@501
   212
    /* 
slouken@561
   213
        A key event can contain multiple characters,
slouken@561
   214
        or no characters at all. In most cases, it
slouken@561
   215
        will contain a single character. If it contains
slouken@561
   216
        0 characters, we'll use 0 as the unicode. If it
slouken@561
   217
        contains multiple characters, we'll use 0 as
slouken@561
   218
        the scancode/keysym.
slouken@501
   219
    */
slouken@390
   220
    chars = [ event characters ];
slouken@561
   221
    numChars = [ chars length ];
slouken@561
   222
slouken@561
   223
    if (numChars == 1) {
slouken@390
   224
slouken@390
   225
        key.scancode = [ event keyCode ];
slouken@561
   226
        key.sym      = keymap [ key.scancode ];
slouken@561
   227
        key.unicode  = [ chars characterAtIndex:0 ];
slouken@561
   228
        key.mod      = KMOD_NONE;
slouken@390
   229
slouken@390
   230
        SDL_PrivateKeyboard (state, &key);
slouken@390
   231
    }
slouken@561
   232
    else if (numChars == 0) {
slouken@561
   233
      
slouken@561
   234
        key.scancode = [ event keyCode ];
slouken@561
   235
        key.sym      = keymap [ key.scancode ];
slouken@561
   236
        key.unicode  = 0;
slouken@561
   237
        key.mod      = KMOD_NONE;
slouken@561
   238
slouken@561
   239
        SDL_PrivateKeyboard (state, &key);
slouken@561
   240
    }
slouken@561
   241
    else /* (numChars > 1) */ {
slouken@561
   242
      
slouken@561
   243
        int i;
slouken@561
   244
        for (i = 0; i < numChars; i++) {
slouken@561
   245
slouken@561
   246
            key.scancode = 0;
slouken@561
   247
            key.sym      = 0;
slouken@561
   248
            key.unicode  = [ chars characterAtIndex:i];
slouken@561
   249
            key.mod      = KMOD_NONE;
slouken@561
   250
slouken@561
   251
            SDL_PrivateKeyboard (state, &key);
slouken@561
   252
        }
slouken@561
   253
    }
slouken@47
   254
}
slouken@47
   255
slouken@501
   256
static void QZ_DoModifiers (_THIS, unsigned int newMods) {
slouken@47
   257
slouken@390
   258
    const int mapping[] = { SDLK_CAPSLOCK, SDLK_LSHIFT, SDLK_LCTRL, SDLK_LALT, SDLK_LMETA } ;
slouken@47
   259
slouken@390
   260
    int i;
slouken@390
   261
    int bit;
slouken@390
   262
    SDL_keysym key;
slouken@47
   263
slouken@390
   264
    key.scancode = 0;
slouken@390
   265
    key.sym         = SDLK_UNKNOWN;
slouken@390
   266
    key.unicode     = 0;
slouken@390
   267
    key.mod         = KMOD_NONE;
slouken@172
   268
slouken@390
   269
    /* Iterate through the bits, testing each against the current modifiers */
slouken@390
   270
    for (i = 0, bit = NSAlphaShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) {
slouken@390
   271
slouken@390
   272
        unsigned int currentMask, newMask;
slouken@390
   273
slouken@501
   274
        currentMask = current_mods & bit;
slouken@501
   275
        newMask     = newMods & bit;
slouken@390
   276
slouken@390
   277
        if ( currentMask &&
slouken@390
   278
             currentMask != newMask ) {     /* modifier up event */
slouken@390
   279
slouken@390
   280
             key.sym = mapping[i];
slouken@390
   281
             /* If this was Caps Lock, we need some additional voodoo to make SDL happy */
slouken@390
   282
             if (bit == NSAlphaShiftKeyMask)
slouken@390
   283
             SDL_PrivateKeyboard (SDL_PRESSED, &key);
slouken@390
   284
             SDL_PrivateKeyboard (SDL_RELEASED, &key);
slouken@390
   285
        }
slouken@390
   286
        else if ( newMask &&
slouken@390
   287
                  currentMask != newMask ) {     /* modifier down event */
slouken@390
   288
        
slouken@390
   289
             key.sym = mapping[i];
slouken@390
   290
             SDL_PrivateKeyboard (SDL_PRESSED, &key);
slouken@390
   291
             /* If this was Caps Lock, we need some additional voodoo to make SDL happy */
slouken@390
   292
             if (bit == NSAlphaShiftKeyMask)
slouken@390
   293
                  SDL_PrivateKeyboard (SDL_RELEASED, &key);
slouken@390
   294
        }
slouken@390
   295
    }
slouken@390
   296
slouken@501
   297
    current_mods = newMods;
slouken@47
   298
}
slouken@47
   299
slouken@117
   300
static void QZ_DoActivate (_THIS)
slouken@117
   301
{
slouken@501
   302
    in_foreground = YES;
icculus@563
   303
    
slouken@615
   304
    /* Hide the cursor if it was hidden by SDL_ShowCursor() */
slouken@615
   305
    if (!cursor_visible && !cursor_hidden) {
icculus@563
   306
        HideCursor ();
slouken@615
   307
        cursor_hidden = YES;
slouken@390
   308
    }
slouken@168
   309
icculus@563
   310
    /* Regrab input, only if it was previously grabbed */
icculus@563
   311
    if ( current_grab_mode == SDL_GRAB_ON ) {
icculus@563
   312
        
icculus@563
   313
        /* Restore cursor location if input was grabbed */
icculus@563
   314
        QZ_PrivateWarpCursor (this, cursor_loc.x, cursor_loc.y);
icculus@563
   315
        QZ_ChangeGrabState (this, QZ_ENABLE_GRAB);
slouken@390
   316
    }
slouken@390
   317
slouken@390
   318
    SDL_PrivateAppActive (1, SDL_APPINPUTFOCUS);
slouken@47
   319
}
slouken@47
   320
slouken@47
   321
static void QZ_DoDeactivate (_THIS) {
slouken@47
   322
slouken@501
   323
    in_foreground = NO;
slouken@168
   324
icculus@563
   325
    /* Get the current cursor location, for restore on activate */
icculus@563
   326
    cursor_loc = [ NSEvent mouseLocation ]; /* global coordinates */
icculus@563
   327
    if (qz_window)
icculus@563
   328
        QZ_PrivateGlobalToLocal (this, &cursor_loc);
icculus@563
   329
    QZ_PrivateCocoaToSDL (this, &cursor_loc);
icculus@563
   330
    
icculus@563
   331
    /* Reassociate mouse and cursor */
icculus@563
   332
    CGAssociateMouseAndMouseCursorPosition (1);
slouken@390
   333
slouken@615
   334
    /* Show the cursor if it was hidden by SDL_ShowCursor() */
slouken@615
   335
    if (!cursor_visible && cursor_hidden) {
slouken@615
   336
        ShowCursor ();
slouken@615
   337
        cursor_hidden = NO;
slouken@615
   338
    }
slouken@390
   339
slouken@390
   340
    SDL_PrivateAppActive (0, SDL_APPINPUTFOCUS);
slouken@47
   341
}
slouken@47
   342
slouken@555
   343
void QZ_SleepNotificationHandler (void * refcon,
slouken@555
   344
                                  io_service_t service,
slouken@555
   345
                                  natural_t messageType,
slouken@555
   346
                                  void * messageArgument )
slouken@555
   347
{
slouken@555
   348
     SDL_VideoDevice *this = (SDL_VideoDevice*)refcon;
slouken@555
   349
     
slouken@555
   350
     switch(messageType)
slouken@555
   351
     {
slouken@555
   352
         case kIOMessageSystemWillSleep:
icculus@563
   353
             IOAllowPowerChange(power_connection, (long) messageArgument);
slouken@555
   354
             break;
slouken@555
   355
         case kIOMessageCanSystemSleep:
icculus@563
   356
             IOAllowPowerChange(power_connection, (long) messageArgument);
slouken@555
   357
             break;
slouken@555
   358
         case kIOMessageSystemHasPoweredOn:
slouken@555
   359
			/* awake */
slouken@555
   360
            SDL_PrivateExpose();
slouken@555
   361
            break;
slouken@555
   362
     }
slouken@555
   363
}
slouken@555
   364
slouken@555
   365
static void QZ_RegisterForSleepNotifications (_THIS)
slouken@555
   366
{
slouken@555
   367
     CFRunLoopSourceRef rls;
slouken@555
   368
     IONotificationPortRef thePortRef;
slouken@555
   369
     io_object_t notifier;
slouken@555
   370
icculus@563
   371
     power_connection = IORegisterForSystemPower (this, &thePortRef, QZ_SleepNotificationHandler, &notifier);
slouken@555
   372
icculus@563
   373
     if (power_connection == 0)
slouken@555
   374
         NSLog(@"SDL: QZ_SleepNotificationHandler() IORegisterForSystemPower failed.");
slouken@555
   375
slouken@555
   376
     rls = IONotificationPortGetRunLoopSource (thePortRef);
slouken@555
   377
     CFRunLoopAddSource (CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
slouken@555
   378
     CFRelease (rls);
slouken@555
   379
}
slouken@555
   380
slouken@117
   381
static void QZ_PumpEvents (_THIS)
slouken@158
   382
{
slouken@435
   383
    int firstMouseEvent;
slouken@390
   384
    CGMouseDelta dx, dy;
slouken@390
   385
slouken@390
   386
    NSDate *distantPast;
slouken@390
   387
    NSEvent *event;
slouken@390
   388
    NSRect winRect;
slouken@390
   389
    NSRect titleBarRect;
slouken@390
   390
    NSAutoreleasePool *pool;
slouken@390
   391
slouken@390
   392
    pool = [ [ NSAutoreleasePool alloc ] init ];
slouken@390
   393
    distantPast = [ NSDate distantPast ];
slouken@390
   394
slouken@390
   395
    winRect = NSMakeRect (0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h);
slouken@435
   396
    titleBarRect = NSMakeRect (0, SDL_VideoSurface->h, SDL_VideoSurface->w,
slouken@435
   397
                                SDL_VideoSurface->h + 22);
slouken@435
   398
    
slouken@435
   399
    /* send the first mouse event in absolute coordinates */
slouken@435
   400
    firstMouseEvent = 1;
slouken@435
   401
    
slouken@435
   402
    /* accumulate any additional mouse moved events into one SDL mouse event */
slouken@390
   403
    dx = 0;
slouken@390
   404
    dy = 0;
slouken@390
   405
    
slouken@390
   406
    do {
slouken@390
   407
    
slouken@390
   408
        /* Poll for an event. This will not block */
slouken@390
   409
        event = [ NSApp nextEventMatchingMask:NSAnyEventMask
slouken@390
   410
                                    untilDate:distantPast
slouken@390
   411
                                    inMode: NSDefaultRunLoopMode dequeue:YES ];
slouken@390
   412
        if (event != nil) {
slouken@390
   413
slouken@390
   414
            unsigned int type;
slouken@390
   415
            BOOL isForGameWin;
icculus@563
   416
            BOOL isInGameWin;
icculus@563
   417
            
icculus@563
   418
            #define DO_MOUSE_DOWN(button) do {                                               \
slouken@501
   419
                            if ( in_foreground ) {                                           \
icculus@563
   420
                                if ( isInGameWin ) {                                         \
icculus@563
   421
                                    SDL_PrivateMouseButton (SDL_PRESSED, button, 0, 0);      \
icculus@563
   422
                                    expect_mouse_up |= 1<<button;                            \
icculus@563
   423
                                }                                                            \
slouken@390
   424
                            }                                                                \
slouken@390
   425
                            else {                                                           \
slouken@390
   426
                                QZ_DoActivate (this);                                        \
slouken@390
   427
                            }                                                                \
slouken@390
   428
                            [ NSApp sendEvent:event ];                                       \
slouken@390
   429
            } while(0)
slouken@272
   430
            
icculus@563
   431
            #define DO_MOUSE_UP(button) do {                                            \
icculus@563
   432
                            if ( expect_mouse_up & (1<<button) ) {                      \
icculus@563
   433
                                SDL_PrivateMouseButton (SDL_RELEASED, button, 0, 0);    \
icculus@563
   434
                                expect_mouse_up &= ~(1<<button);                        \
icculus@563
   435
                            }                                                           \
icculus@563
   436
                            [ NSApp sendEvent:event ];                                  \
slouken@390
   437
            } while(0)
slouken@390
   438
            
slouken@390
   439
            type = [ event type ];
slouken@390
   440
            isForGameWin = (qz_window == [ event window ]);
icculus@563
   441
            isInGameWin = NSPointInRect([event locationInWindow], winRect);
slouken@390
   442
            switch (type) {
slouken@390
   443
                case NSLeftMouseDown:
slouken@511
   444
                    if ( getenv("SDL_HAS3BUTTONMOUSE") ) {
icculus@563
   445
                        DO_MOUSE_DOWN (SDL_BUTTON_LEFT);
slouken@511
   446
                    } else {
slouken@511
   447
                        if ( NSCommandKeyMask & current_mods ) {
icculus@563
   448
                            last_virtual_button = SDL_BUTTON_RIGHT;
icculus@563
   449
                            DO_MOUSE_DOWN (SDL_BUTTON_RIGHT);
slouken@511
   450
                        }
slouken@511
   451
                        else if ( NSAlternateKeyMask & current_mods ) {
icculus@563
   452
                            last_virtual_button = SDL_BUTTON_MIDDLE;
icculus@563
   453
                            DO_MOUSE_DOWN (SDL_BUTTON_MIDDLE);
slouken@511
   454
                        }
slouken@511
   455
                        else {
icculus@563
   456
                            DO_MOUSE_DOWN (SDL_BUTTON_LEFT);
slouken@511
   457
                        }
slouken@390
   458
                    }
slouken@390
   459
                    break;
icculus@563
   460
                case NSOtherMouseDown: DO_MOUSE_DOWN (SDL_BUTTON_MIDDLE); break;
icculus@563
   461
                case NSRightMouseDown: DO_MOUSE_DOWN (SDL_BUTTON_RIGHT);  break;
slouken@390
   462
                case NSLeftMouseUp:
slouken@390
   463
                    if ( last_virtual_button != 0 ) {
icculus@563
   464
                        DO_MOUSE_UP (last_virtual_button);
slouken@390
   465
                        last_virtual_button = 0;
slouken@390
   466
                    }
slouken@390
   467
                    else {
icculus@563
   468
                        DO_MOUSE_UP (SDL_BUTTON_LEFT);
slouken@390
   469
                    }
slouken@390
   470
                    break;
icculus@563
   471
                case NSOtherMouseUp:   DO_MOUSE_UP (SDL_BUTTON_MIDDLE); break;
icculus@563
   472
                case NSRightMouseUp:   DO_MOUSE_UP (SDL_BUTTON_RIGHT);  break;
slouken@390
   473
                case NSSystemDefined:
slouken@501
   474
                    /*
slouken@501
   475
                        Future: up to 32 "mouse" buttons can be handled.
slouken@501
   476
                        if ([event subtype] == 7) {
slouken@501
   477
                            unsigned int buttons;
slouken@501
   478
                            buttons = [ event data2 ];
slouken@501
   479
                    */
slouken@390
   480
                    break;
slouken@390
   481
                case NSLeftMouseDragged:
slouken@390
   482
                case NSRightMouseDragged:
slouken@435
   483
                case NSOtherMouseDragged: /* usually middle mouse dragged */
slouken@390
   484
                case NSMouseMoved:
icculus@563
   485
                    if ( grab_state == QZ_INVISIBLE_GRAB ) {
slouken@272
   486
                
slouken@501
   487
                        /*
icculus@563
   488
                            If input is grabbed+hidden, the cursor doesn't move,
slouken@501
   489
                            so we have to call the lowlevel window server
slouken@501
   490
                            function. This is less accurate but works OK.                         
slouken@501
   491
                        */
slouken@390
   492
                        CGMouseDelta dx1, dy1;
slouken@390
   493
                        CGGetLastMouseDelta (&dx1, &dy1);
slouken@390
   494
                        dx += dx1;
slouken@390
   495
                        dy += dy1;
slouken@390
   496
                    }
slouken@435
   497
                    else if (firstMouseEvent) {
slouken@435
   498
                        
slouken@501
   499
                        /*
slouken@501
   500
                            Get the first mouse event in a possible
slouken@501
   501
                            sequence of mouse moved events. Since we
slouken@501
   502
                            use absolute coordinates, this serves to
slouken@501
   503
                            compensate any inaccuracy in deltas, and
slouken@501
   504
                            provides the first known mouse position,
slouken@501
   505
                            since everything after this uses deltas
slouken@501
   506
                        */
slouken@435
   507
                        NSPoint p = [ event locationInWindow ];
icculus@563
   508
                        QZ_PrivateCocoaToSDL (this, &p);
slouken@454
   509
                        SDL_PrivateMouseMotion (0, 0, p.x, p.y);
slouken@435
   510
                        firstMouseEvent = 0;
slouken@435
   511
                    }
slouken@435
   512
                    else {
slouken@435
   513
                    
slouken@501
   514
                        /*
slouken@501
   515
                            Get the amount moved since the last drag or move event,
slouken@501
   516
                            add it on for one big move event at the end.
slouken@501
   517
                        */
slouken@501
   518
                        dx += [ event deltaX ];
slouken@501
   519
                        dy += [ event deltaY ];
slouken@435
   520
                    }
icculus@563
   521
                    
icculus@563
   522
                    /* 
icculus@563
   523
                        Handle grab input+cursor visible by warping the cursor back
icculus@563
   524
                        into the game window. This still generates a mouse moved event,
icculus@563
   525
                        but not as a result of the warp (so it's in the right direction).
icculus@563
   526
                    */
icculus@563
   527
                    if ( grab_state == QZ_VISIBLE_GRAB &&
icculus@563
   528
                         !isInGameWin ) {
icculus@563
   529
                       
icculus@563
   530
                        NSPoint p = [ event locationInWindow ]; 
icculus@563
   531
                        QZ_PrivateCocoaToSDL (this, &p);
icculus@563
   532
icculus@563
   533
                        if ( p.x < 0.0 ) 
icculus@563
   534
                            p.x = 0.0;
icculus@563
   535
                        
icculus@563
   536
                        if ( p.y < 0.0 ) 
icculus@563
   537
                            p.y = 0.0;
icculus@563
   538
                        
icculus@563
   539
                        if ( p.x >= winRect.size.width ) 
icculus@563
   540
                            p.x = winRect.size.width-1;
icculus@563
   541
                        
icculus@563
   542
                        if ( p.y >= winRect.size.height ) 
icculus@563
   543
                            p.y = winRect.size.height-1;
icculus@563
   544
                        
icculus@563
   545
                        QZ_PrivateWarpCursor (this, p.x, p.y);
icculus@563
   546
                    }
slouken@390
   547
                    break;
slouken@390
   548
                case NSScrollWheel:
icculus@563
   549
                    if ( isInGameWin ) {
slouken@390
   550
                        float dy;
slouken@502
   551
                        Uint8 button;
slouken@390
   552
                        dy = [ event deltaY ];
slouken@390
   553
                        if ( dy > 0.0 ) /* Scroll up */
slouken@502
   554
                            button = SDL_BUTTON_WHEELUP;
slouken@390
   555
                        else /* Scroll down */
slouken@502
   556
                            button = SDL_BUTTON_WHEELDOWN;
icculus@563
   557
                        /* For now, wheel is sent as a quick down+up */
slouken@502
   558
                        SDL_PrivateMouseButton (SDL_PRESSED, button, 0, 0);
slouken@502
   559
                        SDL_PrivateMouseButton (SDL_RELEASED, button, 0, 0);
slouken@390
   560
                    }
slouken@390
   561
                    break;
slouken@390
   562
                case NSKeyUp:
slouken@501
   563
                    QZ_DoKey (this, SDL_RELEASED, event);
slouken@390
   564
                    break;
slouken@390
   565
                case NSKeyDown:
slouken@501
   566
                    QZ_DoKey (this, SDL_PRESSED, event);
slouken@390
   567
                    break;
slouken@390
   568
                case NSFlagsChanged:
slouken@501
   569
                    QZ_DoModifiers(this, [ event modifierFlags ] );
slouken@390
   570
                    break;
slouken@390
   571
                case NSAppKitDefined:
slouken@390
   572
                    switch ( [ event subtype ] ) {
slouken@390
   573
                        case NSApplicationActivatedEventType:
slouken@390
   574
                            QZ_DoActivate (this);
slouken@390
   575
                            break;
slouken@390
   576
                        case NSApplicationDeactivatedEventType:
slouken@390
   577
                            QZ_DoDeactivate (this);
slouken@390
   578
                            break;
slouken@390
   579
                    }
slouken@390
   580
                    [ NSApp sendEvent:event ];
slouken@390
   581
                    break;
slouken@390
   582
                    /* case NSApplicationDefined: break; */
slouken@390
   583
                    /* case NSPeriodic: break; */
slouken@390
   584
                    /* case NSCursorUpdate: break; */
slouken@390
   585
                default:
slouken@390
   586
                    [ NSApp sendEvent:event ];
slouken@272
   587
            }
slouken@272
   588
        }
slouken@390
   589
    } while (event != nil);
slouken@390
   590
    
slouken@435
   591
    /* handle accumulated mouse moved events */
slouken@390
   592
    if (dx != 0 || dy != 0)
slouken@435
   593
        SDL_PrivateMouseMotion (0, 1, dx, dy);
slouken@390
   594
    
slouken@390
   595
    [ pool release ];
slouken@502
   596
}