Fix high DPI breaking edge detection and mouse delta calculation #5030

This commit is contained in:
Jerry (Xinyu Hou) 2015-10-19 11:20:56 -07:00
parent 66335cd6f8
commit a09bfc5f07
4 changed files with 69 additions and 24 deletions

View File

@ -31,6 +31,7 @@
#include "synergy/App.h" #include "synergy/App.h"
#include "synergy/ArgsBase.h" #include "synergy/ArgsBase.h"
#include "synergy/ClientApp.h" #include "synergy/ClientApp.h"
#include "synergy/DpiHelper.h"
#include "mt/Lock.h" #include "mt/Lock.h"
#include "mt/Thread.h" #include "mt/Thread.h"
#include "arch/win32/ArchMiscWindows.h" #include "arch/win32/ArchMiscWindows.h"
@ -143,6 +144,11 @@ MSWindowsScreen::MSWindowsScreen(
this, &MSWindowsScreen::updateKeysCB), this, &MSWindowsScreen::updateKeysCB),
stopOnDeskSwitch); stopOnDeskSwitch);
m_keyState = new MSWindowsKeyState(m_desks, getEventTarget(), m_events); m_keyState = new MSWindowsKeyState(m_desks, getEventTarget(), m_events);
DpiHelper::calculateDpi(
GetSystemMetrics(SM_CXVIRTUALSCREEN),
GetSystemMetrics(SM_CYVIRTUALSCREEN));
updateScreenShape(); updateScreenShape();
m_class = createWindowClass(); m_class = createWindowClass();
m_window = createWindow(m_class, "Synergy"); m_window = createWindow(m_class, "Synergy");
@ -1347,6 +1353,14 @@ MSWindowsScreen::onMouseButton(WPARAM wParam, LPARAM lParam)
bool bool
MSWindowsScreen::onMouseMove(SInt32 mx, SInt32 my) 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 // compute motion delta (relative to the last known
// mouse position) // mouse position)
SInt32 x = mx - m_xCursor; SInt32 x = mx - m_xCursor;
@ -1370,7 +1384,7 @@ MSWindowsScreen::onMouseMove(SInt32 mx, SInt32 my)
// motion on primary screen // motion on primary screen
sendEvent( sendEvent(
m_events->forIPrimaryScreen().motionOnPrimary(), m_events->forIPrimaryScreen().motionOnPrimary(),
MotionInfo::alloc(m_xCursor, m_yCursor)); MotionInfo::alloc(originalMX, originalMY));
if (m_buttons[kButtonLeft] == true && m_draggingStarted == false) { if (m_buttons[kButtonLeft] == true && m_draggingStarted == false) {
m_draggingStarted = true; m_draggingStarted = true;
@ -1527,18 +1541,23 @@ MSWindowsScreen::warpCursorNoFlush(SInt32 x, SInt32 y)
POINT cursorPos; POINT cursorPos;
GetCursorPos(&cursorPos); GetCursorPos(&cursorPos);
if ((cursorPos.x != x) && (cursorPos.y != y)) { // there is a bug or round error in SetCursorPos and GetCursorPos on
LOG((CLOG_DEBUG "SetCursorPos did not work; using fakeMouseMove instead")); // 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.
// when at Vista/7 login screen, SetCursorPos does not work (which could be if (!isPrimary()) {
// an MS security feature). instead we can use fakeMouseMove, which calls if ((cursorPos.x != x) && (cursorPos.y != y)) {
// mouse_event. LOG((CLOG_DEBUG "SetCursorPos did not work; using fakeMouseMove instead"));
// IMPORTANT: as of implementing this function, it has an annoying side LOG((CLOG_DEBUG "cursor pos %d, %d expected pos %d, %d", cursorPos.x, cursorPos.y, x, y));
// effect; instead of the mouse returning to the correct exit point, it // when at Vista/7 login screen, SetCursorPos does not work (which could be
// returns to the center of the screen. this could have something to do with // an MS security feature). instead we can use fakeMouseMove, which calls
// the center screen warping technique used (see comments for onMouseMove // mouse_event.
// definition). // IMPORTANT: as of implementing this function, it has an annoying side
fakeMouseMove(x, y); // 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: // yield the CPU. there's a race condition when warping:
@ -1582,16 +1601,25 @@ MSWindowsScreen::ignore() const
void void
MSWindowsScreen::updateScreenShape() 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_x = GetSystemMetrics(SM_XVIRTUALSCREEN);
m_y = GetSystemMetrics(SM_YVIRTUALSCREEN); 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 // check for multiple monitors
m_multimon = (m_w != GetSystemMetrics(SM_CXSCREEN) || m_multimon = (m_w != GetSystemMetrics(SM_CXSCREEN) ||
m_h != GetSystemMetrics(SM_CYSCREEN)); m_h != GetSystemMetrics(SM_CYSCREEN));

View File

@ -51,6 +51,12 @@ public:
*/ */
void getJumpCursorPos(SInt32& x, SInt32& y) const; 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 // IScreen

View File

@ -148,7 +148,7 @@ public:
virtual synergy::IStream* virtual synergy::IStream*
getStream() const { return NULL; } getStream() const { return NULL; }
bool isPrimary() const { return true; }
private: private:
synergy::Screen* m_screen; synergy::Screen* m_screen;
bool m_clipboardDirty[kClipboardEnd]; bool m_clipboardDirty[kClipboardEnd];

View File

@ -33,6 +33,7 @@
#include "synergy/KeyState.h" #include "synergy/KeyState.h"
#include "synergy/Screen.h" #include "synergy/Screen.h"
#include "synergy/PacketStreamFilter.h" #include "synergy/PacketStreamFilter.h"
#include "synergy/DpiHelper.h"
#include "net/TCPSocket.h" #include "net/TCPSocket.h"
#include "net/IDataSocket.h" #include "net/IDataSocket.h"
#include "net/IListenSocket.h" #include "net/IListenSocket.h"
@ -2000,8 +2001,18 @@ Server::onMouseMoveSecondary(SInt32 dx, SInt32 dy)
m_sendFileThread = NULL; 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 // switch screens
switchScreen(newScreen, m_x, m_y, false); switchScreen(newScreen, newX, newY, false);
} }
else { else {
// same screen. clamp mouse to edge. // same screen. clamp mouse to edge.