KeyModifierMask CMSWindowsKeyState::pollActiveModifiers() const { KeyModifierMask state = 0; // get non-toggle modifiers from our own shadow key state for (size_t i = 0; i < sizeof(s_modifiers) / sizeof(s_modifiers[0]); ++i) { KeyButton button = virtualKeyToButton(s_modifiers[i].m_vk); if (button != 0 && isKeyDown(button)) { state |= s_modifiers[i].m_mask; } } // we can get toggle modifiers from the system if ((GetKeyState(VK_CAPITAL) & 0x01) != 0) { state |= KeyModifierCapsLock; } if ((GetKeyState(VK_NUMLOCK) & 0x01) != 0) { state |= KeyModifierNumLock; } if ((GetKeyState(VK_SCROLL) & 0x01) != 0) { state |= KeyModifierScrollLock; } return state; }
bool CMSWindowsKeyState::fakeCtrlAltDel() { if (!m_is95Family) { // to fake ctrl+alt+del on the NT family we broadcast a suitable // hotkey to all windows on the winlogon desktop. however, the // current thread must be on that desktop to do the broadcast // and we can't switch just any thread because some own windows // or hooks. so start a new thread to do the real work. HANDLE hEvtSendSas = OpenEvent( EVENT_MODIFY_STATE, FALSE, "Global\\SendSAS" ); if ( hEvtSendSas ) { LOG((CLOG_DEBUG "found the SendSAS event - signaling my launcher to simulate ctrl+alt+del")); SetEvent( hEvtSendSas ); CloseHandle( hEvtSendSas ); } else { CThread cad(new CFunctionJob(&CMSWindowsKeyState::ctrlAltDelThread)); cad.wait(); } } else { // simulate ctrl+alt+del fakeKeyDown(kKeyDelete, KeyModifierControl | KeyModifierAlt, virtualKeyToButton(VK_DELETE)); } return true; }
void MSWindowsKeyState::pollPressedKeys(KeyButtonSet& pressedKeys) const { BYTE keyState[256]; if (!GetKeyboardState(keyState)) { LOG((CLOG_ERR "GetKeyboardState returned false on pollPressedKeys")); return; } for (KeyButton i = 1; i < 256; ++i) { if ((keyState[i] & 0x80) != 0) { KeyButton keyButton = virtualKeyToButton(i); if (keyButton != 0) { pressedKeys.insert(keyButton); } } } }
bool CMSWindowsKeyState::fakeCtrlAltDel() { if (!m_is95Family) { // to fake ctrl+alt+del on the NT family we broadcast a suitable // hotkey to all windows on the winlogon desktop. however, the // current thread must be on that desktop to do the broadcast // and we can't switch just any thread because some own windows // or hooks. so start a new thread to do the real work. CThread cad(new CFunctionJob(&CMSWindowsKeyState::ctrlAltDelThread)); cad.wait(); } else { // simulate ctrl+alt+del fakeKeyDown(kKeyDelete, KeyModifierControl | KeyModifierAlt, virtualKeyToButton(VK_DELETE)); } return true; }
void CMSWindowsKeyState::fixKeys() { // fake key releases for the windows keys if we think they're // down but they're really up. we have to do this because if the // user presses and releases a windows key without pressing any // other key while it's down then the system will eat the key // release. if we don't detect that and synthesize the release // then the client won't take the usual windows key release action // (which on windows is to show the start menu). // // only check on the windows 95 family since the NT family reports // the key releases as usual. if (!m_is95Family) { return; } KeyButton leftButton = virtualKeyToButton(VK_LWIN); KeyButton rightButton = virtualKeyToButton(VK_RWIN); bool leftDown = isKeyDown(leftButton); bool rightDown = isKeyDown(rightButton); bool fix = (leftDown || rightDown); if (fix) { // check if either button is not really down bool leftAsyncDown = ((GetAsyncKeyState(VK_LWIN) & 0x8000) != 0); bool rightAsyncDown = ((GetAsyncKeyState(VK_RWIN) & 0x8000) != 0); if (leftAsyncDown != leftDown || rightAsyncDown != rightDown) { KeyModifierMask state = getActiveModifiers(); if (!leftAsyncDown && !rightAsyncDown) { // no win keys are down so remove super modifier state &= ~KeyModifierSuper; } // report up events if (leftDown && !leftAsyncDown) { LOG((CLOG_DEBUG1 "event: fake key release left windows key (0x%03x)", leftButton)); CKeyState::onKey(leftButton, false, state); CKeyState::sendKeyEvent(m_eventTarget, false, false, kKeySuper_L, state, 1, leftButton); } if (rightDown && !rightAsyncDown) { LOG((CLOG_DEBUG1 "event: fake key release right windows key (0x%03x)", rightButton)); CKeyState::onKey(rightButton, false, state); CKeyState::sendKeyEvent(m_eventTarget, false, false, kKeySuper_R, state, 1, rightButton); } } } if (fix && m_fixTimer == NULL) { // schedule check m_fixTimer = EVENTQUEUE->newTimer(0.1, NULL); EVENTQUEUE->adoptHandler(CEvent::kTimer, m_fixTimer, new TMethodEventJob<CMSWindowsKeyState>( this, &CMSWindowsKeyState::handleFixKeys)); } else if (!fix && m_fixTimer != NULL) { // remove scheduled check EVENTQUEUE->removeHandler(CEvent::kTimer, m_fixTimer); EVENTQUEUE->deleteTimer(m_fixTimer); m_fixTimer = NULL; } }