Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members

COSXKeyState.cpp

00001 /*
00002  * synergy -- mouse and keyboard sharing utility
00003  * Copyright (C) 2004 Chris Schoeneman
00004  * 
00005  * This package is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU General Public License
00007  * found in the file COPYING that should have accompanied this file.
00008  * 
00009  * This package is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  */
00014 
00015 #include "COSXKeyState.h"
00016 #include "CLog.h"
00017 #include "CArch.h"
00018 
00019 // Hardcoded virtual key table.  Oddly, Apple doesn't document the
00020 // meaning of virtual key codes.  The whole point of *virtual* key
00021 // codes is to make them hardware independent so these codes should
00022 // be constant across OS versions and hardware.  Yet they don't
00023 // tell us what codes map to what keys so we have to figure it out
00024 // for ourselves.
00025 //
00026 // Note that some virtual keys codes appear more than once.  The
00027 // first instance of a virtual key code maps to the KeyID that we
00028 // want to generate for that code.  The others are for mapping
00029 // different KeyIDs to a single key code.
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     // cursor keys.  if we don't do this we'll may still get these from
00044     // the keyboard resource but they may not correspond to the arrow
00045     // keys.
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     // function keys
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     // virtual key 110 is fn+enter and i have no idea what that's supposed
00092     // to map to.  also the enter key with numlock on is a modifier but i
00093     // don't know which.
00094 
00095     // modifier keys.  OS X doesn't seem to support right handed versions
00096     // of modifier keys so we map them to the left handed versions.
00097     { kKeyShift_L,      s_shiftVK },
00098     { kKeyShift_R,      s_shiftVK }, // 60
00099     { kKeyControl_L,    s_controlVK },
00100     { kKeyControl_R,    s_controlVK }, // 62
00101     { kKeyAlt_L,        s_altVK },
00102     { kKeyAlt_R,        s_altVK },
00103     { kKeySuper_L,      s_superVK },
00104     { kKeySuper_R,      s_superVK }, // 61
00105     { kKeyMeta_L,       s_superVK },
00106     { kKeyMeta_R,       s_superVK }, // 61
00107 
00108     // toggle modifiers
00109     { kKeyNumLock,      s_numLockVK },
00110     { kKeyCapsLock,     s_capsLockVK }
00111 };
00112 
00113 
00114 //
00115 // COSXKeyState
00116 //
00117 
00118 COSXKeyState::COSXKeyState() :
00119     m_deadKeyState(0)
00120 {
00121 
00122     // build virtual key map
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     // do nothing
00133 }
00134 
00135 KeyModifierMask
00136 COSXKeyState::mapModifiersFromOSX(UInt32 mask) const
00137 {
00138 LOG((CLOG_DEBUG1 "mask: %04x", mask));
00139     // convert
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     // map modifier key
00179     if (maskOut != NULL) {
00180         KeyModifierMask activeMask = getActiveModifiers();
00181         activeMask &= ~KeyModifierAltGr;
00182         *maskOut    = activeMask;
00183     }
00184 
00185     // get virtual key
00186     UInt32 vkCode;
00187     GetEventParameter(event, kEventParamKeyCode, typeUInt32,
00188                             NULL, sizeof(vkCode), NULL, &vkCode);
00189 
00190     // handle up events
00191     UInt32 eventKind = GetEventKind(event);
00192     if (eventKind == kEventRawKeyUp) {
00193         // the id isn't used.  we just need the same button we used on
00194         // the key press.  note that we don't use or reset the dead key
00195         // state;  up events should not affect the dead key state.
00196         ids.push_back(kKeyNone);
00197         return mapVirtualKeyToKeyButton(vkCode);
00198     }
00199 
00200     // check for special keys
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     // get keyboard info
00209 
00210     TISInputSourceRef currentKeyboardLayout = TISCopyCurrentKeyboardLayoutInputSource(); 
00211     if (currentKeyboardLayout == NULL) {
00212         return kKeyNone;
00213     }
00214 
00215     // get the event modifiers and remove the command and control
00216     // keys.  note if we used them though.
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     // if we've used a command key then we want the glyph produced without
00226     // the option key (i.e. the base glyph).
00227     if (isCommand) {
00228         modifiers &= ~optionKey;
00229     }
00230 
00231     // choose action
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     // translate via uchr resource
00246     CFDataRef ref = (CFDataRef) TISGetInputSourceProperty(currentKeyboardLayout,
00247                                 kTISPropertyUnicodeKeyLayoutData);
00248     const UCKeyboardLayout* layout = (const UCKeyboardLayout*) CFDataGetBytePtr(ref);
00249     if (layout != NULL) {
00250 
00251         // translate key
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         // get the characters
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     // pass keys through unchanged
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     // update keyboard groups
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         // add special keys
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         // let system figure out character for us
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         // add a delay if client data isn't zero
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     // special keys are insensitive to modifers and none are dead keys
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             // all locking keys are half duplex on OS X
00406             keyMap.addHalfDuplexButton(item.m_button);
00407         }
00408     }
00409 
00410     // note:  we don't special case the number pad keys.  querying the
00411     // mac keyboard returns the non-keypad version of those keys but
00412     // a CKeyState always provides a mapping from keypad keys to
00413     // non-keypad keys so we'll be able to generate the characters
00414     // anyway.
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     // space for all possible modifier combinations
00426     std::vector<bool> modifiers(r.getNumModifierCombinations());
00427 
00428     // make space for the keys that any single button can synthesize
00429     std::vector<std::pair<KeyID, bool> > buttonKeys(r.getNumTables());
00430 
00431     // iterate over each button
00432     CKeyMap::KeyItem item;
00433     for (UInt32 i = 0; i < r.getNumButtons(); ++i) {
00434         item.m_button = mapVirtualKeyToKeyButton(i);
00435 
00436         // the KeyIDs we've already handled
00437         std::set<KeyID> keys;
00438 
00439         // convert the entry in each table for this button to a KeyID
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         // iterate over each character table
00446         for (UInt32 j = 0; j < r.getNumTables(); ++j) {
00447             // get the KeyID for the button/table
00448             KeyID id = buttonKeys[j].first;
00449             if (id == kKeyNone) {
00450                 continue;
00451             }
00452 
00453             // if we've already handled the KeyID in the table then
00454             // move on to the next table
00455             if (keys.count(id) > 0) {
00456                 continue;
00457             }
00458             keys.insert(id);
00459 
00460             // prepare item.  the client state is 1 for dead keys.
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                 // all locking keys are half duplex on OS X
00468                 keyMap.addHalfDuplexButton(i);
00469             }
00470 
00471             // collect the tables that map to the same KeyID.  we know it
00472             // can't be any earlier tables because of the check above.
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             // collect the modifier combinations that map to any of the
00482             // tables we just collected
00483             for (UInt32 k = 0; k < r.getNumModifierCombinations(); ++k) {
00484                 modifiers[k] = (tables.count(r.getTableForModifier(k)) > 0);
00485             }
00486 
00487             // figure out which modifiers the key is sensitive to.  the
00488             // key is insensitive to a modifier if for every modifier mask
00489             // with the modifier bit unset in the modifiers we also find
00490             // the same mask with the bit set.
00491             //
00492             // we ignore a few modifiers that we know aren't important
00493             // for generating characters.  in fact, we want to ignore any
00494             // characters generated by the control key.  we don't map
00495             // those and instead expect the control modifier plus a key.
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             // find each required modifier mask.  the key can be synthesized
00514             // using any of the masks.
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             // now add a key entry for each key/required modifier pair.
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     // look up button for key
00540     KeyButton button = getButton(key, pollActiveGroup());
00541     if (button == 0 && key != kKeyNone) {
00542         return false;
00543     }
00544     macVirtualKey = mapKeyButtonToVirtualKey(button);
00545     
00546     // calculate modifier mask
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     // compute changed modifiers
00575     KeyModifierMask changed = (oldMask ^ newMask);
00576 
00577     // synthesize changed modifier keys
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     // get number of layouts
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     // get each layout
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     // XXX -- should call this when notified that groups have changed.
00648     // if no notification for that then we should poll.
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     // 'A' maps to 0 so shift every id
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 // COSXKeyState::CKeyResource
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         // ASCII
00699         return static_cast<KeyID>(c);
00700     }
00701     else {
00702         // handle special keys
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             // OS X maps all the function keys (F1, etc) to this one key.
00736             // we can't determine the right key here so we have to do it
00737             // some other way.
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             // discard other control characters
00774             return kKeyNone;
00775 
00776         default:
00777             // not special or unknown
00778             break;
00779         }
00780 
00781         // create string with character
00782         char str[2];
00783         str[0] = static_cast<char>(c);
00784         str[1] = 0;
00785 
00786         // get current keyboard script
00787 
00788     TISInputSourceRef isref = TISCopyCurrentKeyboardInputSource();
00789     CFArrayRef langs = (CFArrayRef) TISGetInputSourceProperty(isref, kTISPropertyInputSourceLanguages);
00790 
00791         // convert to unicode
00792         CFStringRef cfString =
00793             CFStringCreateWithCStringNoCopy(kCFAllocatorDefault,
00794                             str, CFStringConvertIANACharSetNameToEncoding((CFStringRef) CFArrayGetValueAtIndex(langs, 0)),
00795                             kCFAllocatorNull);
00796 
00797         // sometimes CFStringCreate...() returns NULL (e.g. Apple Korean
00798         // encoding with char value 214).  if it did then make no key,
00799         // otherwise CFStringCreateMutableCopy() will crash.
00800         if (cfString == NULL) {
00801             return kKeyNone; 
00802         }
00803 
00804         // convert to precomposed
00805         CFMutableStringRef mcfString =
00806             CFStringCreateMutableCopy(kCFAllocatorDefault, 0, cfString);
00807         CFRelease(cfString);
00808         CFStringNormalize(mcfString, kCFStringNormalizationFormC);
00809 
00810         // check result
00811         int unicodeLength = CFStringGetLength(mcfString);
00812         if (unicodeLength == 0) {
00813             CFRelease(mcfString);
00814             return kKeyNone;
00815         }
00816         if (unicodeLength > 1) {
00817             // FIXME -- more than one character, we should handle this
00818             CFRelease(mcfString);
00819             return kKeyNone;
00820         }
00821 
00822         // get unicode character
00823         UniChar uc = CFStringGetCharacterAtIndex(mcfString, 0);
00824         CFRelease(mcfString);
00825 
00826         // convert to KeyID
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 // COSXKeyState::CUCHRKeyResource
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     // find the keyboard info for the current keyboard type
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             // found the default.  use it unless we find a match.
00890             th = r->keyboardTypeList + i;
00891         }
00892     }
00893     if (th == NULL) {
00894         // cannot find a suitable keyboard type
00895         return;
00896     }
00897 
00898     // get tables for keyboard type
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     // find the space key, but only if it can combine with dead keys.
00916     // a dead key followed by a space yields the non-dead version of
00917     // the dead key.
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     // only 32 (not 256) because the righthanded modifier bits are ignored
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     // XXX -- no support for multiple characters
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         // XXX -- should we be using some other fallback?
01013         return false;
01014     }
01015 
01016     UInt16 state = 0;
01017     if (!getKeyRecord(keys, index, state)) {
01018         return false;
01019     }
01020     if (state == 0) {
01021         // not a dead key
01022         return true;
01023     }
01024 
01025     // no dead keys if we couldn't find the space key
01026     if (m_spaceOutput == 0xffffu) {
01027         return false;
01028     }
01029 
01030     // the dead key should not have put anything in the key list
01031     if (!keys.empty()) {
01032         return false;
01033     }
01034 
01035     // get the character generated by pressing the space key after the
01036     // dead key.  if we're still in a compose state afterwards then we're
01037     // confused so we bail.
01038     if (!getKeyRecord(keys, m_spaceOutput, state) || state != 0) {
01039         return false;
01040     }
01041 
01042     // convert keys to their dead counterparts
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         // we have a next entry
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             // XXX -- not supported yet
01088             break;
01089 
01090         default:
01091             // XXX -- unknown format
01092             return false;
01093         }
01094     }
01095     if (!found) {
01096         // use a terminator
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     // next
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             // XXX -- sequences not supported yet
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 }

Generated on Fri Nov 6 00:21:14 2009 for synergy-plus by  doxygen 1.3.9.1