comparison src/video/quartz/SDL_QuartzEvents.m @ 934:af585d6efec8

Date: Thu, 17 Jun 2004 11:38:51 -0700 (PDT) From: Eric Wing <ewing2121@yahoo.com> Subject: New OS X patch (was Re: [SDL] Bug with inverted mouse coordinates in I have a new patch for OS X I would like to submit. First, it appears no further action has been taken on my fix from Apple on the OpenGL windowed mode mouse inversion problem. The fix would reunify the code, and no longer require case checking for which version of the OS you are running. This is probably a good fix because the behavior with the old code could change again with future versions of the OS, so those fixes are included in this new patch. But in addition, when I was at Apple, I asked them about the ability to distinguish between the modifier keys on the left and right sides of the keyboard (e.g. Left Shift, Right Shift, Left/Right Alt, L/R Cmd, L/R Ctrl). They told me that starting with Panther, the OS began supporting this feature. This has always been a source of annoyance for me when bringing a program that comes from Windows or Linux to OS X when the keybindings happened to need distinguishable left-side and right-side keys. So the rest of the patch I am submitting contains new code to support this feature on Panther (and presumably later versions of the OS). So after removing the OS version checks for the mouse inversion problem, I reused the OS version checks to activate the Left/Right detection of modifier keys. If you are running Panther (or above), the new code will attempt to distinguish between sides. For the older OS's, the code path reverts to the original code. I've tested with Panther on a G4 Cube, G5 dual processor, and Powerbook Rev C. The Cube and G5 keyboards demonstrated the ability to distinguish between sides. The Powerbook seems to only have left-side keys, but the patch was still able to handle it by producing the same results as before the patch. I also wanted to test a non-Apple keyboard. Unfortunately, I don't have any PC USB keyboards. However, I was able to borrow a Sun Microsystems USB keyboard, so I tried that out on the G5, and I got the correct behavior for left and right sides. I'm expecting that if it worked with a Sun keyboard, most other keyboards should work with no problems.
author Sam Lantinga <slouken@libsdl.org>
date Fri, 20 Aug 2004 22:35:23 +0000
parents f221cadd6eda
children 8e1815fd9777
comparison
equal deleted inserted replaced
933:4272450dd8d0 934:af585d6efec8
24 24
25 #include <stdlib.h> // For getenv() 25 #include <stdlib.h> // For getenv()
26 #include <IOKit/IOMessage.h> // For wake from sleep detection 26 #include <IOKit/IOMessage.h> // For wake from sleep detection
27 #include <IOKit/pwr_mgt/IOPMLib.h> // For wake from sleep detection 27 #include <IOKit/pwr_mgt/IOPMLib.h> // For wake from sleep detection
28 #include "SDL_QuartzKeys.h" 28 #include "SDL_QuartzKeys.h"
29
30 /*
31 * In Panther, this header defines device dependent masks for
32 * right side keys. These definitions only exist in Panther, but
33 * the header seems to exist at least in Jaguar and probably earlier
34 * versions of the OS, so this should't break anything.
35 */
36 #include <IOKit/hidsystem/IOLLEvent.h>
37 /*
38 * These are not defined before Panther. To keep the code compiling
39 * on systems without these, I will define if they don't exist.
40 */
41 #ifndef NX_DEVICERCTLKEYMASK
42 #define NX_DEVICELCTLKEYMASK 0x00000001
43 #endif
44 #ifndef NX_DEVICELSHIFTKEYMASK
45 #define NX_DEVICELSHIFTKEYMASK 0x00000002
46 #endif
47 #ifndef NX_DEVICERSHIFTKEYMASK
48 #define NX_DEVICERSHIFTKEYMASK 0x00000004
49 #endif
50 #ifndef NX_DEVICELCMDKEYMASK
51 #define NX_DEVICELCMDKEYMASK 0x00000008
52 #endif
53 #ifndef NX_DEVICERCMDKEYMASK
54 #define NX_DEVICERCMDKEYMASK 0x00000010
55 #endif
56 #ifndef NX_DEVICELALTKEYMASK
57 #define NX_DEVICELALTKEYMASK 0x00000020
58 #endif
59 #ifndef NX_DEVICERALTKEYMASK
60 #define NX_DEVICERALTKEYMASK 0x00000040
61 #endif
62 #ifndef NX_DEVICERCTLKEYMASK
63 #define NX_DEVICERCTLKEYMASK 0x00002000
64 #endif
29 65
30 void QZ_InitOSKeymap (_THIS) { 66 void QZ_InitOSKeymap (_THIS) {
31 const void *KCHRPtr; 67 const void *KCHRPtr;
32 UInt32 state; 68 UInt32 state;
33 UInt32 value; 69 UInt32 value;
113 keymap[QZ_KP4] = SDLK_KP4; 149 keymap[QZ_KP4] = SDLK_KP4;
114 keymap[QZ_KP5] = SDLK_KP5; 150 keymap[QZ_KP5] = SDLK_KP5;
115 keymap[QZ_KP6] = SDLK_KP6; 151 keymap[QZ_KP6] = SDLK_KP6;
116 keymap[QZ_KP_PLUS] = SDLK_KP_PLUS; 152 keymap[QZ_KP_PLUS] = SDLK_KP_PLUS;
117 keymap[QZ_LSHIFT] = SDLK_LSHIFT; 153 keymap[QZ_LSHIFT] = SDLK_LSHIFT;
154 keymap[QZ_RSHIFT] = SDLK_RSHIFT;
118 keymap[QZ_z] = SDLK_z; 155 keymap[QZ_z] = SDLK_z;
119 keymap[QZ_x] = SDLK_x; 156 keymap[QZ_x] = SDLK_x;
120 keymap[QZ_c] = SDLK_c; 157 keymap[QZ_c] = SDLK_c;
121 keymap[QZ_v] = SDLK_v; 158 keymap[QZ_v] = SDLK_v;
122 keymap[QZ_b] = SDLK_b; 159 keymap[QZ_b] = SDLK_b;
131 keymap[QZ_KP3] = SDLK_KP3; 168 keymap[QZ_KP3] = SDLK_KP3;
132 keymap[QZ_KP_ENTER] = SDLK_KP_ENTER; 169 keymap[QZ_KP_ENTER] = SDLK_KP_ENTER;
133 keymap[QZ_LCTRL] = SDLK_LCTRL; 170 keymap[QZ_LCTRL] = SDLK_LCTRL;
134 keymap[QZ_LALT] = SDLK_LALT; 171 keymap[QZ_LALT] = SDLK_LALT;
135 keymap[QZ_LMETA] = SDLK_LMETA; 172 keymap[QZ_LMETA] = SDLK_LMETA;
173 keymap[QZ_RCTRL] = SDLK_RCTRL;
174 keymap[QZ_RALT] = SDLK_RALT;
175 keymap[QZ_RMETA] = SDLK_RMETA;
136 keymap[QZ_SPACE] = SDLK_SPACE; 176 keymap[QZ_SPACE] = SDLK_SPACE;
137 keymap[QZ_LEFT] = SDLK_LEFT; 177 keymap[QZ_LEFT] = SDLK_LEFT;
138 keymap[QZ_DOWN] = SDLK_DOWN; 178 keymap[QZ_DOWN] = SDLK_DOWN;
139 keymap[QZ_RIGHT] = SDLK_RIGHT; 179 keymap[QZ_RIGHT] = SDLK_RIGHT;
140 keymap[QZ_KP0] = SDLK_KP0; 180 keymap[QZ_KP0] = SDLK_KP0;
257 297
258 if (getenv ("SDL_ENABLEAPPEVENTS")) 298 if (getenv ("SDL_ENABLEAPPEVENTS"))
259 [ NSApp sendEvent:event ]; 299 [ NSApp sendEvent:event ];
260 } 300 }
261 301
262 static void QZ_DoModifiers (_THIS, unsigned int newMods) { 302 /* This is the original behavior, before support was added for
303 * differentiating between left and right versions of the keys.
304 */
305 static void QZ_DoUnsidedModifiers (_THIS, unsigned int newMods) {
263 306
264 const int mapping[] = { SDLK_CAPSLOCK, SDLK_LSHIFT, SDLK_LCTRL, SDLK_LALT, SDLK_LMETA }; 307 const int mapping[] = { SDLK_CAPSLOCK, SDLK_LSHIFT, SDLK_LCTRL, SDLK_LALT, SDLK_LMETA };
265 308
266 int i; 309 int i;
267 int bit; 310 int bit;
268 SDL_keysym key; 311 SDL_keysym key;
269 312
270 if (current_mods == newMods)
271 return;
272
273 key.scancode = 0; 313 key.scancode = 0;
274 key.sym = SDLK_UNKNOWN; 314 key.sym = SDLK_UNKNOWN;
275 key.unicode = 0; 315 key.unicode = 0;
276 key.mod = KMOD_NONE; 316 key.mod = KMOD_NONE;
277 317
300 /* If this was Caps Lock, we need some additional voodoo to make SDL happy */ 340 /* If this was Caps Lock, we need some additional voodoo to make SDL happy */
301 if (bit == NSAlphaShiftKeyMask) 341 if (bit == NSAlphaShiftKeyMask)
302 SDL_PrivateKeyboard (SDL_RELEASED, &key); 342 SDL_PrivateKeyboard (SDL_RELEASED, &key);
303 } 343 }
304 } 344 }
305 345 }
346
347 /* This is a helper function for QZ_HandleModifierSide. This
348 * function reverts back to behavior before the distinction between
349 * sides was made.
350 */
351 static void QZ_HandleNonDeviceModifier ( _THIS, unsigned int device_independent_mask, unsigned int newMods, unsigned int key_sym) {
352 unsigned int currentMask, newMask;
353 SDL_keysym key;
354
355 key.scancode = 0;
356 key.sym = key_sym;
357 key.unicode = 0;
358 key.mod = KMOD_NONE;
359
360 /* Isolate just the bits we care about in the depedent bits so we can
361 * figure out what changed
362 */
363 currentMask = current_mods & device_independent_mask;
364 newMask = newMods & device_independent_mask;
365
366 if ( currentMask &&
367 currentMask != newMask ) { /* modifier up event */
368 SDL_PrivateKeyboard (SDL_RELEASED, &key);
369 }
370 else if ( newMask &&
371 currentMask != newMask ) { /* modifier down event */
372 SDL_PrivateKeyboard (SDL_PRESSED, &key);
373 }
374 }
375
376 /* This is a helper function for QZ_HandleModifierSide.
377 * This function sets the actual SDL_PrivateKeyboard event.
378 */
379 static void QZ_HandleModifierOneSide ( _THIS, unsigned int newMods,
380 unsigned int key_sym,
381 unsigned int sided_device_dependent_mask ) {
382
383 SDL_keysym key;
384 unsigned int current_dep_mask, new_dep_mask;
385
386 key.scancode = 0;
387 key.sym = key_sym;
388 key.unicode = 0;
389 key.mod = KMOD_NONE;
390
391 /* Isolate just the bits we care about in the depedent bits so we can
392 * figure out what changed
393 */
394 current_dep_mask = current_mods & sided_device_dependent_mask;
395 new_dep_mask = newMods & sided_device_dependent_mask;
396
397 /* We now know that this side bit flipped. But we don't know if
398 * it went pressed to released or released to pressed, so we must
399 * find out which it is.
400 */
401 if( new_dep_mask &&
402 current_dep_mask != new_dep_mask ) {
403 /* Modifier down event */
404 SDL_PrivateKeyboard (SDL_PRESSED, &key);
405 }
406 else /* Modifier up event */ {
407 SDL_PrivateKeyboard (SDL_RELEASED, &key);
408 }
409 }
410
411 /* This is a helper function for QZ_DoSidedModifiers.
412 * This function will figure out if the modifier key is the left or right side,
413 * e.g. left-shift vs right-shift.
414 */
415 static void QZ_HandleModifierSide ( _THIS, int device_independent_mask,
416 unsigned int newMods,
417 unsigned int left_key_sym,
418 unsigned int right_key_sym,
419 unsigned int left_device_dependent_mask,
420 unsigned int right_device_dependent_mask ) {
421 unsigned int device_dependent_mask = 0;
422 unsigned int diff_mod = 0;
423
424 device_dependent_mask = left_device_dependent_mask | right_device_dependent_mask;
425 /* On the basis that the device independent mask is set, but there are
426 * no device dependent flags set, we'll assume that we can't detect this
427 * keyboard and revert to the unsided behavior.
428 */
429 if ( (device_dependent_mask & newMods) == 0 ) {
430 /* Revert to the old behavior */
431 QZ_HandleNonDeviceModifier ( this, device_independent_mask, newMods, left_key_sym );
432 return;
433 }
434
435 /* XOR the previous state against the new state to see if there's a change */
436 diff_mod = (device_dependent_mask & current_mods)
437 ^ (device_dependent_mask & newMods);
438
439 if ( diff_mod ) {
440 /* A change in state was found. Isolate the left and right bits
441 * to handle them separately just in case the values can simulataneously
442 * change or if the bits don't both exist.
443 */
444 if ( left_device_dependent_mask & diff_mod ) {
445 QZ_HandleModifierOneSide ( this, newMods, left_key_sym, left_device_dependent_mask );
446 }
447 if ( right_device_dependent_mask & diff_mod ) {
448 QZ_HandleModifierOneSide ( this, newMods, right_key_sym, right_device_dependent_mask );
449 }
450 }
451 }
452
453 /* This is a helper function for QZ_DoSidedModifiers.
454 * This function will release a key press in the case that
455 * it is clear that the modifier has been released (i.e. one side
456 * can't still be down).
457 */
458 static void QZ_ReleaseModifierSide ( _THIS,
459 unsigned int device_independent_mask,
460 unsigned int newMods,
461 unsigned int left_key_sym,
462 unsigned int right_key_sym,
463 unsigned int left_device_dependent_mask,
464 unsigned int right_device_dependent_mask ) {
465 unsigned int device_dependent_mask = 0;
466 SDL_keysym key;
467
468 key.scancode = 0;
469 key.sym = SDLK_UNKNOWN;
470 key.unicode = 0;
471 key.mod = KMOD_NONE;
472
473 device_dependent_mask = left_device_dependent_mask | right_device_dependent_mask;
474 /* On the basis that the device independent mask is set, but there are
475 * no device dependent flags set, we'll assume that we can't detect this
476 * keyboard and revert to the unsided behavior.
477 */
478 if ( (device_dependent_mask & current_mods) == 0 ) {
479 /* In this case, we can't detect the keyboard, so use the left side
480 * to represent both, and release it.
481 */
482 key.sym = left_key_sym;
483 SDL_PrivateKeyboard (SDL_RELEASED, &key);
484
485 return;
486 }
487
488
489 /*
490 * This could have been done in an if-else case because at this point,
491 * we know that all keys have been released when calling this function.
492 * But I'm being paranoid so I want to handle each separately,
493 * so I hope this doesn't cause other problems.
494 */
495 if ( left_device_dependent_mask & current_mods ) {
496 key.sym = left_key_sym;
497 SDL_PrivateKeyboard (SDL_RELEASED, &key);
498 }
499 if ( right_device_dependent_mask & current_mods ) {
500 key.sym = right_key_sym;
501 SDL_PrivateKeyboard (SDL_RELEASED, &key);
502 }
503 }
504
505 /* This is a helper function for QZ_DoSidedModifiers.
506 * This function handles the CapsLock case.
507 */
508 static void QZ_HandleCapsLock (_THIS, unsigned int newMods) {
509 unsigned int currentMask, newMask;
510 SDL_keysym key;
511
512 key.scancode = 0;
513 key.sym = SDLK_CAPSLOCK;
514 key.unicode = 0;
515 key.mod = KMOD_NONE;
516
517 currentMask = current_mods & NSAlphaShiftKeyMask;
518 newMask = newMods & NSAlphaShiftKeyMask;
519
520 if ( currentMask &&
521 currentMask != newMask ) { /* modifier up event */
522 /* If this was Caps Lock, we need some additional voodoo to make SDL happy */
523 SDL_PrivateKeyboard (SDL_PRESSED, &key);
524 SDL_PrivateKeyboard (SDL_RELEASED, &key);
525 }
526 else if ( newMask &&
527 currentMask != newMask ) { /* modifier down event */
528 /* If this was Caps Lock, we need some additional voodoo to make SDL happy */
529 SDL_PrivateKeyboard (SDL_PRESSED, &key);
530 SDL_PrivateKeyboard (SDL_RELEASED, &key);
531 }
532 }
533
534 /* This function will handle the modifier keys and also determine the
535 * correct side of the key.
536 */
537 static void QZ_DoSidedModifiers (_THIS, unsigned int newMods) {
538 /* Set up arrays for the key syms for the left and right side. */
539 const unsigned int left_mapping[] = { SDLK_LSHIFT, SDLK_LCTRL, SDLK_LALT, SDLK_LMETA };
540 const unsigned int right_mapping[] = { SDLK_RSHIFT, SDLK_RCTRL, SDLK_RALT, SDLK_RMETA };
541 /* Set up arrays for the device dependent masks with indices that
542 * correspond to the _mapping arrays
543 */
544 const unsigned int left_device_mapping[] = { NX_DEVICELSHIFTKEYMASK, NX_DEVICELCTLKEYMASK, NX_DEVICELALTKEYMASK, NX_DEVICELCMDKEYMASK };
545 const unsigned int right_device_mapping[] = { NX_DEVICERSHIFTKEYMASK, NX_DEVICERCTLKEYMASK, NX_DEVICERALTKEYMASK, NX_DEVICERCMDKEYMASK };
546
547 unsigned int i;
548 unsigned int bit;
549
550 /* Handle CAPSLOCK separately because it doesn't have a left/right side */
551 QZ_HandleCapsLock ( this, newMods );
552
553 /* Iterate through the bits, testing each against the current modifiers */
554 for (i = 0, bit = NSShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) {
555
556 unsigned int currentMask, newMask;
557
558 currentMask = current_mods & bit;
559 newMask = newMods & bit;
560
561 /* If the bit is set, we must always examine it because the left
562 * and right side keys may alternate or both may be pressed.
563 */
564 if ( newMask ) {
565 QZ_HandleModifierSide ( this, bit, newMods,
566 left_mapping[i],
567 right_mapping[i],
568 left_device_mapping[i],
569 right_device_mapping[i] );
570 }
571 /* If the state changed from pressed to unpressed, we must examine
572 * the device dependent bits to release the correct keys.
573 */
574 else if ( currentMask &&
575 currentMask != newMask ) { /* modifier up event */
576 QZ_ReleaseModifierSide ( this, bit, newMods,
577 left_mapping[i],
578 right_mapping[i],
579 left_device_mapping[i],
580 right_device_mapping[i] );
581 }
582 }
583 }
584
585 /* This function is called to handle the modifiers.
586 * It will try to distinguish between the left side and right side
587 * of the keyboard for those modifiers that qualify if the
588 * operating system version supports it. Otherwise, the code
589 * will not try to make the distinction.
590 */
591 static void QZ_DoModifiers (_THIS, unsigned int newMods) {
592
593 if (current_mods == newMods)
594 return;
595
596 /*
597 * Starting with Panther (10.3.0), the ability to distinguish between
598 * left side and right side modifiers is available.
599 */
600 if( system_version >= 0x1030 ) {
601 QZ_DoSidedModifiers (this, newMods);
602 }
603 else {
604 QZ_DoUnsidedModifiers (this, newMods);
605 }
606
306 current_mods = newMods; 607 current_mods = newMods;
307 } 608 }
308 609
309 static void QZ_GetMouseLocation (_THIS, NSPoint *p) { 610 static void QZ_GetMouseLocation (_THIS, NSPoint *p) {
310 *p = [ NSEvent mouseLocation ]; /* global coordinates */ 611 *p = [ NSEvent mouseLocation ]; /* global coordinates */