void CKeyState::fakeKeyEvents(const Keystrokes& keys, UInt32 count) { // do nothing if no keys or no repeats if (count == 0 || keys.empty()) { return; } // generate key events LOG((CLOG_DEBUG2 "keystrokes:")); for (Keystrokes::const_iterator k = keys.begin(); k != keys.end(); ) { if (k->m_repeat) { // repeat from here up to but not including the next key // with m_repeat == false count times. Keystrokes::const_iterator start = k; while (count-- > 0) { // send repeating events for (k = start; k != keys.end() && k->m_repeat; ++k) { fakeKeyEvent(k->m_key, k->m_press, true); } } // note -- k is now on the first non-repeat key after the // repeat keys, exactly where we'd like to continue from. } else { // send event fakeKeyEvent(k->m_key, k->m_press, false); // next key ++k; } } }
void CKeyState::fakeKeyRepeat( KeyID id, KeyModifierMask mask, SInt32 count, KeyButton serverID) { serverID &= kButtonMask; // if we haven't seen this button go down then ignore it KeyButton oldLocalID = m_serverKeys[serverID]; if (oldLocalID == 0) { return; } // get keys for key repeat Keystrokes keys; ModifierToKeys oldActiveModifiers = m_activeModifiers; const CKeyMap::KeyItem* keyItem = m_keyMap.mapKey(keys, id, pollActiveGroup(), m_activeModifiers, m_mask, mask, true); if (keyItem == NULL) { return; } KeyButton localID = (KeyButton)(keyItem->m_button & kButtonMask); if (localID == 0) { return; } // if the KeyButton for the auto-repeat is not the same as for the // initial press then mark the initial key as released and the new // key as pressed. this can happen when we auto-repeat after a // dead key. for example, a dead accent followed by 'a' will // generate an 'a with accent' followed by a repeating 'a'. the // KeyButtons for the two KeyIDs might be different. if (localID != oldLocalID) { // replace key up with previous KeyButton but leave key down // alone so it uses the new KeyButton. for (Keystrokes::iterator index = keys.begin(); index != keys.end(); ++index) { if (index->m_type == Keystroke::kButton && index->m_data.m_button.m_button == localID) { index->m_data.m_button.m_button = oldLocalID; break; } } // note that old key is now up --m_keys[oldLocalID]; --m_syntheticKeys[oldLocalID]; // note keys down updateModifierKeyState(localID, oldActiveModifiers, m_activeModifiers); ++m_keys[localID]; ++m_syntheticKeys[localID]; m_keyClientData[localID] = keyItem->m_client; m_serverKeys[serverID] = localID; } // generate key events fakeKeys(keys, count); }
void CKeyState::fakeKeyRepeat( KeyID id, KeyModifierMask mask, SInt32 count, KeyButton button) { button &= kButtonMask; // if we haven't seen this button go down then ignore it KeyButton oldLocalID = m_serverKeyMap[button]; if (oldLocalID == 0) { return; } // get the sequence of keys to simulate key repeat and the final // modifier state. Keystrokes keys; KeyButton localID = (KeyButton)(mapKey(keys, id, mask, true) & kButtonMask); if (localID == 0) { LOG((CLOG_DEBUG2 "cannot map key 0x%08x", id)); return; } if (keys.empty()) { // do nothing if there are no associated keys return; } // if the keycode for the auto-repeat is not the same as for the // initial press then mark the initial key as released and the new // key as pressed. this can happen when we auto-repeat after a // dead key. for example, a dead accent followed by 'a' will // generate an 'a with accent' followed by a repeating 'a'. the // keycodes for the two keysyms might be different. if (localID != oldLocalID) { // replace key up with previous key id but leave key down // alone so it uses the new keycode. for (Keystrokes::iterator index = keys.begin(); index != keys.end(); ++index) { if (index->m_key == localID) { index->m_key = oldLocalID; break; } } // note that old key is now up m_keys[oldLocalID] &= ~kDown; // map server key to new key m_serverKeyMap[button] = localID; // note that new key is now down m_keys[localID] |= kDown; } // generate key events fakeKeyEvents(keys, count); }