2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2009 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 /* Get a pointer to the systems cached KCHR */
216 KCHRPtr = (void *)GetScriptManagerVariable(smKCHRCache);
219 /* Loop over all 127 possible scan codes */
220 for (i = 0; i < 0x7F; i++)
222 /* We pretend a clean start to begin with (i.e. no dead keys active */
225 /* Now translate the key code to a key value */
226 value = KeyTranslate(KCHRPtr, i, &state) & 0xff;
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 */
231 value = KeyTranslate(KCHRPtr, i, &state) & 0xff;
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_* */
236 else if (value >= 32) /* non-control ASCII char */
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
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;
268 static void QZ_DoKey (_THIS, int state, NSEvent *event) {
270 NSString *chars = NULL;
271 unsigned int i, numChars;
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
282 if (SDL_TranslateUNICODE && state == SDL_PRESSED) {
283 [field_edit interpretKeyEvents:[NSArray arrayWithObject:event]];
284 chars = [ event characters ];
285 numChars = [ chars length ];
287 [field_edit setString:@""];
294 key.scancode = [ event keyCode ];
295 key.sym = keymap [ key.scancode ];
299 SDL_PrivateKeyboard (state, &key);
301 else if (numChars >= 1) {
303 key.scancode = [ event keyCode ];
304 key.sym = keymap [ key.scancode ];
305 key.unicode = [ chars characterAtIndex:0 ];
308 SDL_PrivateKeyboard (state, &key);
310 for (i = 1; i < numChars; i++) {
314 key.unicode = [ chars characterAtIndex:i];
317 SDL_PrivateKeyboard (state, &key);
321 if (SDL_getenv ("SDL_ENABLEAPPEVENTS"))
322 [ NSApp sendEvent:event ];
325 /* This is the original behavior, before support was added for
326 * differentiating between left and right versions of the keys.
328 static void QZ_DoUnsidedModifiers (_THIS, unsigned int newMods) {
330 const int mapping[] = { SDLK_CAPSLOCK, SDLK_LSHIFT, SDLK_LCTRL, SDLK_LALT, SDLK_LMETA };
337 key.sym = SDLK_UNKNOWN;
341 /* Iterate through the bits, testing each against the current modifiers */
342 for (i = 0, bit = NSAlphaShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) {
344 unsigned int currentMask, newMask;
346 currentMask = current_mods & bit;
347 newMask = newMods & bit;
350 currentMask != newMask ) { /* modifier up event */
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);
359 currentMask != newMask ) { /* modifier down event */
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);
370 /* This is a helper function for QZ_HandleModifierSide. This
371 * function reverts back to behavior before the distinction between
374 static void QZ_HandleNonDeviceModifier ( _THIS, unsigned int device_independent_mask, unsigned int newMods, unsigned int key_sym) {
375 unsigned int currentMask, newMask;
383 /* Isolate just the bits we care about in the depedent bits so we can
384 * figure out what changed
386 currentMask = current_mods & device_independent_mask;
387 newMask = newMods & device_independent_mask;
390 currentMask != newMask ) { /* modifier up event */
391 SDL_PrivateKeyboard (SDL_RELEASED, &key);
394 currentMask != newMask ) { /* modifier down event */
395 SDL_PrivateKeyboard (SDL_PRESSED, &key);
399 /* This is a helper function for QZ_HandleModifierSide.
400 * This function sets the actual SDL_PrivateKeyboard event.
402 static void QZ_HandleModifierOneSide ( _THIS, unsigned int newMods,
403 unsigned int key_sym,
404 unsigned int sided_device_dependent_mask ) {
407 unsigned int current_dep_mask, new_dep_mask;
414 /* Isolate just the bits we care about in the depedent bits so we can
415 * figure out what changed
417 current_dep_mask = current_mods & sided_device_dependent_mask;
418 new_dep_mask = newMods & sided_device_dependent_mask;
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.
425 current_dep_mask != new_dep_mask ) {
426 /* Modifier down event */
427 SDL_PrivateKeyboard (SDL_PRESSED, &key);
429 else /* Modifier up event */ {
430 SDL_PrivateKeyboard (SDL_RELEASED, &key);
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.
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;
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.
452 if ( (device_dependent_mask & newMods) == 0 ) {
453 /* Revert to the old behavior */
454 QZ_HandleNonDeviceModifier ( this, device_independent_mask, newMods, left_key_sym );
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);
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.
467 if ( left_device_dependent_mask & diff_mod ) {
468 QZ_HandleModifierOneSide ( this, newMods, left_key_sym, left_device_dependent_mask );
470 if ( right_device_dependent_mask & diff_mod ) {
471 QZ_HandleModifierOneSide ( this, newMods, right_key_sym, right_device_dependent_mask );
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).
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;
492 key.sym = SDLK_UNKNOWN;
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.
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.
505 key.sym = left_key_sym;
506 SDL_PrivateKeyboard (SDL_RELEASED, &key);
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.
518 if ( left_device_dependent_mask & current_mods ) {
519 key.sym = left_key_sym;
520 SDL_PrivateKeyboard (SDL_RELEASED, &key);
522 if ( right_device_dependent_mask & current_mods ) {
523 key.sym = right_key_sym;
524 SDL_PrivateKeyboard (SDL_RELEASED, &key);
528 /* This is a helper function for QZ_DoSidedModifiers.
529 * This function handles the CapsLock case.
531 static void QZ_HandleCapsLock (_THIS, unsigned int newMods) {
532 unsigned int currentMask, newMask;
536 key.sym = SDLK_CAPSLOCK;
540 currentMask = current_mods & NSAlphaShiftKeyMask;
541 newMask = newMods & NSAlphaShiftKeyMask;
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);
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);
557 /* This function will handle the modifier keys and also determine the
558 * correct side of the key.
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
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 };
573 /* Handle CAPSLOCK separately because it doesn't have a left/right side */
574 QZ_HandleCapsLock ( this, newMods );
576 /* Iterate through the bits, testing each against the current modifiers */
577 for (i = 0, bit = NSShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) {
579 unsigned int currentMask, newMask;
581 currentMask = current_mods & bit;
582 newMask = newMods & bit;
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.
588 QZ_HandleModifierSide ( this, bit, newMods,
591 left_device_mapping[i],
592 right_device_mapping[i] );
594 /* If the state changed from pressed to unpressed, we must examine
595 * the device dependent bits to release the correct keys.
597 else if ( currentMask &&
598 currentMask != newMask ) { /* modifier up event */
599 QZ_ReleaseModifierSide ( this, bit, newMods,
602 left_device_mapping[i],
603 right_device_mapping[i] );
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.
614 static void QZ_DoModifiers (_THIS, unsigned int newMods) {
616 if (current_mods == newMods)
620 * Starting with Panther (10.3.0), the ability to distinguish between
621 * left side and right side modifiers is available.
623 if( system_version >= 0x1030 ) {
624 QZ_DoSidedModifiers (this, newMods);
627 QZ_DoUnsidedModifiers (this, newMods);
630 current_mods = newMods;
633 static void QZ_GetMouseLocation (_THIS, NSPoint *p) {
634 *p = [ NSEvent mouseLocation ]; /* global coordinates */
636 QZ_PrivateGlobalToLocal (this, p);
637 QZ_PrivateCocoaToSDL (this, p);
640 void QZ_DoActivate (_THIS) {
642 SDL_PrivateAppActive (1, SDL_APPINPUTFOCUS | (QZ_IsMouseInWindow (this) ? SDL_APPMOUSEFOCUS : 0));
644 QZ_UpdateCursor(this);
646 /* Regrab input, only if it was previously grabbed */
647 if ( current_grab_mode == SDL_GRAB_ON ) {
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);
654 /* Update SDL's mouse location */
656 QZ_GetMouseLocation (this, &p);
657 SDL_PrivateMouseMotion (0, 0, p.x, p.y);
661 void QZ_DoDeactivate (_THIS) {
663 SDL_PrivateAppActive (0, SDL_APPINPUTFOCUS | SDL_APPMOUSEFOCUS);
665 /* Get the current cursor location, for restore on activate */
666 QZ_GetMouseLocation (this, &cursor_loc);
668 /* Reassociate mouse and cursor */
669 CGAssociateMouseAndMouseCursorPosition (1);
671 QZ_UpdateCursor(this);
674 void QZ_SleepNotificationHandler (void * refcon,
675 io_service_t service,
676 natural_t messageType,
677 void * messageArgument )
679 SDL_VideoDevice *this = (SDL_VideoDevice*)refcon;
683 case kIOMessageSystemWillSleep:
684 IOAllowPowerChange(power_connection, (long) messageArgument);
686 case kIOMessageCanSystemSleep:
687 IOAllowPowerChange(power_connection, (long) messageArgument);
689 case kIOMessageSystemHasPoweredOn:
696 void QZ_RegisterForSleepNotifications (_THIS)
698 CFRunLoopSourceRef rls;
699 IONotificationPortRef thePortRef;
700 io_object_t notifier;
702 power_connection = IORegisterForSystemPower (this, &thePortRef, QZ_SleepNotificationHandler, ¬ifier);
704 if (power_connection == 0)
705 NSLog(@"SDL: QZ_SleepNotificationHandler() IORegisterForSystemPower failed.");
707 rls = IONotificationPortGetRunLoopSource (thePortRef);
708 CFRunLoopAddSource (CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
713 /* Try to map Quartz mouse buttons to SDL's lingo... */
714 static int QZ_OtherMouseButtonToSDL(int button)
719 return(SDL_BUTTON_LEFT); /* 1 */
721 return(SDL_BUTTON_RIGHT); /* 3 */
723 return(SDL_BUTTON_MIDDLE); /* 2 */
726 /* >= 3: skip 4 & 5, since those are the SDL mousewheel buttons. */
731 void QZ_PumpEvents (_THIS)
738 NSAutoreleasePool *pool;
740 if (!SDL_VideoSurface)
741 return; /* don't do anything if there's no screen surface. */
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)
749 UpdateSystemActivity(UsrActivity);
750 screensaverTicks = nowTicks;
754 pool = [ [ NSAutoreleasePool alloc ] init ];
755 distantPast = [ NSDate distantPast ];
757 winRect = NSMakeRect (0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h);
759 /* while grabbed, accumulate all mouse moved events into one SDL mouse event */
765 /* Poll for an event. This will not block */
766 event = [ NSApp nextEventMatchingMask:NSAnyEventMask
767 untilDate:distantPast
768 inMode: NSDefaultRunLoopMode dequeue:YES ];
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; \
780 [ NSApp sendEvent:event ]; \
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); \
788 [ NSApp sendEvent:event ]; \
791 type = [ event type ];
792 isInGameWin = QZ_IsMouseInWindow (this);
794 QZ_DoModifiers(this, [ event modifierFlags ] );
797 case NSLeftMouseDown:
798 if ( SDL_getenv("SDL_HAS3BUTTONMOUSE") ) {
799 DO_MOUSE_DOWN (SDL_BUTTON_LEFT);
801 if ( NSCommandKeyMask & current_mods ) {
802 last_virtual_button = SDL_BUTTON_RIGHT;
803 DO_MOUSE_DOWN (SDL_BUTTON_RIGHT);
805 else if ( NSAlternateKeyMask & current_mods ) {
806 last_virtual_button = SDL_BUTTON_MIDDLE;
807 DO_MOUSE_DOWN (SDL_BUTTON_MIDDLE);
810 DO_MOUSE_DOWN (SDL_BUTTON_LEFT);
816 if ( last_virtual_button != 0 ) {
817 DO_MOUSE_UP (last_virtual_button);
818 last_virtual_button = 0;
821 DO_MOUSE_UP (SDL_BUTTON_LEFT);
825 case NSOtherMouseDown:
826 case NSRightMouseDown:
827 button = QZ_OtherMouseButtonToSDL([ event buttonNumber ]);
828 DO_MOUSE_DOWN (button);
833 button = QZ_OtherMouseButtonToSDL([ event buttonNumber ]);
834 DO_MOUSE_UP (button);
837 case NSSystemDefined:
839 Future: up to 32 "mouse" buttons can be handled.
840 if ([event subtype] == 7) {
841 unsigned int buttons;
842 buttons = [ event data2 ];
845 case NSLeftMouseDragged:
846 case NSRightMouseDragged:
847 case NSOtherMouseDragged: /* usually middle mouse dragged */
849 if ( grab_state == QZ_INVISIBLE_GRAB ) {
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.
856 CGMouseDelta dx1, dy1;
857 CGGetLastMouseDelta (&dx1, &dy1);
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.
875 QZ_GetMouseLocation (this, &p);
876 SDL_PrivateMouseMotion (0, 0, p.x, p.y);
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).
884 if ( grab_state == QZ_VISIBLE_GRAB && !isInGameWin ) {
887 QZ_GetMouseLocation (this, &p);
895 if ( p.x >= winRect.size.width )
896 p.x = winRect.size.width-1;
898 if ( p.y >= winRect.size.height )
899 p.y = winRect.size.height-1;
901 QZ_PrivateWarpCursor (this, p.x, p.y);
904 if ( !isInGameWin && (SDL_GetAppState() & SDL_APPMOUSEFOCUS) ) {
906 SDL_PrivateAppActive (0, SDL_APPMOUSEFOCUS);
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);
924 QZ_UpdateCursor(this);
927 if ( isInGameWin && (SDL_GetAppState() & (SDL_APPMOUSEFOCUS | SDL_APPINPUTFOCUS)) == SDL_APPINPUTFOCUS ) {
929 SDL_PrivateAppActive (1, SDL_APPMOUSEFOCUS);
931 QZ_UpdateCursor(this);
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);
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;
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);
957 QZ_DoKey (this, SDL_RELEASED, event);
960 QZ_DoKey (this, SDL_PRESSED, event);
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 ];
974 /* case NSApplicationDefined: break; */
975 /* case NSPeriodic: break; */
976 /* case NSCursorUpdate: break; */
978 [ NSApp sendEvent:event ];
981 } while (event != nil);
983 /* handle accumulated mouse moved events */
984 if (dx != 0 || dy != 0)
985 SDL_PrivateMouseMotion (0, 1, dx, dy);
990 void QZ_UpdateMouse (_THIS)
993 QZ_GetMouseLocation (this, &p);
994 SDL_PrivateAppActive (QZ_IsMouseInWindow (this), SDL_APPMOUSEFOCUS);
995 SDL_PrivateMouseMotion (0, 0, p.x, p.y);