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