Example #1
0
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;
		}
	}
}
Example #2
0
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;
}
Example #3
0
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);
}
Example #4
0
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);
}
Example #5
0
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);
}
Example #6
0
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();
}
Example #7
0
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;
}
Example #8
0
void
CKeyState::fakeKeyDown(KeyID id, KeyModifierMask mask, KeyButton button)
{
	// get the sequence of keys to simulate key press and the final
	// modifier state.
	Keystrokes keys;
	KeyButton localID =
		(KeyButton)(mapKey(keys, id, mask, false) & kButtonMask);
	if (keys.empty()) {
		// do nothing if there are no associated keys
		LOG((CLOG_DEBUG2 "cannot map key 0x%08x", id));
		return;
	}

	// generate key events
	fakeKeyEvents(keys, 1);

	// note that key is down
	updateKeyState((KeyButton)(button & kButtonMask), localID, true, true);
}
Example #9
0
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);
}
Example #10
0
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;
}
Example #11
0
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;
	}
}
Example #12
0
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;
}