void OSXKeyState::getKeyMapForSpecialKeys(synergy::KeyMap& keyMap, SInt32 group) const { // special keys are insensitive to modifers and none are dead keys synergy::KeyMap::KeyItem item; for (size_t i = 0; i < sizeof(s_controlKeys) / sizeof(s_controlKeys[0]); ++i) { const KeyEntry& entry = s_controlKeys[i]; item.m_id = entry.m_keyID; item.m_group = group; item.m_button = mapVirtualKeyToKeyButton(entry.m_virtualKey); item.m_required = 0; item.m_sensitive = 0; item.m_dead = false; item.m_client = 0; synergy::KeyMap::initModifierKey(item); keyMap.addKeyEntry(item); if (item.m_lock) { // all locking keys are half duplex on OS X keyMap.addHalfDuplexButton(item.m_button); } } // note: we don't special case the number pad keys. querying the // mac keyboard returns the non-keypad version of those keys but // a KeyState always provides a mapping from keypad keys to // non-keypad keys so we'll be able to generate the characters // anyway. }
bool OSXKeyState::getKeyMap(synergy::KeyMap& keyMap, SInt32 group, const KeyResource& r) const { if (!r.isValid()) { return false; } // space for all possible modifier combinations std::vector<bool> modifiers(r.getNumModifierCombinations()); // make space for the keys that any single button can synthesize std::vector<std::pair<KeyID, bool> > buttonKeys(r.getNumTables()); // iterate over each button synergy::KeyMap::KeyItem item; for (UInt32 i = 0; i < r.getNumButtons(); ++i) { item.m_button = mapVirtualKeyToKeyButton(i); // the KeyIDs we've already handled std::set<KeyID> keys; // convert the entry in each table for this button to a KeyID for (UInt32 j = 0; j < r.getNumTables(); ++j) { buttonKeys[j].first = r.getKey(j, i); buttonKeys[j].second = synergy::KeyMap::isDeadKey(buttonKeys[j].first); } // iterate over each character table for (UInt32 j = 0; j < r.getNumTables(); ++j) { // get the KeyID for the button/table KeyID id = buttonKeys[j].first; if (id == kKeyNone) { continue; } // if we've already handled the KeyID in the table then // move on to the next table if (keys.count(id) > 0) { continue; } keys.insert(id); // prepare item. the client state is 1 for dead keys. item.m_id = id; item.m_group = group; item.m_dead = buttonKeys[j].second; item.m_client = buttonKeys[j].second ? 1 : 0; synergy::KeyMap::initModifierKey(item); if (item.m_lock) { // all locking keys are half duplex on OS X keyMap.addHalfDuplexButton(i); } // collect the tables that map to the same KeyID. we know it // can't be any earlier tables because of the check above. std::set<UInt8> tables; tables.insert(static_cast<UInt8>(j)); for (UInt32 k = j + 1; k < r.getNumTables(); ++k) { if (buttonKeys[k].first == id) { tables.insert(static_cast<UInt8>(k)); } } // collect the modifier combinations that map to any of the // tables we just collected for (UInt32 k = 0; k < r.getNumModifierCombinations(); ++k) { modifiers[k] = (tables.count(r.getTableForModifier(k)) > 0); } // figure out which modifiers the key is sensitive to. the // key is insensitive to a modifier if for every modifier mask // with the modifier bit unset in the modifiers we also find // the same mask with the bit set. // // we ignore a few modifiers that we know aren't important // for generating characters. in fact, we want to ignore any // characters generated by the control key. we don't map // those and instead expect the control modifier plus a key. UInt32 sensitive = 0; for (UInt32 k = 0; (1u << k) < r.getNumModifierCombinations(); ++k) { UInt32 bit = (1u << k); if ((bit << 8) == cmdKey || (bit << 8) == controlKey || (bit << 8) == rightControlKey) { continue; } for (UInt32 m = 0; m < r.getNumModifierCombinations(); ++m) { if (modifiers[m] != modifiers[m ^ bit]) { sensitive |= bit; break; } } } // find each required modifier mask. the key can be synthesized // using any of the masks. std::set<UInt32> required; for (UInt32 k = 0; k < r.getNumModifierCombinations(); ++k) { if ((k & sensitive) == k && modifiers[k & sensitive]) { required.insert(k); } } // now add a key entry for each key/required modifier pair. item.m_sensitive = mapModifiersFromOSX(sensitive << 8); for (std::set<UInt32>::iterator k = required.begin(); k != required.end(); ++k) { item.m_required = mapModifiersFromOSX(*k << 8); // Quick and dirty workaround for #2765 // #2765 could be due to a bug in the Apple CoreServices // Framework if (item.m_id == 0x20 && item.m_button == 0x7 && item.m_group == 0) { item.m_button = 0x32; LOG((CLOG_WARN "Key button for 0x20 patched")); } keyMap.addKeyEntry(item); } } } return true; }