void CKeyState::fakeToggle(KeyModifierMask modifier) { const KeyButtons& buttons = m_maskToKeys[getIndexForModifier(modifier)]; if (buttons.empty() || !isToggle(modifier)) { return; } KeyButton button = buttons[0]; // get the sequence of keys to simulate key toggle Keystrokes keys; Keystroke keystroke; keystroke.m_key = button; keystroke.m_press = true; keystroke.m_repeat = false; keys.push_back(keystroke); keystroke.m_press = false; keys.push_back(keystroke); // generate key events fakeKeyEvents(keys, 1); // note the toggle m_keys[button] ^= kToggled; m_mask ^= modifier; }
void CKeyState::fakeAllKeysUp() { Keystrokes keys; for (KeyButton i = 0; i < IKeyState::kNumButtons; ++i) { if (m_syntheticKeys[i] > 0) { keys.push_back(Keystroke(i, false, false, m_keyClientData[i])); m_keys[i] = 0; m_syntheticKeys[i] = 0; } } fakeKeys(keys, 1); }
void CKeyState::fakeAllKeysUp() { Keystrokes keys; for (KeyButton i = 0; i < IKeyState::kNumButtons; ++i) { if (m_syntheticKeys[i] > 0) { keys.push_back(Keystroke(i, false, false, m_keyClientData[i])); m_keys[i] = 0; m_syntheticKeys[i] = 0; } } fakeKeys(keys, 1); memset(&m_serverKeys, 0, sizeof(m_serverKeys)); m_activeModifiers.clear(); m_mask = pollActiveModifiers(); }
bool KeyState::fakeKeyUp(KeyButton serverID) { // if we haven't seen this button go down then ignore it KeyButton localID = m_serverKeys[serverID & kButtonMask]; if (localID == 0) { return false; } // get the sequence of keys to simulate key release Keystrokes keys; keys.push_back(Keystroke(localID, false, false, m_keyClientData[localID])); // note keys down --m_keys[localID]; --m_syntheticKeys[localID]; m_serverKeys[serverID] = 0; // check if this is a modifier ModifierToKeys::iterator i = m_activeModifiers.begin(); while (i != m_activeModifiers.end()) { if (i->second.m_button == localID && !i->second.m_lock) { // modifier is no longer down KeyModifierMask mask = i->first; ModifierToKeys::iterator tmp = i; ++i; m_activeModifiers.erase(tmp); if (m_activeModifiers.count(mask) == 0) { // no key for modifier is down so deactivate modifier m_mask &= ~mask; LOG((CLOG_DEBUG1 "new state %04x", m_mask)); } } else { ++i; } } // generate key events fakeKeys(keys, 1); return true; }
void CKeyState::fakeKeyUp(KeyButton button) { // if we haven't seen this button go down then ignore it KeyButton localID = m_serverKeyMap[button & kButtonMask]; if (localID == 0) { return; } // get the sequence of keys to simulate key release Keystrokes keys; Keystroke keystroke; keystroke.m_key = localID; keystroke.m_press = false; keystroke.m_repeat = false; keys.push_back(keystroke); // generate key events fakeKeyEvents(keys, 1); // note that key is now up updateKeyState(button, localID, false, true); }
bool CKeyState::mapModifier(Keystrokes& keys, Keystrokes& undo, KeyModifierMask mask, bool desireActive, bool force) const { // look up modifier const KeyButtons& buttons = m_maskToKeys[getIndexForModifier(mask)]; if (buttons.empty()) { return false; } // ignore if already in desired state if (!force && isModifierActive(mask) == desireActive) { return true; } // initialize keystroke Keystroke keystroke; keystroke.m_repeat = false; // handle toggles if (isToggle(mask)) { keystroke.m_key = buttons[0]; keystroke.m_press = true; keys.push_back(keystroke); keystroke.m_press = false; keys.push_back(keystroke); keystroke.m_press = false; undo.push_back(keystroke); keystroke.m_press = true; undo.push_back(keystroke); } else if (desireActive) { // press keystroke.m_key = buttons[0]; keystroke.m_press = true; keys.push_back(keystroke); keystroke.m_press = false; undo.push_back(keystroke); } else { // releasing a modifier is quite different from pressing one. // when we release a modifier we have to release every keycode that // is assigned to the modifier since the modifier is active if any // one of them is down. when we press a modifier we just have to // press one of those keycodes. for (KeyButtons::const_iterator j = buttons.begin(); j != buttons.end(); ++j) { if (isKeyDown(*j)) { keystroke.m_key = *j; keystroke.m_press = false; keys.push_back(keystroke); keystroke.m_press = true; undo.push_back(keystroke); } } } return true; }
void CKeyMap::addKeystrokes(EKeystroke type, const KeyItem& keyItem, ModifierToKeys& activeModifiers, KeyModifierMask& currentState, Keystrokes& keystrokes) const { KeyButton button = keyItem.m_button; UInt32 data = keyItem.m_client; switch (type) { case kKeystrokePress: keystrokes.push_back(Keystroke(button, true, false, data)); if (keyItem.m_generates != 0) { if (!keyItem.m_lock || (currentState & keyItem.m_generates) == 0) { // add modifier key and activate modifier activeModifiers.insert(std::make_pair( keyItem.m_generates, keyItem)); currentState |= keyItem.m_generates; } else { // deactivate locking modifier activeModifiers.erase(keyItem.m_generates); currentState &= ~keyItem.m_generates; } } break; case kKeystrokeRelease: keystrokes.push_back(Keystroke(button, false, false, data)); if (keyItem.m_generates != 0 && !keyItem.m_lock) { // remove key from active modifiers std::pair<ModifierToKeys::iterator, ModifierToKeys::iterator> range = activeModifiers.equal_range(keyItem.m_generates); for (ModifierToKeys::iterator i = range.first; i != range.second; ++i) { if (i->second.m_button == button) { activeModifiers.erase(i); break; } } // if no more keys for this modifier then deactivate modifier if (activeModifiers.count(keyItem.m_generates) == 0) { currentState &= ~keyItem.m_generates; } } break; case kKeystrokeRepeat: keystrokes.push_back(Keystroke(button, false, true, data)); keystrokes.push_back(Keystroke(button, true, true, data)); // no modifier changes on key repeat break; case kKeystrokeClick: keystrokes.push_back(Keystroke(button, true, false, data)); keystrokes.push_back(Keystroke(button, false, false, data)); // no modifier changes on key click break; case kKeystrokeModify: case kKeystrokeUnmodify: if (keyItem.m_lock) { // we assume there's just one button for this modifier if (m_halfDuplex.count(button) > 0) { if (type == kKeystrokeModify) { // turn half-duplex toggle on (press) keystrokes.push_back(Keystroke(button, true, false, data)); } else { // turn half-duplex toggle off (release) keystrokes.push_back(Keystroke(button, false, false, data)); } } else { // toggle (click) keystrokes.push_back(Keystroke(button, true, false, data)); keystrokes.push_back(Keystroke(button, false, false, data)); } } else if (type == kKeystrokeModify) { // press modifier keystrokes.push_back(Keystroke(button, true, false, data)); } else { // release all the keys that generate the modifier that are // currently down std::pair<ModifierToKeys::const_iterator, ModifierToKeys::const_iterator> range = activeModifiers.equal_range(keyItem.m_generates); for (ModifierToKeys::const_iterator i = range.first; i != range.second; ++i) { keystrokes.push_back(Keystroke(i->second.m_button, false, false, i->second.m_client)); } } if (type == kKeystrokeModify) { activeModifiers.insert(std::make_pair( keyItem.m_generates, keyItem)); currentState |= keyItem.m_generates; } else { activeModifiers.erase(keyItem.m_generates); currentState &= ~keyItem.m_generates; } break; } }
bool CKeyMap::keysForKeyItem(const KeyItem& keyItem, SInt32& group, ModifierToKeys& activeModifiers, KeyModifierMask& currentState, KeyModifierMask desiredState, KeyModifierMask overrideModifiers, bool isAutoRepeat, Keystrokes& keystrokes) const { static const KeyModifierMask s_notRequiredMask = KeyModifierAltGr | KeyModifierNumLock | KeyModifierScrollLock; // add keystrokes to adjust the group if (group != keyItem.m_group) { group = keyItem.m_group; keystrokes.push_back(Keystroke(group, true, false)); } EKeystroke type; if (keyItem.m_dead) { // adjust modifiers for dead key if (!keysForModifierState(keyItem.m_button, group, activeModifiers, currentState, keyItem.m_required, keyItem.m_sensitive, 0, keystrokes)) { LOG((CLOG_DEBUG1 "unable to match modifier state for dead key %d", keyItem.m_button)); return false; } // press and release the dead key type = kKeystrokeClick; } else { // if this a command key then we don't have to match some of the // key's required modifiers. KeyModifierMask sensitive = keyItem.m_sensitive & ~overrideModifiers; // XXX -- must handle pressing a modifier. in particular, if we want // to synthesize a KeyID on level 1 of a KeyButton that has Shift_L // mapped to level 0 then we must release that button if it's down // (in order to satisfy a shift modifier) then press a different // button (any other button) mapped to the shift modifier and then // the Shift_L button. // match key's required state LOG((CLOG_DEBUG1 "state: %04x,%04x,%04x", currentState, keyItem.m_required, sensitive)); if (!keysForModifierState(keyItem.m_button, group, activeModifiers, currentState, keyItem.m_required, sensitive, 0, keystrokes)) { LOG((CLOG_DEBUG1 "unable to match modifier state (%04x,%04x) for key %d", keyItem.m_required, keyItem.m_sensitive, keyItem.m_button)); return false; } // match desiredState as closely as possible. we must not // change any modifiers in keyItem.m_sensitive. and if the key // is a modifier, we don't want to change that modifier. LOG((CLOG_DEBUG1 "desired state: %04x %04x,%04x,%04x", desiredState, currentState, keyItem.m_required, keyItem.m_sensitive)); if (!keysForModifierState(keyItem.m_button, group, activeModifiers, currentState, desiredState, ~(sensitive | keyItem.m_generates), s_notRequiredMask, keystrokes)) { LOG((CLOG_DEBUG1 "unable to match desired modifier state (%04x,%04x) for key %d", desiredState, ~keyItem.m_sensitive & 0xffffu, keyItem.m_button)); return false; } // repeat or press of key type = isAutoRepeat ? kKeystrokeRepeat : kKeystrokePress; } addKeystrokes(type, keyItem, activeModifiers, currentState, keystrokes); return true; }