src/video/quartz/SDL_QuartzEvents.m
author Sam Lantinga <slouken@libsdl.org>
Wed, 07 Jan 2004 15:01:51 +0000
changeset 779 68c8da837fc0
parent 761 c5b2b6d2d1fe
child 782 dbc5905402b0
permissions -rw-r--r--
Date: Tue, 6 Jan 2004 21:54:02 +0100
From: Max Horn
Subject: Auto hide mouse & other changes

the attached bug adds the auto-hide-mouse feature I talked about
earlier. Turned out it was a lot simpler than I thought, simply by
using our existing code :-). I actually spent much more time on fixing
various bugs in the code and correcting (IMO) some behavior (although,
due to the lack of real specs for SDL, it's probably arguable what
'correct' means...).

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