From 784ab183aed65efe1a305fcdf357dfa16000b49e Mon Sep 17 00:00:00 2001 From: crs Date: Sun, 8 Jun 2003 22:12:12 +0000 Subject: [PATCH] ctrl+alt+del emulation checkpoint. --- lib/platform/CMSWindowsPrimaryScreen.cpp | 24 +++++++-- lib/platform/CMSWindowsSecondaryScreen.cpp | 59 ++++++++++++++++++++++ lib/platform/CMSWindowsSecondaryScreen.h | 6 +++ lib/platform/CXWindowsPrimaryScreen.cpp | 26 +++++++++- lib/platform/CXWindowsSecondaryScreen.cpp | 11 ++++ 5 files changed, 119 insertions(+), 7 deletions(-) diff --git a/lib/platform/CMSWindowsPrimaryScreen.cpp b/lib/platform/CMSWindowsPrimaryScreen.cpp index 8734e540..232561ed 100644 --- a/lib/platform/CMSWindowsPrimaryScreen.cpp +++ b/lib/platform/CMSWindowsPrimaryScreen.cpp @@ -521,15 +521,29 @@ CMSWindowsPrimaryScreen::onPreDispatch(const CEvent* event) case SYNERGY_MSG_KEY: // ignore message if posted prior to last mark change if (!ignore()) { + WPARAM wParam = msg->wParam; + LPARAM lParam = msg->lParam; + + // check for ctrl+alt+del emulation + if ((wParam == VK_PAUSE || wParam == VK_CANCEL) && + (m_keys[VK_CONTROL] & 0x80) != 0 && + (m_keys[VK_MENU] & 0x80) != 0) { + LOG((CLOG_DEBUG "emulate ctrl+alt+del")); + wParam = VK_DELETE; + lParam &= 0xffff0000; + lParam |= 0x00000001; + } + + // process key normally KeyModifierMask mask; - const KeyID key = mapKey(msg->wParam, msg->lParam, &mask); + const KeyID key = mapKey(wParam, lParam, &mask); KeyButton button = static_cast( - (msg->lParam & 0x00ff0000u) >> 16); + (lParam & 0x00ff0000u) >> 16); if (key != kKeyNone && key != kKeyMultiKey) { - if ((msg->lParam & 0x80000000) == 0) { + if ((lParam & 0x80000000) == 0) { // key press - const bool wasDown = ((msg->lParam & 0x40000000) != 0); - const SInt32 repeat = (SInt32)(msg->lParam & 0xffff); + const bool wasDown = ((lParam & 0x40000000) != 0); + const SInt32 repeat = (SInt32)(lParam & 0xffff); if (repeat >= 2 || wasDown) { LOG((CLOG_DEBUG1 "event: key repeat key=%d mask=0x%04x count=%d button=0x%04x", key, mask, repeat, button)); m_receiver->onKeyRepeat(key, mask, repeat, button); diff --git a/lib/platform/CMSWindowsSecondaryScreen.cpp b/lib/platform/CMSWindowsSecondaryScreen.cpp index 8b2658b1..e8dfe395 100644 --- a/lib/platform/CMSWindowsSecondaryScreen.cpp +++ b/lib/platform/CMSWindowsSecondaryScreen.cpp @@ -16,6 +16,8 @@ #include "CMSWindowsScreen.h" #include "XScreen.h" #include "CLock.h" +#include "CThread.h" +#include "CFunctionJob.h" #include "CLog.h" #include "CArchMiscWindows.h" #include @@ -94,6 +96,14 @@ CMSWindowsSecondaryScreen::keyDown(KeyID key, CLock lock(&m_mutex); m_screen->syncDesktop(); + // check for ctrl+alt+del emulation + if (key == kKeyDelete && + (mask & (KeyModifierControl | KeyModifierAlt)) == + (KeyModifierControl | KeyModifierAlt)) { + synthesizeCtrlAltDel(); + return; + } + // get the sequence of keys to simulate key press and the final // modifier state. m_mask = mapKey(keys, virtualKey, key, mask, kPress); @@ -1517,3 +1527,52 @@ CMSWindowsSecondaryScreen::getCodePageFromLangID(LANGID langid) const return codePage; } + +void +CMSWindowsSecondaryScreen::synthesizeCtrlAltDel() +{ + LOG((CLOG_DEBUG "emulating ctrl+alt+del")); + 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, we + // 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( + &CMSWindowsSecondaryScreen::ctrlAltDelThread)); + cad.wait(); + } + else { + Keystrokes keys; + UINT virtualKey; + KeyID key = kKeyDelete; + KeyModifierMask mask = KeyModifierControl | KeyModifierAlt; + + // get the sequence of keys to simulate ctrl+alt+del + mapKey(keys, virtualKey, key, mask, kPress); + if (!keys.empty()) { + // generate key events + doKeystrokes(keys, 1); + } + } +} + +void +CMSWindowsSecondaryScreen::ctrlAltDelThread(void*) +{ + // get the Winlogon desktop at whatever privilege we can + HDESK desk = OpenDesktop("Winlogon", 0, FALSE, MAXIMUM_ALLOWED); + if (desk != NULL) { + if (SetThreadDesktop(desk)) { + PostMessage(HWND_BROADCAST, WM_HOTKEY, 0, + MAKELPARAM(MOD_CONTROL | MOD_ALT, VK_DELETE)); + } + else { + LOG((CLOG_DEBUG "can't switch to Winlogon desk: %d", GetLastError())); + } + CloseDesktop(desk); + } + else { + LOG((CLOG_DEBUG "can't open Winlogon desk: %d", GetLastError())); + } +} diff --git a/lib/platform/CMSWindowsSecondaryScreen.h b/lib/platform/CMSWindowsSecondaryScreen.h index 7f97d3ce..f56c7c40 100644 --- a/lib/platform/CMSWindowsSecondaryScreen.h +++ b/lib/platform/CMSWindowsSecondaryScreen.h @@ -122,6 +122,12 @@ private: UINT getCodePageFromLangID(LANGID) const; + // generate a fake ctrl+alt+del + void synthesizeCtrlAltDel(); + + // thread that generates fake ctrl+alt+del + static void ctrlAltDelThread(void*); + private: CMutex m_mutex; CMSWindowsScreen* m_screen; diff --git a/lib/platform/CXWindowsPrimaryScreen.cpp b/lib/platform/CXWindowsPrimaryScreen.cpp index 857ad119..b19b412a 100644 --- a/lib/platform/CXWindowsPrimaryScreen.cpp +++ b/lib/platform/CXWindowsPrimaryScreen.cpp @@ -239,8 +239,18 @@ CXWindowsPrimaryScreen::onEvent(CEvent* event) { LOG((CLOG_DEBUG1 "event: KeyPress code=%d, state=0x%04x", xevent.xkey.keycode, xevent.xkey.state)); const KeyModifierMask mask = mapModifier(xevent.xkey.state); - const KeyID key = mapKey(&xevent.xkey); + KeyID key = mapKey(&xevent.xkey); if (key != kKeyNone) { + // check for ctrl+alt+del emulation + if ((key == kKeyPause || key == kKeyCancel) && + (mask & (KeyModifierControl | KeyModifierAlt)) == + (KeyModifierControl | KeyModifierAlt)) { + // pretend it's ctrl+alt+del + LOG((CLOG_DEBUG "emulate ctrl+alt+del")); + key = kKeyDelete; + } + + // handle key m_receiver->onKeyDown(key, mask, static_cast(xevent.xkey.keycode)); if (key == kKeyCapsLock && m_capsLockHalfDuplex) { @@ -258,7 +268,7 @@ CXWindowsPrimaryScreen::onEvent(CEvent* event) case KeyRelease: { const KeyModifierMask mask = mapModifier(xevent.xkey.state); - const KeyID key = mapKey(&xevent.xkey); + KeyID key = mapKey(&xevent.xkey); if (key != kKeyNone) { // check if this is a key repeat by getting the next // KeyPress event that has the same key and time as @@ -279,6 +289,18 @@ CXWindowsPrimaryScreen::onEvent(CEvent* event) &CXWindowsPrimaryScreen::findKeyEvent, (XPointer)&filter) == True); } + + // check for ctrl+alt+del emulation + if ((key == kKeyPause || key == kKeyCancel) && + (mask & (KeyModifierControl | KeyModifierAlt)) == + (KeyModifierControl | KeyModifierAlt)) { + // pretend it's ctrl+alt+del and ignore autorepeat + LOG((CLOG_DEBUG "emulate ctrl+alt+del")); + key = kKeyDelete; + hasPress = false; + } + + if (!hasPress) { // no press event follows so it's a plain release LOG((CLOG_DEBUG1 "event: KeyRelease code=%d, state=0x%04x", xevent.xkey.keycode, xevent.xkey.state)); diff --git a/lib/platform/CXWindowsSecondaryScreen.cpp b/lib/platform/CXWindowsSecondaryScreen.cpp index 186065b5..542f1528 100644 --- a/lib/platform/CXWindowsSecondaryScreen.cpp +++ b/lib/platform/CXWindowsSecondaryScreen.cpp @@ -117,6 +117,17 @@ CXWindowsSecondaryScreen::keyDown(KeyID key, Keystrokes keys; KeyCode keycode; + // check for ctrl+alt+del emulation + if ((mask & (KeyModifierControl | KeyModifierAlt)) == + (KeyModifierControl | KeyModifierAlt) && + key == XK_Up - 0xff00 + 0xef00) { + // just convert the key to Delete and synthesize the key + // normally. the X server/window manager will do the right + // thing (or, at least XFree86/KDE will). + LOG((CLOG_DEBUG "ctrl+alt+del emulation")); + key = XK_Delete - 0xff00u + 0xef00u; + } + // get the sequence of keys to simulate key press and the final // modifier state. m_mask = mapKey(keys, keycode, key, mask, kPress);