diff --git a/lib/platform/CMSWindowsScreen.cpp b/lib/platform/CMSWindowsScreen.cpp index 5af88523..4a65e810 100644 --- a/lib/platform/CMSWindowsScreen.cpp +++ b/lib/platform/CMSWindowsScreen.cpp @@ -106,7 +106,9 @@ CMSWindowsScreen::CMSWindowsScreen(bool isPrimary, m_setMode(NULL), m_keyState(NULL), m_suspend(suspend), - m_resume(resume) + m_resume(resume), + m_hasMouse(GetSystemMetrics(SM_MOUSEPRESENT) != 0), + m_showingMouse(false) { assert(s_instance != NULL); assert(s_screen == NULL); @@ -125,6 +127,7 @@ CMSWindowsScreen::CMSWindowsScreen(bool isPrimary, updateScreenShape(); m_class = createWindowClass(); m_window = createWindow(m_class, "Synergy"); + forceShowCursor(); LOG((CLOG_DEBUG "screen shape: %d,%d %dx%d %s", m_x, m_y, m_w, m_h, m_multimon ? "(multi-monitor)" : "")); LOG((CLOG_DEBUG "window is 0x%08x", m_window)); } @@ -240,6 +243,7 @@ CMSWindowsScreen::disable() m_nextClipboardWindow = NULL; m_isOnScreen = m_isPrimary; + forceShowCursor(); } void @@ -259,6 +263,7 @@ CMSWindowsScreen::enter() // now on screen m_isOnScreen = true; + forceShowCursor(); } bool @@ -292,6 +297,7 @@ CMSWindowsScreen::leave() // now off screen m_isOnScreen = false; + forceShowCursor(); return true; } @@ -525,6 +531,36 @@ CMSWindowsScreen::updateKeys() m_desks->updateKeys(); } +void +CMSWindowsScreen::fakeKeyDown(KeyID id, KeyModifierMask mask, + KeyButton button) +{ + CPlatformScreen::fakeKeyDown(id, mask, button); + updateForceShowCursor(); +} + +void +CMSWindowsScreen::fakeKeyRepeat(KeyID id, KeyModifierMask mask, + SInt32 count, KeyButton button) +{ + CPlatformScreen::fakeKeyRepeat(id, mask, count, button); + updateForceShowCursor(); +} + +void +CMSWindowsScreen::fakeKeyUp(KeyButton button) +{ + CPlatformScreen::fakeKeyUp(button); + updateForceShowCursor(); +} + +void +CMSWindowsScreen::fakeToggle(KeyModifierMask modifier) +{ + CPlatformScreen::fakeToggle(modifier); + updateForceShowCursor(); +} + HINSTANCE CMSWindowsScreen::openHookLibrary(const char* name) { @@ -829,6 +865,16 @@ CMSWindowsScreen::onEvent(HWND, UINT msg, } *result = TRUE; return true; + + case WM_DEVICECHANGE: + forceShowCursor(); + break; + + case WM_SETTINGCHANGE: + if (wParam == SPI_SETMOUSEKEYS) { + forceShowCursor(); + } + break; } return false; @@ -1377,6 +1423,60 @@ CMSWindowsScreen::updateKeysCB(void*) updateButtons(); } +void +CMSWindowsScreen::forceShowCursor() +{ + // check for mouse + m_hasMouse = (GetSystemMetrics(SM_MOUSEPRESENT) != 0); + + // decide if we should show the mouse + bool showMouse = (!m_hasMouse && !m_isPrimary && m_isOnScreen); + + // show/hide the mouse + if (showMouse != m_showingMouse) { + if (showMouse) { + m_oldMouseKeys.cbSize = sizeof(m_oldMouseKeys); + m_gotOldMouseKeys = + (SystemParametersInfo(SPI_GETMOUSEKEYS, + m_oldMouseKeys.cbSize, &m_oldMouseKeys, 0) != 0); + if (m_gotOldMouseKeys) { + m_mouseKeys = m_oldMouseKeys; + m_showingMouse = true; + updateForceShowCursor(); + } + } + else { + if (m_gotOldMouseKeys) { + SystemParametersInfo(SPI_SETMOUSEKEYS, + m_oldMouseKeys.cbSize, + &m_oldMouseKeys, SPIF_SENDCHANGE); + m_showingMouse = false; + } + } + } +} + +void +CMSWindowsScreen::updateForceShowCursor() +{ + DWORD oldFlags = m_mouseKeys.dwFlags; + + // turn on MouseKeys + m_mouseKeys.dwFlags = MKF_AVAILABLE | MKF_MOUSEKEYSON; + + // make sure MouseKeys is active in whatever state the NumLock is + // not currently in. + if ((m_keyState->getActiveModifiers() & KeyModifierNumLock) != 0) { + m_mouseKeys.dwFlags |= MKF_REPLACENUMBERS; + } + + // update MouseKeys + if (oldFlags != m_mouseKeys.dwFlags) { + SystemParametersInfo(SPI_SETMOUSEKEYS, + m_mouseKeys.cbSize, &m_mouseKeys, SPIF_SENDCHANGE); + } +} + LRESULT CALLBACK CMSWindowsScreen::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { diff --git a/lib/platform/CMSWindowsScreen.h b/lib/platform/CMSWindowsScreen.h index 5bb3d587..6fcb691a 100644 --- a/lib/platform/CMSWindowsScreen.h +++ b/lib/platform/CMSWindowsScreen.h @@ -80,6 +80,12 @@ public: // IKeyState overrides virtual void updateKeys(); + virtual void fakeKeyDown(KeyID id, KeyModifierMask mask, + KeyButton button); + virtual void fakeKeyRepeat(KeyID id, KeyModifierMask mask, + SInt32 count, KeyButton button); + virtual void fakeKeyUp(KeyButton button); + virtual void fakeToggle(KeyModifierMask modifier); // IPlatformScreen overrides virtual void enable(); @@ -174,6 +180,16 @@ private: // job to update the key state void updateKeysCB(void*); + // determine whether the mouse is hidden by the system and force + // it to be displayed if user has entered this secondary screen. + void forceShowCursor(); + + // forceShowCursor uses MouseKeys to show the cursor. since we + // don't actually want MouseKeys behavior we have to make sure + // it applies when NumLock is in whatever state it's not in now. + // this method does that. + void updateForceShowCursor(); + // our window proc static LRESULT CALLBACK wndProc(HWND, UINT, WPARAM, LPARAM); @@ -250,6 +266,23 @@ private: IJob* m_suspend; IJob* m_resume; + // the system shows the mouse cursor when an internal display count + // is >= 0. this count is maintained per application but there's + // apparently a system wide count added to the application's count. + // this system count is 0 if there's a mouse attached to the system + // and -1 otherwise. the MouseKeys accessibility feature can modify + // this system count by making the system appear to have a mouse. + // + // m_hasMouse is true iff there's a mouse attached to the system or + // MouseKeys is simulating one. we track this so we can force the + // cursor to be displayed when the user has entered this screen. + // m_showingMouse is true when we're doing that. + bool m_hasMouse; + bool m_showingMouse; + bool m_gotOldMouseKeys; + MOUSEKEYS m_mouseKeys; + MOUSEKEYS m_oldMouseKeys; + static CMSWindowsScreen* s_screen; };