• Main Page
  • Classes
  • Files
  • File List

COSXKeyState.cpp

00001 /*
00002  * synergy -- mouse and keyboard sharing utility
00003  * Copyright (C) 2012 Bolton Software Ltd.
00004  * Copyright (C) 2004 Chris Schoeneman
00005  * 
00006  * This package is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * found in the file COPYING that should have accompanied this file.
00009  * 
00010  * This package is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
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 // Note that some virtual keys codes appear more than once.  The
00028 // first instance of a virtual key code maps to the KeyID that we
00029 // want to generate for that code.  The others are for mapping
00030 // different KeyIDs to a single key code.
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; // 71
00039 #else
00040 // Hardcoded virtual key table on 10.4 and below.
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     // cursor keys.  if we don't do this we'll may still get these from
00059     // the keyboard resource but they may not correspond to the arrow
00060     // keys.
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 }, // Mac Keyboards have 'Help' on 'Insert'
00070 
00071     // function keys
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   // Hardcoded virtual key table on 10.4 and below.
00108     // cursor keys.
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     // function keys
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     // virtual key 110 is fn+enter and i have no idea what that's supposed
00157     // to map to.  also the enter key with numlock on is a modifier but i
00158     // don't know which.
00159 
00160     // modifier keys.  OS X doesn't seem to support right handed versions
00161     // of modifier keys so we map them to the left handed versions.
00162     { kKeyShift_L,      s_shiftVK },
00163     { kKeyShift_R,      s_shiftVK }, // 60
00164     { kKeyControl_L,    s_controlVK },
00165     { kKeyControl_R,    s_controlVK }, // 62
00166     { kKeyAlt_L,        s_altVK },
00167     { kKeyAlt_R,        s_altVK },
00168     { kKeySuper_L,      s_superVK },
00169     { kKeySuper_R,      s_superVK }, // 61
00170     { kKeyMeta_L,       s_superVK },
00171     { kKeyMeta_R,       s_superVK }, // 61
00172 
00173     // toggle modifiers
00174     { kKeyNumLock,      s_numLockVK },
00175     { kKeyCapsLock,     s_capsLockVK }
00176 };
00177 
00178 
00179 //
00180 // COSXKeyState
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     // initialize modifier key values
00204     shiftPressed = false;
00205     controlPressed = false;
00206     altPressed = false;
00207     superPressed = false;
00208     capsPressed = false;
00209 
00210     // build virtual key map
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     // map modifier key
00279     if (maskOut != NULL) {
00280         KeyModifierMask activeMask = getActiveModifiers();
00281         activeMask &= ~KeyModifierAltGr;
00282         *maskOut    = activeMask;
00283     }
00284 
00285     // get virtual key
00286     UInt32 vkCode = CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode);
00287 
00288     // handle up events
00289     UInt32 eventKind = CGEventGetType(event);
00290     if (eventKind == kCGEventKeyUp) {
00291         // the id isn't used.  we just need the same button we used on
00292         // the key press.  note that we don't use or reset the dead key
00293         // state;  up events should not affect the dead key state.
00294         ids.push_back(kKeyNone);
00295         return mapVirtualKeyToKeyButton(vkCode);
00296     }
00297 
00298     // check for special keys
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     // get keyboard info
00307 
00308 #if defined(MAC_OS_X_VERSION_10_5)
00309     TISInputSourceRef currentKeyboardLayout = TISCopyCurrentKeyboardLayoutInputSource(); 
00310 #else
00311     KeyboardLayoutRef currentKeyboardLayout;
00312     OSStatus status = KLGetCurrentKeyboardLayout(&currentKeyboardLayout);
00313 #endif
00314     if (currentKeyboardLayout == NULL) {
00315         return kKeyNone;
00316     }
00317 
00318     // get the event modifiers and remove the command and control
00319     // keys.  note if we used them though.
00320     // UCKeyTranslate expects old-style Carbon modifiers, so convert.
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     // if we've used a command key then we want the glyph produced without
00329     // the option key (i.e. the base glyph).
00330     //if (isCommand) {
00331         modifiers &= ~optionKey;
00332     //}
00333 
00334     // choose action
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     // translate via uchr resource
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         // translate key
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         // get the characters
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     // pass keys through unchanged
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     // update keyboard groups
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         // add special keys
00451         getKeyMapForSpecialKeys(keyMap, g);
00452 
00453         const void* resource;
00454         bool layoutValid = false;
00455         
00456         // add regular keys
00457         // try uchr resource first
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         // let system figure out character for us
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             // check the key for specials and store the value (persistent until changed)
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             //Set the event flags for special keys - see following link:
00511             //http://stackoverflow.com/questions/2008126/cgeventpost-possible-bug-when-simulating-keyboard-events
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             // add a delay if client data isn't zero
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     // special keys are insensitive to modifers and none are dead keys
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             // all locking keys are half duplex on OS X
00564             keyMap.addHalfDuplexButton(item.m_button);
00565         }
00566     }
00567 
00568     // note:  we don't special case the number pad keys.  querying the
00569     // mac keyboard returns the non-keypad version of those keys but
00570     // a CKeyState always provides a mapping from keypad keys to
00571     // non-keypad keys so we'll be able to generate the characters
00572     // anyway.
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     // space for all possible modifier combinations
00584     std::vector<bool> modifiers(r.getNumModifierCombinations());
00585 
00586     // make space for the keys that any single button can synthesize
00587     std::vector<std::pair<KeyID, bool> > buttonKeys(r.getNumTables());
00588 
00589     // iterate over each button
00590     CKeyMap::KeyItem item;
00591     for (UInt32 i = 0; i < r.getNumButtons(); ++i) {
00592         item.m_button = mapVirtualKeyToKeyButton(i);
00593 
00594         // the KeyIDs we've already handled
00595         std::set<KeyID> keys;
00596 
00597         // convert the entry in each table for this button to a KeyID
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         // iterate over each character table
00604         for (UInt32 j = 0; j < r.getNumTables(); ++j) {
00605             // get the KeyID for the button/table
00606             KeyID id = buttonKeys[j].first;
00607             if (id == kKeyNone) {
00608                 continue;
00609             }
00610 
00611             // if we've already handled the KeyID in the table then
00612             // move on to the next table
00613             if (keys.count(id) > 0) {
00614                 continue;
00615             }
00616             keys.insert(id);
00617 
00618             // prepare item.  the client state is 1 for dead keys.
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                 // all locking keys are half duplex on OS X
00626                 keyMap.addHalfDuplexButton(i);
00627             }
00628 
00629             // collect the tables that map to the same KeyID.  we know it
00630             // can't be any earlier tables because of the check above.
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             // collect the modifier combinations that map to any of the
00640             // tables we just collected
00641             for (UInt32 k = 0; k < r.getNumModifierCombinations(); ++k) {
00642                 modifiers[k] = (tables.count(r.getTableForModifier(k)) > 0);
00643             }
00644 
00645             // figure out which modifiers the key is sensitive to.  the
00646             // key is insensitive to a modifier if for every modifier mask
00647             // with the modifier bit unset in the modifiers we also find
00648             // the same mask with the bit set.
00649             //
00650             // we ignore a few modifiers that we know aren't important
00651             // for generating characters.  in fact, we want to ignore any
00652             // characters generated by the control key.  we don't map
00653             // those and instead expect the control modifier plus a key.
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             // find each required modifier mask.  the key can be synthesized
00672             // using any of the masks.
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             // now add a key entry for each key/required modifier pair.
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     // look up button for key
00698     KeyButton button = getButton(key, pollActiveGroup());
00699     if (button == 0 && key != kKeyNone) {
00700         return false;
00701     }
00702     macVirtualKey = mapKeyButtonToVirtualKey(button);
00703     
00704     // calculate modifier mask
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     // compute changed modifiers
00733     KeyModifierMask changed = (oldMask ^ newMask);
00734 
00735     // synthesize changed modifier keys
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     // get number of layouts
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     // get each layout
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     // XXX -- should call this when notified that groups have changed.
00828     // if no notification for that then we should poll.
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     // 'A' maps to 0 so shift every id
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 // COSXKeyState::CKeyResource
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         // ASCII
00879         return static_cast<KeyID>(c);
00880     }
00881     else {
00882         // handle special keys
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             // OS X maps all the function keys (F1, etc) to this one key.
00916             // we can't determine the right key here so we have to do it
00917             // some other way.
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             // discard other control characters
00954             return kKeyNone;
00955 
00956         default:
00957             // not special or unknown
00958             break;
00959         }
00960 
00961         // create string with character
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         // get current keyboard script
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         // convert to unicode
00975         CFStringRef cfString =
00976             CFStringCreateWithCStringNoCopy(
00977                 kCFAllocatorDefault, str, encoding, kCFAllocatorNull);
00978 
00979         // sometimes CFStringCreate...() returns NULL (e.g. Apple Korean
00980         // encoding with char value 214).  if it did then make no key,
00981         // otherwise CFStringCreateMutableCopy() will crash.
00982         if (cfString == NULL) {
00983             return kKeyNone; 
00984         }
00985 
00986         // convert to precomposed
00987         CFMutableStringRef mcfString =
00988             CFStringCreateMutableCopy(kCFAllocatorDefault, 0, cfString);
00989         CFRelease(cfString);
00990         CFStringNormalize(mcfString, kCFStringNormalizationFormC);
00991 
00992         // check result
00993         int unicodeLength = CFStringGetLength(mcfString);
00994         if (unicodeLength == 0) {
00995             CFRelease(mcfString);
00996             return kKeyNone;
00997         }
00998         if (unicodeLength > 1) {
00999             // FIXME -- more than one character, we should handle this
01000             CFRelease(mcfString);
01001             return kKeyNone;
01002         }
01003 
01004         // get unicode character
01005         UniChar uc = CFStringGetCharacterAtIndex(mcfString, 0);
01006         CFRelease(mcfString);
01007 
01008         // convert to KeyID
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 // COSXKeyState::CUCHRKeyResource
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     // find the keyboard info for the current keyboard type
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             // found the default.  use it unless we find a match.
01072             th = r->keyboardTypeList + i;
01073         }
01074     }
01075     if (th == NULL) {
01076         // cannot find a suitable keyboard type
01077         return;
01078     }
01079 
01080     // get tables for keyboard type
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     // find the space key, but only if it can combine with dead keys.
01098     // a dead key followed by a space yields the non-dead version of
01099     // the dead key.
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     // only 32 (not 256) because the righthanded modifier bits are ignored
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     // XXX -- no support for multiple characters
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         // XXX -- should we be using some other fallback?
01195         return false;
01196     }
01197 
01198     UInt16 state = 0;
01199     if (!getKeyRecord(keys, index, state)) {
01200         return false;
01201     }
01202     if (state == 0) {
01203         // not a dead key
01204         return true;
01205     }
01206 
01207     // no dead keys if we couldn't find the space key
01208     if (m_spaceOutput == 0xffffu) {
01209         return false;
01210     }
01211 
01212     // the dead key should not have put anything in the key list
01213     if (!keys.empty()) {
01214         return false;
01215     }
01216 
01217     // get the character generated by pressing the space key after the
01218     // dead key.  if we're still in a compose state afterwards then we're
01219     // confused so we bail.
01220     if (!getKeyRecord(keys, m_spaceOutput, state) || state != 0) {
01221         return false;
01222     }
01223 
01224     // convert keys to their dead counterparts
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         // we have a next entry
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             // XXX -- not supported yet
01270             break;
01271 
01272         default:
01273             // XXX -- unknown format
01274             return false;
01275         }
01276     }
01277     if (!found) {
01278         // use a terminator
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     // next
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             // XXX -- sequences not supported yet
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 }

Generated on Sun May 19 2013 00:00:05 for Synergy by  doxygen 1.7.1