src/video/quartz/SDL_QuartzEvents.m
author Sam Lantinga <slouken@libsdl.org>
Mon, 04 Aug 2003 01:00:30 +0000
changeset 664 abfdc08eb289
parent 631 52864d66d168
child 683 5d2f027b3349
permissions -rw-r--r--
Date: Sun, 3 Aug 2003 22:07:57 +0200
From: Max Horn
Subject: SDL OSX fullscreen FIX

the attached patch fixes the fullscreen problems on SDL/OSX. The cause
was that click events are bounded by winRect. Now, winRect is set to
the size of the video surface. But if you e.g. request a 640x420
surface, you might get a 640x480 "real" surface. Still,
SDL_VideoSurface->h will be set to 420! Thus, the upper 60 pixels in my
example received no mouse down events.

My fix simply disables this clipping when in full screen mode - after
all, all clicks then should be inside the screen surface. Higher SDL
functions ensure that the coordinates then are clipped to 640x420. It
works fine in all my tests here. I don't know if it's the right thing
to do in multi screen scenarios, though.
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@664
   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@664
   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
icculus@624
   381
icculus@624
   382
// Try to map Quartz mouse buttons to SDL's lingo...
icculus@624
   383
static int QZ_OtherMouseButtonToSDL(int button)
icculus@624
   384
{
icculus@624
   385
    switch (button)
icculus@624
   386
    {
icculus@624
   387
        case 0:
icculus@624
   388
            return(SDL_BUTTON_LEFT);   // 1
icculus@624
   389
        case 1:
icculus@624
   390
            return(SDL_BUTTON_RIGHT);  // 3
icculus@624
   391
        case 2:
icculus@624
   392
            return(SDL_BUTTON_MIDDLE); // 2
icculus@624
   393
    }
icculus@624
   394
icculus@624
   395
    // >= 3: skip 4 & 5, since those are the SDL mousewheel buttons.
icculus@624
   396
    return(button + 3);
icculus@624
   397
}
icculus@624
   398
icculus@624
   399
slouken@117
   400
static void QZ_PumpEvents (_THIS)
slouken@158
   401
{
slouken@435
   402
    int firstMouseEvent;
slouken@390
   403
    CGMouseDelta dx, dy;
slouken@390
   404
slouken@390
   405
    NSDate *distantPast;
slouken@390
   406
    NSEvent *event;
slouken@390
   407
    NSRect winRect;
slouken@390
   408
    NSAutoreleasePool *pool;
slouken@390
   409
icculus@619
   410
    /* Update activity every five seconds to prevent screensaver. --ryan. */
icculus@619
   411
    static Uint32 screensaverTicks = 0;
icculus@619
   412
    Uint32 nowTicks = SDL_GetTicks();
icculus@619
   413
    if ((nowTicks - screensaverTicks) > 5000)
icculus@619
   414
    {
icculus@619
   415
        UpdateSystemActivity(UsrActivity);
icculus@619
   416
        screensaverTicks = nowTicks;
icculus@619
   417
    }
icculus@619
   418
slouken@390
   419
    pool = [ [ NSAutoreleasePool alloc ] init ];
slouken@390
   420
    distantPast = [ NSDate distantPast ];
slouken@390
   421
slouken@390
   422
    winRect = NSMakeRect (0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h);
slouken@435
   423
    
slouken@435
   424
    /* send the first mouse event in absolute coordinates */
slouken@435
   425
    firstMouseEvent = 1;
slouken@435
   426
    
slouken@435
   427
    /* accumulate any additional mouse moved events into one SDL mouse event */
slouken@390
   428
    dx = 0;
slouken@390
   429
    dy = 0;
slouken@390
   430
    
slouken@390
   431
    do {
slouken@390
   432
    
slouken@390
   433
        /* Poll for an event. This will not block */
slouken@390
   434
        event = [ NSApp nextEventMatchingMask:NSAnyEventMask
slouken@390
   435
                                    untilDate:distantPast
slouken@390
   436
                                    inMode: NSDefaultRunLoopMode dequeue:YES ];
slouken@390
   437
        if (event != nil) {
slouken@390
   438
icculus@624
   439
            int button;
slouken@390
   440
            unsigned int type;
slouken@390
   441
            BOOL isForGameWin;
icculus@563
   442
            BOOL isInGameWin;
icculus@563
   443
            
icculus@563
   444
            #define DO_MOUSE_DOWN(button) do {                                               \
slouken@501
   445
                            if ( in_foreground ) {                                           \
icculus@563
   446
                                if ( isInGameWin ) {                                         \
icculus@563
   447
                                    SDL_PrivateMouseButton (SDL_PRESSED, button, 0, 0);      \
icculus@563
   448
                                    expect_mouse_up |= 1<<button;                            \
icculus@563
   449
                                }                                                            \
slouken@390
   450
                            }                                                                \
slouken@390
   451
                            else {                                                           \
slouken@390
   452
                                QZ_DoActivate (this);                                        \
slouken@390
   453
                            }                                                                \
slouken@390
   454
                            [ NSApp sendEvent:event ];                                       \
slouken@390
   455
            } while(0)
slouken@272
   456
            
icculus@563
   457
            #define DO_MOUSE_UP(button) do {                                            \
icculus@563
   458
                            if ( expect_mouse_up & (1<<button) ) {                      \
icculus@563
   459
                                SDL_PrivateMouseButton (SDL_RELEASED, button, 0, 0);    \
icculus@563
   460
                                expect_mouse_up &= ~(1<<button);                        \
icculus@563
   461
                            }                                                           \
icculus@563
   462
                            [ NSApp sendEvent:event ];                                  \
slouken@390
   463
            } while(0)
slouken@390
   464
            
slouken@390
   465
            type = [ event type ];
slouken@390
   466
            isForGameWin = (qz_window == [ event window ]);
slouken@664
   467
            isInGameWin = (mode_flags & SDL_FULLSCREEN) ? true : NSPointInRect([event locationInWindow], winRect);
slouken@390
   468
            switch (type) {
slouken@390
   469
                case NSLeftMouseDown:
slouken@511
   470
                    if ( getenv("SDL_HAS3BUTTONMOUSE") ) {
icculus@563
   471
                        DO_MOUSE_DOWN (SDL_BUTTON_LEFT);
slouken@511
   472
                    } else {
slouken@511
   473
                        if ( NSCommandKeyMask & current_mods ) {
icculus@563
   474
                            last_virtual_button = SDL_BUTTON_RIGHT;
icculus@563
   475
                            DO_MOUSE_DOWN (SDL_BUTTON_RIGHT);
slouken@511
   476
                        }
slouken@511
   477
                        else if ( NSAlternateKeyMask & current_mods ) {
icculus@563
   478
                            last_virtual_button = SDL_BUTTON_MIDDLE;
icculus@563
   479
                            DO_MOUSE_DOWN (SDL_BUTTON_MIDDLE);
slouken@511
   480
                        }
slouken@511
   481
                        else {
icculus@563
   482
                            DO_MOUSE_DOWN (SDL_BUTTON_LEFT);
slouken@511
   483
                        }
slouken@390
   484
                    }
slouken@390
   485
                    break;
icculus@624
   486
slouken@390
   487
                case NSLeftMouseUp:
slouken@390
   488
                    if ( last_virtual_button != 0 ) {
icculus@563
   489
                        DO_MOUSE_UP (last_virtual_button);
slouken@390
   490
                        last_virtual_button = 0;
slouken@390
   491
                    }
slouken@390
   492
                    else {
icculus@563
   493
                        DO_MOUSE_UP (SDL_BUTTON_LEFT);
slouken@390
   494
                    }
slouken@390
   495
                    break;
icculus@624
   496
icculus@624
   497
                case NSOtherMouseDown:
icculus@624
   498
                case NSRightMouseDown:
icculus@624
   499
                    button = QZ_OtherMouseButtonToSDL([ event buttonNumber ]);
icculus@624
   500
                    DO_MOUSE_DOWN (button);
icculus@624
   501
                    break;
icculus@624
   502
icculus@624
   503
                case NSOtherMouseUp:
icculus@624
   504
                case NSRightMouseUp:
icculus@624
   505
                    button = QZ_OtherMouseButtonToSDL([ event buttonNumber ]);
icculus@624
   506
                    DO_MOUSE_UP (button);
icculus@624
   507
                    break;
icculus@624
   508
slouken@390
   509
                case NSSystemDefined:
slouken@501
   510
                    /*
slouken@501
   511
                        Future: up to 32 "mouse" buttons can be handled.
slouken@501
   512
                        if ([event subtype] == 7) {
slouken@501
   513
                            unsigned int buttons;
slouken@501
   514
                            buttons = [ event data2 ];
slouken@501
   515
                    */
slouken@390
   516
                    break;
slouken@390
   517
                case NSLeftMouseDragged:
slouken@390
   518
                case NSRightMouseDragged:
slouken@435
   519
                case NSOtherMouseDragged: /* usually middle mouse dragged */
slouken@390
   520
                case NSMouseMoved:
icculus@563
   521
                    if ( grab_state == QZ_INVISIBLE_GRAB ) {
slouken@272
   522
                
slouken@501
   523
                        /*
icculus@563
   524
                            If input is grabbed+hidden, the cursor doesn't move,
slouken@501
   525
                            so we have to call the lowlevel window server
slouken@501
   526
                            function. This is less accurate but works OK.                         
slouken@501
   527
                        */
slouken@390
   528
                        CGMouseDelta dx1, dy1;
slouken@390
   529
                        CGGetLastMouseDelta (&dx1, &dy1);
slouken@390
   530
                        dx += dx1;
slouken@390
   531
                        dy += dy1;
slouken@390
   532
                    }
slouken@435
   533
                    else if (firstMouseEvent) {
slouken@435
   534
                        
slouken@501
   535
                        /*
slouken@501
   536
                            Get the first mouse event in a possible
slouken@501
   537
                            sequence of mouse moved events. Since we
slouken@501
   538
                            use absolute coordinates, this serves to
slouken@501
   539
                            compensate any inaccuracy in deltas, and
slouken@501
   540
                            provides the first known mouse position,
slouken@501
   541
                            since everything after this uses deltas
slouken@501
   542
                        */
slouken@435
   543
                        NSPoint p = [ event locationInWindow ];
icculus@563
   544
                        QZ_PrivateCocoaToSDL (this, &p);
slouken@454
   545
                        SDL_PrivateMouseMotion (0, 0, p.x, p.y);
slouken@435
   546
                        firstMouseEvent = 0;
slouken@435
   547
                    }
slouken@435
   548
                    else {
slouken@435
   549
                    
slouken@501
   550
                        /*
slouken@501
   551
                            Get the amount moved since the last drag or move event,
slouken@501
   552
                            add it on for one big move event at the end.
slouken@501
   553
                        */
slouken@501
   554
                        dx += [ event deltaX ];
slouken@501
   555
                        dy += [ event deltaY ];
slouken@435
   556
                    }
icculus@563
   557
                    
icculus@563
   558
                    /* 
icculus@563
   559
                        Handle grab input+cursor visible by warping the cursor back
icculus@563
   560
                        into the game window. This still generates a mouse moved event,
icculus@563
   561
                        but not as a result of the warp (so it's in the right direction).
icculus@563
   562
                    */
icculus@563
   563
                    if ( grab_state == QZ_VISIBLE_GRAB &&
icculus@563
   564
                         !isInGameWin ) {
icculus@563
   565
                       
icculus@563
   566
                        NSPoint p = [ event locationInWindow ]; 
icculus@563
   567
                        QZ_PrivateCocoaToSDL (this, &p);
icculus@563
   568
icculus@563
   569
                        if ( p.x < 0.0 ) 
icculus@563
   570
                            p.x = 0.0;
icculus@563
   571
                        
icculus@563
   572
                        if ( p.y < 0.0 ) 
icculus@563
   573
                            p.y = 0.0;
icculus@563
   574
                        
icculus@563
   575
                        if ( p.x >= winRect.size.width ) 
icculus@563
   576
                            p.x = winRect.size.width-1;
icculus@563
   577
                        
icculus@563
   578
                        if ( p.y >= winRect.size.height ) 
icculus@563
   579
                            p.y = winRect.size.height-1;
icculus@563
   580
                        
icculus@563
   581
                        QZ_PrivateWarpCursor (this, p.x, p.y);
icculus@563
   582
                    }
slouken@631
   583
                    else
slouken@631
   584
                    if ( !isInGameWin && (SDL_GetAppState() & SDL_APPMOUSEFOCUS) ) {
slouken@631
   585
                    
slouken@631
   586
                        SDL_PrivateAppActive (0, SDL_APPMOUSEFOCUS);
slouken@631
   587
                    }
slouken@631
   588
                    else
slouken@631
   589
                    if ( isInGameWin && !(SDL_GetAppState() & SDL_APPMOUSEFOCUS) ) {
slouken@631
   590
                    
slouken@631
   591
                        SDL_PrivateAppActive (1, SDL_APPMOUSEFOCUS);
slouken@631
   592
                    }
slouken@390
   593
                    break;
slouken@390
   594
                case NSScrollWheel:
icculus@563
   595
                    if ( isInGameWin ) {
slouken@390
   596
                        float dy;
slouken@502
   597
                        Uint8 button;
slouken@390
   598
                        dy = [ event deltaY ];
slouken@390
   599
                        if ( dy > 0.0 ) /* Scroll up */
slouken@502
   600
                            button = SDL_BUTTON_WHEELUP;
slouken@390
   601
                        else /* Scroll down */
slouken@502
   602
                            button = SDL_BUTTON_WHEELDOWN;
icculus@563
   603
                        /* For now, wheel is sent as a quick down+up */
slouken@502
   604
                        SDL_PrivateMouseButton (SDL_PRESSED, button, 0, 0);
slouken@502
   605
                        SDL_PrivateMouseButton (SDL_RELEASED, button, 0, 0);
slouken@390
   606
                    }
slouken@390
   607
                    break;
slouken@390
   608
                case NSKeyUp:
slouken@501
   609
                    QZ_DoKey (this, SDL_RELEASED, event);
slouken@390
   610
                    break;
slouken@390
   611
                case NSKeyDown:
slouken@501
   612
                    QZ_DoKey (this, SDL_PRESSED, event);
slouken@390
   613
                    break;
slouken@390
   614
                case NSFlagsChanged:
slouken@501
   615
                    QZ_DoModifiers(this, [ event modifierFlags ] );
slouken@390
   616
                    break;
slouken@390
   617
                case NSAppKitDefined:
slouken@390
   618
                    switch ( [ event subtype ] ) {
slouken@390
   619
                        case NSApplicationActivatedEventType:
slouken@390
   620
                            QZ_DoActivate (this);
slouken@390
   621
                            break;
slouken@390
   622
                        case NSApplicationDeactivatedEventType:
slouken@390
   623
                            QZ_DoDeactivate (this);
slouken@390
   624
                            break;
slouken@390
   625
                    }
slouken@390
   626
                    [ NSApp sendEvent:event ];
slouken@390
   627
                    break;
slouken@390
   628
                    /* case NSApplicationDefined: break; */
slouken@390
   629
                    /* case NSPeriodic: break; */
slouken@390
   630
                    /* case NSCursorUpdate: break; */
slouken@390
   631
                default:
slouken@390
   632
                    [ NSApp sendEvent:event ];
slouken@272
   633
            }
slouken@272
   634
        }
slouken@390
   635
    } while (event != nil);
slouken@390
   636
    
slouken@435
   637
    /* handle accumulated mouse moved events */
slouken@390
   638
    if (dx != 0 || dy != 0)
slouken@435
   639
        SDL_PrivateMouseMotion (0, 1, dx, dy);
slouken@390
   640
    
slouken@390
   641
    [ pool release ];
slouken@502
   642
}