SDL-1.2.14
[sdl_omap.git] / src / video / quartz / SDL_QuartzEvents.m
1 /*
2     SDL - Simple DirectMedia Layer
3     Copyright (C) 1997-2009  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     const void *KCHRPtr;
82     UInt32 state;
83     UInt32 value;
84     int 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     /* Get a pointer to the systems cached KCHR */
216     KCHRPtr = (void *)GetScriptManagerVariable(smKCHRCache);
217     if (KCHRPtr)
218     {
219         /* Loop over all 127 possible scan codes */
220         for (i = 0; i < 0x7F; i++)
221         {
222             /* We pretend a clean start to begin with (i.e. no dead keys active */
223             state = 0;
224
225             /* Now translate the key code to a key value */
226             value = KeyTranslate(KCHRPtr, i, &state) & 0xff;
227
228             /* If the state become 0, it was a dead key. We need to translate again,
229                 passing in the new state, to get the actual key value */
230             if (state != 0)
231                 value = KeyTranslate(KCHRPtr, i, &state) & 0xff;
232
233             /* Now we should have an ascii value, or 0. Try to figure out to which SDL symbol it maps */
234             if (value >= 128)     /* Some non-ASCII char, map it to SDLK_WORLD_* */
235                 keymap[i] = world++;
236             else if (value >= 32)     /* non-control ASCII char */
237                 keymap[i] = value;
238         }
239     }
240
241     /* 
242         The keypad codes are re-setup here, because the loop above cannot
243         distinguish between a key on the keypad and a regular key. We maybe
244         could get around this problem in another fashion: NSEvent's flags
245         include a "NSNumericPadKeyMask" bit; we could check that and modify
246         the symbol we return on the fly. However, this flag seems to exhibit
247         some weird behaviour related to the num lock key
248     */
249     keymap[QZ_KP0] = SDLK_KP0;
250     keymap[QZ_KP1] = SDLK_KP1;
251     keymap[QZ_KP2] = SDLK_KP2;
252     keymap[QZ_KP3] = SDLK_KP3;
253     keymap[QZ_KP4] = SDLK_KP4;
254     keymap[QZ_KP5] = SDLK_KP5;
255     keymap[QZ_KP6] = SDLK_KP6;
256     keymap[QZ_KP7] = SDLK_KP7;
257     keymap[QZ_KP8] = SDLK_KP8;
258     keymap[QZ_KP9] = SDLK_KP9;
259     keymap[QZ_KP_MINUS] = SDLK_KP_MINUS;
260     keymap[QZ_KP_PLUS] = SDLK_KP_PLUS;
261     keymap[QZ_KP_PERIOD] = SDLK_KP_PERIOD;
262     keymap[QZ_KP_EQUALS] = SDLK_KP_EQUALS;
263     keymap[QZ_KP_DIVIDE] = SDLK_KP_DIVIDE;
264     keymap[QZ_KP_MULTIPLY] = SDLK_KP_MULTIPLY;
265     keymap[QZ_KP_ENTER] = SDLK_KP_ENTER;
266 }
267
268 static void QZ_DoKey (_THIS, int state, NSEvent *event) {
269
270     NSString *chars = NULL;
271     unsigned int i, numChars;
272     SDL_keysym key;
273     
274     /* 
275         A key event can contain multiple characters,
276         or no characters at all. In most cases, it
277         will contain a single character. If it contains
278         0 characters, we'll use 0 as the unicode. If it
279         contains multiple characters, we'll use 0 as
280         the scancode/keysym.
281     */
282     if (SDL_TranslateUNICODE && state == SDL_PRESSED) {
283         [field_edit interpretKeyEvents:[NSArray arrayWithObject:event]];
284         chars = [ event characters ];
285         numChars = [ chars length ];
286         if (numChars > 0)
287             [field_edit setString:@""];
288     } else {
289         numChars = 0;
290     }
291
292     if (numChars == 0) {
293       
294         key.scancode = [ event keyCode ];
295         key.sym      = keymap [ key.scancode ];
296         key.unicode  = 0;
297         key.mod      = KMOD_NONE;
298
299         SDL_PrivateKeyboard (state, &key);
300     }
301     else if (numChars >= 1) {
302
303         key.scancode = [ event keyCode ];
304         key.sym      = keymap [ key.scancode ];
305         key.unicode  = [ chars characterAtIndex:0 ];
306         key.mod      = KMOD_NONE;
307
308         SDL_PrivateKeyboard (state, &key);
309       
310         for (i = 1; i < numChars; i++) {
311
312             key.scancode = 0;
313             key.sym      = 0;
314             key.unicode  = [ chars characterAtIndex:i];
315             key.mod      = KMOD_NONE;
316
317             SDL_PrivateKeyboard (state, &key);
318         }
319     }
320     
321     if (SDL_getenv ("SDL_ENABLEAPPEVENTS"))
322         [ NSApp sendEvent:event ];
323 }
324
325 /* This is the original behavior, before support was added for 
326  * differentiating between left and right versions of the keys.
327  */
328 static void QZ_DoUnsidedModifiers (_THIS, unsigned int newMods) {
329
330     const int mapping[] = { SDLK_CAPSLOCK, SDLK_LSHIFT, SDLK_LCTRL, SDLK_LALT, SDLK_LMETA };
331
332     int i;
333     int bit;
334     SDL_keysym key;
335     
336     key.scancode    = 0;
337     key.sym         = SDLK_UNKNOWN;
338     key.unicode     = 0;
339     key.mod         = KMOD_NONE;
340
341     /* Iterate through the bits, testing each against the current modifiers */
342     for (i = 0, bit = NSAlphaShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) {
343
344         unsigned int currentMask, newMask;
345
346         currentMask = current_mods & bit;
347         newMask     = newMods & bit;
348
349         if ( currentMask &&
350              currentMask != newMask ) {     /* modifier up event */
351
352              key.sym = mapping[i];
353              /* If this was Caps Lock, we need some additional voodoo to make SDL happy */
354              if (bit == NSAlphaShiftKeyMask)
355                   SDL_PrivateKeyboard (SDL_PRESSED, &key);
356              SDL_PrivateKeyboard (SDL_RELEASED, &key);
357         }
358         else if ( newMask &&
359                   currentMask != newMask ) {     /* modifier down event */
360         
361              key.sym = mapping[i];
362              SDL_PrivateKeyboard (SDL_PRESSED, &key);
363              /* If this was Caps Lock, we need some additional voodoo to make SDL happy */
364              if (bit == NSAlphaShiftKeyMask)
365                   SDL_PrivateKeyboard (SDL_RELEASED, &key);
366         }
367     }
368 }
369
370 /* This is a helper function for QZ_HandleModifierSide. This 
371  * function reverts back to behavior before the distinction between
372  * sides was made.
373  */
374 static void QZ_HandleNonDeviceModifier ( _THIS, unsigned int device_independent_mask, unsigned int newMods, unsigned int key_sym) {
375     unsigned int currentMask, newMask;
376     SDL_keysym key;
377     
378     key.scancode    = 0;
379     key.sym         = key_sym;
380     key.unicode     = 0;
381     key.mod         = KMOD_NONE;
382     
383     /* Isolate just the bits we care about in the depedent bits so we can 
384      * figure out what changed
385      */ 
386     currentMask = current_mods & device_independent_mask;
387     newMask     = newMods & device_independent_mask;
388     
389     if ( currentMask &&
390          currentMask != newMask ) {     /* modifier up event */
391          SDL_PrivateKeyboard (SDL_RELEASED, &key);
392     }
393     else if ( newMask &&
394           currentMask != newMask ) {     /* modifier down event */
395           SDL_PrivateKeyboard (SDL_PRESSED, &key);
396     }
397 }
398
399 /* This is a helper function for QZ_HandleModifierSide. 
400  * This function sets the actual SDL_PrivateKeyboard event.
401  */
402 static void QZ_HandleModifierOneSide ( _THIS, unsigned int newMods,
403                                        unsigned int key_sym, 
404                                        unsigned int sided_device_dependent_mask ) {
405     
406     SDL_keysym key;
407     unsigned int current_dep_mask, new_dep_mask;
408     
409     key.scancode    = 0;
410     key.sym         = key_sym;
411     key.unicode     = 0;
412     key.mod         = KMOD_NONE;
413     
414     /* Isolate just the bits we care about in the depedent bits so we can 
415      * figure out what changed
416      */ 
417     current_dep_mask = current_mods & sided_device_dependent_mask;
418     new_dep_mask     = newMods & sided_device_dependent_mask;
419     
420     /* We now know that this side bit flipped. But we don't know if
421      * it went pressed to released or released to pressed, so we must 
422      * find out which it is.
423      */
424     if( new_dep_mask &&
425         current_dep_mask != new_dep_mask ) { 
426         /* Modifier down event */
427         SDL_PrivateKeyboard (SDL_PRESSED, &key);
428     }
429     else /* Modifier up event */ {
430         SDL_PrivateKeyboard (SDL_RELEASED, &key);
431     }
432 }
433
434 /* This is a helper function for QZ_DoSidedModifiers.
435  * This function will figure out if the modifier key is the left or right side, 
436  * e.g. left-shift vs right-shift. 
437  */
438 static void QZ_HandleModifierSide ( _THIS, int device_independent_mask, 
439                                     unsigned int newMods, 
440                                     unsigned int left_key_sym, 
441                                     unsigned int right_key_sym,
442                                     unsigned int left_device_dependent_mask, 
443                                     unsigned int right_device_dependent_mask ) {
444     unsigned int device_dependent_mask = 0;
445     unsigned int diff_mod = 0;
446     
447     device_dependent_mask = left_device_dependent_mask | right_device_dependent_mask;
448     /* On the basis that the device independent mask is set, but there are 
449      * no device dependent flags set, we'll assume that we can't detect this 
450      * keyboard and revert to the unsided behavior.
451      */
452     if ( (device_dependent_mask & newMods) == 0 ) {
453         /* Revert to the old behavior */
454         QZ_HandleNonDeviceModifier ( this, device_independent_mask, newMods, left_key_sym );
455         return;
456     }
457         
458     /* XOR the previous state against the new state to see if there's a change */
459     diff_mod = (device_dependent_mask & current_mods)
460         ^ (device_dependent_mask & newMods);
461
462     if ( diff_mod ) {
463         /* A change in state was found. Isolate the left and right bits 
464          * to handle them separately just in case the values can simulataneously
465          * change or if the bits don't both exist.
466          */
467         if ( left_device_dependent_mask & diff_mod ) {
468             QZ_HandleModifierOneSide ( this, newMods, left_key_sym, left_device_dependent_mask );
469         }
470         if ( right_device_dependent_mask & diff_mod ) {
471             QZ_HandleModifierOneSide ( this, newMods, right_key_sym, right_device_dependent_mask );
472         }
473     }
474 }
475    
476 /* This is a helper function for QZ_DoSidedModifiers.
477  * This function will release a key press in the case that 
478  * it is clear that the modifier has been released (i.e. one side 
479  * can't still be down).
480  */
481 static void QZ_ReleaseModifierSide ( _THIS, 
482                                      unsigned int device_independent_mask, 
483                                      unsigned int newMods,
484                                      unsigned int left_key_sym, 
485                                      unsigned int right_key_sym,
486                                      unsigned int left_device_dependent_mask, 
487                                      unsigned int right_device_dependent_mask ) {
488     unsigned int device_dependent_mask = 0;
489     SDL_keysym key;
490     
491     key.scancode    = 0;
492     key.sym         = SDLK_UNKNOWN;
493     key.unicode     = 0;
494     key.mod         = KMOD_NONE;
495     
496     device_dependent_mask = left_device_dependent_mask | right_device_dependent_mask;
497     /* On the basis that the device independent mask is set, but there are 
498      * no device dependent flags set, we'll assume that we can't detect this 
499      * keyboard and revert to the unsided behavior.
500      */
501     if ( (device_dependent_mask & current_mods) == 0 ) {
502         /* In this case, we can't detect the keyboard, so use the left side 
503          * to represent both, and release it. 
504          */
505         key.sym = left_key_sym;
506         SDL_PrivateKeyboard (SDL_RELEASED, &key);
507
508         return;
509     }
510         
511         
512     /* 
513      * This could have been done in an if-else case because at this point,
514      * we know that all keys have been released when calling this function. 
515      * But I'm being paranoid so I want to handle each separately,
516      * so I hope this doesn't cause other problems.
517      */
518     if ( left_device_dependent_mask & current_mods ) {
519         key.sym = left_key_sym;
520         SDL_PrivateKeyboard (SDL_RELEASED, &key);
521     }
522     if ( right_device_dependent_mask & current_mods ) {
523         key.sym = right_key_sym;
524         SDL_PrivateKeyboard (SDL_RELEASED, &key);
525     }
526 }
527
528 /* This is a helper function for QZ_DoSidedModifiers.
529  * This function handles the CapsLock case.
530  */
531 static void QZ_HandleCapsLock (_THIS, unsigned int newMods) {
532     unsigned int currentMask, newMask;
533     SDL_keysym key;
534     
535     key.scancode    = 0;
536     key.sym         = SDLK_CAPSLOCK;
537     key.unicode     = 0;
538     key.mod         = KMOD_NONE;
539     
540     currentMask = current_mods & NSAlphaShiftKeyMask;
541     newMask     = newMods & NSAlphaShiftKeyMask;
542
543     if ( currentMask &&
544          currentMask != newMask ) {     /* modifier up event */
545          /* If this was Caps Lock, we need some additional voodoo to make SDL happy */
546          SDL_PrivateKeyboard (SDL_PRESSED, &key);
547          SDL_PrivateKeyboard (SDL_RELEASED, &key);
548     }
549     else if ( newMask &&
550               currentMask != newMask ) {     /* modifier down event */
551         /* If this was Caps Lock, we need some additional voodoo to make SDL happy */
552         SDL_PrivateKeyboard (SDL_PRESSED, &key);
553         SDL_PrivateKeyboard (SDL_RELEASED, &key);
554     }
555 }
556
557 /* This function will handle the modifier keys and also determine the 
558  * correct side of the key.
559  */
560 static void QZ_DoSidedModifiers (_THIS, unsigned int newMods) {
561         /* Set up arrays for the key syms for the left and right side. */
562     const unsigned int left_mapping[]  = { SDLK_LSHIFT, SDLK_LCTRL, SDLK_LALT, SDLK_LMETA };
563     const unsigned int right_mapping[] = { SDLK_RSHIFT, SDLK_RCTRL, SDLK_RALT, SDLK_RMETA };
564         /* Set up arrays for the device dependent masks with indices that 
565      * correspond to the _mapping arrays 
566      */
567     const unsigned int left_device_mapping[]  = { NX_DEVICELSHIFTKEYMASK, NX_DEVICELCTLKEYMASK, NX_DEVICELALTKEYMASK, NX_DEVICELCMDKEYMASK };
568     const unsigned int right_device_mapping[] = { NX_DEVICERSHIFTKEYMASK, NX_DEVICERCTLKEYMASK, NX_DEVICERALTKEYMASK, NX_DEVICERCMDKEYMASK };
569
570     unsigned int i;
571     unsigned int bit;
572     
573     /* Handle CAPSLOCK separately because it doesn't have a left/right side */
574     QZ_HandleCapsLock ( this, newMods );
575         
576     /* Iterate through the bits, testing each against the current modifiers */
577     for (i = 0, bit = NSShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) {
578                 
579         unsigned int currentMask, newMask;
580                 
581         currentMask = current_mods & bit;
582         newMask     = newMods & bit;
583                 
584         /* If the bit is set, we must always examine it because the left
585          * and right side keys may alternate or both may be pressed.
586          */
587         if ( newMask ) {
588             QZ_HandleModifierSide ( this, bit, newMods, 
589                                        left_mapping[i],
590                                        right_mapping[i],
591                                        left_device_mapping[i],
592                                        right_device_mapping[i] );
593         }
594         /* If the state changed from pressed to unpressed, we must examine
595             * the device dependent bits to release the correct keys.
596             */
597         else if ( currentMask &&
598                   currentMask != newMask ) { /* modifier up event */
599                   QZ_ReleaseModifierSide ( this, bit, newMods,
600                                            left_mapping[i],
601                                            right_mapping[i],
602                                            left_device_mapping[i],
603                                            right_device_mapping[i] );
604         }
605     }
606 }
607
608 /* This function is called to handle the modifiers.
609  * It will try to distinguish between the left side and right side 
610  * of the keyboard for those modifiers that qualify if the 
611  * operating system version supports it. Otherwise, the code 
612  * will not try to make the distinction.
613  */
614 static void QZ_DoModifiers (_THIS, unsigned int newMods) {
615         
616     if (current_mods == newMods)
617         return;
618     
619     /* 
620      * Starting with Panther (10.3.0), the ability to distinguish between 
621      * left side and right side modifiers is available.
622      */
623     if( system_version >= 0x1030 ) {
624         QZ_DoSidedModifiers (this, newMods);
625     }
626     else {
627         QZ_DoUnsidedModifiers (this, newMods);
628     }
629     
630     current_mods = newMods;
631 }
632
633 static void QZ_GetMouseLocation (_THIS, NSPoint *p) {
634     *p = [ NSEvent mouseLocation ]; /* global coordinates */
635     if (qz_window)
636         QZ_PrivateGlobalToLocal (this, p);
637     QZ_PrivateCocoaToSDL (this, p);
638 }
639
640 void QZ_DoActivate (_THIS) {
641
642     SDL_PrivateAppActive (1, SDL_APPINPUTFOCUS | (QZ_IsMouseInWindow (this) ? SDL_APPMOUSEFOCUS : 0));
643
644     QZ_UpdateCursor(this);
645
646     /* Regrab input, only if it was previously grabbed */
647     if ( current_grab_mode == SDL_GRAB_ON ) {
648         
649         /* Restore cursor location if input was grabbed */
650         QZ_PrivateWarpCursor (this, cursor_loc.x, cursor_loc.y);
651         QZ_ChangeGrabState (this, QZ_ENABLE_GRAB);
652     }
653     else {
654         /* Update SDL's mouse location */
655         NSPoint p;
656         QZ_GetMouseLocation (this, &p);
657         SDL_PrivateMouseMotion (0, 0, p.x, p.y);
658     }
659 }
660
661 void QZ_DoDeactivate (_THIS) {
662     
663     SDL_PrivateAppActive (0, SDL_APPINPUTFOCUS | SDL_APPMOUSEFOCUS);
664
665     /* Get the current cursor location, for restore on activate */
666     QZ_GetMouseLocation (this, &cursor_loc);
667     
668     /* Reassociate mouse and cursor */
669     CGAssociateMouseAndMouseCursorPosition (1);
670
671     QZ_UpdateCursor(this);
672 }
673
674 void QZ_SleepNotificationHandler (void * refcon,
675                                   io_service_t service,
676                                   natural_t messageType,
677                                   void * messageArgument )
678 {
679      SDL_VideoDevice *this = (SDL_VideoDevice*)refcon;
680      
681      switch(messageType)
682      {
683          case kIOMessageSystemWillSleep:
684              IOAllowPowerChange(power_connection, (long) messageArgument);
685              break;
686          case kIOMessageCanSystemSleep:
687              IOAllowPowerChange(power_connection, (long) messageArgument);
688              break;
689          case kIOMessageSystemHasPoweredOn:
690             /* awake */
691             SDL_PrivateExpose();
692             break;
693      }
694 }
695
696 void QZ_RegisterForSleepNotifications (_THIS)
697 {
698      CFRunLoopSourceRef rls;
699      IONotificationPortRef thePortRef;
700      io_object_t notifier;
701
702      power_connection = IORegisterForSystemPower (this, &thePortRef, QZ_SleepNotificationHandler, &notifier);
703
704      if (power_connection == 0)
705          NSLog(@"SDL: QZ_SleepNotificationHandler() IORegisterForSystemPower failed.");
706
707      rls = IONotificationPortGetRunLoopSource (thePortRef);
708      CFRunLoopAddSource (CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
709      CFRelease (rls);
710 }
711
712
713 /* Try to map Quartz mouse buttons to SDL's lingo... */
714 static int QZ_OtherMouseButtonToSDL(int button)
715 {
716     switch (button)
717     {
718         case 0:
719             return(SDL_BUTTON_LEFT);   /* 1 */
720         case 1:
721             return(SDL_BUTTON_RIGHT);  /* 3 */
722         case 2:
723             return(SDL_BUTTON_MIDDLE); /* 2 */
724     }
725
726     /* >= 3: skip 4 & 5, since those are the SDL mousewheel buttons. */
727     return(button + 3);
728 }
729
730
731 void QZ_PumpEvents (_THIS)
732 {
733     CGMouseDelta dx, dy;
734
735     NSDate *distantPast;
736     NSEvent *event;
737     NSRect winRect;
738     NSAutoreleasePool *pool;
739
740     if (!SDL_VideoSurface)
741         return;  /* don't do anything if there's no screen surface. */
742
743     /* Update activity every five seconds to prevent screensaver. --ryan. */
744     if (!allow_screensaver) {
745         static Uint32 screensaverTicks;
746         Uint32 nowTicks = SDL_GetTicks();
747         if ((nowTicks - screensaverTicks) > 5000)
748         {
749             UpdateSystemActivity(UsrActivity);
750             screensaverTicks = nowTicks;
751         }
752     }
753
754     pool = [ [ NSAutoreleasePool alloc ] init ];
755     distantPast = [ NSDate distantPast ];
756
757     winRect = NSMakeRect (0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h);
758     
759     /* while grabbed, accumulate all mouse moved events into one SDL mouse event */
760     dx = 0;
761     dy = 0;
762     
763     do {
764     
765         /* Poll for an event. This will not block */
766         event = [ NSApp nextEventMatchingMask:NSAnyEventMask
767                                     untilDate:distantPast
768                                     inMode: NSDefaultRunLoopMode dequeue:YES ];
769         if (event != nil) {
770
771             int button;
772             unsigned int type;
773             BOOL isInGameWin;
774             
775             #define DO_MOUSE_DOWN(button) do {                                               \
776                             if ( SDL_GetAppState() & SDL_APPMOUSEFOCUS ) {                   \
777                                 SDL_PrivateMouseButton (SDL_PRESSED, button, 0, 0);          \
778                                 expect_mouse_up |= 1<<button;                                \
779                             }                                                                \
780                             [ NSApp sendEvent:event ];                                       \
781             } while(0)
782             
783             #define DO_MOUSE_UP(button) do {                                            \
784                             if ( expect_mouse_up & (1<<button) ) {                      \
785                                 SDL_PrivateMouseButton (SDL_RELEASED, button, 0, 0);    \
786                                 expect_mouse_up &= ~(1<<button);                        \
787                             }                                                           \
788                             [ NSApp sendEvent:event ];                                  \
789             } while(0)
790             
791             type = [ event type ];
792             isInGameWin = QZ_IsMouseInWindow (this);
793
794             QZ_DoModifiers(this, [ event modifierFlags ] );
795
796             switch (type) {
797                 case NSLeftMouseDown:
798                     if ( SDL_getenv("SDL_HAS3BUTTONMOUSE") ) {
799                         DO_MOUSE_DOWN (SDL_BUTTON_LEFT);
800                     } else {
801                         if ( NSCommandKeyMask & current_mods ) {
802                             last_virtual_button = SDL_BUTTON_RIGHT;
803                             DO_MOUSE_DOWN (SDL_BUTTON_RIGHT);
804                         }
805                         else if ( NSAlternateKeyMask & current_mods ) {
806                             last_virtual_button = SDL_BUTTON_MIDDLE;
807                             DO_MOUSE_DOWN (SDL_BUTTON_MIDDLE);
808                         }
809                         else {
810                             DO_MOUSE_DOWN (SDL_BUTTON_LEFT);
811                         }
812                     }
813                     break;
814
815                 case NSLeftMouseUp:
816                     if ( last_virtual_button != 0 ) {
817                         DO_MOUSE_UP (last_virtual_button);
818                         last_virtual_button = 0;
819                     }
820                     else {
821                         DO_MOUSE_UP (SDL_BUTTON_LEFT);
822                     }
823                     break;
824
825                 case NSOtherMouseDown:
826                 case NSRightMouseDown:
827                     button = QZ_OtherMouseButtonToSDL([ event buttonNumber ]);
828                     DO_MOUSE_DOWN (button);
829                     break;
830
831                 case NSOtherMouseUp:
832                 case NSRightMouseUp:
833                     button = QZ_OtherMouseButtonToSDL([ event buttonNumber ]);
834                     DO_MOUSE_UP (button);
835                     break;
836
837                 case NSSystemDefined:
838                     /*
839                         Future: up to 32 "mouse" buttons can be handled.
840                         if ([event subtype] == 7) {
841                             unsigned int buttons;
842                             buttons = [ event data2 ];
843                     */
844                     break;
845                 case NSLeftMouseDragged:
846                 case NSRightMouseDragged:
847                 case NSOtherMouseDragged: /* usually middle mouse dragged */
848                 case NSMouseMoved:
849                     if ( grab_state == QZ_INVISIBLE_GRAB ) {
850                 
851                         /*
852                             If input is grabbed+hidden, the cursor doesn't move,
853                             so we have to call the lowlevel window server
854                             function. This is less accurate but works OK.                         
855                         */
856                         CGMouseDelta dx1, dy1;
857                         CGGetLastMouseDelta (&dx1, &dy1);
858                         dx += dx1;
859                         dy += dy1;
860                     }
861                     else {
862                         
863                         /*
864                             Get the absolute mouse location. This is not the
865                             mouse location after the currently processed event,
866                             but the *current* mouse location, i.e. after all
867                             pending events. This means that if there are
868                             multiple mouse moved events in the queue, we make
869                             multiple identical calls to SDL_PrivateMouseMotion(),
870                             but that's no problem since the latter only
871                             generates SDL events for nonzero movements. In my
872                             experience on PBG4/10.4.8, this rarely happens anyway.
873                         */
874                         NSPoint p;
875                         QZ_GetMouseLocation (this, &p);
876                         SDL_PrivateMouseMotion (0, 0, p.x, p.y);
877                     }
878                     
879                     /* 
880                         Handle grab input+cursor visible by warping the cursor back
881                         into the game window. This still generates a mouse moved event,
882                         but not as a result of the warp (so it's in the right direction).
883                     */
884                     if ( grab_state == QZ_VISIBLE_GRAB && !isInGameWin ) {
885                        
886                         NSPoint p;
887                         QZ_GetMouseLocation (this, &p);
888
889                         if ( p.x < 0.0 ) 
890                             p.x = 0.0;
891                         
892                         if ( p.y < 0.0 ) 
893                             p.y = 0.0;
894                         
895                         if ( p.x >= winRect.size.width ) 
896                             p.x = winRect.size.width-1;
897                         
898                         if ( p.y >= winRect.size.height ) 
899                             p.y = winRect.size.height-1;
900                         
901                         QZ_PrivateWarpCursor (this, p.x, p.y);
902                     }
903                     else
904                     if ( !isInGameWin && (SDL_GetAppState() & SDL_APPMOUSEFOCUS) ) {
905                     
906                         SDL_PrivateAppActive (0, SDL_APPMOUSEFOCUS);
907
908                         if (grab_state == QZ_INVISIBLE_GRAB)
909                             /*The cursor has left the window even though it is
910                               disassociated from the mouse (and therefore
911                               shouldn't move): this can happen with Wacom
912                               tablets, and it effectively breaks the grab, since
913                               mouse down events now go to background
914                               applications. The only possibility to avoid this
915                               seems to be talking to the tablet driver
916                               (AppleEvents) to constrain its mapped area to the
917                               window, which may not be worth the effort. For
918                               now, handle the condition more gracefully than
919                               before by reassociating cursor and mouse until the
920                               cursor enters the window again, making it obvious
921                               to the user that the grab is broken.*/
922                             CGAssociateMouseAndMouseCursorPosition (1);
923
924                         QZ_UpdateCursor(this);
925                     }
926                     else
927                     if ( isInGameWin && (SDL_GetAppState() & (SDL_APPMOUSEFOCUS | SDL_APPINPUTFOCUS)) == SDL_APPINPUTFOCUS ) {
928                     
929                         SDL_PrivateAppActive (1, SDL_APPMOUSEFOCUS);
930
931                         QZ_UpdateCursor(this);
932
933                         if (grab_state == QZ_INVISIBLE_GRAB) { /*see comment above*/
934                             QZ_PrivateWarpCursor (this, SDL_VideoSurface->w / 2, SDL_VideoSurface->h / 2);
935                             CGAssociateMouseAndMouseCursorPosition (0);
936                         }
937                     }
938                     break;
939                 case NSScrollWheel:
940                     if ( isInGameWin ) {
941                         float dy, dx;
942                         Uint8 button;
943                         dy = [ event deltaY ];
944                         dx = [ event deltaX ];
945                         if ( dy > 0.0 ) /* Scroll up */
946                             button = SDL_BUTTON_WHEELUP;
947                         else if ( dy < 0.0 ) /* Scroll down */
948                             button = SDL_BUTTON_WHEELDOWN;
949                         else
950                             break; /* Horizontal scroll */
951                         /* For now, wheel is sent as a quick down+up */
952                         SDL_PrivateMouseButton (SDL_PRESSED, button, 0, 0);
953                         SDL_PrivateMouseButton (SDL_RELEASED, button, 0, 0);
954                     }
955                     break;
956                 case NSKeyUp:
957                     QZ_DoKey (this, SDL_RELEASED, event);
958                     break;
959                 case NSKeyDown:
960                     QZ_DoKey (this, SDL_PRESSED, event);
961                     break;
962                 case NSFlagsChanged:
963                     break;
964                 case NSAppKitDefined:
965                     [ NSApp sendEvent:event ];
966                     if ([ event subtype ] == NSApplicationActivatedEventType && (mode_flags & SDL_FULLSCREEN)) {
967                         /* 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 */
968                         SDL_Cursor *sdlc = SDL_GetCursor();
969                         if (sdlc != NULL && sdlc->wm_cursor != NULL) {
970                             [ sdlc->wm_cursor->nscursor set ];
971                         }
972                     }
973                     break;
974                     /* case NSApplicationDefined: break; */
975                     /* case NSPeriodic: break; */
976                     /* case NSCursorUpdate: break; */
977                 default:
978                     [ NSApp sendEvent:event ];
979             }
980         }
981     } while (event != nil);
982     
983     /* handle accumulated mouse moved events */
984     if (dx != 0 || dy != 0)
985         SDL_PrivateMouseMotion (0, 1, dx, dy);
986     
987     [ pool release ];
988 }
989
990 void QZ_UpdateMouse (_THIS)
991 {
992     NSPoint p;
993     QZ_GetMouseLocation (this, &p);
994     SDL_PrivateAppActive (QZ_IsMouseInWindow (this), SDL_APPMOUSEFOCUS);
995     SDL_PrivateMouseMotion (0, 0, p.x, p.y);
996 }