src/video/quartz/SDL_QuartzEvents.m
author Ryan C. Gordon
Sun, 01 Jan 2012 20:45:31 -0500
branchSDL-1.2
changeset 6150 5f0b3693ab60
parent 6137 4720145f848b
child 8911 606600f0f6d7
permissions -rw-r--r--
Throw around some QZ_UpdateCursor() calls to fix wrongly-shown system cursor.

Fixes Bugzilla #1339.
     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@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 }