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