From a09bfc5f07088f06e4c97f4f8f355036edbc8043 Mon Sep 17 00:00:00 2001 From: "Jerry (Xinyu Hou)" Date: Mon, 19 Oct 2015 11:20:56 -0700 Subject: [PATCH] Fix high DPI breaking edge detection and mouse delta calculation #5030 --- src/lib/platform/MSWindowsScreen.cpp | 72 +++++++++++++++++++--------- src/lib/server/BaseClientProxy.h | 6 +++ src/lib/server/PrimaryClient.h | 2 +- src/lib/server/Server.cpp | 13 ++++- 4 files changed, 69 insertions(+), 24 deletions(-) diff --git a/src/lib/platform/MSWindowsScreen.cpp b/src/lib/platform/MSWindowsScreen.cpp index 5473feb3..602e5390 100644 --- a/src/lib/platform/MSWindowsScreen.cpp +++ b/src/lib/platform/MSWindowsScreen.cpp @@ -31,6 +31,7 @@ #include "synergy/App.h" #include "synergy/ArgsBase.h" #include "synergy/ClientApp.h" +#include "synergy/DpiHelper.h" #include "mt/Lock.h" #include "mt/Thread.h" #include "arch/win32/ArchMiscWindows.h" @@ -143,6 +144,11 @@ MSWindowsScreen::MSWindowsScreen( this, &MSWindowsScreen::updateKeysCB), stopOnDeskSwitch); m_keyState = new MSWindowsKeyState(m_desks, getEventTarget(), m_events); + + DpiHelper::calculateDpi( + GetSystemMetrics(SM_CXVIRTUALSCREEN), + GetSystemMetrics(SM_CYVIRTUALSCREEN)); + updateScreenShape(); m_class = createWindowClass(); m_window = createWindow(m_class, "Synergy"); @@ -1347,6 +1353,14 @@ MSWindowsScreen::onMouseButton(WPARAM wParam, LPARAM lParam) bool MSWindowsScreen::onMouseMove(SInt32 mx, SInt32 my) { + SInt32 originalMX = mx; + SInt32 originalMY = my; + + if (DpiHelper::s_dpiScaled) { + mx = (SInt32)(mx / DpiHelper::getDpi()); + my = (SInt32)(my / DpiHelper::getDpi()); + } + // compute motion delta (relative to the last known // mouse position) SInt32 x = mx - m_xCursor; @@ -1370,7 +1384,7 @@ MSWindowsScreen::onMouseMove(SInt32 mx, SInt32 my) // motion on primary screen sendEvent( m_events->forIPrimaryScreen().motionOnPrimary(), - MotionInfo::alloc(m_xCursor, m_yCursor)); + MotionInfo::alloc(originalMX, originalMY)); if (m_buttons[kButtonLeft] == true && m_draggingStarted == false) { m_draggingStarted = true; @@ -1527,20 +1541,25 @@ MSWindowsScreen::warpCursorNoFlush(SInt32 x, SInt32 y) POINT cursorPos; GetCursorPos(&cursorPos); - if ((cursorPos.x != x) && (cursorPos.y != y)) { - LOG((CLOG_DEBUG "SetCursorPos did not work; using fakeMouseMove instead")); - - // when at Vista/7 login screen, SetCursorPos does not work (which could be - // an MS security feature). instead we can use fakeMouseMove, which calls - // mouse_event. - // IMPORTANT: as of implementing this function, it has an annoying side - // effect; instead of the mouse returning to the correct exit point, it - // returns to the center of the screen. this could have something to do with - // the center screen warping technique used (see comments for onMouseMove - // definition). - fakeMouseMove(x, y); + // there is a bug or round error in SetCursorPos and GetCursorPos on + // a high DPI setting. The check here is for Vista/7 login screen. + // since this feature is mainly for client, so only check on client. + if (!isPrimary()) { + if ((cursorPos.x != x) && (cursorPos.y != y)) { + LOG((CLOG_DEBUG "SetCursorPos did not work; using fakeMouseMove instead")); + LOG((CLOG_DEBUG "cursor pos %d, %d expected pos %d, %d", cursorPos.x, cursorPos.y, x, y)); + // when at Vista/7 login screen, SetCursorPos does not work (which could be + // an MS security feature). instead we can use fakeMouseMove, which calls + // mouse_event. + // IMPORTANT: as of implementing this function, it has an annoying side + // effect; instead of the mouse returning to the correct exit point, it + // returns to the center of the screen. this could have something to do with + // the center screen warping technique used (see comments for onMouseMove + // definition). + fakeMouseMove(x, y); + } } - + // yield the CPU. there's a race condition when warping: // a hardware mouse event occurs // the mouse hook is not called because that process doesn't have the CPU @@ -1582,16 +1601,25 @@ MSWindowsScreen::ignore() const void MSWindowsScreen::updateScreenShape() { - // get shape + // get shape and center + if (DpiHelper::s_dpiScaled) { + m_w = (SInt32)DpiHelper::s_resolutionWidth; + m_h = (SInt32)DpiHelper::s_resolutionHeight; + + m_xCenter = (SInt32)DpiHelper::s_primaryWidthCenter; + m_yCenter = (SInt32)DpiHelper::s_primaryHeightCenter; + } + else { + m_w = GetSystemMetrics(SM_CXVIRTUALSCREEN); + m_h = GetSystemMetrics(SM_CYVIRTUALSCREEN); + + m_xCenter = GetSystemMetrics(SM_CXSCREEN) >> 1; + m_yCenter = GetSystemMetrics(SM_CYSCREEN) >> 1; + } + + // get position m_x = GetSystemMetrics(SM_XVIRTUALSCREEN); m_y = GetSystemMetrics(SM_YVIRTUALSCREEN); - m_w = GetSystemMetrics(SM_CXVIRTUALSCREEN); - m_h = GetSystemMetrics(SM_CYVIRTUALSCREEN); - - // get center for cursor - m_xCenter = GetSystemMetrics(SM_CXSCREEN) >> 1; - m_yCenter = GetSystemMetrics(SM_CYSCREEN) >> 1; - // check for multiple monitors m_multimon = (m_w != GetSystemMetrics(SM_CXSCREEN) || m_h != GetSystemMetrics(SM_CYSCREEN)); diff --git a/src/lib/server/BaseClientProxy.h b/src/lib/server/BaseClientProxy.h index 146b635a..746f4797 100644 --- a/src/lib/server/BaseClientProxy.h +++ b/src/lib/server/BaseClientProxy.h @@ -51,6 +51,12 @@ public: */ void getJumpCursorPos(SInt32& x, SInt32& y) const; + //! Get cursor position + /*! + Return if this proxy is for client or primary. + */ + virtual bool isPrimary() const { return false; } + //@} // IScreen diff --git a/src/lib/server/PrimaryClient.h b/src/lib/server/PrimaryClient.h index a0934159..61f20618 100644 --- a/src/lib/server/PrimaryClient.h +++ b/src/lib/server/PrimaryClient.h @@ -148,7 +148,7 @@ public: virtual synergy::IStream* getStream() const { return NULL; } - + bool isPrimary() const { return true; } private: synergy::Screen* m_screen; bool m_clipboardDirty[kClipboardEnd]; diff --git a/src/lib/server/Server.cpp b/src/lib/server/Server.cpp index 1baf6150..c8226720 100644 --- a/src/lib/server/Server.cpp +++ b/src/lib/server/Server.cpp @@ -33,6 +33,7 @@ #include "synergy/KeyState.h" #include "synergy/Screen.h" #include "synergy/PacketStreamFilter.h" +#include "synergy/DpiHelper.h" #include "net/TCPSocket.h" #include "net/IDataSocket.h" #include "net/IListenSocket.h" @@ -2000,8 +2001,18 @@ Server::onMouseMoveSecondary(SInt32 dx, SInt32 dy) m_sendFileThread = NULL; } + SInt32 newX = m_x; + SInt32 newY = m_y; + + if (DpiHelper::s_dpiScaled) { + // only scale if it's going back to server + if (newScreen->isPrimary()) { + newX = (SInt32)(newX / DpiHelper::getDpi()); + newY = (SInt32)(newY / DpiHelper::getDpi()); + } + } // switch screens - switchScreen(newScreen, m_x, m_y, false); + switchScreen(newScreen, newX, newY, false); } else { // same screen. clamp mouse to edge.