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; } }
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; }
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; } } }
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; }
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; }
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; } }