From dc6652a21a91ff51d1fe892c12614d140e203680 Mon Sep 17 00:00:00 2001 From: crs Date: Sat, 17 May 2003 20:58:27 +0000 Subject: [PATCH] Fixed getting locked to screen after ctrl+alt+del. Also fixed cursor not being hidden on win32 server when on client screens (which happened when using low-level hooks). --- lib/platform/CMSWindowsPrimaryScreen.cpp | 57 +++++++++++++++++++-- lib/platform/CMSWindowsPrimaryScreen.h | 10 ++-- lib/platform/CMSWindowsScreen.cpp | 24 ++++++--- lib/platform/CMSWindowsScreen.h | 7 +++ lib/platform/CMSWindowsSecondaryScreen.cpp | 7 +++ lib/platform/CMSWindowsSecondaryScreen.h | 1 + lib/platform/CSynergyHook.cpp | 13 +++-- lib/platform/IMSWindowsScreenEventHandler.h | 7 +++ lib/synergy/CPrimaryScreen.cpp | 6 +-- 9 files changed, 111 insertions(+), 21 deletions(-) diff --git a/lib/platform/CMSWindowsPrimaryScreen.cpp b/lib/platform/CMSWindowsPrimaryScreen.cpp index 92d3e832..75f8c2f1 100644 --- a/lib/platform/CMSWindowsPrimaryScreen.cpp +++ b/lib/platform/CMSWindowsPrimaryScreen.cpp @@ -319,7 +319,8 @@ CMSWindowsPrimaryScreen::CMSWindowsPrimaryScreen( m_threadID(0), m_mark(0), m_markReceived(0), - m_lowLevel(false) + m_lowLevel(false), + m_cursorThread(0) { assert(m_receiver != NULL); @@ -787,6 +788,13 @@ CMSWindowsPrimaryScreen::preDestroyWindow(HWND) m_uninstall(); } +void +CMSWindowsPrimaryScreen::onAccessibleDesktop() +{ + // get the current keyboard state + updateKeys(); +} + void CMSWindowsPrimaryScreen::onPreMainLoop() { @@ -833,6 +841,18 @@ CMSWindowsPrimaryScreen::onPostClose() void CMSWindowsPrimaryScreen::onPreEnter() { + // show cursor if we hid it + if (m_cursorThread != 0) { + if (m_threadID != m_cursorThread) { + AttachThreadInput(m_threadID, m_cursorThread, TRUE); + } + ShowCursor(TRUE); + if (m_threadID != m_cursorThread) { + AttachThreadInput(m_threadID, m_cursorThread, FALSE); + } + m_cursorThread = 0; + } + // enable ctrl+alt+del, alt+tab, etc if (m_is95Family) { DWORD dummy = 0; @@ -869,6 +889,19 @@ CMSWindowsPrimaryScreen::onPostLeave(bool success) DWORD dummy = 0; SystemParametersInfo(SPI_SETSCREENSAVERRUNNING, TRUE, &dummy, 0); } + + // hide the cursor if using low level hooks + if (m_lowLevel) { + HWND hwnd = GetForegroundWindow(); + m_cursorThread = GetWindowThreadProcessId(hwnd, NULL); + if (m_threadID != m_cursorThread) { + AttachThreadInput(m_threadID, m_cursorThread, TRUE); + } + ShowCursor(FALSE); + if (m_threadID != m_cursorThread) { + AttachThreadInput(m_threadID, m_cursorThread, FALSE); + } + } } } @@ -876,10 +909,13 @@ void CMSWindowsPrimaryScreen::createWindow() { // open the desktop and the window - HWND window = m_screen->openDesktop(); - if (window == NULL) { + m_window = m_screen->openDesktop(); + if (m_window == NULL) { throw XScreenOpenFailure(); } + + // we don't ever want our window to activate + EnableWindow(m_window, FALSE); } void @@ -892,14 +928,25 @@ CMSWindowsPrimaryScreen::destroyWindow() bool CMSWindowsPrimaryScreen::showWindow() { - // do nothing. we don't need to show a window to capture input. + // we don't need a window to capture input but we need a window + // to hide the cursor when using low-level hooks. do not try to + // take the activation; we want the currently active window to + // stay active. + if (m_lowLevel) { + SetWindowPos(m_window, HWND_TOPMOST, m_xCenter, m_yCenter, 1, 1, + SWP_NOACTIVATE); + ShowWindow(m_window, SW_SHOWNA); + } return true; } void CMSWindowsPrimaryScreen::hideWindow() { - // do nothing. we don't need to show a window to capture input. + // hide our window + if (m_lowLevel) { + ShowWindow(m_window, SW_HIDE); + } } void diff --git a/lib/platform/CMSWindowsPrimaryScreen.h b/lib/platform/CMSWindowsPrimaryScreen.h index dfe40adf..a80ddbe7 100644 --- a/lib/platform/CMSWindowsPrimaryScreen.h +++ b/lib/platform/CMSWindowsPrimaryScreen.h @@ -52,6 +52,7 @@ public: virtual SInt32 getJumpZoneSize() const; virtual void postCreateWindow(HWND); virtual void preDestroyWindow(HWND); + virtual void onAccessibleDesktop(); protected: // CPrimaryScreen overrides @@ -101,6 +102,9 @@ private: // the main loop's thread id DWORD m_threadID; + // my window + HWND m_window; + // used to discard queued messages that are no longer needed UInt32 m_mark; UInt32 m_markReceived; @@ -128,10 +132,8 @@ private: SetRelayFunc m_setRelay; bool m_lowLevel; - // stuff for restoring active window - HWND m_lastForegroundWindow; - HWND m_lastActiveWindow; - DWORD m_lastActiveThread; + // stuff for hiding the cursor + DWORD m_cursorThread; }; #endif diff --git a/lib/platform/CMSWindowsScreen.cpp b/lib/platform/CMSWindowsScreen.cpp index 1e848b1c..d75257c5 100644 --- a/lib/platform/CMSWindowsScreen.cpp +++ b/lib/platform/CMSWindowsScreen.cpp @@ -68,7 +68,8 @@ CMSWindowsScreen::CMSWindowsScreen(IScreenReceiver* receiver, m_installScreensaver(NULL), m_uninstallScreensaver(NULL), m_screensaver(NULL), - m_screensaverNotify(false) + m_screensaverNotify(false), + m_inaccessibleDesktop(false) { assert(s_screen == NULL); assert(m_receiver != NULL); @@ -384,7 +385,7 @@ CMSWindowsScreen::syncDesktop() // of sucking up more and more CPU each time it's called (even if // the threads are already attached). since we only expect one // thread to call this more than once we can save just the last - // the attached thread. + // attached thread. DWORD threadID = GetCurrentThreadId(); if (threadID != m_lastThreadID && threadID != m_threadID) { m_lastThreadID = threadID; @@ -493,16 +494,27 @@ CMSWindowsScreen::onPreDispatch(const CEvent* event) if (isCurrentDesktop(desk)) { CloseDesktop(desk); } - else if (!m_screensaver->isActive()) { + else if (m_screensaver->isActive()) { // don't switch desktops when the screensaver is // active. we'd most likely switch to the // screensaver desktop which would have the side // effect of forcing the screensaver to stop. - switchDesktop(desk); - } - else { CloseDesktop(desk); } + else { + switchDesktop(desk); + } + + // if the desktop was inaccessible then notify the + // event handler of that. + if (m_inaccessibleDesktop) { + m_inaccessibleDesktop = false; + m_eventHandler->onAccessibleDesktop(); + } + } + else if (!m_inaccessibleDesktop) { + // the desktop has become inaccessible + m_inaccessibleDesktop = true; } } diff --git a/lib/platform/CMSWindowsScreen.h b/lib/platform/CMSWindowsScreen.h index b7b97156..f4af0cac 100644 --- a/lib/platform/CMSWindowsScreen.h +++ b/lib/platform/CMSWindowsScreen.h @@ -191,6 +191,13 @@ private: CMSWindowsScreenSaver* m_screensaver; bool m_screensaverNotify; + // true when the current desktop is inaccessible. while + // the desktop is inaccessible we won't receive user input + // and we'll lose track of the keyboard state. when the + // desktop becomes accessible again we'll notify the event + // handler of that. + bool m_inaccessibleDesktop; + static CMSWindowsScreen* s_screen; }; diff --git a/lib/platform/CMSWindowsSecondaryScreen.cpp b/lib/platform/CMSWindowsSecondaryScreen.cpp index d6ad9c47..aa3d9785 100644 --- a/lib/platform/CMSWindowsSecondaryScreen.cpp +++ b/lib/platform/CMSWindowsSecondaryScreen.cpp @@ -417,6 +417,13 @@ CMSWindowsSecondaryScreen::preDestroyWindow(HWND) // do nothing } +void +CMSWindowsSecondaryScreen::onAccessibleDesktop() +{ + // get the current keyboard state + updateKeys(); +} + void CMSWindowsSecondaryScreen::onPreMainLoop() { diff --git a/lib/platform/CMSWindowsSecondaryScreen.h b/lib/platform/CMSWindowsSecondaryScreen.h index b975b46c..906f28b9 100644 --- a/lib/platform/CMSWindowsSecondaryScreen.h +++ b/lib/platform/CMSWindowsSecondaryScreen.h @@ -59,6 +59,7 @@ public: virtual SInt32 getJumpZoneSize() const; virtual void postCreateWindow(HWND); virtual void preDestroyWindow(HWND); + virtual void onAccessibleDesktop(); protected: // CSecondaryScreen overrides diff --git a/lib/platform/CSynergyHook.cpp b/lib/platform/CSynergyHook.cpp index d5dcc1e5..904d46bd 100644 --- a/lib/platform/CSynergyHook.cpp +++ b/lib/platform/CSynergyHook.cpp @@ -111,10 +111,17 @@ void hideCursor(DWORD thread) { // we should be running the context of the window who's cursor - // we want to hide so we shouldn't have to attach thread input. - g_cursor = GetCursor(); + // we want to hide so we shouldn't have to attach thread input + // but we'll check to make sure. g_cursorThread = thread; - SetCursor(NULL); + if (g_cursorThread != 0) { + DWORD myThread = GetCurrentThreadId(); + if (myThread != g_cursorThread) + AttachThreadInput(myThread, g_cursorThread, TRUE); + g_cursor = SetCursor(NULL); + if (myThread != g_cursorThread) + AttachThreadInput(myThread, g_cursorThread, FALSE); + } } static diff --git a/lib/platform/IMSWindowsScreenEventHandler.h b/lib/platform/IMSWindowsScreenEventHandler.h index 2ce8b90a..ee24ea8e 100644 --- a/lib/platform/IMSWindowsScreenEventHandler.h +++ b/lib/platform/IMSWindowsScreenEventHandler.h @@ -37,6 +37,13 @@ public: */ virtual void preDestroyWindow(HWND) = 0; + //! Notify of newly accessible desktop + /*! + This is called when the user switched from an inaccessible desktop + to an accessible desktop. + */ + virtual void onAccessibleDesktop() = 0; + //@} // IScreenEventHandler overrides diff --git a/lib/synergy/CPrimaryScreen.cpp b/lib/synergy/CPrimaryScreen.cpp index 79d0384e..19bbc8b2 100644 --- a/lib/synergy/CPrimaryScreen.cpp +++ b/lib/synergy/CPrimaryScreen.cpp @@ -172,12 +172,12 @@ CPrimaryScreen::leave() // get keyboard state as we leave updateKeys(); - // subclass hook - onPostLeave(true); - // warp mouse to center warpCursorToCenter(); + // subclass hook + onPostLeave(true); + // local client now active m_active = true;