src/video/quartz/SDL_QuartzEvents.m
author Sam Lantinga <slouken@libsdl.org>
Fri, 13 Feb 2004 17:57:16 +0000
changeset 816 428f688f2ad2
parent 782 dbc5905402b0
child 897 9e27fdb98eab
permissions -rw-r--r--
Date: Fri, 13 Feb 2004 17:03:16 +0100
From: Max Horn
Subject: Modifier key fix

The internal modifier state can get out of sync with reality. To
trigger this, do for example this:
1) Launch an SDL app
2) Alt-click on the desktop (this will hide the SDL app).
3) Bring the SDL app back to the front
4) SDL will still think alt is pressed (and as such will treat left
clicks like middle clicks). If you press and release alt, it'll be fine
again.

The attached patch cures this by rechecking the modifier state whenever
we process an event.
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@816
   269
    
slouken@816
   270
    if (current_mods == newMods)
slouken@816
   271
    	return;
slouken@47
   272
slouken@664
   273
    key.scancode    = 0;
slouken@390
   274
    key.sym         = SDLK_UNKNOWN;
slouken@390
   275
    key.unicode     = 0;
slouken@390
   276
    key.mod         = KMOD_NONE;
slouken@172
   277
slouken@390
   278
    /* Iterate through the bits, testing each against the current modifiers */
slouken@390
   279
    for (i = 0, bit = NSAlphaShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) {
slouken@390
   280
slouken@390
   281
        unsigned int currentMask, newMask;
slouken@390
   282
slouken@501
   283
        currentMask = current_mods & bit;
slouken@501
   284
        newMask     = newMods & bit;
slouken@390
   285
slouken@390
   286
        if ( currentMask &&
slouken@390
   287
             currentMask != newMask ) {     /* modifier up event */
slouken@390
   288
slouken@390
   289
             key.sym = mapping[i];
slouken@390
   290
             /* If this was Caps Lock, we need some additional voodoo to make SDL happy */
slouken@390
   291
             if (bit == NSAlphaShiftKeyMask)
slouken@761
   292
                  SDL_PrivateKeyboard (SDL_PRESSED, &key);
slouken@390
   293
             SDL_PrivateKeyboard (SDL_RELEASED, &key);
slouken@390
   294
        }
slouken@390
   295
        else if ( newMask &&
slouken@390
   296
                  currentMask != newMask ) {     /* modifier down event */
slouken@390
   297
        
slouken@390
   298
             key.sym = mapping[i];
slouken@390
   299
             SDL_PrivateKeyboard (SDL_PRESSED, &key);
slouken@390
   300
             /* If this was Caps Lock, we need some additional voodoo to make SDL happy */
slouken@390
   301
             if (bit == NSAlphaShiftKeyMask)
slouken@390
   302
                  SDL_PrivateKeyboard (SDL_RELEASED, &key);
slouken@390
   303
        }
slouken@390
   304
    }
slouken@390
   305
slouken@501
   306
    current_mods = newMods;
slouken@47
   307
}
slouken@47
   308
slouken@782
   309
static void QZ_GetMouseLocation (_THIS, NSPoint *p) {
slouken@782
   310
    *p = [ NSEvent mouseLocation ]; /* global coordinates */
slouken@782
   311
    if (qz_window)
slouken@782
   312
        QZ_PrivateGlobalToLocal (this, p);
slouken@782
   313
    QZ_PrivateCocoaToSDL (this, p);
slouken@782
   314
}
slouken@782
   315
slouken@117
   316
static void QZ_DoActivate (_THIS)
slouken@117
   317
{
slouken@615
   318
    /* Hide the cursor if it was hidden by SDL_ShowCursor() */
slouken@761
   319
    if (!cursor_should_be_visible)
slouken@761
   320
        QZ_HideMouse (this);
slouken@168
   321
icculus@563
   322
    /* Regrab input, only if it was previously grabbed */
icculus@563
   323
    if ( current_grab_mode == SDL_GRAB_ON ) {
icculus@563
   324
        
icculus@563
   325
        /* Restore cursor location if input was grabbed */
icculus@563
   326
        QZ_PrivateWarpCursor (this, cursor_loc.x, cursor_loc.y);
icculus@563
   327
        QZ_ChangeGrabState (this, QZ_ENABLE_GRAB);
slouken@390
   328
    }
slouken@47
   329
}
slouken@47
   330
slouken@47
   331
static void QZ_DoDeactivate (_THIS) {
slouken@47
   332
icculus@563
   333
    /* Get the current cursor location, for restore on activate */
slouken@782
   334
    QZ_GetMouseLocation (this, &cursor_loc);
icculus@563
   335
    
icculus@563
   336
    /* Reassociate mouse and cursor */
icculus@563
   337
    CGAssociateMouseAndMouseCursorPosition (1);
slouken@390
   338
slouken@615
   339
    /* Show the cursor if it was hidden by SDL_ShowCursor() */
slouken@761
   340
    if (!cursor_should_be_visible)
slouken@761
   341
        QZ_ShowMouse (this);
slouken@47
   342
}
slouken@47
   343
slouken@555
   344
void QZ_SleepNotificationHandler (void * refcon,
slouken@555
   345
                                  io_service_t service,
slouken@555
   346
                                  natural_t messageType,
slouken@555
   347
                                  void * messageArgument )
slouken@555
   348
{
slouken@555
   349
     SDL_VideoDevice *this = (SDL_VideoDevice*)refcon;
slouken@555
   350
     
slouken@555
   351
     switch(messageType)
slouken@555
   352
     {
slouken@555
   353
         case kIOMessageSystemWillSleep:
icculus@563
   354
             IOAllowPowerChange(power_connection, (long) messageArgument);
slouken@555
   355
             break;
slouken@555
   356
         case kIOMessageCanSystemSleep:
icculus@563
   357
             IOAllowPowerChange(power_connection, (long) messageArgument);
slouken@555
   358
             break;
slouken@555
   359
         case kIOMessageSystemHasPoweredOn:
slouken@761
   360
            /* awake */
slouken@555
   361
            SDL_PrivateExpose();
slouken@555
   362
            break;
slouken@555
   363
     }
slouken@555
   364
}
slouken@555
   365
slouken@761
   366
void QZ_RegisterForSleepNotifications (_THIS)
slouken@555
   367
{
slouken@555
   368
     CFRunLoopSourceRef rls;
slouken@555
   369
     IONotificationPortRef thePortRef;
slouken@555
   370
     io_object_t notifier;
slouken@555
   371
icculus@563
   372
     power_connection = IORegisterForSystemPower (this, &thePortRef, QZ_SleepNotificationHandler, &notifier);
slouken@555
   373
icculus@563
   374
     if (power_connection == 0)
slouken@555
   375
         NSLog(@"SDL: QZ_SleepNotificationHandler() IORegisterForSystemPower failed.");
slouken@555
   376
slouken@555
   377
     rls = IONotificationPortGetRunLoopSource (thePortRef);
slouken@555
   378
     CFRunLoopAddSource (CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
slouken@555
   379
     CFRelease (rls);
slouken@555
   380
}
slouken@555
   381
icculus@624
   382
icculus@624
   383
// Try to map Quartz mouse buttons to SDL's lingo...
icculus@624
   384
static int QZ_OtherMouseButtonToSDL(int button)
icculus@624
   385
{
icculus@624
   386
    switch (button)
icculus@624
   387
    {
icculus@624
   388
        case 0:
icculus@624
   389
            return(SDL_BUTTON_LEFT);   // 1
icculus@624
   390
        case 1:
icculus@624
   391
            return(SDL_BUTTON_RIGHT);  // 3
icculus@624
   392
        case 2:
icculus@624
   393
            return(SDL_BUTTON_MIDDLE); // 2
icculus@624
   394
    }
icculus@624
   395
icculus@624
   396
    // >= 3: skip 4 & 5, since those are the SDL mousewheel buttons.
icculus@624
   397
    return(button + 3);
icculus@624
   398
}
icculus@624
   399
icculus@624
   400
slouken@761
   401
void QZ_PumpEvents (_THIS)
slouken@158
   402
{
slouken@435
   403
    int firstMouseEvent;
slouken@390
   404
    CGMouseDelta dx, dy;
slouken@390
   405
slouken@390
   406
    NSDate *distantPast;
slouken@390
   407
    NSEvent *event;
slouken@390
   408
    NSRect winRect;
slouken@390
   409
    NSAutoreleasePool *pool;
slouken@390
   410
icculus@619
   411
    /* Update activity every five seconds to prevent screensaver. --ryan. */
icculus@619
   412
    static Uint32 screensaverTicks = 0;
icculus@619
   413
    Uint32 nowTicks = SDL_GetTicks();
icculus@619
   414
    if ((nowTicks - screensaverTicks) > 5000)
icculus@619
   415
    {
icculus@619
   416
        UpdateSystemActivity(UsrActivity);
icculus@619
   417
        screensaverTicks = nowTicks;
icculus@619
   418
    }
icculus@619
   419
slouken@390
   420
    pool = [ [ NSAutoreleasePool alloc ] init ];
slouken@390
   421
    distantPast = [ NSDate distantPast ];
slouken@390
   422
slouken@390
   423
    winRect = NSMakeRect (0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h);
slouken@435
   424
    
slouken@435
   425
    /* send the first mouse event in absolute coordinates */
slouken@435
   426
    firstMouseEvent = 1;
slouken@435
   427
    
slouken@435
   428
    /* accumulate any additional mouse moved events into one SDL mouse event */
slouken@390
   429
    dx = 0;
slouken@390
   430
    dy = 0;
slouken@390
   431
    
slouken@390
   432
    do {
slouken@390
   433
    
slouken@390
   434
        /* Poll for an event. This will not block */
slouken@390
   435
        event = [ NSApp nextEventMatchingMask:NSAnyEventMask
slouken@390
   436
                                    untilDate:distantPast
slouken@390
   437
                                    inMode: NSDefaultRunLoopMode dequeue:YES ];
slouken@390
   438
        if (event != nil) {
slouken@390
   439
icculus@624
   440
            int button;
slouken@390
   441
            unsigned int type;
icculus@563
   442
            BOOL isInGameWin;
icculus@563
   443
            
icculus@563
   444
            #define DO_MOUSE_DOWN(button) do {                                               \
slouken@761
   445
                            if ( [ NSApp isActive ] ) {                                      \
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@779
   466
            isInGameWin = QZ_IsMouseInWindow (this);
slouken@782
   467
slouken@816
   468
            QZ_DoModifiers(this, [ event modifierFlags ] );
slouken@816
   469
slouken@390
   470
            switch (type) {
slouken@390
   471
                case NSLeftMouseDown:
slouken@511
   472
                    if ( getenv("SDL_HAS3BUTTONMOUSE") ) {
icculus@563
   473
                        DO_MOUSE_DOWN (SDL_BUTTON_LEFT);
slouken@511
   474
                    } else {
slouken@511
   475
                        if ( NSCommandKeyMask & current_mods ) {
icculus@563
   476
                            last_virtual_button = SDL_BUTTON_RIGHT;
icculus@563
   477
                            DO_MOUSE_DOWN (SDL_BUTTON_RIGHT);
slouken@511
   478
                        }
slouken@511
   479
                        else if ( NSAlternateKeyMask & current_mods ) {
icculus@563
   480
                            last_virtual_button = SDL_BUTTON_MIDDLE;
icculus@563
   481
                            DO_MOUSE_DOWN (SDL_BUTTON_MIDDLE);
slouken@511
   482
                        }
slouken@511
   483
                        else {
icculus@563
   484
                            DO_MOUSE_DOWN (SDL_BUTTON_LEFT);
slouken@511
   485
                        }
slouken@390
   486
                    }
slouken@390
   487
                    break;
icculus@624
   488
slouken@390
   489
                case NSLeftMouseUp:
slouken@390
   490
                    if ( last_virtual_button != 0 ) {
icculus@563
   491
                        DO_MOUSE_UP (last_virtual_button);
slouken@390
   492
                        last_virtual_button = 0;
slouken@390
   493
                    }
slouken@390
   494
                    else {
icculus@563
   495
                        DO_MOUSE_UP (SDL_BUTTON_LEFT);
slouken@390
   496
                    }
slouken@390
   497
                    break;
icculus@624
   498
icculus@624
   499
                case NSOtherMouseDown:
icculus@624
   500
                case NSRightMouseDown:
icculus@624
   501
                    button = QZ_OtherMouseButtonToSDL([ event buttonNumber ]);
icculus@624
   502
                    DO_MOUSE_DOWN (button);
icculus@624
   503
                    break;
icculus@624
   504
icculus@624
   505
                case NSOtherMouseUp:
icculus@624
   506
                case NSRightMouseUp:
icculus@624
   507
                    button = QZ_OtherMouseButtonToSDL([ event buttonNumber ]);
icculus@624
   508
                    DO_MOUSE_UP (button);
icculus@624
   509
                    break;
icculus@624
   510
slouken@390
   511
                case NSSystemDefined:
slouken@501
   512
                    /*
slouken@501
   513
                        Future: up to 32 "mouse" buttons can be handled.
slouken@501
   514
                        if ([event subtype] == 7) {
slouken@501
   515
                            unsigned int buttons;
slouken@501
   516
                            buttons = [ event data2 ];
slouken@501
   517
                    */
slouken@390
   518
                    break;
slouken@390
   519
                case NSLeftMouseDragged:
slouken@390
   520
                case NSRightMouseDragged:
slouken@435
   521
                case NSOtherMouseDragged: /* usually middle mouse dragged */
slouken@390
   522
                case NSMouseMoved:
icculus@563
   523
                    if ( grab_state == QZ_INVISIBLE_GRAB ) {
slouken@272
   524
                
slouken@501
   525
                        /*
icculus@563
   526
                            If input is grabbed+hidden, the cursor doesn't move,
slouken@501
   527
                            so we have to call the lowlevel window server
slouken@501
   528
                            function. This is less accurate but works OK.                         
slouken@501
   529
                        */
slouken@390
   530
                        CGMouseDelta dx1, dy1;
slouken@390
   531
                        CGGetLastMouseDelta (&dx1, &dy1);
slouken@390
   532
                        dx += dx1;
slouken@390
   533
                        dy += dy1;
slouken@390
   534
                    }
slouken@435
   535
                    else if (firstMouseEvent) {
slouken@435
   536
                        
slouken@501
   537
                        /*
slouken@501
   538
                            Get the first mouse event in a possible
slouken@501
   539
                            sequence of mouse moved events. Since we
slouken@501
   540
                            use absolute coordinates, this serves to
slouken@501
   541
                            compensate any inaccuracy in deltas, and
slouken@501
   542
                            provides the first known mouse position,
slouken@501
   543
                            since everything after this uses deltas
slouken@501
   544
                        */
slouken@782
   545
                        NSPoint p;
slouken@782
   546
                        QZ_GetMouseLocation (this, &p);
slouken@454
   547
                        SDL_PrivateMouseMotion (0, 0, p.x, p.y);
slouken@435
   548
                        firstMouseEvent = 0;
slouken@782
   549
                   }
slouken@435
   550
                    else {
slouken@435
   551
                    
slouken@501
   552
                        /*
slouken@501
   553
                            Get the amount moved since the last drag or move event,
slouken@501
   554
                            add it on for one big move event at the end.
slouken@501
   555
                        */
slouken@501
   556
                        dx += [ event deltaX ];
slouken@501
   557
                        dy += [ event deltaY ];
slouken@435
   558
                    }
icculus@563
   559
                    
icculus@563
   560
                    /* 
icculus@563
   561
                        Handle grab input+cursor visible by warping the cursor back
icculus@563
   562
                        into the game window. This still generates a mouse moved event,
icculus@563
   563
                        but not as a result of the warp (so it's in the right direction).
icculus@563
   564
                    */
icculus@563
   565
                    if ( grab_state == QZ_VISIBLE_GRAB &&
icculus@563
   566
                         !isInGameWin ) {
icculus@563
   567
                       
slouken@782
   568
                        NSPoint p;
slouken@782
   569
                        QZ_GetMouseLocation (this, &p);
icculus@563
   570
icculus@563
   571
                        if ( p.x < 0.0 ) 
icculus@563
   572
                            p.x = 0.0;
icculus@563
   573
                        
icculus@563
   574
                        if ( p.y < 0.0 ) 
icculus@563
   575
                            p.y = 0.0;
icculus@563
   576
                        
icculus@563
   577
                        if ( p.x >= winRect.size.width ) 
icculus@563
   578
                            p.x = winRect.size.width-1;
icculus@563
   579
                        
icculus@563
   580
                        if ( p.y >= winRect.size.height ) 
icculus@563
   581
                            p.y = winRect.size.height-1;
icculus@563
   582
                        
icculus@563
   583
                        QZ_PrivateWarpCursor (this, p.x, p.y);
icculus@563
   584
                    }
slouken@631
   585
                    else
slouken@631
   586
                    if ( !isInGameWin && (SDL_GetAppState() & SDL_APPMOUSEFOCUS) ) {
slouken@631
   587
                    
slouken@631
   588
                        SDL_PrivateAppActive (0, SDL_APPMOUSEFOCUS);
slouken@779
   589
                        if (!cursor_should_be_visible)
slouken@779
   590
                            QZ_ShowMouse (this);
slouken@631
   591
                    }
slouken@631
   592
                    else
slouken@631
   593
                    if ( isInGameWin && !(SDL_GetAppState() & SDL_APPMOUSEFOCUS) ) {
slouken@631
   594
                    
slouken@631
   595
                        SDL_PrivateAppActive (1, SDL_APPMOUSEFOCUS);
slouken@779
   596
                        if (!cursor_should_be_visible)
slouken@779
   597
                            QZ_HideMouse (this);
slouken@631
   598
                    }
slouken@390
   599
                    break;
slouken@390
   600
                case NSScrollWheel:
icculus@563
   601
                    if ( isInGameWin ) {
slouken@390
   602
                        float dy;
slouken@502
   603
                        Uint8 button;
slouken@390
   604
                        dy = [ event deltaY ];
slouken@390
   605
                        if ( dy > 0.0 ) /* Scroll up */
slouken@502
   606
                            button = SDL_BUTTON_WHEELUP;
slouken@390
   607
                        else /* Scroll down */
slouken@502
   608
                            button = SDL_BUTTON_WHEELDOWN;
icculus@563
   609
                        /* For now, wheel is sent as a quick down+up */
slouken@502
   610
                        SDL_PrivateMouseButton (SDL_PRESSED, button, 0, 0);
slouken@502
   611
                        SDL_PrivateMouseButton (SDL_RELEASED, button, 0, 0);
slouken@390
   612
                    }
slouken@390
   613
                    break;
slouken@390
   614
                case NSKeyUp:
slouken@501
   615
                    QZ_DoKey (this, SDL_RELEASED, event);
slouken@390
   616
                    break;
slouken@390
   617
                case NSKeyDown:
slouken@501
   618
                    QZ_DoKey (this, SDL_PRESSED, event);
slouken@390
   619
                    break;
slouken@390
   620
                case NSFlagsChanged:
slouken@390
   621
                    break;
slouken@390
   622
                case NSAppKitDefined:
slouken@390
   623
                    switch ( [ event subtype ] ) {
slouken@390
   624
                        case NSApplicationActivatedEventType:
slouken@390
   625
                            QZ_DoActivate (this);
slouken@390
   626
                            break;
slouken@390
   627
                        case NSApplicationDeactivatedEventType:
slouken@390
   628
                            QZ_DoDeactivate (this);
slouken@390
   629
                            break;
slouken@390
   630
                    }
slouken@390
   631
                    [ NSApp sendEvent:event ];
slouken@390
   632
                    break;
slouken@390
   633
                    /* case NSApplicationDefined: break; */
slouken@390
   634
                    /* case NSPeriodic: break; */
slouken@390
   635
                    /* case NSCursorUpdate: break; */
slouken@390
   636
                default:
slouken@390
   637
                    [ NSApp sendEvent:event ];
slouken@272
   638
            }
slouken@272
   639
        }
slouken@390
   640
    } while (event != nil);
slouken@390
   641
    
slouken@435
   642
    /* handle accumulated mouse moved events */
slouken@390
   643
    if (dx != 0 || dy != 0)
slouken@435
   644
        SDL_PrivateMouseMotion (0, 1, dx, dy);
slouken@390
   645
    
slouken@390
   646
    [ pool release ];
slouken@502
   647
}