Esempio n. 1
0
void
CKeyMap::addKeyAliasEntry(KeyID targetID, SInt32 group,
				KeyModifierMask targetRequired,
				KeyModifierMask targetSensitive,
				KeyID sourceID,
				KeyModifierMask sourceRequired,
				KeyModifierMask sourceSensitive)
{
	// if we can already generate the target as desired then we're done.
	if (findCompatibleKey(targetID, group, targetRequired,
								targetSensitive) != NULL) {
		return;
	}

	// find a compatible source, preferably in the same group
	for (SInt32 gd = 0, n = getNumGroups(); gd < n; ++gd) {
		SInt32 eg = getEffectiveGroup(group, gd);
		const KeyItemList* sourceEntry =
			findCompatibleKey(sourceID, eg,
								sourceRequired, sourceSensitive);
		if (sourceEntry != NULL && sourceEntry->size() == 1) {
			CKeyMap::KeyItem targetItem = sourceEntry->back();
			targetItem.m_id    = targetID;
			targetItem.m_group = eg;
			addKeyEntry(targetItem);
			break;
		}
	}
}
void
CMSWindowsKeyState::fakeKey(const Keystroke& keystroke)
{
	switch (keystroke.m_type) {
	case Keystroke::kButton: {
		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"));
		KeyButton button = keystroke.m_data.m_button.m_button;

		// windows doesn't send key ups for key repeats
		if (keystroke.m_data.m_button.m_repeat &&
			!keystroke.m_data.m_button.m_press) {
			LOG((CLOG_DEBUG1 "  discard key repeat release"));
			break;
		}

		// get the virtual key for the button
		UINT vk = keystroke.m_data.m_button.m_client;

		// special handling of VK_SNAPSHOT
		if (vk == VK_SNAPSHOT) {
			if ((getActiveModifiers() & KeyModifierAlt) != 0) {
				// snapshot active window
				button = 1;
			}
			else {
				// snapshot full screen
				button = 0;
			}
		}

		// synthesize event
		m_desks->fakeKeyEvent(button, vk,
								keystroke.m_data.m_button.m_press,
								keystroke.m_data.m_button.m_repeat);
		break;
	}

	case Keystroke::kGroup:
		// we don't restore the group.  we'd like to but we can't be
		// sure the restoring group change will be processed after the
		// key events.
		if (!keystroke.m_data.m_group.m_restore) {
			if (keystroke.m_data.m_group.m_absolute) {
				LOG((CLOG_DEBUG1 "  group %d", keystroke.m_data.m_group.m_group));
				setWindowGroup(keystroke.m_data.m_group.m_group);
			}
			else {
				LOG((CLOG_DEBUG1 "  group %+d", keystroke.m_data.m_group.m_group));
				setWindowGroup(getEffectiveGroup(pollActiveGroup(),
									keystroke.m_data.m_group.m_group));
			}
		}
		break;
	}
}
Esempio n. 3
0
void
XWindowsKeyState::fakeKey(const Keystroke& keystroke)
{
	switch (keystroke.m_type) {
	case Keystroke::kButton:
		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"));
		if (keystroke.m_data.m_button.m_repeat) {
			int c = keystroke.m_data.m_button.m_button;
			int i = (c >> 3);
			int b = 1 << (c & 7);
			if (m_keyboardState.global_auto_repeat == AutoRepeatModeOff ||
				(c!=113 && c!=116 && (m_keyboardState.auto_repeats[i] & b) == 0)) {
				LOG((CLOG_DEBUG1 "  discard autorepeat"));
				break;
			}
		}
		XTestFakeKeyEvent(m_display, keystroke.m_data.m_button.m_button,
							keystroke.m_data.m_button.m_press ? True : False,
							CurrentTime);
		break;

	case Keystroke::kGroup:
		if (keystroke.m_data.m_group.m_absolute) {
			LOG((CLOG_DEBUG1 "  group %d", keystroke.m_data.m_group.m_group));
#if HAVE_XKB_EXTENSION
			if (m_xkb != NULL) {
				if (XkbLockGroup(m_display, XkbUseCoreKbd,
							keystroke.m_data.m_group.m_group) == False) {
					LOG((CLOG_DEBUG1 "XkbLockGroup request not sent"));
				}
			}
			else
#endif
			{
				LOG((CLOG_DEBUG1 "  ignored"));
			}
		}
		else {
			LOG((CLOG_DEBUG1 "  group %+d", keystroke.m_data.m_group.m_group));
#if HAVE_XKB_EXTENSION
			if (m_xkb != NULL) {
				if (XkbLockGroup(m_display, XkbUseCoreKbd,
							getEffectiveGroup(pollActiveGroup(),
								keystroke.m_data.m_group.m_group)) == False) {
					LOG((CLOG_DEBUG1 "XkbLockGroup request not sent"));
				}
			}
			else
#endif
			{
				LOG((CLOG_DEBUG1 "  ignored"));
			}
		}
		break;
	}
Esempio n. 4
0
void
OSXKeyState::fakeKey(const Keystroke& keystroke)
{
	switch (keystroke.m_type) {
	case Keystroke::kButton: {
		
		KeyButton button = keystroke.m_data.m_button.m_button;
		bool keyDown = keystroke.m_data.m_button.m_press;
		UInt32 client = keystroke.m_data.m_button.m_client;
		CGEventSourceRef source = 0;
		CGKeyCode virtualKey = mapKeyButtonToVirtualKey(button);
		
		LOG((CLOG_DEBUG1
			"  button=0x%04x virtualKey=0x%04x keyDown=%s client=0x%04x",
			button, virtualKey, keyDown ? "down" : "up", client));

		CGEventRef ref = CGEventCreateKeyboardEvent(
			source, virtualKey, keyDown);
		
		if (ref == NULL) {
			LOG((CLOG_CRIT "unable to create keyboard event for keystroke"));
			return;
		}

		// persist modifier state.
		if (virtualKey == s_shiftVK) {
			m_shiftPressed = keyDown;
		}
		
		if (virtualKey == s_controlVK) {
			m_controlPressed = keyDown;
		}
		
		if (virtualKey == s_altVK) {
			m_altPressed = keyDown;
		}
		
		if (virtualKey == s_superVK) {
			m_superPressed = keyDown;
		}
		
		if (virtualKey == s_capsLockVK) {
			m_capsPressed = keyDown;
		}

		// set the event flags for special keys
		// http://tinyurl.com/pxl742y
		CGEventFlags modifiers = 0;
		
		if (m_shiftPressed) {
			modifiers |= kCGEventFlagMaskShift;
		}
		
		if (m_controlPressed) {
			modifiers |= kCGEventFlagMaskControl;
		}
		
		if (m_altPressed) {
			modifiers |= kCGEventFlagMaskAlternate;
		}
		
		if (m_superPressed) {
			modifiers |= kCGEventFlagMaskCommand;
		}
		
		if (m_capsPressed) {
			modifiers |= kCGEventFlagMaskAlphaShift;
		}
		
		CGEventSetFlags(ref, modifiers);
		CGEventPost(kCGHIDEventTap, ref);
		CFRelease(ref);

		// add a delay if client data isn't zero
		// FIXME -- why?
		if (client != 0) {
			ARCH->sleep(0.01);
		}
		break;
	}

	case Keystroke::kGroup: {
		SInt32 group = keystroke.m_data.m_group.m_group;
		if (keystroke.m_data.m_group.m_absolute) {
			LOG((CLOG_DEBUG1 "  group %d", group));
			setGroup(group);
		}
		else {
			LOG((CLOG_DEBUG1 "  group %+d", group));
			setGroup(getEffectiveGroup(pollActiveGroup(), group));
		}
		break;
	}
	}
}
Esempio n. 5
0
const CKeyMap::KeyItem*
CKeyMap::mapCharacterKey(Keystrokes& keys, KeyID id, SInt32 group,
				ModifierToKeys& activeModifiers,
				KeyModifierMask& currentState,
				KeyModifierMask desiredMask,
				bool isAutoRepeat) const
{
	// find KeySym in table
	KeyIDMap::const_iterator i = m_keyIDMap.find(id);
	if (i == m_keyIDMap.end()) {
		// unknown key
		LOG((CLOG_DEBUG1 "key %04x is not on keyboard", id));
		return NULL;
	}
	const KeyGroupTable& keyGroupTable = i->second;

	// find best key in any group, starting with the active group
	SInt32 keyIndex  = -1;
	SInt32 numGroups = getNumGroups();
	SInt32 groupOffset;
	LOG((CLOG_DEBUG1 "find best:  %04x %04x", currentState, desiredMask));
	for (groupOffset = 0; groupOffset < numGroups; ++groupOffset) {
		SInt32 effectiveGroup = getEffectiveGroup(group, groupOffset);
		keyIndex = findBestKey(keyGroupTable[effectiveGroup],
								currentState, desiredMask);
		if (keyIndex != -1) {
			LOG((CLOG_DEBUG1 "found key in group %d", effectiveGroup));
			break;
		}
	}
	if (keyIndex == -1) {
		// no mapping for this keysym
		LOG((CLOG_DEBUG1 "no mapping for key %04x", id));
		return NULL;
	}

	// get keys to press for key
	SInt32 effectiveGroup = getEffectiveGroup(group, groupOffset);
	const KeyItemList& itemList = keyGroupTable[effectiveGroup][keyIndex];
	if (itemList.empty()) {
		return NULL;
	}
	const KeyItem& keyItem = itemList.back();

	// make working copy of modifiers
	ModifierToKeys newModifiers = activeModifiers;
	KeyModifierMask newState    = currentState;
	SInt32 newGroup             = group;

	// add each key
	for (size_t j = 0; j < itemList.size(); ++j) {
		if (!keysForKeyItem(itemList[j], newGroup, newModifiers,
							newState, desiredMask,
							0, isAutoRepeat, keys)) {
			LOG((CLOG_DEBUG1 "can't map key"));
			keys.clear();
			return NULL;
		}
	}

	// add keystrokes to restore modifier keys
	if (!keysToRestoreModifiers(keyItem, group, newModifiers, newState,
								activeModifiers, keys)) {
		LOG((CLOG_DEBUG1 "failed to restore modifiers"));
		keys.clear();
		return NULL;
	}

	// add keystrokes to restore group
	if (newGroup != group) {
		keys.push_back(Keystroke(group, true, true));
	}

	// save new modifiers
	activeModifiers = newModifiers;
	currentState    = newState;

	return &keyItem;
}
Esempio n. 6
0
const CKeyMap::KeyItem*
CKeyMap::mapCommandKey(Keystrokes& keys, KeyID id, SInt32 group,
				ModifierToKeys& activeModifiers,
				KeyModifierMask& currentState,
				KeyModifierMask desiredMask,
				bool isAutoRepeat) const
{
	static const KeyModifierMask s_overrideModifiers = 0xffffu;

	// find KeySym in table
	KeyIDMap::const_iterator i = m_keyIDMap.find(id);
	if (i == m_keyIDMap.end()) {
		// unknown key
		LOG((CLOG_DEBUG1 "key %04x is not on keyboard", id));
		return NULL;
	}
	const KeyGroupTable& keyGroupTable = i->second;

	// find the first key that generates this KeyID
	const KeyItem* keyItem = NULL;
	SInt32 numGroups       = getNumGroups();
	for (SInt32 groupOffset = 0; groupOffset < numGroups; ++groupOffset) {
		SInt32 effectiveGroup = getEffectiveGroup(group, groupOffset);
		const KeyEntryList& entryList = keyGroupTable[effectiveGroup];
		for (size_t i = 0; i < entryList.size(); ++i) {
			if (entryList[i].size() != 1) {
				// ignore multikey entries
				continue;
			}

			// only match based on shift;  we're after the right button
			// not the right character.  we'll use desiredMask as-is,
			// overriding the key's required modifiers, when synthesizing
			// this button.
			const KeyItem& item = entryList[i].back();
			if ((item.m_required & KeyModifierShift & desiredMask) ==
				(item.m_sensitive & KeyModifierShift & desiredMask)) {
				LOG((CLOG_DEBUG1 "found key in group %d", effectiveGroup));
				keyItem = &item;
				break;
			}
		}
		if (keyItem != NULL) {
			break;
		}
	}
	if (keyItem == NULL) {
		// no mapping for this keysym
		LOG((CLOG_DEBUG1 "no mapping for key %04x", id));
		return NULL;
	}

	// make working copy of modifiers
	ModifierToKeys newModifiers = activeModifiers;
	KeyModifierMask newState    = currentState;
	SInt32 newGroup             = group;

	// don't try to change CapsLock
	desiredMask = (desiredMask & ~KeyModifierCapsLock) |
					(currentState & KeyModifierCapsLock);

	// add the key
	if (!keysForKeyItem(*keyItem, newGroup, newModifiers,
							newState, desiredMask,
							s_overrideModifiers, isAutoRepeat, keys)) {
		LOG((CLOG_DEBUG1 "can't map key"));
		keys.clear();
		return NULL;
	}

	// add keystrokes to restore modifier keys
	if (!keysToRestoreModifiers(*keyItem, group, newModifiers, newState,
								activeModifiers, keys)) {
		LOG((CLOG_DEBUG1 "failed to restore modifiers"));
		keys.clear();
		return NULL;
	}

	// add keystrokes to restore group
	if (newGroup != group) {
		keys.push_back(Keystroke(group, true, true));
	}

	// save new modifiers
	activeModifiers = newModifiers;
	currentState    = newState;

	return keyItem;
}
Esempio n. 7
0
void
COSXKeyState::fakeKey(const Keystroke& keystroke)
{
	CGEventRef ref;

	switch (keystroke.m_type) {
	case Keystroke::kButton:
		{
			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"));

		// let system figure out character for us
		ref = CGEventCreateKeyboardEvent(0, mapKeyButtonToVirtualKey(
									keystroke.m_data.m_button.m_button),
								keystroke.m_data.m_button.m_press);
		if (ref == NULL) {
			LOG((CLOG_CRIT "unable to create keyboard event for keystroke"));
		}

			UInt32 vk = mapKeyButtonToVirtualKey(keystroke.m_data.m_button.m_button);
			UInt32 modifierDown = keystroke.m_data.m_button.m_press;

			// check the key for specials and store the value (persistent until changed)
			if (vk == s_shiftVK)    shiftPressed=modifierDown;
			if (vk == s_controlVK)  controlPressed=modifierDown;
			if (vk == s_altVK)      altPressed=modifierDown;
			if (vk == s_superVK)    superPressed=modifierDown;
			if (vk == s_capsLockVK) capsPressed=modifierDown;

			//Set the event flags for special keys - see following link:
			//http://stackoverflow.com/questions/2008126/cgeventpost-possible-bug-when-simulating-keyboard-events
			CGEventFlags modifiers = 0;
			if (shiftPressed)   modifiers |= kCGEventFlagMaskShift;
			if (controlPressed) modifiers |= kCGEventFlagMaskControl;
			if (altPressed)     modifiers |= kCGEventFlagMaskAlternate;
			if (superPressed)   modifiers |= kCGEventFlagMaskCommand;
			if (capsPressed)    modifiers |= kCGEventFlagMaskAlphaShift;
			
			CGEventSetFlags(ref, modifiers);
			
			CGEventPost(kCGHIDEventTap, ref);

			// add a delay if client data isn't zero
			if (keystroke.m_data.m_button.m_client) {
				ARCH->sleep(0.01);
			}
		}
		break;

	case Keystroke::kGroup:
		if (keystroke.m_data.m_group.m_absolute) {
			LOG((CLOG_DEBUG1 "  group %d", keystroke.m_data.m_group.m_group));
			setGroup(keystroke.m_data.m_group.m_group);
		}
		else {
			LOG((CLOG_DEBUG1 "  group %+d", keystroke.m_data.m_group.m_group));
			setGroup(getEffectiveGroup(pollActiveGroup(),
									keystroke.m_data.m_group.m_group));
		}
		break;
	}
}