void CKeyState::updateKeyState() { // reset our state memset(&m_keys, 0, sizeof(m_keys)); memset(&m_syntheticKeys, 0, sizeof(m_syntheticKeys)); memset(&m_keyClientData, 0, sizeof(m_keyClientData)); memset(&m_serverKeys, 0, sizeof(m_serverKeys)); m_activeModifiers.clear(); // get the current keyboard state KeyButtonSet keysDown; pollPressedKeys(keysDown); for (KeyButtonSet::const_iterator i = keysDown.begin(); i != keysDown.end(); ++i) { m_keys[*i] = 1; } // get the current modifier state m_mask = pollActiveModifiers(); // set active modifiers CAddActiveModifierContext addModifierContext(pollActiveGroup(), m_mask, m_activeModifiers); m_keyMap.foreachKey(&CKeyState::addActiveModifierCB, &addModifierContext); LOG((CLOG_DEBUG1 "modifiers on update: 0x%04x", m_mask)); }
bool OSXKeyState::mapSynergyHotKeyToMac(KeyID key, KeyModifierMask mask, UInt32 &macVirtualKey, UInt32 &macModifierMask) const { // look up button for key KeyButton button = getButton(key, pollActiveGroup()); if (button == 0 && key != kKeyNone) { return false; } macVirtualKey = mapKeyButtonToVirtualKey(button); // calculate modifier mask macModifierMask = 0; if ((mask & KeyModifierShift) != 0) { macModifierMask |= shiftKey; } if ((mask & KeyModifierControl) != 0) { macModifierMask |= controlKey; } if ((mask & KeyModifierAlt) != 0) { macModifierMask |= cmdKey; } if ((mask & KeyModifierSuper) != 0) { macModifierMask |= optionKey; } if ((mask & KeyModifierCapsLock) != 0) { macModifierMask |= alphaLock; } if ((mask & KeyModifierNumLock) != 0) { macModifierMask |= s_osxNumLock; } return true; }
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 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 KeyState::fakeKeyDown(KeyID id, KeyModifierMask mask, KeyButton serverID) { // if this server key is already down then this is probably a // mis-reported autorepeat. serverID &= kButtonMask; if (m_serverKeys[serverID] != 0) { fakeKeyRepeat(id, mask, 1, serverID); return; } // ignore certain keys if (isIgnoredKey(id, mask)) { LOG((CLOG_DEBUG1 "ignored key %04x %04x", id, mask)); return; } // get keys for key press Keystrokes keys; ModifierToKeys oldActiveModifiers = m_activeModifiers; const barrier::KeyMap::KeyItem* keyItem = m_keyMap.mapKey(keys, id, pollActiveGroup(), m_activeModifiers, getActiveModifiersRValue(), mask, false); if (keyItem == NULL) { // a media key won't be mapped on mac, so we need to fake it in a // special way if (id == kKeyAudioDown || id == kKeyAudioUp || id == kKeyAudioMute || id == kKeyAudioPlay || id == kKeyAudioPrev || id == kKeyAudioNext || id == kKeyBrightnessDown || id == kKeyBrightnessUp ) { LOG((CLOG_DEBUG1 "emulating media key")); fakeMediaKey(id); } return; } KeyButton localID = (KeyButton)(keyItem->m_button & kButtonMask); updateModifierKeyState(localID, oldActiveModifiers, m_activeModifiers); if (localID != 0) { // note keys down ++m_keys[localID]; ++m_syntheticKeys[localID]; m_keyClientData[localID] = keyItem->m_client; m_serverKeys[serverID] = localID; } // generate key events fakeKeys(keys, 1); }
void XWindowsKeyState::setActiveGroup(SInt32 group) { if (group == kGroupPollAndSet) { // we need to set the group to -1 in order for pollActiveGroup() to // actually poll for the group m_group = -1; m_group = pollActiveGroup(); } else if (group == kGroupPoll) { m_group = -1; } else { assert(group >= 0); m_group = group; } }
void CKeyState::fakeKeyDown(KeyID id, KeyModifierMask mask, KeyButton serverID) { // ignore key if serverID is bogus serverID &= kButtonMask; if (serverID == 0) { LOG((CLOG_DEBUG1 "ignored fake key for %04x with serverID of 0", id)); return; } // if this server key is already down then this is probably a // mis-reported autorepeat. if (m_serverKeys[serverID] != 0) { fakeKeyRepeat(id, mask, 1, serverID); return; } // ignore certain keys if (isIgnoredKey(id, mask)) { LOG((CLOG_DEBUG1 "ignored key %04x %04x", id, mask)); return; } // get keys for key press Keystrokes keys; ModifierToKeys oldActiveModifiers = m_activeModifiers; const CKeyMap::KeyItem* keyItem = m_keyMap.mapKey(keys, id, pollActiveGroup(), m_activeModifiers, m_mask, mask, false); if (keyItem == NULL) { return; } KeyButton localID = (KeyButton)(keyItem->m_button & kButtonMask); if (localID != 0) { // 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, 1); }
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; } } }
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; } }