2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2012 Sam Lantinga
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.
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.
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
22 #include "SDL_config.h"
24 #include "SDL_QuartzVideo.h"
25 #include "SDL_QuartzWM.h"
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"
32 * On Leopard, this is missing from the 64-bit headers
34 #if defined(__LP64__) && !defined(__POWER__)
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.
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.
50 #include <IOKit/hidsystem/IOLLEvent.h>
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.
55 #ifndef NX_DEVICERCTLKEYMASK
56 #define NX_DEVICELCTLKEYMASK 0x00000001
58 #ifndef NX_DEVICELSHIFTKEYMASK
59 #define NX_DEVICELSHIFTKEYMASK 0x00000002
61 #ifndef NX_DEVICERSHIFTKEYMASK
62 #define NX_DEVICERSHIFTKEYMASK 0x00000004
64 #ifndef NX_DEVICELCMDKEYMASK
65 #define NX_DEVICELCMDKEYMASK 0x00000008
67 #ifndef NX_DEVICERCMDKEYMASK
68 #define NX_DEVICERCMDKEYMASK 0x00000010
70 #ifndef NX_DEVICELALTKEYMASK
71 #define NX_DEVICELALTKEYMASK 0x00000020
73 #ifndef NX_DEVICERALTKEYMASK
74 #define NX_DEVICERALTKEYMASK 0x00000040
76 #ifndef NX_DEVICERCTLKEYMASK
77 #define NX_DEVICERCTLKEYMASK 0x00002000
80 void QZ_InitOSKeymap (_THIS) {
85 int world = SDLK_WORLD_0;
87 for ( i=0; i<SDL_TABLESIZE(keymap); ++i )
88 keymap[i] = SDLK_UNKNOWN;
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;
108 keymap[QZ_PRINT] = SDLK_PRINT;
109 keymap[QZ_SCROLLOCK] = SDLK_SCROLLOCK;
110 keymap[QZ_PAUSE] = SDLK_PAUSE;
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;
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.
215 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= 1050)
216 if (TISCopyCurrentKeyboardLayoutInputSource != NULL) {
217 TISInputSourceRef src = TISCopyCurrentKeyboardLayoutInputSource();
219 CFDataRef data = (CFDataRef)
220 TISGetInputSourceProperty(src,
221 kTISPropertyUnicodeKeyLayoutData);
223 const UCKeyboardLayout *layout = (const UCKeyboardLayout *)
224 CFDataGetBytePtr(data);
225 if (layout != NULL) {
226 const UInt32 kbdtype = LMGetKbdType();
229 /* Loop over all 127 possible scan codes */
230 for (i = 0; i < 0x7F; i++) {
232 UniCharCount count = 0;
234 /* We pretend a clean start to begin with (i.e. no dead keys active */
237 if (UCKeyTranslate(layout, i, kUCKeyActionDown, 0, kbdtype,
238 0, &state, 16, &count, buf) != noErr) {
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 */
246 if (UCKeyTranslate(layout, i, kUCKeyActionDown, 0, kbdtype,
247 0, &state, 16, &count, buf) != noErr) {
253 continue; /* no multi-char. Use SDL 1.3 instead. :) */
256 value = (UInt32) buf[0];
258 /* Some non-ASCII char, map it to SDLK_WORLD_* */
262 } else if (value >= 32) { /* non-control ASCII char */
273 #if (MAC_OS_X_VERSION_MIN_REQUIRED < 1050)
275 /* Get a pointer to the systems cached KCHR */
276 const void *KCHRPtr = (const void *)GetScriptManagerVariable(smKCHRCache);
279 /* Loop over all 127 possible scan codes */
280 for (i = 0; i < 0x7F; i++)
282 /* We pretend a clean start to begin with (i.e. no dead keys active */
285 /* Now translate the key code to a key value */
286 value = KeyTranslate(KCHRPtr, i, &state) & 0xff;
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 */
291 value = KeyTranslate(KCHRPtr, i, &state) & 0xff;
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_* */
298 } else if (value >= 32) { /* non-control ASCII char */
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
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;
333 static void QZ_DoKey (_THIS, int state, NSEvent *event) {
335 NSString *chars = NULL;
336 unsigned int i, numChars;
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
347 if (SDL_TranslateUNICODE && state == SDL_PRESSED) {
348 [field_edit interpretKeyEvents:[NSArray arrayWithObject:event]];
349 chars = [ event characters ];
350 numChars = [ chars length ];
352 [field_edit setString:@""];
359 key.scancode = [ event keyCode ];
360 key.sym = keymap [ key.scancode ];
364 SDL_PrivateKeyboard (state, &key);
366 else if (numChars >= 1) {
368 key.scancode = [ event keyCode ];
369 key.sym = keymap [ key.scancode ];
370 key.unicode = [ chars characterAtIndex:0 ];
373 SDL_PrivateKeyboard (state, &key);
375 for (i = 1; i < numChars; i++) {
379 key.unicode = [ chars characterAtIndex:i];
382 SDL_PrivateKeyboard (state, &key);
386 if (SDL_getenv ("SDL_ENABLEAPPEVENTS"))
387 [ NSApp sendEvent:event ];
390 /* This is the original behavior, before support was added for
391 * differentiating between left and right versions of the keys.
393 static void QZ_DoUnsidedModifiers (_THIS, unsigned int newMods) {
395 const int mapping[] = { SDLK_CAPSLOCK, SDLK_LSHIFT, SDLK_LCTRL, SDLK_LALT, SDLK_LMETA };
402 key.sym = SDLK_UNKNOWN;
406 /* Iterate through the bits, testing each against the current modifiers */
407 for (i = 0, bit = NSAlphaShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) {
409 unsigned int currentMask, newMask;
411 currentMask = current_mods & bit;
412 newMask = newMods & bit;
415 currentMask != newMask ) { /* modifier up event */
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);
424 currentMask != newMask ) { /* modifier down event */
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);
435 /* This is a helper function for QZ_HandleModifierSide. This
436 * function reverts back to behavior before the distinction between
439 static void QZ_HandleNonDeviceModifier ( _THIS, unsigned int device_independent_mask, unsigned int newMods, unsigned int key_sym) {
440 unsigned int currentMask, newMask;
448 /* Isolate just the bits we care about in the depedent bits so we can
449 * figure out what changed
451 currentMask = current_mods & device_independent_mask;
452 newMask = newMods & device_independent_mask;
455 currentMask != newMask ) { /* modifier up event */
456 SDL_PrivateKeyboard (SDL_RELEASED, &key);
459 currentMask != newMask ) { /* modifier down event */
460 SDL_PrivateKeyboard (SDL_PRESSED, &key);
464 /* This is a helper function for QZ_HandleModifierSide.
465 * This function sets the actual SDL_PrivateKeyboard event.
467 static void QZ_HandleModifierOneSide ( _THIS, unsigned int newMods,
468 unsigned int key_sym,
469 unsigned int sided_device_dependent_mask ) {
472 unsigned int current_dep_mask, new_dep_mask;
479 /* Isolate just the bits we care about in the depedent bits so we can
480 * figure out what changed
482 current_dep_mask = current_mods & sided_device_dependent_mask;
483 new_dep_mask = newMods & sided_device_dependent_mask;
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.
490 current_dep_mask != new_dep_mask ) {
491 /* Modifier down event */
492 SDL_PrivateKeyboard (SDL_PRESSED, &key);
494 else /* Modifier up event */ {
495 SDL_PrivateKeyboard (SDL_RELEASED, &key);
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.
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;
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.
517 if ( (device_dependent_mask & newMods) == 0 ) {
518 /* Revert to the old behavior */
519 QZ_HandleNonDeviceModifier ( this, device_independent_mask, newMods, left_key_sym );
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);
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.
532 if ( left_device_dependent_mask & diff_mod ) {
533 QZ_HandleModifierOneSide ( this, newMods, left_key_sym, left_device_dependent_mask );
535 if ( right_device_dependent_mask & diff_mod ) {
536 QZ_HandleModifierOneSide ( this, newMods, right_key_sym, right_device_dependent_mask );
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).
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;
557 key.sym = SDLK_UNKNOWN;
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.
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.
570 key.sym = left_key_sym;
571 SDL_PrivateKeyboard (SDL_RELEASED, &key);
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.
583 if ( left_device_dependent_mask & current_mods ) {
584 key.sym = left_key_sym;
585 SDL_PrivateKeyboard (SDL_RELEASED, &key);
587 if ( right_device_dependent_mask & current_mods ) {
588 key.sym = right_key_sym;
589 SDL_PrivateKeyboard (SDL_RELEASED, &key);
593 /* This is a helper function for QZ_DoSidedModifiers.
594 * This function handles the CapsLock case.
596 static void QZ_HandleCapsLock (_THIS, unsigned int newMods) {
597 unsigned int currentMask, newMask;
601 key.sym = SDLK_CAPSLOCK;
605 currentMask = current_mods & NSAlphaShiftKeyMask;
606 newMask = newMods & NSAlphaShiftKeyMask;
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);
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);
622 /* This function will handle the modifier keys and also determine the
623 * correct side of the key.
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
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 };
638 /* Handle CAPSLOCK separately because it doesn't have a left/right side */
639 QZ_HandleCapsLock ( this, newMods );
641 /* Iterate through the bits, testing each against the current modifiers */
642 for (i = 0, bit = NSShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) {
644 unsigned int currentMask, newMask;
646 currentMask = current_mods & bit;
647 newMask = newMods & bit;
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.
653 QZ_HandleModifierSide ( this, bit, newMods,
656 left_device_mapping[i],
657 right_device_mapping[i] );
659 /* If the state changed from pressed to unpressed, we must examine
660 * the device dependent bits to release the correct keys.
662 else if ( currentMask &&
663 currentMask != newMask ) { /* modifier up event */
664 QZ_ReleaseModifierSide ( this, bit, newMods,
667 left_device_mapping[i],
668 right_device_mapping[i] );
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.
679 static void QZ_DoModifiers (_THIS, unsigned int newMods) {
681 if (current_mods == newMods)
685 * Starting with Panther (10.3.0), the ability to distinguish between
686 * left side and right side modifiers is available.
688 if( system_version >= 0x1030 ) {
689 QZ_DoSidedModifiers (this, newMods);
692 QZ_DoUnsidedModifiers (this, newMods);
695 current_mods = newMods;
698 static void QZ_GetMouseLocation (_THIS, NSPoint *p) {
699 *p = [ NSEvent mouseLocation ]; /* global coordinates */
701 QZ_PrivateGlobalToLocal (this, p);
702 QZ_PrivateCocoaToSDL (this, p);
705 void QZ_DoActivate (_THIS) {
707 SDL_PrivateAppActive (1, SDL_APPINPUTFOCUS | (QZ_IsMouseInWindow (this) ? SDL_APPMOUSEFOCUS : 0));
709 QZ_UpdateCursor(this);
711 /* Regrab input, only if it was previously grabbed */
712 if ( current_grab_mode == SDL_GRAB_ON ) {
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);
719 /* Update SDL's mouse location */
721 QZ_GetMouseLocation (this, &p);
722 SDL_PrivateMouseMotion (0, 0, p.x, p.y);
725 QZ_UpdateCursor(this);
728 void QZ_DoDeactivate (_THIS) {
730 SDL_PrivateAppActive (0, SDL_APPINPUTFOCUS | SDL_APPMOUSEFOCUS);
732 /* Get the current cursor location, for restore on activate */
733 QZ_GetMouseLocation (this, &cursor_loc);
735 /* Reassociate mouse and cursor */
736 CGAssociateMouseAndMouseCursorPosition (1);
738 QZ_UpdateCursor(this);
741 void QZ_SleepNotificationHandler (void * refcon,
742 io_service_t service,
743 natural_t messageType,
744 void * messageArgument )
746 SDL_VideoDevice *this = (SDL_VideoDevice*)refcon;
750 case kIOMessageSystemWillSleep:
751 IOAllowPowerChange(power_connection, (long) messageArgument);
753 case kIOMessageCanSystemSleep:
754 IOAllowPowerChange(power_connection, (long) messageArgument);
756 case kIOMessageSystemHasPoweredOn:
763 void QZ_RegisterForSleepNotifications (_THIS)
765 CFRunLoopSourceRef rls;
766 IONotificationPortRef thePortRef;
767 io_object_t notifier;
769 power_connection = IORegisterForSystemPower (this, &thePortRef, QZ_SleepNotificationHandler, ¬ifier);
771 if (power_connection == 0)
772 NSLog(@"SDL: QZ_SleepNotificationHandler() IORegisterForSystemPower failed.");
774 rls = IONotificationPortGetRunLoopSource (thePortRef);
775 CFRunLoopAddSource (CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
780 /* Try to map Quartz mouse buttons to SDL's lingo... */
781 static int QZ_OtherMouseButtonToSDL(int button)
786 return(SDL_BUTTON_LEFT); /* 1 */
788 return(SDL_BUTTON_RIGHT); /* 3 */
790 return(SDL_BUTTON_MIDDLE); /* 2 */
793 /* >= 3: skip 4 & 5, since those are the SDL mousewheel buttons. */
798 void QZ_PumpEvents (_THIS)
805 NSAutoreleasePool *pool;
807 if (!SDL_VideoSurface)
808 return; /* don't do anything if there's no screen surface. */
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)
816 UpdateSystemActivity(UsrActivity);
817 screensaverTicks = nowTicks;
821 pool = [ [ NSAutoreleasePool alloc ] init ];
822 distantPast = [ NSDate distantPast ];
824 winRect = NSMakeRect (0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h);
826 /* while grabbed, accumulate all mouse moved events into one SDL mouse event */
832 /* Poll for an event. This will not block */
833 event = [ NSApp nextEventMatchingMask:NSAnyEventMask
834 untilDate:distantPast
835 inMode: NSDefaultRunLoopMode dequeue:YES ];
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; \
847 [ NSApp sendEvent:event ]; \
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); \
855 [ NSApp sendEvent:event ]; \
858 type = [ event type ];
859 isInGameWin = QZ_IsMouseInWindow (this);
861 QZ_DoModifiers(this, [ event modifierFlags ] );
864 case NSLeftMouseDown:
865 if ( SDL_getenv("SDL_HAS3BUTTONMOUSE") ) {
866 DO_MOUSE_DOWN (SDL_BUTTON_LEFT);
868 if ( NSCommandKeyMask & current_mods ) {
869 last_virtual_button = SDL_BUTTON_RIGHT;
870 DO_MOUSE_DOWN (SDL_BUTTON_RIGHT);
872 else if ( NSAlternateKeyMask & current_mods ) {
873 last_virtual_button = SDL_BUTTON_MIDDLE;
874 DO_MOUSE_DOWN (SDL_BUTTON_MIDDLE);
877 DO_MOUSE_DOWN (SDL_BUTTON_LEFT);
883 if ( last_virtual_button != 0 ) {
884 DO_MOUSE_UP (last_virtual_button);
885 last_virtual_button = 0;
888 DO_MOUSE_UP (SDL_BUTTON_LEFT);
892 case NSOtherMouseDown:
893 case NSRightMouseDown:
894 button = QZ_OtherMouseButtonToSDL([ event buttonNumber ]);
895 DO_MOUSE_DOWN (button);
900 button = QZ_OtherMouseButtonToSDL([ event buttonNumber ]);
901 DO_MOUSE_UP (button);
904 case NSSystemDefined:
906 Future: up to 32 "mouse" buttons can be handled.
907 if ([event subtype] == 7) {
908 unsigned int buttons;
909 buttons = [ event data2 ];
912 case NSLeftMouseDragged:
913 case NSRightMouseDragged:
914 case NSOtherMouseDragged: /* usually middle mouse dragged */
916 if ( grab_state == QZ_INVISIBLE_GRAB ) {
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.
924 CGGetLastMouseDelta (&dx1, &dy1);
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.
942 QZ_GetMouseLocation (this, &p);
943 SDL_PrivateMouseMotion (0, 0, p.x, p.y);
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).
951 if ( grab_state == QZ_VISIBLE_GRAB && !isInGameWin ) {
954 QZ_GetMouseLocation (this, &p);
962 if ( p.x >= winRect.size.width )
963 p.x = winRect.size.width-1;
965 if ( p.y >= winRect.size.height )
966 p.y = winRect.size.height-1;
968 QZ_PrivateWarpCursor (this, p.x, p.y);
971 if ( !isInGameWin && (SDL_GetAppState() & SDL_APPMOUSEFOCUS) ) {
973 SDL_PrivateAppActive (0, SDL_APPMOUSEFOCUS);
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);
991 QZ_UpdateCursor(this);
994 if ( isInGameWin && (SDL_GetAppState() & (SDL_APPMOUSEFOCUS | SDL_APPINPUTFOCUS)) == SDL_APPINPUTFOCUS ) {
996 SDL_PrivateAppActive (1, SDL_APPMOUSEFOCUS);
998 QZ_UpdateCursor(this);
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);
1007 if ( isInGameWin ) {
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;
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);
1024 QZ_DoKey (this, SDL_RELEASED, event);
1027 QZ_DoKey (this, SDL_PRESSED, event);
1029 case NSFlagsChanged:
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 ];
1041 /* case NSApplicationDefined: break; */
1042 /* case NSPeriodic: break; */
1043 /* case NSCursorUpdate: break; */
1045 [ NSApp sendEvent:event ];
1048 } while (event != nil);
1050 /* handle accumulated mouse moved events */
1051 if (dx != 0 || dy != 0)
1052 SDL_PrivateMouseMotion (0, 1, dx, dy);
1057 void QZ_UpdateMouse (_THIS)
1060 QZ_GetMouseLocation (this, &p);
1061 SDL_PrivateAppActive (QZ_IsMouseInWindow (this), SDL_APPMOUSEFOCUS);
1062 SDL_PrivateMouseMotion (0, 0, p.x, p.y);