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