Home | History | Annotate | Download | only in quartz
      1 /*
      2     SDL - Simple DirectMedia Layer
      3     Copyright (C) 1997-2012  Sam Lantinga
      4 
      5     This library is free software; you can redistribute it and/or
      6     modify it under the terms of the GNU Library General Public
      7     License as published by the Free Software Foundation; either
      8     version 2 of the License, or (at your option) any later version.
      9 
     10     This library is distributed in the hope that it will be useful,
     11     but WITHOUT ANY WARRANTY; without even the implied warranty of
     12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13     Library General Public License for more details.
     14 
     15     You should have received a copy of the GNU Library General Public
     16     License along with this library; if not, write to the Free
     17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     18 
     19     Sam Lantinga
     20     slouken (at) libsdl.org
     21 */
     22 #include "SDL_config.h"
     23 
     24 #include "SDL_QuartzVideo.h"
     25 #include "SDL_QuartzWM.h"
     26 
     27 #include <IOKit/IOMessage.h> /* For wake from sleep detection */
     28 #include <IOKit/pwr_mgt/IOPMLib.h> /* For wake from sleep detection */
     29 #include "SDL_QuartzKeys.h"
     30 
     31 /*
     32  * On Leopard, this is missing from the 64-bit headers
     33  */
     34 #if defined(__LP64__) && !defined(__POWER__)
     35 /*
     36  * Workaround for a bug in the 10.5 SDK: By accident, OSService.h does
     37  * not include Power.h at all when compiling in 64bit mode. This has
     38  * been fixed in 10.6, but for 10.5, we manually define UsrActivity
     39  * to ensure compilation works.
     40  */
     41 #define UsrActivity 1
     42 #endif
     43 
     44 /*
     45  * In Panther, this header defines device dependent masks for
     46  * right side keys. These definitions only exist in Panther, but
     47  * the header seems to exist at least in Jaguar and probably earlier
     48  * versions of the OS, so this should't break anything.
     49  */
     50 #include <IOKit/hidsystem/IOLLEvent.h>
     51 /*
     52  * These are not defined before Panther. To keep the code compiling
     53  * on systems without these, I will define if they don't exist.
     54  */
     55 #ifndef NX_DEVICERCTLKEYMASK
     56     #define NX_DEVICELCTLKEYMASK    0x00000001
     57 #endif
     58 #ifndef NX_DEVICELSHIFTKEYMASK
     59     #define NX_DEVICELSHIFTKEYMASK  0x00000002
     60 #endif
     61 #ifndef NX_DEVICERSHIFTKEYMASK
     62     #define NX_DEVICERSHIFTKEYMASK  0x00000004
     63 #endif
     64 #ifndef NX_DEVICELCMDKEYMASK
     65     #define NX_DEVICELCMDKEYMASK    0x00000008
     66 #endif
     67 #ifndef NX_DEVICERCMDKEYMASK
     68     #define NX_DEVICERCMDKEYMASK    0x00000010
     69 #endif
     70 #ifndef NX_DEVICELALTKEYMASK
     71     #define NX_DEVICELALTKEYMASK    0x00000020
     72 #endif
     73 #ifndef NX_DEVICERALTKEYMASK
     74     #define NX_DEVICERALTKEYMASK    0x00000040
     75 #endif
     76 #ifndef NX_DEVICERCTLKEYMASK
     77     #define NX_DEVICERCTLKEYMASK    0x00002000
     78 #endif
     79 
     80 void     QZ_InitOSKeymap (_THIS) {
     81     BOOL saw_layout = NO;
     82     UInt32 state;
     83     UInt32 value;
     84     Uint16 i;
     85     int world = SDLK_WORLD_0;
     86 
     87     for ( i=0; i<SDL_TABLESIZE(keymap); ++i )
     88         keymap[i] = SDLK_UNKNOWN;
     89 
     90     /* This keymap is almost exactly the same as the OS 9 one */
     91     keymap[QZ_ESCAPE] = SDLK_ESCAPE;
     92     keymap[QZ_F1] = SDLK_F1;
     93     keymap[QZ_F2] = SDLK_F2;
     94     keymap[QZ_F3] = SDLK_F3;
     95     keymap[QZ_F4] = SDLK_F4;
     96     keymap[QZ_F5] = SDLK_F5;
     97     keymap[QZ_F6] = SDLK_F6;
     98     keymap[QZ_F7] = SDLK_F7;
     99     keymap[QZ_F8] = SDLK_F8;
    100     keymap[QZ_F9] = SDLK_F9;
    101     keymap[QZ_F10] = SDLK_F10;
    102     keymap[QZ_F11] = SDLK_F11;
    103     keymap[QZ_F12] = SDLK_F12;
    104     keymap[QZ_F13] = SDLK_F13;
    105     keymap[QZ_F14] = SDLK_F14;
    106     keymap[QZ_F15] = SDLK_F15;
    107 /*
    108     keymap[QZ_PRINT] = SDLK_PRINT;
    109     keymap[QZ_SCROLLOCK] = SDLK_SCROLLOCK;
    110     keymap[QZ_PAUSE] = SDLK_PAUSE;
    111 */
    112     keymap[QZ_POWER] = SDLK_POWER;
    113     keymap[QZ_BACKQUOTE] = SDLK_BACKQUOTE;
    114     keymap[QZ_1] = SDLK_1;
    115     keymap[QZ_2] = SDLK_2;
    116     keymap[QZ_3] = SDLK_3;
    117     keymap[QZ_4] = SDLK_4;
    118     keymap[QZ_5] = SDLK_5;
    119     keymap[QZ_6] = SDLK_6;
    120     keymap[QZ_7] = SDLK_7;
    121     keymap[QZ_8] = SDLK_8;
    122     keymap[QZ_9] = SDLK_9;
    123     keymap[QZ_0] = SDLK_0;
    124     keymap[QZ_MINUS] = SDLK_MINUS;
    125     keymap[QZ_EQUALS] = SDLK_EQUALS;
    126     keymap[QZ_BACKSPACE] = SDLK_BACKSPACE;
    127     keymap[QZ_INSERT] = SDLK_INSERT;
    128     keymap[QZ_HOME] = SDLK_HOME;
    129     keymap[QZ_PAGEUP] = SDLK_PAGEUP;
    130     keymap[QZ_NUMLOCK] = SDLK_NUMLOCK;
    131     keymap[QZ_KP_EQUALS] = SDLK_KP_EQUALS;
    132     keymap[QZ_KP_DIVIDE] = SDLK_KP_DIVIDE;
    133     keymap[QZ_KP_MULTIPLY] = SDLK_KP_MULTIPLY;
    134     keymap[QZ_TAB] = SDLK_TAB;
    135     keymap[QZ_q] = SDLK_q;
    136     keymap[QZ_w] = SDLK_w;
    137     keymap[QZ_e] = SDLK_e;
    138     keymap[QZ_r] = SDLK_r;
    139     keymap[QZ_t] = SDLK_t;
    140     keymap[QZ_y] = SDLK_y;
    141     keymap[QZ_u] = SDLK_u;
    142     keymap[QZ_i] = SDLK_i;
    143     keymap[QZ_o] = SDLK_o;
    144     keymap[QZ_p] = SDLK_p;
    145     keymap[QZ_LEFTBRACKET] = SDLK_LEFTBRACKET;
    146     keymap[QZ_RIGHTBRACKET] = SDLK_RIGHTBRACKET;
    147     keymap[QZ_BACKSLASH] = SDLK_BACKSLASH;
    148     keymap[QZ_DELETE] = SDLK_DELETE;
    149     keymap[QZ_END] = SDLK_END;
    150     keymap[QZ_PAGEDOWN] = SDLK_PAGEDOWN;
    151     keymap[QZ_KP7] = SDLK_KP7;
    152     keymap[QZ_KP8] = SDLK_KP8;
    153     keymap[QZ_KP9] = SDLK_KP9;
    154     keymap[QZ_KP_MINUS] = SDLK_KP_MINUS;
    155     keymap[QZ_CAPSLOCK] = SDLK_CAPSLOCK;
    156     keymap[QZ_a] = SDLK_a;
    157     keymap[QZ_s] = SDLK_s;
    158     keymap[QZ_d] = SDLK_d;
    159     keymap[QZ_f] = SDLK_f;
    160     keymap[QZ_g] = SDLK_g;
    161     keymap[QZ_h] = SDLK_h;
    162     keymap[QZ_j] = SDLK_j;
    163     keymap[QZ_k] = SDLK_k;
    164     keymap[QZ_l] = SDLK_l;
    165     keymap[QZ_SEMICOLON] = SDLK_SEMICOLON;
    166     keymap[QZ_QUOTE] = SDLK_QUOTE;
    167     keymap[QZ_RETURN] = SDLK_RETURN;
    168     keymap[QZ_KP4] = SDLK_KP4;
    169     keymap[QZ_KP5] = SDLK_KP5;
    170     keymap[QZ_KP6] = SDLK_KP6;
    171     keymap[QZ_KP_PLUS] = SDLK_KP_PLUS;
    172     keymap[QZ_LSHIFT] = SDLK_LSHIFT;
    173     keymap[QZ_RSHIFT] = SDLK_RSHIFT;
    174     keymap[QZ_z] = SDLK_z;
    175     keymap[QZ_x] = SDLK_x;
    176     keymap[QZ_c] = SDLK_c;
    177     keymap[QZ_v] = SDLK_v;
    178     keymap[QZ_b] = SDLK_b;
    179     keymap[QZ_n] = SDLK_n;
    180     keymap[QZ_m] = SDLK_m;
    181     keymap[QZ_COMMA] = SDLK_COMMA;
    182     keymap[QZ_PERIOD] = SDLK_PERIOD;
    183     keymap[QZ_SLASH] = SDLK_SLASH;
    184     keymap[QZ_UP] = SDLK_UP;
    185     keymap[QZ_KP1] = SDLK_KP1;
    186     keymap[QZ_KP2] = SDLK_KP2;
    187     keymap[QZ_KP3] = SDLK_KP3;
    188     keymap[QZ_KP_ENTER] = SDLK_KP_ENTER;
    189     keymap[QZ_LCTRL] = SDLK_LCTRL;
    190     keymap[QZ_LALT] = SDLK_LALT;
    191     keymap[QZ_LMETA] = SDLK_LMETA;
    192     keymap[QZ_RCTRL] = SDLK_RCTRL;
    193     keymap[QZ_RALT] = SDLK_RALT;
    194     keymap[QZ_RMETA] = SDLK_RMETA;
    195     keymap[QZ_SPACE] = SDLK_SPACE;
    196     keymap[QZ_LEFT] = SDLK_LEFT;
    197     keymap[QZ_DOWN] = SDLK_DOWN;
    198     keymap[QZ_RIGHT] = SDLK_RIGHT;
    199     keymap[QZ_KP0] = SDLK_KP0;
    200     keymap[QZ_KP_PERIOD] = SDLK_KP_PERIOD;
    201     keymap[QZ_IBOOK_ENTER] = SDLK_KP_ENTER;
    202     keymap[QZ_IBOOK_RIGHT] = SDLK_RIGHT;
    203     keymap[QZ_IBOOK_DOWN] = SDLK_DOWN;
    204     keymap[QZ_IBOOK_UP]      = SDLK_UP;
    205     keymap[QZ_IBOOK_LEFT] = SDLK_LEFT;
    206 
    207     /*
    208         Up there we setup a static scancode->keysym map. However, it will not
    209         work very well on international keyboard. Hence we now query MacOS
    210         for its own keymap to adjust our own mapping table. However, this is
    211         basically only useful for ascii char keys. This is also the reason
    212         why we keep the static table, too.
    213      */
    214 
    215 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= 1050)
    216     if (TISCopyCurrentKeyboardLayoutInputSource != NULL) {
    217         TISInputSourceRef src = TISCopyCurrentKeyboardLayoutInputSource();
    218         if (src != NULL) {
    219             CFDataRef data = (CFDataRef)
    220                 TISGetInputSourceProperty(src,
    221                     kTISPropertyUnicodeKeyLayoutData);
    222             if (data != NULL) {
    223                 const UCKeyboardLayout *layout = (const UCKeyboardLayout *)
    224                     CFDataGetBytePtr(data);
    225                 if (layout != NULL) {
    226                     const UInt32 kbdtype = LMGetKbdType();
    227                     saw_layout = YES;
    228 
    229                     /* Loop over all 127 possible scan codes */
    230                     for (i = 0; i < 0x7F; i++) {
    231                         UniChar buf[16];
    232                         UniCharCount count = 0;
    233 
    234                         /* We pretend a clean start to begin with (i.e. no dead keys active */
    235                         state = 0;
    236 
    237                         if (UCKeyTranslate(layout, i, kUCKeyActionDown, 0, kbdtype,
    238                                            0, &state, 16, &count, buf) != noErr) {
    239                             continue;
    240                         }
    241 
    242                         /* If the state become 0, it was a dead key. We need to
    243                            translate again, passing in the new state, to get
    244                            the actual key value */
    245                         if (state != 0) {
    246                             if (UCKeyTranslate(layout, i, kUCKeyActionDown, 0, kbdtype,
    247                                                0, &state, 16, &count, buf) != noErr) {
    248                                 continue;
    249                             }
    250                         }
    251 
    252                         if (count != 1) {
    253                             continue;  /* no multi-char. Use SDL 1.3 instead. :) */
    254                         }
    255 
    256                         value = (UInt32) buf[0];
    257                         if (value >= 128) {
    258                             /* Some non-ASCII char, map it to SDLK_WORLD_* */
    259                             if (world < 0xFF) {
    260                                 keymap[i] = world++;
    261                             }
    262                         } else if (value >= 32) {     /* non-control ASCII char */
    263                             keymap[i] = value;
    264                         }
    265                     }
    266                 }
    267             }
    268             CFRelease(src);
    269         }
    270     }
    271 #endif
    272 
    273 #if (MAC_OS_X_VERSION_MIN_REQUIRED < 1050)
    274     if (!saw_layout) {
    275         /* Get a pointer to the systems cached KCHR */
    276         const void *KCHRPtr = (const void *)GetScriptManagerVariable(smKCHRCache);
    277         if (KCHRPtr)
    278         {
    279             /* Loop over all 127 possible scan codes */
    280             for (i = 0; i < 0x7F; i++)
    281             {
    282                 /* We pretend a clean start to begin with (i.e. no dead keys active */
    283                 state = 0;
    284 
    285                 /* Now translate the key code to a key value */
    286                 value = KeyTranslate(KCHRPtr, i, &state) & 0xff;
    287 
    288                 /* If the state become 0, it was a dead key. We need to translate again,
    289                     passing in the new state, to get the actual key value */
    290                 if (state != 0)
    291                     value = KeyTranslate(KCHRPtr, i, &state) & 0xff;
    292 
    293                 /* Now we should have an ascii value, or 0. Try to figure out to which SDL symbol it maps */
    294                 if (value >= 128) {     /* Some non-ASCII char, map it to SDLK_WORLD_* */
    295                     if (world < 0xFF) {
    296                         keymap[i] = world++;
    297                     }
    298                 } else if (value >= 32) {     /* non-control ASCII char */
    299                     keymap[i] = value;
    300                 }
    301             }
    302         }
    303     }
    304 #endif
    305 
    306     /*
    307         The keypad codes are re-setup here, because the loop above cannot
    308         distinguish between a key on the keypad and a regular key. We maybe
    309         could get around this problem in another fashion: NSEvent's flags
    310         include a "NSNumericPadKeyMask" bit; we could check that and modify
    311         the symbol we return on the fly. However, this flag seems to exhibit
    312         some weird behaviour related to the num lock key
    313     */
    314     keymap[QZ_KP0] = SDLK_KP0;
    315     keymap[QZ_KP1] = SDLK_KP1;
    316     keymap[QZ_KP2] = SDLK_KP2;
    317     keymap[QZ_KP3] = SDLK_KP3;
    318     keymap[QZ_KP4] = SDLK_KP4;
    319     keymap[QZ_KP5] = SDLK_KP5;
    320     keymap[QZ_KP6] = SDLK_KP6;
    321     keymap[QZ_KP7] = SDLK_KP7;
    322     keymap[QZ_KP8] = SDLK_KP8;
    323     keymap[QZ_KP9] = SDLK_KP9;
    324     keymap[QZ_KP_MINUS] = SDLK_KP_MINUS;
    325     keymap[QZ_KP_PLUS] = SDLK_KP_PLUS;
    326     keymap[QZ_KP_PERIOD] = SDLK_KP_PERIOD;
    327     keymap[QZ_KP_EQUALS] = SDLK_KP_EQUALS;
    328     keymap[QZ_KP_DIVIDE] = SDLK_KP_DIVIDE;
    329     keymap[QZ_KP_MULTIPLY] = SDLK_KP_MULTIPLY;
    330     keymap[QZ_KP_ENTER] = SDLK_KP_ENTER;
    331 }
    332 
    333 static void QZ_DoKey (_THIS, int state, NSEvent *event) {
    334 
    335     NSString *chars = NULL;
    336     unsigned int i, numChars;
    337     SDL_keysym key;
    338 
    339     /*
    340         A key event can contain multiple characters,
    341         or no characters at all. In most cases, it
    342         will contain a single character. If it contains
    343         0 characters, we'll use 0 as the unicode. If it
    344         contains multiple characters, we'll use 0 as
    345         the scancode/keysym.
    346     */
    347     if (SDL_TranslateUNICODE && state == SDL_PRESSED) {
    348         [field_edit interpretKeyEvents:[NSArray arrayWithObject:event]];
    349         chars = [ event characters ];
    350         numChars = [ chars length ];
    351         if (numChars > 0)
    352             [field_edit setString:@""];
    353     } else {
    354         numChars = 0;
    355     }
    356 
    357     if (numChars == 0) {
    358 
    359         key.scancode = [ event keyCode ];
    360         key.sym      = keymap [ key.scancode ];
    361         key.unicode  = 0;
    362         key.mod      = KMOD_NONE;
    363 
    364         SDL_PrivateKeyboard (state, &key);
    365     }
    366     else if (numChars >= 1) {
    367 
    368         key.scancode = [ event keyCode ];
    369         key.sym      = keymap [ key.scancode ];
    370         key.unicode  = [ chars characterAtIndex:0 ];
    371         key.mod      = KMOD_NONE;
    372 
    373         SDL_PrivateKeyboard (state, &key);
    374 
    375         for (i = 1; i < numChars; i++) {
    376 
    377             key.scancode = 0;
    378             key.sym      = 0;
    379             key.unicode  = [ chars characterAtIndex:i];
    380             key.mod      = KMOD_NONE;
    381 
    382             SDL_PrivateKeyboard (state, &key);
    383         }
    384     }
    385 
    386     if (SDL_getenv ("SDL_ENABLEAPPEVENTS"))
    387         [ NSApp sendEvent:event ];
    388 }
    389 
    390 /* This is the original behavior, before support was added for
    391  * differentiating between left and right versions of the keys.
    392  */
    393 static void QZ_DoUnsidedModifiers (_THIS, unsigned int newMods) {
    394 
    395     const int mapping[] = { SDLK_CAPSLOCK, SDLK_LSHIFT, SDLK_LCTRL, SDLK_LALT, SDLK_LMETA };
    396 
    397     int i;
    398     int bit;
    399     SDL_keysym key;
    400 
    401     key.scancode    = 0;
    402     key.sym         = SDLK_UNKNOWN;
    403     key.unicode     = 0;
    404     key.mod         = KMOD_NONE;
    405 
    406     /* Iterate through the bits, testing each against the current modifiers */
    407     for (i = 0, bit = NSAlphaShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) {
    408 
    409         unsigned int currentMask, newMask;
    410 
    411         currentMask = current_mods & bit;
    412         newMask     = newMods & bit;
    413 
    414         if ( currentMask &&
    415              currentMask != newMask ) {     /* modifier up event */
    416 
    417              key.sym = mapping[i];
    418              /* If this was Caps Lock, we need some additional voodoo to make SDL happy */
    419              if (bit == NSAlphaShiftKeyMask)
    420                   SDL_PrivateKeyboard (SDL_PRESSED, &key);
    421              SDL_PrivateKeyboard (SDL_RELEASED, &key);
    422         }
    423         else if ( newMask &&
    424                   currentMask != newMask ) {     /* modifier down event */
    425 
    426              key.sym = mapping[i];
    427              SDL_PrivateKeyboard (SDL_PRESSED, &key);
    428              /* If this was Caps Lock, we need some additional voodoo to make SDL happy */
    429              if (bit == NSAlphaShiftKeyMask)
    430                   SDL_PrivateKeyboard (SDL_RELEASED, &key);
    431         }
    432     }
    433 }
    434 
    435 /* This is a helper function for QZ_HandleModifierSide. This
    436  * function reverts back to behavior before the distinction between
    437  * sides was made.
    438  */
    439 static void QZ_HandleNonDeviceModifier ( _THIS, unsigned int device_independent_mask, unsigned int newMods, unsigned int key_sym) {
    440     unsigned int currentMask, newMask;
    441     SDL_keysym key;
    442 
    443     key.scancode    = 0;
    444     key.sym         = key_sym;
    445     key.unicode     = 0;
    446     key.mod         = KMOD_NONE;
    447 
    448     /* Isolate just the bits we care about in the depedent bits so we can
    449      * figure out what changed
    450      */
    451     currentMask = current_mods & device_independent_mask;
    452     newMask     = newMods & device_independent_mask;
    453 
    454     if ( currentMask &&
    455          currentMask != newMask ) {     /* modifier up event */
    456          SDL_PrivateKeyboard (SDL_RELEASED, &key);
    457     }
    458     else if ( newMask &&
    459           currentMask != newMask ) {     /* modifier down event */
    460           SDL_PrivateKeyboard (SDL_PRESSED, &key);
    461     }
    462 }
    463 
    464 /* This is a helper function for QZ_HandleModifierSide.
    465  * This function sets the actual SDL_PrivateKeyboard event.
    466  */
    467 static void QZ_HandleModifierOneSide ( _THIS, unsigned int newMods,
    468                                        unsigned int key_sym,
    469                                        unsigned int sided_device_dependent_mask ) {
    470 
    471     SDL_keysym key;
    472     unsigned int current_dep_mask, new_dep_mask;
    473 
    474     key.scancode    = 0;
    475     key.sym         = key_sym;
    476     key.unicode     = 0;
    477     key.mod         = KMOD_NONE;
    478 
    479     /* Isolate just the bits we care about in the depedent bits so we can
    480      * figure out what changed
    481      */
    482     current_dep_mask = current_mods & sided_device_dependent_mask;
    483     new_dep_mask     = newMods & sided_device_dependent_mask;
    484 
    485     /* We now know that this side bit flipped. But we don't know if
    486      * it went pressed to released or released to pressed, so we must
    487      * find out which it is.
    488      */
    489     if( new_dep_mask &&
    490         current_dep_mask != new_dep_mask ) {
    491         /* Modifier down event */
    492         SDL_PrivateKeyboard (SDL_PRESSED, &key);
    493     }
    494     else /* Modifier up event */ {
    495         SDL_PrivateKeyboard (SDL_RELEASED, &key);
    496     }
    497 }
    498 
    499 /* This is a helper function for QZ_DoSidedModifiers.
    500  * This function will figure out if the modifier key is the left or right side,
    501  * e.g. left-shift vs right-shift.
    502  */
    503 static void QZ_HandleModifierSide ( _THIS, int device_independent_mask,
    504                                     unsigned int newMods,
    505                                     unsigned int left_key_sym,
    506                                     unsigned int right_key_sym,
    507                                     unsigned int left_device_dependent_mask,
    508                                     unsigned int right_device_dependent_mask ) {
    509     unsigned int device_dependent_mask = 0;
    510     unsigned int diff_mod = 0;
    511 
    512     device_dependent_mask = left_device_dependent_mask | right_device_dependent_mask;
    513     /* On the basis that the device independent mask is set, but there are
    514      * no device dependent flags set, we'll assume that we can't detect this
    515      * keyboard and revert to the unsided behavior.
    516      */
    517     if ( (device_dependent_mask & newMods) == 0 ) {
    518         /* Revert to the old behavior */
    519         QZ_HandleNonDeviceModifier ( this, device_independent_mask, newMods, left_key_sym );
    520         return;
    521     }
    522 
    523     /* XOR the previous state against the new state to see if there's a change */
    524     diff_mod = (device_dependent_mask & current_mods)
    525         ^ (device_dependent_mask & newMods);
    526 
    527     if ( diff_mod ) {
    528         /* A change in state was found. Isolate the left and right bits
    529          * to handle them separately just in case the values can simulataneously
    530          * change or if the bits don't both exist.
    531          */
    532         if ( left_device_dependent_mask & diff_mod ) {
    533             QZ_HandleModifierOneSide ( this, newMods, left_key_sym, left_device_dependent_mask );
    534         }
    535         if ( right_device_dependent_mask & diff_mod ) {
    536             QZ_HandleModifierOneSide ( this, newMods, right_key_sym, right_device_dependent_mask );
    537         }
    538     }
    539 }
    540 
    541 /* This is a helper function for QZ_DoSidedModifiers.
    542  * This function will release a key press in the case that
    543  * it is clear that the modifier has been released (i.e. one side
    544  * can't still be down).
    545  */
    546 static void QZ_ReleaseModifierSide ( _THIS,
    547                                      unsigned int device_independent_mask,
    548                                      unsigned int newMods,
    549                                      unsigned int left_key_sym,
    550                                      unsigned int right_key_sym,
    551                                      unsigned int left_device_dependent_mask,
    552                                      unsigned int right_device_dependent_mask ) {
    553     unsigned int device_dependent_mask = 0;
    554     SDL_keysym key;
    555 
    556     key.scancode    = 0;
    557     key.sym         = SDLK_UNKNOWN;
    558     key.unicode     = 0;
    559     key.mod         = KMOD_NONE;
    560 
    561     device_dependent_mask = left_device_dependent_mask | right_device_dependent_mask;
    562     /* On the basis that the device independent mask is set, but there are
    563      * no device dependent flags set, we'll assume that we can't detect this
    564      * keyboard and revert to the unsided behavior.
    565      */
    566     if ( (device_dependent_mask & current_mods) == 0 ) {
    567         /* In this case, we can't detect the keyboard, so use the left side
    568          * to represent both, and release it.
    569          */
    570         key.sym = left_key_sym;
    571         SDL_PrivateKeyboard (SDL_RELEASED, &key);
    572 
    573         return;
    574     }
    575 
    576 
    577     /*
    578      * This could have been done in an if-else case because at this point,
    579      * we know that all keys have been released when calling this function.
    580      * But I'm being paranoid so I want to handle each separately,
    581      * so I hope this doesn't cause other problems.
    582      */
    583     if ( left_device_dependent_mask & current_mods ) {
    584         key.sym = left_key_sym;
    585         SDL_PrivateKeyboard (SDL_RELEASED, &key);
    586     }
    587     if ( right_device_dependent_mask & current_mods ) {
    588         key.sym = right_key_sym;
    589         SDL_PrivateKeyboard (SDL_RELEASED, &key);
    590     }
    591 }
    592 
    593 /* This is a helper function for QZ_DoSidedModifiers.
    594  * This function handles the CapsLock case.
    595  */
    596 static void QZ_HandleCapsLock (_THIS, unsigned int newMods) {
    597     unsigned int currentMask, newMask;
    598     SDL_keysym key;
    599 
    600     key.scancode    = 0;
    601     key.sym         = SDLK_CAPSLOCK;
    602     key.unicode     = 0;
    603     key.mod         = KMOD_NONE;
    604 
    605     currentMask = current_mods & NSAlphaShiftKeyMask;
    606     newMask     = newMods & NSAlphaShiftKeyMask;
    607 
    608     if ( currentMask &&
    609          currentMask != newMask ) {     /* modifier up event */
    610          /* If this was Caps Lock, we need some additional voodoo to make SDL happy */
    611          SDL_PrivateKeyboard (SDL_PRESSED, &key);
    612          SDL_PrivateKeyboard (SDL_RELEASED, &key);
    613     }
    614     else if ( newMask &&
    615               currentMask != newMask ) {     /* modifier down event */
    616         /* If this was Caps Lock, we need some additional voodoo to make SDL happy */
    617         SDL_PrivateKeyboard (SDL_PRESSED, &key);
    618         SDL_PrivateKeyboard (SDL_RELEASED, &key);
    619     }
    620 }
    621 
    622 /* This function will handle the modifier keys and also determine the
    623  * correct side of the key.
    624  */
    625 static void QZ_DoSidedModifiers (_THIS, unsigned int newMods) {
    626 	/* Set up arrays for the key syms for the left and right side. */
    627     const unsigned int left_mapping[]  = { SDLK_LSHIFT, SDLK_LCTRL, SDLK_LALT, SDLK_LMETA };
    628     const unsigned int right_mapping[] = { SDLK_RSHIFT, SDLK_RCTRL, SDLK_RALT, SDLK_RMETA };
    629 	/* Set up arrays for the device dependent masks with indices that
    630      * correspond to the _mapping arrays
    631      */
    632     const unsigned int left_device_mapping[]  = { NX_DEVICELSHIFTKEYMASK, NX_DEVICELCTLKEYMASK, NX_DEVICELALTKEYMASK, NX_DEVICELCMDKEYMASK };
    633     const unsigned int right_device_mapping[] = { NX_DEVICERSHIFTKEYMASK, NX_DEVICERCTLKEYMASK, NX_DEVICERALTKEYMASK, NX_DEVICERCMDKEYMASK };
    634 
    635     unsigned int i;
    636     unsigned int bit;
    637 
    638     /* Handle CAPSLOCK separately because it doesn't have a left/right side */
    639     QZ_HandleCapsLock ( this, newMods );
    640 
    641     /* Iterate through the bits, testing each against the current modifiers */
    642     for (i = 0, bit = NSShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) {
    643 
    644         unsigned int currentMask, newMask;
    645 
    646         currentMask = current_mods & bit;
    647         newMask     = newMods & bit;
    648 
    649         /* If the bit is set, we must always examine it because the left
    650          * and right side keys may alternate or both may be pressed.
    651          */
    652         if ( newMask ) {
    653             QZ_HandleModifierSide ( this, bit, newMods,
    654                                        left_mapping[i],
    655                                        right_mapping[i],
    656                                        left_device_mapping[i],
    657                                        right_device_mapping[i] );
    658         }
    659         /* If the state changed from pressed to unpressed, we must examine
    660             * the device dependent bits to release the correct keys.
    661             */
    662         else if ( currentMask &&
    663                   currentMask != newMask ) { /* modifier up event */
    664                   QZ_ReleaseModifierSide ( this, bit, newMods,
    665                                            left_mapping[i],
    666                                            right_mapping[i],
    667                                            left_device_mapping[i],
    668                                            right_device_mapping[i] );
    669         }
    670     }
    671 }
    672 
    673 /* This function is called to handle the modifiers.
    674  * It will try to distinguish between the left side and right side
    675  * of the keyboard for those modifiers that qualify if the
    676  * operating system version supports it. Otherwise, the code
    677  * will not try to make the distinction.
    678  */
    679 static void QZ_DoModifiers (_THIS, unsigned int newMods) {
    680 
    681     if (current_mods == newMods)
    682     	return;
    683 
    684     /*
    685      * Starting with Panther (10.3.0), the ability to distinguish between
    686      * left side and right side modifiers is available.
    687      */
    688     if( system_version >= 0x1030 ) {
    689         QZ_DoSidedModifiers (this, newMods);
    690     }
    691     else {
    692         QZ_DoUnsidedModifiers (this, newMods);
    693     }
    694 
    695     current_mods = newMods;
    696 }
    697 
    698 static void QZ_GetMouseLocation (_THIS, NSPoint *p) {
    699     *p = [ NSEvent mouseLocation ]; /* global coordinates */
    700     if (qz_window)
    701         QZ_PrivateGlobalToLocal (this, p);
    702     QZ_PrivateCocoaToSDL (this, p);
    703 }
    704 
    705 void QZ_DoActivate (_THIS) {
    706 
    707     SDL_PrivateAppActive (1, SDL_APPINPUTFOCUS | (QZ_IsMouseInWindow (this) ? SDL_APPMOUSEFOCUS : 0));
    708 
    709     QZ_UpdateCursor(this);
    710 
    711     /* Regrab input, only if it was previously grabbed */
    712     if ( current_grab_mode == SDL_GRAB_ON ) {
    713 
    714         /* Restore cursor location if input was grabbed */
    715         QZ_PrivateWarpCursor (this, cursor_loc.x, cursor_loc.y);
    716         QZ_ChangeGrabState (this, QZ_ENABLE_GRAB);
    717     }
    718     else {
    719         /* Update SDL's mouse location */
    720         NSPoint p;
    721         QZ_GetMouseLocation (this, &p);
    722         SDL_PrivateMouseMotion (0, 0, p.x, p.y);
    723     }
    724 
    725     QZ_UpdateCursor(this);
    726 }
    727 
    728 void QZ_DoDeactivate (_THIS) {
    729 
    730     SDL_PrivateAppActive (0, SDL_APPINPUTFOCUS | SDL_APPMOUSEFOCUS);
    731 
    732     /* Get the current cursor location, for restore on activate */
    733     QZ_GetMouseLocation (this, &cursor_loc);
    734 
    735     /* Reassociate mouse and cursor */
    736     CGAssociateMouseAndMouseCursorPosition (1);
    737 
    738     QZ_UpdateCursor(this);
    739 }
    740 
    741 void QZ_SleepNotificationHandler (void * refcon,
    742                                   io_service_t service,
    743                                   natural_t messageType,
    744                                   void * messageArgument )
    745 {
    746      SDL_VideoDevice *this = (SDL_VideoDevice*)refcon;
    747 
    748      switch(messageType)
    749      {
    750          case kIOMessageSystemWillSleep:
    751              IOAllowPowerChange(power_connection, (long) messageArgument);
    752              break;
    753          case kIOMessageCanSystemSleep:
    754              IOAllowPowerChange(power_connection, (long) messageArgument);
    755              break;
    756          case kIOMessageSystemHasPoweredOn:
    757             /* awake */
    758             SDL_PrivateExpose();
    759             break;
    760      }
    761 }
    762 
    763 void QZ_RegisterForSleepNotifications (_THIS)
    764 {
    765      CFRunLoopSourceRef rls;
    766      IONotificationPortRef thePortRef;
    767      io_object_t notifier;
    768 
    769      power_connection = IORegisterForSystemPower (this, &thePortRef, QZ_SleepNotificationHandler, &notifier);
    770 
    771      if (power_connection == 0)
    772          NSLog(@"SDL: QZ_SleepNotificationHandler() IORegisterForSystemPower failed.");
    773 
    774      rls = IONotificationPortGetRunLoopSource (thePortRef);
    775      CFRunLoopAddSource (CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
    776      CFRelease (rls);
    777 }
    778 
    779 
    780 /* Try to map Quartz mouse buttons to SDL's lingo... */
    781 static int QZ_OtherMouseButtonToSDL(int button)
    782 {
    783     switch (button)
    784     {
    785         case 0:
    786             return(SDL_BUTTON_LEFT);   /* 1 */
    787         case 1:
    788             return(SDL_BUTTON_RIGHT);  /* 3 */
    789         case 2:
    790             return(SDL_BUTTON_MIDDLE); /* 2 */
    791     }
    792 
    793     /* >= 3: skip 4 & 5, since those are the SDL mousewheel buttons. */
    794     return(button + 3);
    795 }
    796 
    797 
    798 void QZ_PumpEvents (_THIS)
    799 {
    800     int32_t dx, dy;
    801 
    802     NSDate *distantPast;
    803     NSEvent *event;
    804     NSRect winRect;
    805     NSAutoreleasePool *pool;
    806 
    807     if (!SDL_VideoSurface)
    808         return;  /* don't do anything if there's no screen surface. */
    809 
    810     /* Update activity every five seconds to prevent screensaver. --ryan. */
    811     if (!allow_screensaver) {
    812         static Uint32 screensaverTicks;
    813         Uint32 nowTicks = SDL_GetTicks();
    814         if ((nowTicks - screensaverTicks) > 5000)
    815         {
    816             UpdateSystemActivity(UsrActivity);
    817             screensaverTicks = nowTicks;
    818         }
    819     }
    820 
    821     pool = [ [ NSAutoreleasePool alloc ] init ];
    822     distantPast = [ NSDate distantPast ];
    823 
    824     winRect = NSMakeRect (0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h);
    825 
    826     /* while grabbed, accumulate all mouse moved events into one SDL mouse event */
    827     dx = 0;
    828     dy = 0;
    829 
    830     do {
    831 
    832         /* Poll for an event. This will not block */
    833         event = [ NSApp nextEventMatchingMask:NSAnyEventMask
    834                                     untilDate:distantPast
    835                                     inMode: NSDefaultRunLoopMode dequeue:YES ];
    836         if (event != nil) {
    837 
    838             int button;
    839             unsigned int type;
    840             BOOL isInGameWin;
    841 
    842             #define DO_MOUSE_DOWN(button) do {                                               \
    843                             if ( SDL_GetAppState() & SDL_APPMOUSEFOCUS ) {                   \
    844                                 SDL_PrivateMouseButton (SDL_PRESSED, button, 0, 0);          \
    845                                 expect_mouse_up |= 1<<button;                                \
    846                             }                                                                \
    847                             [ NSApp sendEvent:event ];                                       \
    848             } while(0)
    849 
    850             #define DO_MOUSE_UP(button) do {                                            \
    851                             if ( expect_mouse_up & (1<<button) ) {                      \
    852                                 SDL_PrivateMouseButton (SDL_RELEASED, button, 0, 0);    \
    853                                 expect_mouse_up &= ~(1<<button);                        \
    854                             }                                                           \
    855                             [ NSApp sendEvent:event ];                                  \
    856             } while(0)
    857 
    858             type = [ event type ];
    859             isInGameWin = QZ_IsMouseInWindow (this);
    860 
    861             QZ_DoModifiers(this, [ event modifierFlags ] );
    862 
    863             switch (type) {
    864                 case NSLeftMouseDown:
    865                     if ( SDL_getenv("SDL_HAS3BUTTONMOUSE") ) {
    866                         DO_MOUSE_DOWN (SDL_BUTTON_LEFT);
    867                     } else {
    868                         if ( NSCommandKeyMask & current_mods ) {
    869                             last_virtual_button = SDL_BUTTON_RIGHT;
    870                             DO_MOUSE_DOWN (SDL_BUTTON_RIGHT);
    871                         }
    872                         else if ( NSAlternateKeyMask & current_mods ) {
    873                             last_virtual_button = SDL_BUTTON_MIDDLE;
    874                             DO_MOUSE_DOWN (SDL_BUTTON_MIDDLE);
    875                         }
    876                         else {
    877                             DO_MOUSE_DOWN (SDL_BUTTON_LEFT);
    878                         }
    879                     }
    880                     break;
    881 
    882                 case NSLeftMouseUp:
    883                     if ( last_virtual_button != 0 ) {
    884                         DO_MOUSE_UP (last_virtual_button);
    885                         last_virtual_button = 0;
    886                     }
    887                     else {
    888                         DO_MOUSE_UP (SDL_BUTTON_LEFT);
    889                     }
    890                     break;
    891 
    892                 case NSOtherMouseDown:
    893                 case NSRightMouseDown:
    894                     button = QZ_OtherMouseButtonToSDL([ event buttonNumber ]);
    895                     DO_MOUSE_DOWN (button);
    896                     break;
    897 
    898                 case NSOtherMouseUp:
    899                 case NSRightMouseUp:
    900                     button = QZ_OtherMouseButtonToSDL([ event buttonNumber ]);
    901                     DO_MOUSE_UP (button);
    902                     break;
    903 
    904                 case NSSystemDefined:
    905                     /*
    906                         Future: up to 32 "mouse" buttons can be handled.
    907                         if ([event subtype] == 7) {
    908                             unsigned int buttons;
    909                             buttons = [ event data2 ];
    910                     */
    911                     break;
    912                 case NSLeftMouseDragged:
    913                 case NSRightMouseDragged:
    914                 case NSOtherMouseDragged: /* usually middle mouse dragged */
    915                 case NSMouseMoved:
    916                     if ( grab_state == QZ_INVISIBLE_GRAB ) {
    917 
    918                         /*
    919                             If input is grabbed+hidden, the cursor doesn't move,
    920                             so we have to call the lowlevel window server
    921                             function. This is less accurate but works OK.
    922                         */
    923                         int32_t dx1, dy1;
    924                         CGGetLastMouseDelta (&dx1, &dy1);
    925                         dx += dx1;
    926                         dy += dy1;
    927                     }
    928                     else {
    929 
    930                         /*
    931                             Get the absolute mouse location. This is not the
    932                             mouse location after the currently processed event,
    933                             but the *current* mouse location, i.e. after all
    934                             pending events. This means that if there are
    935                             multiple mouse moved events in the queue, we make
    936                             multiple identical calls to SDL_PrivateMouseMotion(),
    937                             but that's no problem since the latter only
    938                             generates SDL events for nonzero movements. In my
    939                             experience on PBG4/10.4.8, this rarely happens anyway.
    940                         */
    941                         NSPoint p;
    942                         QZ_GetMouseLocation (this, &p);
    943                         SDL_PrivateMouseMotion (0, 0, p.x, p.y);
    944                     }
    945 
    946                     /*
    947                         Handle grab input+cursor visible by warping the cursor back
    948                         into the game window. This still generates a mouse moved event,
    949                         but not as a result of the warp (so it's in the right direction).
    950                     */
    951                     if ( grab_state == QZ_VISIBLE_GRAB && !isInGameWin ) {
    952 
    953                         NSPoint p;
    954                         QZ_GetMouseLocation (this, &p);
    955 
    956                         if ( p.x < 0.0 )
    957                             p.x = 0.0;
    958 
    959                         if ( p.y < 0.0 )
    960                             p.y = 0.0;
    961 
    962                         if ( p.x >= winRect.size.width )
    963                             p.x = winRect.size.width-1;
    964 
    965                         if ( p.y >= winRect.size.height )
    966                             p.y = winRect.size.height-1;
    967 
    968                         QZ_PrivateWarpCursor (this, p.x, p.y);
    969                     }
    970                     else
    971                     if ( !isInGameWin && (SDL_GetAppState() & SDL_APPMOUSEFOCUS) ) {
    972 
    973                         SDL_PrivateAppActive (0, SDL_APPMOUSEFOCUS);
    974 
    975                         if (grab_state == QZ_INVISIBLE_GRAB)
    976                             /*The cursor has left the window even though it is
    977                               disassociated from the mouse (and therefore
    978                               shouldn't move): this can happen with Wacom
    979                               tablets, and it effectively breaks the grab, since
    980                               mouse down events now go to background
    981                               applications. The only possibility to avoid this
    982                               seems to be talking to the tablet driver
    983                               (AppleEvents) to constrain its mapped area to the
    984                               window, which may not be worth the effort. For
    985                               now, handle the condition more gracefully than
    986                               before by reassociating cursor and mouse until the
    987                               cursor enters the window again, making it obvious
    988                               to the user that the grab is broken.*/
    989                             CGAssociateMouseAndMouseCursorPosition (1);
    990 
    991                         QZ_UpdateCursor(this);
    992                     }
    993                     else
    994                     if ( isInGameWin && (SDL_GetAppState() & (SDL_APPMOUSEFOCUS | SDL_APPINPUTFOCUS)) == SDL_APPINPUTFOCUS ) {
    995 
    996                         SDL_PrivateAppActive (1, SDL_APPMOUSEFOCUS);
    997 
    998                         QZ_UpdateCursor(this);
    999 
   1000                         if (grab_state == QZ_INVISIBLE_GRAB) { /*see comment above*/
   1001                             QZ_PrivateWarpCursor (this, SDL_VideoSurface->w / 2, SDL_VideoSurface->h / 2);
   1002                             CGAssociateMouseAndMouseCursorPosition (0);
   1003                         }
   1004                     }
   1005                     break;
   1006                 case NSScrollWheel:
   1007                     if ( isInGameWin ) {
   1008                         float dy, dx;
   1009                         Uint8 button;
   1010                         dy = [ event deltaY ];
   1011                         dx = [ event deltaX ];
   1012                         if ( dy > 0.0 ) /* Scroll up */
   1013                             button = SDL_BUTTON_WHEELUP;
   1014                         else if ( dy < 0.0 ) /* Scroll down */
   1015                             button = SDL_BUTTON_WHEELDOWN;
   1016                         else
   1017                             break; /* Horizontal scroll */
   1018                         /* For now, wheel is sent as a quick down+up */
   1019                         SDL_PrivateMouseButton (SDL_PRESSED, button, 0, 0);
   1020                         SDL_PrivateMouseButton (SDL_RELEASED, button, 0, 0);
   1021                     }
   1022                     break;
   1023                 case NSKeyUp:
   1024                     QZ_DoKey (this, SDL_RELEASED, event);
   1025                     break;
   1026                 case NSKeyDown:
   1027                     QZ_DoKey (this, SDL_PRESSED, event);
   1028                     break;
   1029                 case NSFlagsChanged:
   1030                     break;
   1031                 case NSAppKitDefined:
   1032                     [ NSApp sendEvent:event ];
   1033                     if ([ event subtype ] == NSApplicationActivatedEventType && (mode_flags & SDL_FULLSCREEN)) {
   1034                         /* the default handling of this event seems to reset any cursor set by [NSCursor set] (used by SDL_SetCursor() in fullscreen mode) to the default system arrow cursor */
   1035                         SDL_Cursor *sdlc = SDL_GetCursor();
   1036                         if (sdlc != NULL && sdlc->wm_cursor != NULL) {
   1037                             [ sdlc->wm_cursor->nscursor set ];
   1038                         }
   1039                     }
   1040                     break;
   1041                     /* case NSApplicationDefined: break; */
   1042                     /* case NSPeriodic: break; */
   1043                     /* case NSCursorUpdate: break; */
   1044                 default:
   1045                     [ NSApp sendEvent:event ];
   1046             }
   1047         }
   1048     } while (event != nil);
   1049 
   1050     /* handle accumulated mouse moved events */
   1051     if (dx != 0 || dy != 0)
   1052         SDL_PrivateMouseMotion (0, 1, dx, dy);
   1053 
   1054     [ pool release ];
   1055 }
   1056 
   1057 void QZ_UpdateMouse (_THIS)
   1058 {
   1059     NSPoint p;
   1060     QZ_GetMouseLocation (this, &p);
   1061     SDL_PrivateAppActive (QZ_IsMouseInWindow (this), SDL_APPMOUSEFOCUS);
   1062     SDL_PrivateMouseMotion (0, 0, p.x, p.y);
   1063 }
   1064