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