00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "COSXKeyState.h"
00020 #include "CLog.h"
00021 #include "CArch.h"
00022
00023 #if defined(MAC_OS_X_VERSION_10_5)
00024 #include <Carbon/Carbon.h>
00025 #endif
00026
00027
00028
00029
00030
00031
00032 #if defined(MAC_OS_X_VERSION_10_5)
00033 static const UInt32 s_shiftVK = kVK_Shift;
00034 static const UInt32 s_controlVK = kVK_Control;
00035 static const UInt32 s_altVK = kVK_Option;
00036 static const UInt32 s_superVK = kVK_Command;
00037 static const UInt32 s_capsLockVK = kVK_CapsLock;
00038 static const UInt32 s_numLockVK = kVK_ANSI_KeypadClear;
00039 #else
00040
00041 static const UInt32 s_shiftVK = 56;
00042 static const UInt32 s_controlVK = 59;
00043 static const UInt32 s_altVK = 58;
00044 static const UInt32 s_superVK = 55;
00045 static const UInt32 s_capsLockVK = 57;
00046 static const UInt32 s_numLockVK = 71;
00047 #endif
00048
00049 static const UInt32 s_osxNumLock = 1 << 16;
00050
00051 struct CKeyEntry {
00052 public:
00053 KeyID m_keyID;
00054 UInt32 m_virtualKey;
00055 };
00056 static const CKeyEntry s_controlKeys[] = {
00057 #if defined(MAC_OS_X_VERSION_10_5)
00058
00059
00060
00061 { kKeyLeft, kVK_LeftArrow },
00062 { kKeyRight, kVK_RightArrow },
00063 { kKeyUp, kVK_UpArrow },
00064 { kKeyDown, kVK_DownArrow },
00065 { kKeyHome, kVK_Home },
00066 { kKeyEnd, kVK_End },
00067 { kKeyPageUp, kVK_PageUp },
00068 { kKeyPageDown, kVK_PageDown },
00069 { kKeyInsert, kVK_Help },
00070
00071
00072 { kKeyF1, kVK_F1 },
00073 { kKeyF2, kVK_F2 },
00074 { kKeyF3, kVK_F3 },
00075 { kKeyF4, kVK_F4 },
00076 { kKeyF5, kVK_F5 },
00077 { kKeyF6, kVK_F6 },
00078 { kKeyF7, kVK_F7 },
00079 { kKeyF8, kVK_F8 },
00080 { kKeyF9, kVK_F9 },
00081 { kKeyF10, kVK_F10 },
00082 { kKeyF11, kVK_F11 },
00083 { kKeyF12, kVK_F12 },
00084 { kKeyF13, kVK_F13 },
00085 { kKeyF14, kVK_F14 },
00086 { kKeyF15, kVK_F15 },
00087 { kKeyF16, kVK_F16 },
00088
00089 { kKeyKP_0, kVK_ANSI_Keypad0 },
00090 { kKeyKP_1, kVK_ANSI_Keypad1 },
00091 { kKeyKP_2, kVK_ANSI_Keypad2 },
00092 { kKeyKP_3, kVK_ANSI_Keypad3 },
00093 { kKeyKP_4, kVK_ANSI_Keypad4 },
00094 { kKeyKP_5, kVK_ANSI_Keypad5 },
00095 { kKeyKP_6, kVK_ANSI_Keypad6 },
00096 { kKeyKP_7, kVK_ANSI_Keypad7 },
00097 { kKeyKP_8, kVK_ANSI_Keypad8 },
00098 { kKeyKP_9, kVK_ANSI_Keypad9 },
00099 { kKeyKP_Decimal, kVK_ANSI_KeypadDecimal },
00100 { kKeyKP_Equal, kVK_ANSI_KeypadEquals },
00101 { kKeyKP_Multiply, kVK_ANSI_KeypadMultiply },
00102 { kKeyKP_Add, kVK_ANSI_KeypadPlus },
00103 { kKeyKP_Divide, kVK_ANSI_KeypadDivide },
00104 { kKeyKP_Subtract, kVK_ANSI_KeypadMinus },
00105 { kKeyKP_Enter, kVK_ANSI_KeypadEnter },
00106 #else
00107
00108
00109 { kKeyLeft, 123 },
00110 { kKeyRight, 124 },
00111 { kKeyUp, 126 },
00112 { kKeyDown, 125 },
00113 { kKeyHome, 115 },
00114 { kKeyEnd, 119 },
00115 { kKeyPageUp, 116 },
00116 { kKeyPageDown, 121 },
00117 { kKeyInsert, 114 },
00118
00119
00120 { kKeyF1, 122 },
00121 { kKeyF2, 120 },
00122 { kKeyF3, 99 },
00123 { kKeyF4, 118 },
00124 { kKeyF5, 96 },
00125 { kKeyF6, 97 },
00126 { kKeyF7, 98 },
00127 { kKeyF8, 100 },
00128 { kKeyF9, 101 },
00129 { kKeyF10, 109 },
00130 { kKeyF11, 103 },
00131 { kKeyF12, 111 },
00132 { kKeyF13, 105 },
00133 { kKeyF14, 107 },
00134 { kKeyF15, 113 },
00135 { kKeyF16, 106 },
00136
00137 { kKeyKP_0, 82 },
00138 { kKeyKP_1, 83 },
00139 { kKeyKP_2, 84 },
00140 { kKeyKP_3, 85 },
00141 { kKeyKP_4, 86 },
00142 { kKeyKP_5, 87 },
00143 { kKeyKP_6, 88 },
00144 { kKeyKP_7, 89 },
00145 { kKeyKP_8, 91 },
00146 { kKeyKP_9, 92 },
00147 { kKeyKP_Decimal, 65 },
00148 { kKeyKP_Equal, 81 },
00149 { kKeyKP_Multiply, 67 },
00150 { kKeyKP_Add, 69 },
00151 { kKeyKP_Divide, 75 },
00152 { kKeyKP_Subtract, 78 },
00153 { kKeyKP_Enter, 76 },
00154 #endif
00155
00156
00157
00158
00159
00160
00161
00162 { kKeyShift_L, s_shiftVK },
00163 { kKeyShift_R, s_shiftVK },
00164 { kKeyControl_L, s_controlVK },
00165 { kKeyControl_R, s_controlVK },
00166 { kKeyAlt_L, s_altVK },
00167 { kKeyAlt_R, s_altVK },
00168 { kKeySuper_L, s_superVK },
00169 { kKeySuper_R, s_superVK },
00170 { kKeyMeta_L, s_superVK },
00171 { kKeyMeta_R, s_superVK },
00172
00173
00174 { kKeyNumLock, s_numLockVK },
00175 { kKeyCapsLock, s_capsLockVK }
00176 };
00177
00178
00179
00180
00181
00182
00183 COSXKeyState::COSXKeyState() :
00184 m_deadKeyState(0)
00185 {
00186 init();
00187 }
00188
00189 COSXKeyState::COSXKeyState(IEventQueue& eventQueue, CKeyMap& keyMap) :
00190 CKeyState(eventQueue, keyMap),
00191 m_deadKeyState(0)
00192 {
00193 init();
00194 }
00195
00196 COSXKeyState::~COSXKeyState()
00197 {
00198 }
00199
00200 void
00201 COSXKeyState::init()
00202 {
00203
00204 shiftPressed = false;
00205 controlPressed = false;
00206 altPressed = false;
00207 superPressed = false;
00208 capsPressed = false;
00209
00210
00211 for (size_t i = 0; i < sizeof(s_controlKeys) /
00212 sizeof(s_controlKeys[0]); ++i) {
00213 m_virtualKeyMap[s_controlKeys[i].m_virtualKey] =
00214 s_controlKeys[i].m_keyID;
00215 }
00216 }
00217
00218 KeyModifierMask
00219 COSXKeyState::mapModifiersFromOSX(UInt32 mask) const
00220 {
00221 LOG((CLOG_DEBUG1 "mask: %04x", mask));
00222
00223 KeyModifierMask outMask = 0;
00224 if ((mask & kCGEventFlagMaskShift) != 0) {
00225 outMask |= KeyModifierShift;
00226 }
00227 if ((mask & kCGEventFlagMaskControl) != 0) {
00228 outMask |= KeyModifierControl;
00229 }
00230 if ((mask & kCGEventFlagMaskAlternate) != 0) {
00231 outMask |= KeyModifierAlt;
00232 }
00233 if ((mask & kCGEventFlagMaskCommand) != 0) {
00234 outMask |= KeyModifierSuper;
00235 }
00236 if ((mask & kCGEventFlagMaskAlphaShift) != 0) {
00237 outMask |= KeyModifierCapsLock;
00238 }
00239 if ((mask & kCGEventFlagMaskNumericPad) != 0) {
00240 outMask |= KeyModifierNumLock;
00241 }
00242
00243 return outMask;
00244 }
00245
00246 KeyModifierMask
00247 COSXKeyState::mapModifiersToCarbon(UInt32 mask) const
00248 {
00249 KeyModifierMask outMask = 0;
00250 if ((mask & kCGEventFlagMaskShift) != 0) {
00251 outMask |= shiftKey;
00252 }
00253 if ((mask & kCGEventFlagMaskControl) != 0) {
00254 outMask |= controlKey;
00255 }
00256 if ((mask & kCGEventFlagMaskCommand) != 0) {
00257 outMask |= cmdKey;
00258 }
00259 if ((mask & kCGEventFlagMaskAlternate) != 0) {
00260 outMask |= optionKey;
00261 }
00262 if ((mask & kCGEventFlagMaskAlphaShift) != 0) {
00263 outMask |= alphaLock;
00264 }
00265 if ((mask & kCGEventFlagMaskNumericPad) != 0) {
00266 outMask |= s_osxNumLock;
00267 }
00268
00269 return outMask;
00270 }
00271
00272 KeyButton
00273 COSXKeyState::mapKeyFromEvent(CKeyIDs& ids,
00274 KeyModifierMask* maskOut, CGEventRef event) const
00275 {
00276 ids.clear();
00277
00278
00279 if (maskOut != NULL) {
00280 KeyModifierMask activeMask = getActiveModifiers();
00281 activeMask &= ~KeyModifierAltGr;
00282 *maskOut = activeMask;
00283 }
00284
00285
00286 UInt32 vkCode = CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode);
00287
00288
00289 UInt32 eventKind = CGEventGetType(event);
00290 if (eventKind == kCGEventKeyUp) {
00291
00292
00293
00294 ids.push_back(kKeyNone);
00295 return mapVirtualKeyToKeyButton(vkCode);
00296 }
00297
00298
00299 CVirtualKeyMap::const_iterator i = m_virtualKeyMap.find(vkCode);
00300 if (i != m_virtualKeyMap.end()) {
00301 m_deadKeyState = 0;
00302 ids.push_back(i->second);
00303 return mapVirtualKeyToKeyButton(vkCode);
00304 }
00305
00306
00307
00308 #if defined(MAC_OS_X_VERSION_10_5)
00309 TISInputSourceRef currentKeyboardLayout = TISCopyCurrentKeyboardLayoutInputSource();
00310 #else
00311 KeyboardLayoutRef currentKeyboardLayout;
00312 OSStatus status = KLGetCurrentKeyboardLayout(¤tKeyboardLayout);
00313 #endif
00314 if (currentKeyboardLayout == NULL) {
00315 return kKeyNone;
00316 }
00317
00318
00319
00320
00321 UInt32 modifiers;
00322 modifiers = mapModifiersToCarbon(CGEventGetFlags(event));
00323 static const UInt32 s_commandModifiers =
00324 cmdKey | controlKey | rightControlKey;
00325 bool isCommand = ((modifiers & s_commandModifiers) != 0);
00326 modifiers &= ~s_commandModifiers;
00327
00328
00329
00330
00331 modifiers &= ~optionKey;
00332
00333
00334
00335 UInt16 action;
00336 if(eventKind==kCGEventKeyDown) {
00337 action = kUCKeyActionDown;
00338 }
00339 else if(CGEventGetIntegerValueField(event, kCGKeyboardEventAutorepeat)==1) {
00340 action = kUCKeyActionAutoKey;
00341 }
00342 else {
00343 return 0;
00344 }
00345
00346
00347 #if defined(MAC_OS_X_VERSION_10_5)
00348 CFDataRef ref = (CFDataRef) TISGetInputSourceProperty(currentKeyboardLayout,
00349 kTISPropertyUnicodeKeyLayoutData);
00350 const UCKeyboardLayout* layout = (const UCKeyboardLayout*) CFDataGetBytePtr(ref);
00351 const bool layoutValid = (layout != NULL);
00352 #else
00353 const void* resource;
00354 int err = KLGetKeyboardLayoutProperty(currentKeyboardLayout, kKLuchrData, &resource);
00355 const bool layoutValid = (err == noErr);
00356 const UCKeyboardLayout* layout = (const UCKeyboardLayout*)resource;
00357 #endif
00358
00359 if (layoutValid) {
00360
00361 UniCharCount count;
00362 UniChar chars[2];
00363 LOG((CLOG_DEBUG2 "modifiers: %08x", modifiers & 0xffu));
00364 OSStatus status = UCKeyTranslate(layout,
00365 vkCode & 0xffu, action,
00366 (modifiers >> 8) & 0xffu,
00367 LMGetKbdType(), 0, &m_deadKeyState,
00368 sizeof(chars) / sizeof(chars[0]), &count, chars);
00369
00370
00371 if (status == 0) {
00372 if (count != 0 || m_deadKeyState == 0) {
00373 m_deadKeyState = 0;
00374 for (UniCharCount i = 0; i < count; ++i) {
00375 ids.push_back(CKeyResource::unicharToKeyID(chars[i]));
00376 }
00377 adjustAltGrModifier(ids, maskOut, isCommand);
00378 return mapVirtualKeyToKeyButton(vkCode);
00379 }
00380 return 0;
00381 }
00382 }
00383
00384 return 0;
00385 }
00386
00387 bool
00388 COSXKeyState::fakeCtrlAltDel()
00389 {
00390
00391 return false;
00392 }
00393
00394 KeyModifierMask
00395 COSXKeyState::pollActiveModifiers() const
00396 {
00397 return mapModifiersFromOSX(GetCurrentKeyModifiers());
00398 }
00399
00400 SInt32
00401 COSXKeyState::pollActiveGroup() const
00402 {
00403 bool layoutValid = true;
00404 #if defined(MAC_OS_X_VERSION_10_5)
00405 TISInputSourceRef keyboardLayout = TISCopyCurrentKeyboardLayoutInputSource();
00406 #else
00407 KeyboardLayoutRef keyboardLayout;
00408 OSStatus status = KLGetCurrentKeyboardLayout(&keyboardLayout);
00409 layoutValid = (status == noErr);
00410 #endif
00411
00412 if (layoutValid) {
00413 GroupMap::const_iterator i = m_groupMap.find(keyboardLayout);
00414 if (i != m_groupMap.end()) {
00415 return i->second;
00416 }
00417 }
00418 return 0;
00419 }
00420
00421 void
00422 COSXKeyState::pollPressedKeys(KeyButtonSet& pressedKeys) const
00423 {
00424 KeyMap km;
00425 GetKeys(km);
00426 const UInt8* m = reinterpret_cast<const UInt8*>(km);
00427 for (UInt32 i = 0; i < 16; ++i) {
00428 for (UInt32 j = 0; j < 8; ++j) {
00429 if ((m[i] & (1u << j)) != 0) {
00430 pressedKeys.insert(mapVirtualKeyToKeyButton(8 * i + j));
00431 }
00432 }
00433 }
00434 }
00435
00436 void
00437 COSXKeyState::getKeyMap(CKeyMap& keyMap)
00438 {
00439
00440 if (getGroups(m_groups)) {
00441 m_groupMap.clear();
00442 SInt32 numGroups = (SInt32)m_groups.size();
00443 for (SInt32 g = 0; g < numGroups; ++g) {
00444 m_groupMap[m_groups[g]] = g;
00445 }
00446 }
00447
00448 UInt32 keyboardType = LMGetKbdType();
00449 for (SInt32 g = 0, n = (SInt32)m_groups.size(); g < n; ++g) {
00450
00451 getKeyMapForSpecialKeys(keyMap, g);
00452
00453 const void* resource;
00454 bool layoutValid = false;
00455
00456
00457
00458 #if defined(MAC_OS_X_VERSION_10_5)
00459 CFDataRef resourceRef = (CFDataRef)TISGetInputSourceProperty(
00460 m_groups[g], kTISPropertyUnicodeKeyLayoutData);
00461 layoutValid = resourceRef != NULL;
00462 if (layoutValid)
00463 resource = CFDataGetBytePtr(resourceRef);
00464 #else
00465 layoutValid = KLGetKeyboardLayoutProperty(
00466 m_groups[g], kKLuchrData, &resource);
00467 #endif
00468
00469 if (layoutValid) {
00470 CUCHRKeyResource uchr(resource, keyboardType);
00471 if (uchr.isValid()) {
00472 LOG((CLOG_DEBUG1 "using uchr resource for group %d", g));
00473 getKeyMap(keyMap, g, uchr);
00474 continue;
00475 }
00476 }
00477
00478 LOG((CLOG_DEBUG1 "no keyboard resource for group %d", g));
00479 }
00480 }
00481
00482 void
00483 COSXKeyState::fakeKey(const Keystroke& keystroke)
00484 {
00485 CGEventRef ref;
00486
00487 switch (keystroke.m_type) {
00488 case Keystroke::kButton:
00489 {
00490 LOG((CLOG_DEBUG1 " %03x (%08x) %s", keystroke.m_data.m_button.m_button, keystroke.m_data.m_button.m_client, keystroke.m_data.m_button.m_press ? "down" : "up"));
00491
00492
00493 ref = CGEventCreateKeyboardEvent(0, mapKeyButtonToVirtualKey(
00494 keystroke.m_data.m_button.m_button),
00495 keystroke.m_data.m_button.m_press);
00496 if (ref == NULL) {
00497 LOG((CLOG_CRIT "unable to create keyboard event for keystroke"));
00498 }
00499
00500 UInt32 vk = mapKeyButtonToVirtualKey(keystroke.m_data.m_button.m_button);
00501 UInt32 modifierDown = keystroke.m_data.m_button.m_press;
00502
00503
00504 if (vk == s_shiftVK) shiftPressed=modifierDown;
00505 if (vk == s_controlVK) controlPressed=modifierDown;
00506 if (vk == s_altVK) altPressed=modifierDown;
00507 if (vk == s_superVK) superPressed=modifierDown;
00508 if (vk == s_capsLockVK) capsPressed=modifierDown;
00509
00510
00511
00512 CGEventFlags modifiers = 0;
00513 if (shiftPressed) modifiers |= kCGEventFlagMaskShift;
00514 if (controlPressed) modifiers |= kCGEventFlagMaskControl;
00515 if (altPressed) modifiers |= kCGEventFlagMaskAlternate;
00516 if (superPressed) modifiers |= kCGEventFlagMaskCommand;
00517 if (capsPressed) modifiers |= kCGEventFlagMaskAlphaShift;
00518
00519 CGEventSetFlags(ref, modifiers);
00520
00521 CGEventPost(kCGHIDEventTap, ref);
00522
00523
00524 if (keystroke.m_data.m_button.m_client) {
00525 ARCH->sleep(0.01);
00526 }
00527 }
00528 break;
00529
00530 case Keystroke::kGroup:
00531 if (keystroke.m_data.m_group.m_absolute) {
00532 LOG((CLOG_DEBUG1 " group %d", keystroke.m_data.m_group.m_group));
00533 setGroup(keystroke.m_data.m_group.m_group);
00534 }
00535 else {
00536 LOG((CLOG_DEBUG1 " group %+d", keystroke.m_data.m_group.m_group));
00537 setGroup(getEffectiveGroup(pollActiveGroup(),
00538 keystroke.m_data.m_group.m_group));
00539 }
00540 break;
00541 }
00542 }
00543
00544 void
00545 COSXKeyState::getKeyMapForSpecialKeys(CKeyMap& keyMap, SInt32 group) const
00546 {
00547
00548 CKeyMap::KeyItem item;
00549 for (size_t i = 0; i < sizeof(s_controlKeys) /
00550 sizeof(s_controlKeys[0]); ++i) {
00551 const CKeyEntry& entry = s_controlKeys[i];
00552 item.m_id = entry.m_keyID;
00553 item.m_group = group;
00554 item.m_button = mapVirtualKeyToKeyButton(entry.m_virtualKey);
00555 item.m_required = 0;
00556 item.m_sensitive = 0;
00557 item.m_dead = false;
00558 item.m_client = 0;
00559 CKeyMap::initModifierKey(item);
00560 keyMap.addKeyEntry(item);
00561
00562 if (item.m_lock) {
00563
00564 keyMap.addHalfDuplexButton(item.m_button);
00565 }
00566 }
00567
00568
00569
00570
00571
00572
00573 }
00574
00575 bool
00576 COSXKeyState::getKeyMap(CKeyMap& keyMap,
00577 SInt32 group, const CKeyResource& r) const
00578 {
00579 if (!r.isValid()) {
00580 return false;
00581 }
00582
00583
00584 std::vector<bool> modifiers(r.getNumModifierCombinations());
00585
00586
00587 std::vector<std::pair<KeyID, bool> > buttonKeys(r.getNumTables());
00588
00589
00590 CKeyMap::KeyItem item;
00591 for (UInt32 i = 0; i < r.getNumButtons(); ++i) {
00592 item.m_button = mapVirtualKeyToKeyButton(i);
00593
00594
00595 std::set<KeyID> keys;
00596
00597
00598 for (UInt32 j = 0; j < r.getNumTables(); ++j) {
00599 buttonKeys[j].first = r.getKey(j, i);
00600 buttonKeys[j].second = CKeyMap::isDeadKey(buttonKeys[j].first);
00601 }
00602
00603
00604 for (UInt32 j = 0; j < r.getNumTables(); ++j) {
00605
00606 KeyID id = buttonKeys[j].first;
00607 if (id == kKeyNone) {
00608 continue;
00609 }
00610
00611
00612
00613 if (keys.count(id) > 0) {
00614 continue;
00615 }
00616 keys.insert(id);
00617
00618
00619 item.m_id = id;
00620 item.m_group = group;
00621 item.m_dead = buttonKeys[j].second;
00622 item.m_client = buttonKeys[j].second ? 1 : 0;
00623 CKeyMap::initModifierKey(item);
00624 if (item.m_lock) {
00625
00626 keyMap.addHalfDuplexButton(i);
00627 }
00628
00629
00630
00631 std::set<UInt8> tables;
00632 tables.insert(static_cast<UInt8>(j));
00633 for (UInt32 k = j + 1; k < r.getNumTables(); ++k) {
00634 if (buttonKeys[k].first == id) {
00635 tables.insert(static_cast<UInt8>(k));
00636 }
00637 }
00638
00639
00640
00641 for (UInt32 k = 0; k < r.getNumModifierCombinations(); ++k) {
00642 modifiers[k] = (tables.count(r.getTableForModifier(k)) > 0);
00643 }
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654 UInt32 sensitive = 0;
00655 for (UInt32 k = 0; (1u << k) <
00656 r.getNumModifierCombinations(); ++k) {
00657 UInt32 bit = (1u << k);
00658 if ((bit << 8) == cmdKey ||
00659 (bit << 8) == controlKey ||
00660 (bit << 8) == rightControlKey) {
00661 continue;
00662 }
00663 for (UInt32 m = 0; m < r.getNumModifierCombinations(); ++m) {
00664 if (modifiers[m] != modifiers[m ^ bit]) {
00665 sensitive |= bit;
00666 break;
00667 }
00668 }
00669 }
00670
00671
00672
00673 std::set<UInt32> required;
00674 for (UInt32 k = 0; k < r.getNumModifierCombinations(); ++k) {
00675 if ((k & sensitive) == k && modifiers[k & sensitive]) {
00676 required.insert(k);
00677 }
00678 }
00679
00680
00681 item.m_sensitive = mapModifiersFromOSX(sensitive << 8);
00682 for (std::set<UInt32>::iterator k = required.begin();
00683 k != required.end(); ++k) {
00684 item.m_required = mapModifiersFromOSX(*k << 8);
00685 keyMap.addKeyEntry(item);
00686 }
00687 }
00688 }
00689
00690 return true;
00691 }
00692
00693 bool
00694 COSXKeyState::mapSynergyHotKeyToMac(KeyID key, KeyModifierMask mask,
00695 UInt32 &macVirtualKey, UInt32 &macModifierMask) const
00696 {
00697
00698 KeyButton button = getButton(key, pollActiveGroup());
00699 if (button == 0 && key != kKeyNone) {
00700 return false;
00701 }
00702 macVirtualKey = mapKeyButtonToVirtualKey(button);
00703
00704
00705 macModifierMask = 0;
00706 if ((mask & KeyModifierShift) != 0) {
00707 macModifierMask |= shiftKey;
00708 }
00709 if ((mask & KeyModifierControl) != 0) {
00710 macModifierMask |= controlKey;
00711 }
00712 if ((mask & KeyModifierAlt) != 0) {
00713 macModifierMask |= cmdKey;
00714 }
00715 if ((mask & KeyModifierSuper) != 0) {
00716 macModifierMask |= optionKey;
00717 }
00718 if ((mask & KeyModifierCapsLock) != 0) {
00719 macModifierMask |= alphaLock;
00720 }
00721 if ((mask & KeyModifierNumLock) != 0) {
00722 macModifierMask |= s_osxNumLock;
00723 }
00724
00725 return true;
00726 }
00727
00728 void
00729 COSXKeyState::handleModifierKeys(void* target,
00730 KeyModifierMask oldMask, KeyModifierMask newMask)
00731 {
00732
00733 KeyModifierMask changed = (oldMask ^ newMask);
00734
00735
00736 if ((changed & KeyModifierShift) != 0) {
00737 handleModifierKey(target, s_shiftVK, kKeyShift_L,
00738 (newMask & KeyModifierShift) != 0, newMask);
00739 }
00740 if ((changed & KeyModifierControl) != 0) {
00741 handleModifierKey(target, s_controlVK, kKeyControl_L,
00742 (newMask & KeyModifierControl) != 0, newMask);
00743 }
00744 if ((changed & KeyModifierAlt) != 0) {
00745 handleModifierKey(target, s_altVK, kKeyAlt_L,
00746 (newMask & KeyModifierAlt) != 0, newMask);
00747 }
00748 if ((changed & KeyModifierSuper) != 0) {
00749 handleModifierKey(target, s_superVK, kKeySuper_L,
00750 (newMask & KeyModifierSuper) != 0, newMask);
00751 }
00752 if ((changed & KeyModifierCapsLock) != 0) {
00753 handleModifierKey(target, s_capsLockVK, kKeyCapsLock,
00754 (newMask & KeyModifierCapsLock) != 0, newMask);
00755 }
00756 if ((changed & KeyModifierNumLock) != 0) {
00757 handleModifierKey(target, s_numLockVK, kKeyNumLock,
00758 (newMask & KeyModifierNumLock) != 0, newMask);
00759 }
00760 }
00761
00762 void
00763 COSXKeyState::handleModifierKey(void* target,
00764 UInt32 virtualKey, KeyID id,
00765 bool down, KeyModifierMask newMask)
00766 {
00767 KeyButton button = mapVirtualKeyToKeyButton(virtualKey);
00768 onKey(button, down, newMask);
00769 sendKeyEvent(target, down, false, id, newMask, 0, button);
00770 }
00771
00772 bool
00773 COSXKeyState::getGroups(GroupList& groups) const
00774 {
00775 CFIndex n;
00776 bool gotLayouts = false;
00777
00778 #if defined(MAC_OS_X_VERSION_10_5)
00779
00780 CFStringRef keys[] = { kTISPropertyInputSourceCategory };
00781 CFStringRef values[] = { kTISCategoryKeyboardInputSource };
00782 CFDictionaryRef dict = CFDictionaryCreate(NULL, (const void **)keys, (const void **)values, 1, NULL, NULL);
00783 CFArrayRef kbds = TISCreateInputSourceList(dict, false);
00784 n = CFArrayGetCount(kbds);
00785 gotLayouts = (n != 0);
00786 #else
00787 OSStatus status = KLGetKeyboardLayoutCount(&n);
00788 gotLayouts = (status == noErr);
00789 #endif
00790
00791 if (!gotLayouts) {
00792 LOG((CLOG_DEBUG1 "can't get keyboard layouts"));
00793 return false;
00794 }
00795
00796
00797 groups.clear();
00798 for (CFIndex i = 0; i < n; ++i) {
00799 bool addToGroups = true;
00800 #if defined(MAC_OS_X_VERSION_10_5)
00801 TISInputSourceRef keyboardLayout =
00802 (TISInputSourceRef)CFArrayGetValueAtIndex(kbds, i);
00803 #else
00804 KeyboardLayoutRef keyboardLayout;
00805 status = KLGetKeyboardLayoutAtIndex(i, &keyboardLayout);
00806 addToGroups == (status == noErr);
00807 #endif
00808 if (addToGroups)
00809 groups.push_back(keyboardLayout);
00810 }
00811 return true;
00812 }
00813
00814 void
00815 COSXKeyState::setGroup(SInt32 group)
00816 {
00817 #if defined(MAC_OS_X_VERSION_10_5)
00818 TISSetInputMethodKeyboardLayoutOverride(m_groups[group]);
00819 #else
00820 KLSetCurrentKeyboardLayout(m_groups[group]);
00821 #endif
00822 }
00823
00824 void
00825 COSXKeyState::checkKeyboardLayout()
00826 {
00827
00828
00829 GroupList groups;
00830 if (getGroups(groups) && groups != m_groups) {
00831 updateKeyMap();
00832 updateKeyState();
00833 }
00834 }
00835
00836 void
00837 COSXKeyState::adjustAltGrModifier(const CKeyIDs& ids,
00838 KeyModifierMask* mask, bool isCommand) const
00839 {
00840 if (!isCommand) {
00841 for (CKeyIDs::const_iterator i = ids.begin(); i != ids.end(); ++i) {
00842 KeyID id = *i;
00843 if (id != kKeyNone &&
00844 ((id < 0xe000u || id > 0xefffu) ||
00845 (id >= kKeyKP_Equal && id <= kKeyKP_9))) {
00846 *mask |= KeyModifierAltGr;
00847 return;
00848 }
00849 }
00850 }
00851 }
00852
00853 KeyButton
00854 COSXKeyState::mapVirtualKeyToKeyButton(UInt32 keyCode)
00855 {
00856
00857 return static_cast<KeyButton>(keyCode + KeyButtonOffset);
00858 }
00859
00860 UInt32
00861 COSXKeyState::mapKeyButtonToVirtualKey(KeyButton keyButton)
00862 {
00863 return static_cast<UInt32>(keyButton - KeyButtonOffset);
00864 }
00865
00866
00867
00868
00869
00870
00871 KeyID
00872 COSXKeyState::CKeyResource::getKeyID(UInt8 c)
00873 {
00874 if (c == 0) {
00875 return kKeyNone;
00876 }
00877 else if (c >= 32 && c < 127) {
00878
00879 return static_cast<KeyID>(c);
00880 }
00881 else {
00882
00883 switch (c) {
00884 case 0x01:
00885 return kKeyHome;
00886
00887 case 0x02:
00888 return kKeyKP_Enter;
00889
00890 case 0x03:
00891 return kKeyKP_Enter;
00892
00893 case 0x04:
00894 return kKeyEnd;
00895
00896 case 0x05:
00897 return kKeyHelp;
00898
00899 case 0x08:
00900 return kKeyBackSpace;
00901
00902 case 0x09:
00903 return kKeyTab;
00904
00905 case 0x0b:
00906 return kKeyPageUp;
00907
00908 case 0x0c:
00909 return kKeyPageDown;
00910
00911 case 0x0d:
00912 return kKeyReturn;
00913
00914 case 0x10:
00915
00916
00917
00918 return kKeyNone;
00919
00920 case 0x1b:
00921 return kKeyEscape;
00922
00923 case 0x1c:
00924 return kKeyLeft;
00925
00926 case 0x1d:
00927 return kKeyRight;
00928
00929 case 0x1e:
00930 return kKeyUp;
00931
00932 case 0x1f:
00933 return kKeyDown;
00934
00935 case 0x7f:
00936 return kKeyDelete;
00937
00938 case 0x06:
00939 case 0x07:
00940 case 0x0a:
00941 case 0x0e:
00942 case 0x0f:
00943 case 0x11:
00944 case 0x12:
00945 case 0x13:
00946 case 0x14:
00947 case 0x15:
00948 case 0x16:
00949 case 0x17:
00950 case 0x18:
00951 case 0x19:
00952 case 0x1a:
00953
00954 return kKeyNone;
00955
00956 default:
00957
00958 break;
00959 }
00960
00961
00962 char str[2];
00963 str[0] = static_cast<char>(c);
00964 str[1] = 0;
00965
00966 #if defined(MAC_OS_X_VERSION_10_5)
00967
00968 TISInputSourceRef isref = TISCopyCurrentKeyboardInputSource();
00969 CFArrayRef langs = (CFArrayRef) TISGetInputSourceProperty(isref, kTISPropertyInputSourceLanguages);
00970 CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)CFArrayGetValueAtIndex(langs, 0));
00971 #else
00972 CFStringEncoding encoding = GetScriptManagerVariable(smKeyScript);
00973 #endif
00974
00975 CFStringRef cfString =
00976 CFStringCreateWithCStringNoCopy(
00977 kCFAllocatorDefault, str, encoding, kCFAllocatorNull);
00978
00979
00980
00981
00982 if (cfString == NULL) {
00983 return kKeyNone;
00984 }
00985
00986
00987 CFMutableStringRef mcfString =
00988 CFStringCreateMutableCopy(kCFAllocatorDefault, 0, cfString);
00989 CFRelease(cfString);
00990 CFStringNormalize(mcfString, kCFStringNormalizationFormC);
00991
00992
00993 int unicodeLength = CFStringGetLength(mcfString);
00994 if (unicodeLength == 0) {
00995 CFRelease(mcfString);
00996 return kKeyNone;
00997 }
00998 if (unicodeLength > 1) {
00999
01000 CFRelease(mcfString);
01001 return kKeyNone;
01002 }
01003
01004
01005 UniChar uc = CFStringGetCharacterAtIndex(mcfString, 0);
01006 CFRelease(mcfString);
01007
01008
01009 return static_cast<KeyID>(uc);
01010 }
01011 }
01012
01013 KeyID
01014 COSXKeyState::CKeyResource::unicharToKeyID(UniChar c)
01015 {
01016 switch (c) {
01017 case 3:
01018 return kKeyKP_Enter;
01019
01020 case 8:
01021 return kKeyBackSpace;
01022
01023 case 9:
01024 return kKeyTab;
01025
01026 case 13:
01027 return kKeyReturn;
01028
01029 case 27:
01030 return kKeyEscape;
01031
01032 case 127:
01033 return kKeyDelete;
01034
01035 default:
01036 if (c < 32) {
01037 return kKeyNone;
01038 }
01039 return static_cast<KeyID>(c);
01040 }
01041 }
01042
01043
01044
01045
01046
01047
01048 COSXKeyState::CUCHRKeyResource::CUCHRKeyResource(const void* resource,
01049 UInt32 keyboardType) :
01050 m_m(NULL),
01051 m_cti(NULL),
01052 m_sdi(NULL),
01053 m_sri(NULL),
01054 m_st(NULL)
01055 {
01056 m_resource = reinterpret_cast<const UCKeyboardLayout*>(resource);
01057 if (m_resource == NULL) {
01058 return;
01059 }
01060
01061
01062 const UCKeyboardTypeHeader* th = NULL;
01063 const UCKeyboardLayout* r = m_resource;
01064 for (ItemCount i = 0; i < r->keyboardTypeCount; ++i) {
01065 if (keyboardType >= r->keyboardTypeList[i].keyboardTypeFirst &&
01066 keyboardType <= r->keyboardTypeList[i].keyboardTypeLast) {
01067 th = r->keyboardTypeList + i;
01068 break;
01069 }
01070 if (r->keyboardTypeList[i].keyboardTypeFirst == 0) {
01071
01072 th = r->keyboardTypeList + i;
01073 }
01074 }
01075 if (th == NULL) {
01076
01077 return;
01078 }
01079
01080
01081 const UInt8* base = reinterpret_cast<const UInt8*>(m_resource);
01082 m_m = reinterpret_cast<const UCKeyModifiersToTableNum*>(base +
01083 th->keyModifiersToTableNumOffset);
01084 m_cti = reinterpret_cast<const UCKeyToCharTableIndex*>(base +
01085 th->keyToCharTableIndexOffset);
01086 m_sdi = reinterpret_cast<const UCKeySequenceDataIndex*>(base +
01087 th->keySequenceDataIndexOffset);
01088 if (th->keyStateRecordsIndexOffset != 0) {
01089 m_sri = reinterpret_cast<const UCKeyStateRecordsIndex*>(base +
01090 th->keyStateRecordsIndexOffset);
01091 }
01092 if (th->keyStateTerminatorsOffset != 0) {
01093 m_st = reinterpret_cast<const UCKeyStateTerminators*>(base +
01094 th->keyStateTerminatorsOffset);
01095 }
01096
01097
01098
01099
01100 m_spaceOutput = 0xffffu;
01101 UInt32 table = getTableForModifier(0);
01102 for (UInt32 button = 0, n = getNumButtons(); button < n; ++button) {
01103 KeyID id = getKey(table, button);
01104 if (id == 0x20) {
01105 UCKeyOutput c =
01106 reinterpret_cast<const UCKeyOutput*>(base +
01107 m_cti->keyToCharTableOffsets[table])[button];
01108 if ((c & kUCKeyOutputTestForIndexMask) ==
01109 kUCKeyOutputStateIndexMask) {
01110 m_spaceOutput = (c & kUCKeyOutputGetIndexMask);
01111 break;
01112 }
01113 }
01114 }
01115 }
01116
01117 bool
01118 COSXKeyState::CUCHRKeyResource::isValid() const
01119 {
01120 return (m_m != NULL);
01121 }
01122
01123 UInt32
01124 COSXKeyState::CUCHRKeyResource::getNumModifierCombinations() const
01125 {
01126
01127 return 32;
01128 }
01129
01130 UInt32
01131 COSXKeyState::CUCHRKeyResource::getNumTables() const
01132 {
01133 return m_cti->keyToCharTableCount;
01134 }
01135
01136 UInt32
01137 COSXKeyState::CUCHRKeyResource::getNumButtons() const
01138 {
01139 return m_cti->keyToCharTableSize;
01140 }
01141
01142 UInt32
01143 COSXKeyState::CUCHRKeyResource::getTableForModifier(UInt32 mask) const
01144 {
01145 if (mask >= m_m->modifiersCount) {
01146 return m_m->defaultTableNum;
01147 }
01148 else {
01149 return m_m->tableNum[mask];
01150 }
01151 }
01152
01153 KeyID
01154 COSXKeyState::CUCHRKeyResource::getKey(UInt32 table, UInt32 button) const
01155 {
01156 assert(table < getNumTables());
01157 assert(button < getNumButtons());
01158
01159 const UInt8* base = reinterpret_cast<const UInt8*>(m_resource);
01160 const UCKeyOutput* cPtr = reinterpret_cast<const UCKeyOutput*>(base +
01161 m_cti->keyToCharTableOffsets[table]);
01162
01163 const UCKeyOutput c = cPtr[button];
01164
01165 KeySequence keys;
01166 switch (c & kUCKeyOutputTestForIndexMask) {
01167 case kUCKeyOutputStateIndexMask:
01168 if (!getDeadKey(keys, c & kUCKeyOutputGetIndexMask)) {
01169 return kKeyNone;
01170 }
01171 break;
01172
01173 case kUCKeyOutputSequenceIndexMask:
01174 default:
01175 if (!addSequence(keys, c)) {
01176 return kKeyNone;
01177 }
01178 break;
01179 }
01180
01181
01182 if (keys.size() != 1) {
01183 return kKeyNone;
01184 }
01185
01186 return keys.front();
01187 }
01188
01189 bool
01190 COSXKeyState::CUCHRKeyResource::getDeadKey(
01191 KeySequence& keys, UInt16 index) const
01192 {
01193 if (m_sri == NULL || index >= m_sri->keyStateRecordCount) {
01194
01195 return false;
01196 }
01197
01198 UInt16 state = 0;
01199 if (!getKeyRecord(keys, index, state)) {
01200 return false;
01201 }
01202 if (state == 0) {
01203
01204 return true;
01205 }
01206
01207
01208 if (m_spaceOutput == 0xffffu) {
01209 return false;
01210 }
01211
01212
01213 if (!keys.empty()) {
01214 return false;
01215 }
01216
01217
01218
01219
01220 if (!getKeyRecord(keys, m_spaceOutput, state) || state != 0) {
01221 return false;
01222 }
01223
01224
01225 for (KeySequence::iterator i = keys.begin(); i != keys.end(); ++i) {
01226 *i = CKeyMap::getDeadKey(*i);
01227 }
01228
01229 return true;
01230 }
01231
01232 bool
01233 COSXKeyState::CUCHRKeyResource::getKeyRecord(
01234 KeySequence& keys, UInt16 index, UInt16& state) const
01235 {
01236 const UInt8* base = reinterpret_cast<const UInt8*>(m_resource);
01237 const UCKeyStateRecord* sr =
01238 reinterpret_cast<const UCKeyStateRecord*>(base +
01239 m_sri->keyStateRecordOffsets[index]);
01240 const UCKeyStateEntryTerminal* kset =
01241 reinterpret_cast<const UCKeyStateEntryTerminal*>(sr->stateEntryData);
01242
01243 UInt16 nextState = 0;
01244 bool found = false;
01245 if (state == 0) {
01246 found = true;
01247 nextState = sr->stateZeroNextState;
01248 if (!addSequence(keys, sr->stateZeroCharData)) {
01249 return false;
01250 }
01251 }
01252 else {
01253
01254 switch (sr->stateEntryFormat) {
01255 case kUCKeyStateEntryTerminalFormat:
01256 for (UInt16 j = 0; j < sr->stateEntryCount; ++j) {
01257 if (kset[j].curState == state) {
01258 if (!addSequence(keys, kset[j].charData)) {
01259 return false;
01260 }
01261 nextState = 0;
01262 found = true;
01263 break;
01264 }
01265 }
01266 break;
01267
01268 case kUCKeyStateEntryRangeFormat:
01269
01270 break;
01271
01272 default:
01273
01274 return false;
01275 }
01276 }
01277 if (!found) {
01278
01279 if (m_st != NULL && state < m_st->keyStateTerminatorCount) {
01280 if (!addSequence(keys, m_st->keyStateTerminators[state - 1])) {
01281 return false;
01282 }
01283 }
01284 nextState = sr->stateZeroNextState;
01285 if (!addSequence(keys, sr->stateZeroCharData)) {
01286 return false;
01287 }
01288 }
01289
01290
01291 state = nextState;
01292
01293 return true;
01294 }
01295
01296 bool
01297 COSXKeyState::CUCHRKeyResource::addSequence(
01298 KeySequence& keys, UCKeyCharSeq c) const
01299 {
01300 if ((c & kUCKeyOutputTestForIndexMask) == kUCKeyOutputSequenceIndexMask) {
01301 UInt16 index = (c & kUCKeyOutputGetIndexMask);
01302 if (index < m_sdi->charSequenceCount &&
01303 m_sdi->charSequenceOffsets[index] !=
01304 m_sdi->charSequenceOffsets[index + 1]) {
01305
01306 return false;
01307 }
01308 }
01309
01310 if (c != 0xfffe && c != 0xffff) {
01311 KeyID id = unicharToKeyID(c);
01312 if (id != kKeyNone) {
01313 keys.push_back(id);
01314 }
01315 }
01316
01317 return true;
01318 }