Imported Upstream version 1.2.15
[platform/upstream/SDL.git] / src / video / quartz / SDL_QuartzEvents.m
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 }