From 3db9facb6c8721d4971a61a0d936688df082ddfc Mon Sep 17 00:00:00 2001 From: crs Date: Mon, 5 Apr 2004 21:10:06 +0000 Subject: [PATCH] Added workaround for win32 low-level mouse hook position weirdness. The low-level hook can report mouse positions outside the boundaries of the screen and bogus retrograde motion. This messes up switch on double tap. This change attempts to detect and suppress the bogus events. --- lib/platform/CSynergyHook.cpp | 44 ++++++++++++++++++++----- lib/server/CServer.cpp | 60 +++++++++++++++++++++++++++++++---- lib/server/CServer.h | 7 ++++ 3 files changed, 96 insertions(+), 15 deletions(-) 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;