diff --git a/lib/platform/CSynergyHook.cpp b/lib/platform/CSynergyHook.cpp index 0fb0b79c..a4aeb098 100644 --- a/lib/platform/CSynergyHook.cpp +++ b/lib/platform/CSynergyHook.cpp @@ -457,6 +457,33 @@ mouseHookHandler(WPARAM wParam, SInt32 x, SInt32 y, SInt32 data) return true; } else if (g_mode == kHOOK_WATCH_JUMP_ZONE) { + // low level hooks can report bogus mouse positions that are + // outside of the screen. jeez. naturally we end up getting + // fake motion in the other direction to get the position back + // on the screen, which plays havoc with switch on double tap. + // CServer deals with that. we'll clamp positions onto the + // screen. also, if we discard events for positions outside + // of the screen then the mouse appears to get a bit jerky + // near the edge. we can either accept that or pass the bogus + // events. we'll try passing the events. + bool bogus = false; + if (x < g_xScreen) { + x = g_xScreen; + bogus = true; + } + else if (x >= g_xScreen + g_wScreen) { + x = g_xScreen + g_wScreen - 1; + bogus = true; + } + if (y < g_yScreen) { + y = g_yScreen; + bogus = true; + } + else if (y >= g_yScreen + g_hScreen) { + y = g_yScreen + g_hScreen - 1; + bogus = true; + } + // check for mouse inside jump zone bool inside = false; if (!inside && (g_zoneSides & kLeftMask) != 0) { @@ -475,8 +502,8 @@ mouseHookHandler(WPARAM wParam, SInt32 x, SInt32 y, SInt32 data) // relay the event PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_MOVE, x, y); - // if inside then eat the event - return inside; + // if inside and not bogus then eat the event + return inside && !bogus; } } @@ -518,13 +545,13 @@ mouseHook(int code, WPARAM wParam, LPARAM lParam) // them. switch (g_wheelSupport) { case kWheelModern: - w = static_cast(LOWORD(info->dwExtraInfo)); + w = static_cast(LOWORD(info->dwExtraInfo)); break; case kWheelWin2000: { const MOUSEHOOKSTRUCTWin2000* info2k = (const MOUSEHOOKSTRUCTWin2000*)lParam; - w = static_cast(HIWORD(info2k->mouseData)); + w = static_cast(HIWORD(info2k->mouseData)); break; } } @@ -561,7 +588,8 @@ getMessageHook(int code, WPARAM wParam, LPARAM lParam) if (msg->message == g_wmMouseWheel) { // post message to our window PostThreadMessage(g_threadID, - SYNERGY_MSG_MOUSE_WHEEL, msg->wParam, 0); + SYNERGY_MSG_MOUSE_WHEEL, + static_cast(msg->wParam & 0xffffu), 0); // zero out the delta in the message so it's (hopefully) // ignored @@ -627,9 +655,9 @@ mouseLLHook(int code, WPARAM wParam, LPARAM lParam) if (code >= 0) { // decode the message MSLLHOOKSTRUCT* info = reinterpret_cast(lParam); - SInt32 x = (SInt32)info->pt.x; - SInt32 y = (SInt32)info->pt.y; - SInt32 w = (SInt32)HIWORD(info->mouseData); + SInt32 x = static_cast(info->pt.x); + SInt32 y = static_cast(info->pt.y); + SInt32 w = static_cast(HIWORD(info->mouseData)); // handle the message if (mouseHookHandler(wParam, x, y, w)) { diff --git a/lib/server/CServer.cpp b/lib/server/CServer.cpp index 79a13bb9..912272b6 100644 --- a/lib/server/CServer.cpp +++ b/lib/server/CServer.cpp @@ -40,6 +40,10 @@ CServer::CServer(const CConfig& config, CPrimaryClient* primaryClient) : m_primaryClient(primaryClient), m_active(primaryClient), m_seqNum(0), + m_xDelta(0), + m_yDelta(0), + m_xDelta2(0), + m_yDelta2(0), m_config(config), m_activeSaver(NULL), m_switchDir(kNoDirection), @@ -374,8 +378,12 @@ CServer::switchScreen(IClient* dst, SInt32 x, SInt32 y, bool forScreensaver) stopSwitch(); // record new position - m_x = x; - m_y = y; + m_x = x; + m_y = y; + m_xDelta = 0; + m_yDelta = 0; + m_xDelta2 = 0; + m_yDelta2 = 0; // wrapping means leaving the active screen and entering it again. // since that's a waste of time we skip that and just warp the @@ -758,7 +766,29 @@ CServer::armSwitchTwoTap(SInt32 x, SInt32 y) } if (x >= ax + tapZone && x < ax + aw - tapZone && y >= ay + tapZone && y < ay + ah - tapZone) { - m_switchTwoTapArmed = true; + // win32 can generate bogus mouse events that appear to + // move in the opposite direction that the mouse actually + // moved. try to ignore that crap here. + switch (m_switchDir) { + case kLeft: + m_switchTwoTapArmed = (m_xDelta > 0 && m_xDelta2 > 0); + break; + + case kRight: + m_switchTwoTapArmed = (m_xDelta < 0 && m_xDelta2 < 0); + break; + + case kTop: + m_switchTwoTapArmed = (m_yDelta > 0 && m_yDelta2 > 0); + break; + + case kBottom: + m_switchTwoTapArmed = (m_yDelta < 0 && m_yDelta2 < 0); + break; + + default: + break; + } } } } @@ -1242,9 +1272,17 @@ CServer::onMouseMovePrimary(SInt32 x, SInt32 y) return false; } + // save last delta + m_xDelta2 = m_xDelta; + m_yDelta2 = m_yDelta; + + // save current delta + m_xDelta = x - m_x; + m_yDelta = y - m_y; + // save position - m_x = x; - m_y = y; + m_x = x; + m_y = y; // get screen shape SInt32 ax, ay, aw, ah; @@ -1305,9 +1343,17 @@ CServer::onMouseMoveSecondary(SInt32 dx, SInt32 dy) const SInt32 xOld = m_x; const SInt32 yOld = m_y; + // save last delta + m_xDelta2 = m_xDelta; + m_yDelta2 = m_yDelta; + + // save current delta + m_xDelta = dx; + m_yDelta = dy; + // accumulate motion - m_x += dx; - m_y += dy; + m_x += dx; + m_y += dy; // get screen shape SInt32 ax, ay, aw, ah; diff --git a/lib/server/CServer.h b/lib/server/CServer.h index 286eab0e..0e28eee7 100644 --- a/lib/server/CServer.h +++ b/lib/server/CServer.h @@ -278,6 +278,13 @@ private: // whichever screen is active SInt32 m_x, m_y; + // last mouse deltas. this is needed to smooth out double tap + // on win32 which reports bogus mouse motion at the edge of + // the screen when using low level hooks, synthesizing motion + // in the opposite direction the mouse actually moved. + SInt32 m_xDelta, m_yDelta; + SInt32 m_xDelta2, m_yDelta2; + // current configuration CConfig m_config;