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