1/* 2 SDL - Simple DirectMedia Layer 3 Copyright (C) 1997-2012 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 BOOL saw_layout = NO; 82 UInt32 state; 83 UInt32 value; 84 Uint16 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#if (MAC_OS_X_VERSION_MAX_ALLOWED >= 1050) 216 if (TISCopyCurrentKeyboardLayoutInputSource != NULL) { 217 TISInputSourceRef src = TISCopyCurrentKeyboardLayoutInputSource(); 218 if (src != NULL) { 219 CFDataRef data = (CFDataRef) 220 TISGetInputSourceProperty(src, 221 kTISPropertyUnicodeKeyLayoutData); 222 if (data != NULL) { 223 const UCKeyboardLayout *layout = (const UCKeyboardLayout *) 224 CFDataGetBytePtr(data); 225 if (layout != NULL) { 226 const UInt32 kbdtype = LMGetKbdType(); 227 saw_layout = YES; 228 229 /* Loop over all 127 possible scan codes */ 230 for (i = 0; i < 0x7F; i++) { 231 UniChar buf[16]; 232 UniCharCount count = 0; 233 234 /* We pretend a clean start to begin with (i.e. no dead keys active */ 235 state = 0; 236 237 if (UCKeyTranslate(layout, i, kUCKeyActionDown, 0, kbdtype, 238 0, &state, 16, &count, buf) != noErr) { 239 continue; 240 } 241 242 /* If the state become 0, it was a dead key. We need to 243 translate again, passing in the new state, to get 244 the actual key value */ 245 if (state != 0) { 246 if (UCKeyTranslate(layout, i, kUCKeyActionDown, 0, kbdtype, 247 0, &state, 16, &count, buf) != noErr) { 248 continue; 249 } 250 } 251 252 if (count != 1) { 253 continue; /* no multi-char. Use SDL 1.3 instead. :) */ 254 } 255 256 value = (UInt32) buf[0]; 257 if (value >= 128) { 258 /* Some non-ASCII char, map it to SDLK_WORLD_* */ 259 if (world < 0xFF) { 260 keymap[i] = world++; 261 } 262 } else if (value >= 32) { /* non-control ASCII char */ 263 keymap[i] = value; 264 } 265 } 266 } 267 } 268 CFRelease(src); 269 } 270 } 271#endif 272 273#if (MAC_OS_X_VERSION_MIN_REQUIRED < 1050) 274 if (!saw_layout) { 275 /* Get a pointer to the systems cached KCHR */ 276 const void *KCHRPtr = (const void *)GetScriptManagerVariable(smKCHRCache); 277 if (KCHRPtr) 278 { 279 /* Loop over all 127 possible scan codes */ 280 for (i = 0; i < 0x7F; i++) 281 { 282 /* We pretend a clean start to begin with (i.e. no dead keys active */ 283 state = 0; 284 285 /* Now translate the key code to a key value */ 286 value = KeyTranslate(KCHRPtr, i, &state) & 0xff; 287 288 /* If the state become 0, it was a dead key. We need to translate again, 289 passing in the new state, to get the actual key value */ 290 if (state != 0) 291 value = KeyTranslate(KCHRPtr, i, &state) & 0xff; 292 293 /* Now we should have an ascii value, or 0. Try to figure out to which SDL symbol it maps */ 294 if (value >= 128) { /* Some non-ASCII char, map it to SDLK_WORLD_* */ 295 if (world < 0xFF) { 296 keymap[i] = world++; 297 } 298 } else if (value >= 32) { /* non-control ASCII char */ 299 keymap[i] = value; 300 } 301 } 302 } 303 } 304#endif 305 306 /* 307 The keypad codes are re-setup here, because the loop above cannot 308 distinguish between a key on the keypad and a regular key. We maybe 309 could get around this problem in another fashion: NSEvent's flags 310 include a "NSNumericPadKeyMask" bit; we could check that and modify 311 the symbol we return on the fly. However, this flag seems to exhibit 312 some weird behaviour related to the num lock key 313 */ 314 keymap[QZ_KP0] = SDLK_KP0; 315 keymap[QZ_KP1] = SDLK_KP1; 316 keymap[QZ_KP2] = SDLK_KP2; 317 keymap[QZ_KP3] = SDLK_KP3; 318 keymap[QZ_KP4] = SDLK_KP4; 319 keymap[QZ_KP5] = SDLK_KP5; 320 keymap[QZ_KP6] = SDLK_KP6; 321 keymap[QZ_KP7] = SDLK_KP7; 322 keymap[QZ_KP8] = SDLK_KP8; 323 keymap[QZ_KP9] = SDLK_KP9; 324 keymap[QZ_KP_MINUS] = SDLK_KP_MINUS; 325 keymap[QZ_KP_PLUS] = SDLK_KP_PLUS; 326 keymap[QZ_KP_PERIOD] = SDLK_KP_PERIOD; 327 keymap[QZ_KP_EQUALS] = SDLK_KP_EQUALS; 328 keymap[QZ_KP_DIVIDE] = SDLK_KP_DIVIDE; 329 keymap[QZ_KP_MULTIPLY] = SDLK_KP_MULTIPLY; 330 keymap[QZ_KP_ENTER] = SDLK_KP_ENTER; 331} 332 333static void QZ_DoKey (_THIS, int state, NSEvent *event) { 334 335 NSString *chars = NULL; 336 unsigned int i, numChars; 337 SDL_keysym key; 338 339 /* 340 A key event can contain multiple characters, 341 or no characters at all. In most cases, it 342 will contain a single character. If it contains 343 0 characters, we'll use 0 as the unicode. If it 344 contains multiple characters, we'll use 0 as 345 the scancode/keysym. 346 */ 347 if (SDL_TranslateUNICODE && state == SDL_PRESSED) { 348 [field_edit interpretKeyEvents:[NSArray arrayWithObject:event]]; 349 chars = [ event characters ]; 350 numChars = [ chars length ]; 351 if (numChars > 0) 352 [field_edit setString:@""]; 353 } else { 354 numChars = 0; 355 } 356 357 if (numChars == 0) { 358 359 key.scancode = [ event keyCode ]; 360 key.sym = keymap [ key.scancode ]; 361 key.unicode = 0; 362 key.mod = KMOD_NONE; 363 364 SDL_PrivateKeyboard (state, &key); 365 } 366 else if (numChars >= 1) { 367 368 key.scancode = [ event keyCode ]; 369 key.sym = keymap [ key.scancode ]; 370 key.unicode = [ chars characterAtIndex:0 ]; 371 key.mod = KMOD_NONE; 372 373 SDL_PrivateKeyboard (state, &key); 374 375 for (i = 1; i < numChars; i++) { 376 377 key.scancode = 0; 378 key.sym = 0; 379 key.unicode = [ chars characterAtIndex:i]; 380 key.mod = KMOD_NONE; 381 382 SDL_PrivateKeyboard (state, &key); 383 } 384 } 385 386 if (SDL_getenv ("SDL_ENABLEAPPEVENTS")) 387 [ NSApp sendEvent:event ]; 388} 389 390/* This is the original behavior, before support was added for 391 * differentiating between left and right versions of the keys. 392 */ 393static void QZ_DoUnsidedModifiers (_THIS, unsigned int newMods) { 394 395 const int mapping[] = { SDLK_CAPSLOCK, SDLK_LSHIFT, SDLK_LCTRL, SDLK_LALT, SDLK_LMETA }; 396 397 int i; 398 int bit; 399 SDL_keysym key; 400 401 key.scancode = 0; 402 key.sym = SDLK_UNKNOWN; 403 key.unicode = 0; 404 key.mod = KMOD_NONE; 405 406 /* Iterate through the bits, testing each against the current modifiers */ 407 for (i = 0, bit = NSAlphaShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) { 408 409 unsigned int currentMask, newMask; 410 411 currentMask = current_mods & bit; 412 newMask = newMods & bit; 413 414 if ( currentMask && 415 currentMask != newMask ) { /* modifier up event */ 416 417 key.sym = mapping[i]; 418 /* If this was Caps Lock, we need some additional voodoo to make SDL happy */ 419 if (bit == NSAlphaShiftKeyMask) 420 SDL_PrivateKeyboard (SDL_PRESSED, &key); 421 SDL_PrivateKeyboard (SDL_RELEASED, &key); 422 } 423 else if ( newMask && 424 currentMask != newMask ) { /* modifier down event */ 425 426 key.sym = mapping[i]; 427 SDL_PrivateKeyboard (SDL_PRESSED, &key); 428 /* If this was Caps Lock, we need some additional voodoo to make SDL happy */ 429 if (bit == NSAlphaShiftKeyMask) 430 SDL_PrivateKeyboard (SDL_RELEASED, &key); 431 } 432 } 433} 434 435/* This is a helper function for QZ_HandleModifierSide. This 436 * function reverts back to behavior before the distinction between 437 * sides was made. 438 */ 439static void QZ_HandleNonDeviceModifier ( _THIS, unsigned int device_independent_mask, unsigned int newMods, unsigned int key_sym) { 440 unsigned int currentMask, newMask; 441 SDL_keysym key; 442 443 key.scancode = 0; 444 key.sym = key_sym; 445 key.unicode = 0; 446 key.mod = KMOD_NONE; 447 448 /* Isolate just the bits we care about in the depedent bits so we can 449 * figure out what changed 450 */ 451 currentMask = current_mods & device_independent_mask; 452 newMask = newMods & device_independent_mask; 453 454 if ( currentMask && 455 currentMask != newMask ) { /* modifier up event */ 456 SDL_PrivateKeyboard (SDL_RELEASED, &key); 457 } 458 else if ( newMask && 459 currentMask != newMask ) { /* modifier down event */ 460 SDL_PrivateKeyboard (SDL_PRESSED, &key); 461 } 462} 463 464/* This is a helper function for QZ_HandleModifierSide. 465 * This function sets the actual SDL_PrivateKeyboard event. 466 */ 467static void QZ_HandleModifierOneSide ( _THIS, unsigned int newMods, 468 unsigned int key_sym, 469 unsigned int sided_device_dependent_mask ) { 470 471 SDL_keysym key; 472 unsigned int current_dep_mask, new_dep_mask; 473 474 key.scancode = 0; 475 key.sym = key_sym; 476 key.unicode = 0; 477 key.mod = KMOD_NONE; 478 479 /* Isolate just the bits we care about in the depedent bits so we can 480 * figure out what changed 481 */ 482 current_dep_mask = current_mods & sided_device_dependent_mask; 483 new_dep_mask = newMods & sided_device_dependent_mask; 484 485 /* We now know that this side bit flipped. But we don't know if 486 * it went pressed to released or released to pressed, so we must 487 * find out which it is. 488 */ 489 if( new_dep_mask && 490 current_dep_mask != new_dep_mask ) { 491 /* Modifier down event */ 492 SDL_PrivateKeyboard (SDL_PRESSED, &key); 493 } 494 else /* Modifier up event */ { 495 SDL_PrivateKeyboard (SDL_RELEASED, &key); 496 } 497} 498 499/* This is a helper function for QZ_DoSidedModifiers. 500 * This function will figure out if the modifier key is the left or right side, 501 * e.g. left-shift vs right-shift. 502 */ 503static void QZ_HandleModifierSide ( _THIS, int device_independent_mask, 504 unsigned int newMods, 505 unsigned int left_key_sym, 506 unsigned int right_key_sym, 507 unsigned int left_device_dependent_mask, 508 unsigned int right_device_dependent_mask ) { 509 unsigned int device_dependent_mask = 0; 510 unsigned int diff_mod = 0; 511 512 device_dependent_mask = left_device_dependent_mask | right_device_dependent_mask; 513 /* On the basis that the device independent mask is set, but there are 514 * no device dependent flags set, we'll assume that we can't detect this 515 * keyboard and revert to the unsided behavior. 516 */ 517 if ( (device_dependent_mask & newMods) == 0 ) { 518 /* Revert to the old behavior */ 519 QZ_HandleNonDeviceModifier ( this, device_independent_mask, newMods, left_key_sym ); 520 return; 521 } 522 523 /* XOR the previous state against the new state to see if there's a change */ 524 diff_mod = (device_dependent_mask & current_mods) 525 ^ (device_dependent_mask & newMods); 526 527 if ( diff_mod ) { 528 /* A change in state was found. Isolate the left and right bits 529 * to handle them separately just in case the values can simulataneously 530 * change or if the bits don't both exist. 531 */ 532 if ( left_device_dependent_mask & diff_mod ) { 533 QZ_HandleModifierOneSide ( this, newMods, left_key_sym, left_device_dependent_mask ); 534 } 535 if ( right_device_dependent_mask & diff_mod ) { 536 QZ_HandleModifierOneSide ( this, newMods, right_key_sym, right_device_dependent_mask ); 537 } 538 } 539} 540 541/* This is a helper function for QZ_DoSidedModifiers. 542 * This function will release a key press in the case that 543 * it is clear that the modifier has been released (i.e. one side 544 * can't still be down). 545 */ 546static void QZ_ReleaseModifierSide ( _THIS, 547 unsigned int device_independent_mask, 548 unsigned int newMods, 549 unsigned int left_key_sym, 550 unsigned int right_key_sym, 551 unsigned int left_device_dependent_mask, 552 unsigned int right_device_dependent_mask ) { 553 unsigned int device_dependent_mask = 0; 554 SDL_keysym key; 555 556 key.scancode = 0; 557 key.sym = SDLK_UNKNOWN; 558 key.unicode = 0; 559 key.mod = KMOD_NONE; 560 561 device_dependent_mask = left_device_dependent_mask | right_device_dependent_mask; 562 /* On the basis that the device independent mask is set, but there are 563 * no device dependent flags set, we'll assume that we can't detect this 564 * keyboard and revert to the unsided behavior. 565 */ 566 if ( (device_dependent_mask & current_mods) == 0 ) { 567 /* In this case, we can't detect the keyboard, so use the left side 568 * to represent both, and release it. 569 */ 570 key.sym = left_key_sym; 571 SDL_PrivateKeyboard (SDL_RELEASED, &key); 572 573 return; 574 } 575 576 577 /* 578 * This could have been done in an if-else case because at this point, 579 * we know that all keys have been released when calling this function. 580 * But I'm being paranoid so I want to handle each separately, 581 * so I hope this doesn't cause other problems. 582 */ 583 if ( left_device_dependent_mask & current_mods ) { 584 key.sym = left_key_sym; 585 SDL_PrivateKeyboard (SDL_RELEASED, &key); 586 } 587 if ( right_device_dependent_mask & current_mods ) { 588 key.sym = right_key_sym; 589 SDL_PrivateKeyboard (SDL_RELEASED, &key); 590 } 591} 592 593/* This is a helper function for QZ_DoSidedModifiers. 594 * This function handles the CapsLock case. 595 */ 596static void QZ_HandleCapsLock (_THIS, unsigned int newMods) { 597 unsigned int currentMask, newMask; 598 SDL_keysym key; 599 600 key.scancode = 0; 601 key.sym = SDLK_CAPSLOCK; 602 key.unicode = 0; 603 key.mod = KMOD_NONE; 604 605 currentMask = current_mods & NSAlphaShiftKeyMask; 606 newMask = newMods & NSAlphaShiftKeyMask; 607 608 if ( currentMask && 609 currentMask != newMask ) { /* modifier up event */ 610 /* If this was Caps Lock, we need some additional voodoo to make SDL happy */ 611 SDL_PrivateKeyboard (SDL_PRESSED, &key); 612 SDL_PrivateKeyboard (SDL_RELEASED, &key); 613 } 614 else if ( newMask && 615 currentMask != newMask ) { /* modifier down event */ 616 /* If this was Caps Lock, we need some additional voodoo to make SDL happy */ 617 SDL_PrivateKeyboard (SDL_PRESSED, &key); 618 SDL_PrivateKeyboard (SDL_RELEASED, &key); 619 } 620} 621 622/* This function will handle the modifier keys and also determine the 623 * correct side of the key. 624 */ 625static void QZ_DoSidedModifiers (_THIS, unsigned int newMods) { 626 /* Set up arrays for the key syms for the left and right side. */ 627 const unsigned int left_mapping[] = { SDLK_LSHIFT, SDLK_LCTRL, SDLK_LALT, SDLK_LMETA }; 628 const unsigned int right_mapping[] = { SDLK_RSHIFT, SDLK_RCTRL, SDLK_RALT, SDLK_RMETA }; 629 /* Set up arrays for the device dependent masks with indices that 630 * correspond to the _mapping arrays 631 */ 632 const unsigned int left_device_mapping[] = { NX_DEVICELSHIFTKEYMASK, NX_DEVICELCTLKEYMASK, NX_DEVICELALTKEYMASK, NX_DEVICELCMDKEYMASK }; 633 const unsigned int right_device_mapping[] = { NX_DEVICERSHIFTKEYMASK, NX_DEVICERCTLKEYMASK, NX_DEVICERALTKEYMASK, NX_DEVICERCMDKEYMASK }; 634 635 unsigned int i; 636 unsigned int bit; 637 638 /* Handle CAPSLOCK separately because it doesn't have a left/right side */ 639 QZ_HandleCapsLock ( this, newMods ); 640 641 /* Iterate through the bits, testing each against the current modifiers */ 642 for (i = 0, bit = NSShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) { 643 644 unsigned int currentMask, newMask; 645 646 currentMask = current_mods & bit; 647 newMask = newMods & bit; 648 649 /* If the bit is set, we must always examine it because the left 650 * and right side keys may alternate or both may be pressed. 651 */ 652 if ( newMask ) { 653 QZ_HandleModifierSide ( this, bit, newMods, 654 left_mapping[i], 655 right_mapping[i], 656 left_device_mapping[i], 657 right_device_mapping[i] ); 658 } 659 /* If the state changed from pressed to unpressed, we must examine 660 * the device dependent bits to release the correct keys. 661 */ 662 else if ( currentMask && 663 currentMask != newMask ) { /* modifier up event */ 664 QZ_ReleaseModifierSide ( this, bit, newMods, 665 left_mapping[i], 666 right_mapping[i], 667 left_device_mapping[i], 668 right_device_mapping[i] ); 669 } 670 } 671} 672 673/* This function is called to handle the modifiers. 674 * It will try to distinguish between the left side and right side 675 * of the keyboard for those modifiers that qualify if the 676 * operating system version supports it. Otherwise, the code 677 * will not try to make the distinction. 678 */ 679static void QZ_DoModifiers (_THIS, unsigned int newMods) { 680 681 if (current_mods == newMods) 682 return; 683 684 /* 685 * Starting with Panther (10.3.0), the ability to distinguish between 686 * left side and right side modifiers is available. 687 */ 688 if( system_version >= 0x1030 ) { 689 QZ_DoSidedModifiers (this, newMods); 690 } 691 else { 692 QZ_DoUnsidedModifiers (this, newMods); 693 } 694 695 current_mods = newMods; 696} 697 698static void QZ_GetMouseLocation (_THIS, NSPoint *p) { 699 *p = [ NSEvent mouseLocation ]; /* global coordinates */ 700 if (qz_window) 701 QZ_PrivateGlobalToLocal (this, p); 702 QZ_PrivateCocoaToSDL (this, p); 703} 704 705void QZ_DoActivate (_THIS) { 706 707 SDL_PrivateAppActive (1, SDL_APPINPUTFOCUS | (QZ_IsMouseInWindow (this) ? SDL_APPMOUSEFOCUS : 0)); 708 709 QZ_UpdateCursor(this); 710 711 /* Regrab input, only if it was previously grabbed */ 712 if ( current_grab_mode == SDL_GRAB_ON ) { 713 714 /* Restore cursor location if input was grabbed */ 715 QZ_PrivateWarpCursor (this, cursor_loc.x, cursor_loc.y); 716 QZ_ChangeGrabState (this, QZ_ENABLE_GRAB); 717 } 718 else { 719 /* Update SDL's mouse location */ 720 NSPoint p; 721 QZ_GetMouseLocation (this, &p); 722 SDL_PrivateMouseMotion (0, 0, p.x, p.y); 723 } 724 725 QZ_UpdateCursor(this); 726} 727 728void QZ_DoDeactivate (_THIS) { 729 730 SDL_PrivateAppActive (0, SDL_APPINPUTFOCUS | SDL_APPMOUSEFOCUS); 731 732 /* Get the current cursor location, for restore on activate */ 733 QZ_GetMouseLocation (this, &cursor_loc); 734 735 /* Reassociate mouse and cursor */ 736 CGAssociateMouseAndMouseCursorPosition (1); 737 738 QZ_UpdateCursor(this); 739} 740 741void QZ_SleepNotificationHandler (void * refcon, 742 io_service_t service, 743 natural_t messageType, 744 void * messageArgument ) 745{ 746 SDL_VideoDevice *this = (SDL_VideoDevice*)refcon; 747 748 switch(messageType) 749 { 750 case kIOMessageSystemWillSleep: 751 IOAllowPowerChange(power_connection, (long) messageArgument); 752 break; 753 case kIOMessageCanSystemSleep: 754 IOAllowPowerChange(power_connection, (long) messageArgument); 755 break; 756 case kIOMessageSystemHasPoweredOn: 757 /* awake */ 758 SDL_PrivateExpose(); 759 break; 760 } 761} 762 763void QZ_RegisterForSleepNotifications (_THIS) 764{ 765 CFRunLoopSourceRef rls; 766 IONotificationPortRef thePortRef; 767 io_object_t notifier; 768 769 power_connection = IORegisterForSystemPower (this, &thePortRef, QZ_SleepNotificationHandler, ¬ifier); 770 771 if (power_connection == 0) 772 NSLog(@"SDL: QZ_SleepNotificationHandler() IORegisterForSystemPower failed."); 773 774 rls = IONotificationPortGetRunLoopSource (thePortRef); 775 CFRunLoopAddSource (CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); 776 CFRelease (rls); 777} 778 779 780/* Try to map Quartz mouse buttons to SDL's lingo... */ 781static int QZ_OtherMouseButtonToSDL(int button) 782{ 783 switch (button) 784 { 785 case 0: 786 return(SDL_BUTTON_LEFT); /* 1 */ 787 case 1: 788 return(SDL_BUTTON_RIGHT); /* 3 */ 789 case 2: 790 return(SDL_BUTTON_MIDDLE); /* 2 */ 791 } 792 793 /* >= 3: skip 4 & 5, since those are the SDL mousewheel buttons. */ 794 return(button + 3); 795} 796 797 798void QZ_PumpEvents (_THIS) 799{ 800 int32_t dx, dy; 801 802 NSDate *distantPast; 803 NSEvent *event; 804 NSRect winRect; 805 NSAutoreleasePool *pool; 806 807 if (!SDL_VideoSurface) 808 return; /* don't do anything if there's no screen surface. */ 809 810 /* Update activity every five seconds to prevent screensaver. --ryan. */ 811 if (!allow_screensaver) { 812 static Uint32 screensaverTicks; 813 Uint32 nowTicks = SDL_GetTicks(); 814 if ((nowTicks - screensaverTicks) > 5000) 815 { 816 UpdateSystemActivity(UsrActivity); 817 screensaverTicks = nowTicks; 818 } 819 } 820 821 pool = [ [ NSAutoreleasePool alloc ] init ]; 822 distantPast = [ NSDate distantPast ]; 823 824 winRect = NSMakeRect (0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h); 825 826 /* while grabbed, accumulate all mouse moved events into one SDL mouse event */ 827 dx = 0; 828 dy = 0; 829 830 do { 831 832 /* Poll for an event. This will not block */ 833 event = [ NSApp nextEventMatchingMask:NSAnyEventMask 834 untilDate:distantPast 835 inMode: NSDefaultRunLoopMode dequeue:YES ]; 836 if (event != nil) { 837 838 int button; 839 unsigned int type; 840 BOOL isInGameWin; 841 842 #define DO_MOUSE_DOWN(button) do { \ 843 if ( SDL_GetAppState() & SDL_APPMOUSEFOCUS ) { \ 844 SDL_PrivateMouseButton (SDL_PRESSED, button, 0, 0); \ 845 expect_mouse_up |= 1<<button; \ 846 } \ 847 [ NSApp sendEvent:event ]; \ 848 } while(0) 849 850 #define DO_MOUSE_UP(button) do { \ 851 if ( expect_mouse_up & (1<<button) ) { \ 852 SDL_PrivateMouseButton (SDL_RELEASED, button, 0, 0); \ 853 expect_mouse_up &= ~(1<<button); \ 854 } \ 855 [ NSApp sendEvent:event ]; \ 856 } while(0) 857 858 type = [ event type ]; 859 isInGameWin = QZ_IsMouseInWindow (this); 860 861 QZ_DoModifiers(this, [ event modifierFlags ] ); 862 863 switch (type) { 864 case NSLeftMouseDown: 865 if ( SDL_getenv("SDL_HAS3BUTTONMOUSE") ) { 866 DO_MOUSE_DOWN (SDL_BUTTON_LEFT); 867 } else { 868 if ( NSCommandKeyMask & current_mods ) { 869 last_virtual_button = SDL_BUTTON_RIGHT; 870 DO_MOUSE_DOWN (SDL_BUTTON_RIGHT); 871 } 872 else if ( NSAlternateKeyMask & current_mods ) { 873 last_virtual_button = SDL_BUTTON_MIDDLE; 874 DO_MOUSE_DOWN (SDL_BUTTON_MIDDLE); 875 } 876 else { 877 DO_MOUSE_DOWN (SDL_BUTTON_LEFT); 878 } 879 } 880 break; 881 882 case NSLeftMouseUp: 883 if ( last_virtual_button != 0 ) { 884 DO_MOUSE_UP (last_virtual_button); 885 last_virtual_button = 0; 886 } 887 else { 888 DO_MOUSE_UP (SDL_BUTTON_LEFT); 889 } 890 break; 891 892 case NSOtherMouseDown: 893 case NSRightMouseDown: 894 button = QZ_OtherMouseButtonToSDL([ event buttonNumber ]); 895 DO_MOUSE_DOWN (button); 896 break; 897 898 case NSOtherMouseUp: 899 case NSRightMouseUp: 900 button = QZ_OtherMouseButtonToSDL([ event buttonNumber ]); 901 DO_MOUSE_UP (button); 902 break; 903 904 case NSSystemDefined: 905 /* 906 Future: up to 32 "mouse" buttons can be handled. 907 if ([event subtype] == 7) { 908 unsigned int buttons; 909 buttons = [ event data2 ]; 910 */ 911 break; 912 case NSLeftMouseDragged: 913 case NSRightMouseDragged: 914 case NSOtherMouseDragged: /* usually middle mouse dragged */ 915 case NSMouseMoved: 916 if ( grab_state == QZ_INVISIBLE_GRAB ) { 917 918 /* 919 If input is grabbed+hidden, the cursor doesn't move, 920 so we have to call the lowlevel window server 921 function. This is less accurate but works OK. 922 */ 923 int32_t dx1, dy1; 924 CGGetLastMouseDelta (&dx1, &dy1); 925 dx += dx1; 926 dy += dy1; 927 } 928 else { 929 930 /* 931 Get the absolute mouse location. This is not the 932 mouse location after the currently processed event, 933 but the *current* mouse location, i.e. after all 934 pending events. This means that if there are 935 multiple mouse moved events in the queue, we make 936 multiple identical calls to SDL_PrivateMouseMotion(), 937 but that's no problem since the latter only 938 generates SDL events for nonzero movements. In my 939 experience on PBG4/10.4.8, this rarely happens anyway. 940 */ 941 NSPoint p; 942 QZ_GetMouseLocation (this, &p); 943 SDL_PrivateMouseMotion (0, 0, p.x, p.y); 944 } 945 946 /* 947 Handle grab input+cursor visible by warping the cursor back 948 into the game window. This still generates a mouse moved event, 949 but not as a result of the warp (so it's in the right direction). 950 */ 951 if ( grab_state == QZ_VISIBLE_GRAB && !isInGameWin ) { 952 953 NSPoint p; 954 QZ_GetMouseLocation (this, &p); 955 956 if ( p.x < 0.0 ) 957 p.x = 0.0; 958 959 if ( p.y < 0.0 ) 960 p.y = 0.0; 961 962 if ( p.x >= winRect.size.width ) 963 p.x = winRect.size.width-1; 964 965 if ( p.y >= winRect.size.height ) 966 p.y = winRect.size.height-1; 967 968 QZ_PrivateWarpCursor (this, p.x, p.y); 969 } 970 else 971 if ( !isInGameWin && (SDL_GetAppState() & SDL_APPMOUSEFOCUS) ) { 972 973 SDL_PrivateAppActive (0, SDL_APPMOUSEFOCUS); 974 975 if (grab_state == QZ_INVISIBLE_GRAB) 976 /*The cursor has left the window even though it is 977 disassociated from the mouse (and therefore 978 shouldn't move): this can happen with Wacom 979 tablets, and it effectively breaks the grab, since 980 mouse down events now go to background 981 applications. The only possibility to avoid this 982 seems to be talking to the tablet driver 983 (AppleEvents) to constrain its mapped area to the 984 window, which may not be worth the effort. For 985 now, handle the condition more gracefully than 986 before by reassociating cursor and mouse until the 987 cursor enters the window again, making it obvious 988 to the user that the grab is broken.*/ 989 CGAssociateMouseAndMouseCursorPosition (1); 990 991 QZ_UpdateCursor(this); 992 } 993 else 994 if ( isInGameWin && (SDL_GetAppState() & (SDL_APPMOUSEFOCUS | SDL_APPINPUTFOCUS)) == SDL_APPINPUTFOCUS ) { 995 996 SDL_PrivateAppActive (1, SDL_APPMOUSEFOCUS); 997 998 QZ_UpdateCursor(this); 999 1000 if (grab_state == QZ_INVISIBLE_GRAB) { /*see comment above*/ 1001 QZ_PrivateWarpCursor (this, SDL_VideoSurface->w / 2, SDL_VideoSurface->h / 2); 1002 CGAssociateMouseAndMouseCursorPosition (0); 1003 } 1004 } 1005 break; 1006 case NSScrollWheel: 1007 if ( isInGameWin ) { 1008 float dy, dx; 1009 Uint8 button; 1010 dy = [ event deltaY ]; 1011 dx = [ event deltaX ]; 1012 if ( dy > 0.0 ) /* Scroll up */ 1013 button = SDL_BUTTON_WHEELUP; 1014 else if ( dy < 0.0 ) /* Scroll down */ 1015 button = SDL_BUTTON_WHEELDOWN; 1016 else 1017 break; /* Horizontal scroll */ 1018 /* For now, wheel is sent as a quick down+up */ 1019 SDL_PrivateMouseButton (SDL_PRESSED, button, 0, 0); 1020 SDL_PrivateMouseButton (SDL_RELEASED, button, 0, 0); 1021 } 1022 break; 1023 case NSKeyUp: 1024 QZ_DoKey (this, SDL_RELEASED, event); 1025 break; 1026 case NSKeyDown: 1027 QZ_DoKey (this, SDL_PRESSED, event); 1028 break; 1029 case NSFlagsChanged: 1030 break; 1031 case NSAppKitDefined: 1032 [ NSApp sendEvent:event ]; 1033 if ([ event subtype ] == NSApplicationActivatedEventType && (mode_flags & SDL_FULLSCREEN)) { 1034 /* the default handling of this event seems to reset any cursor set by [NSCursor set] (used by SDL_SetCursor() in fullscreen mode) to the default system arrow cursor */ 1035 SDL_Cursor *sdlc = SDL_GetCursor(); 1036 if (sdlc != NULL && sdlc->wm_cursor != NULL) { 1037 [ sdlc->wm_cursor->nscursor set ]; 1038 } 1039 } 1040 break; 1041 /* case NSApplicationDefined: break; */ 1042 /* case NSPeriodic: break; */ 1043 /* case NSCursorUpdate: break; */ 1044 default: 1045 [ NSApp sendEvent:event ]; 1046 } 1047 } 1048 } while (event != nil); 1049 1050 /* handle accumulated mouse moved events */ 1051 if (dx != 0 || dy != 0) 1052 SDL_PrivateMouseMotion (0, 1, dx, dy); 1053 1054 [ pool release ]; 1055} 1056 1057void QZ_UpdateMouse (_THIS) 1058{ 1059 NSPoint p; 1060 QZ_GetMouseLocation (this, &p); 1061 SDL_PrivateAppActive (QZ_IsMouseInWindow (this), SDL_APPMOUSEFOCUS); 1062 SDL_PrivateMouseMotion (0, 0, p.x, p.y); 1063} 1064