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.
This commit is contained in:
crs 2004-04-05 21:10:06 +00:00
parent 6d6ebf7926
commit 3db9facb6c
3 changed files with 96 additions and 15 deletions

View File

@ -457,6 +457,33 @@ mouseHookHandler(WPARAM wParam, SInt32 x, SInt32 y, SInt32 data)
return true; return true;
} }
else if (g_mode == kHOOK_WATCH_JUMP_ZONE) { 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 // check for mouse inside jump zone
bool inside = false; bool inside = false;
if (!inside && (g_zoneSides & kLeftMask) != 0) { if (!inside && (g_zoneSides & kLeftMask) != 0) {
@ -475,8 +502,8 @@ mouseHookHandler(WPARAM wParam, SInt32 x, SInt32 y, SInt32 data)
// relay the event // relay the event
PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_MOVE, x, y); PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_MOVE, x, y);
// if inside then eat the event // if inside and not bogus then eat the event
return inside; return inside && !bogus;
} }
} }
@ -518,13 +545,13 @@ mouseHook(int code, WPARAM wParam, LPARAM lParam)
// them. // them.
switch (g_wheelSupport) { switch (g_wheelSupport) {
case kWheelModern: case kWheelModern:
w = static_cast<SInt32>(LOWORD(info->dwExtraInfo)); w = static_cast<SInt16>(LOWORD(info->dwExtraInfo));
break; break;
case kWheelWin2000: { case kWheelWin2000: {
const MOUSEHOOKSTRUCTWin2000* info2k = const MOUSEHOOKSTRUCTWin2000* info2k =
(const MOUSEHOOKSTRUCTWin2000*)lParam; (const MOUSEHOOKSTRUCTWin2000*)lParam;
w = static_cast<SInt32>(HIWORD(info2k->mouseData)); w = static_cast<SInt16>(HIWORD(info2k->mouseData));
break; break;
} }
} }
@ -561,7 +588,8 @@ getMessageHook(int code, WPARAM wParam, LPARAM lParam)
if (msg->message == g_wmMouseWheel) { if (msg->message == g_wmMouseWheel) {
// post message to our window // post message to our window
PostThreadMessage(g_threadID, PostThreadMessage(g_threadID,
SYNERGY_MSG_MOUSE_WHEEL, msg->wParam, 0); SYNERGY_MSG_MOUSE_WHEEL,
static_cast<SInt16>(msg->wParam & 0xffffu), 0);
// zero out the delta in the message so it's (hopefully) // zero out the delta in the message so it's (hopefully)
// ignored // ignored
@ -627,9 +655,9 @@ mouseLLHook(int code, WPARAM wParam, LPARAM lParam)
if (code >= 0) { if (code >= 0) {
// decode the message // decode the message
MSLLHOOKSTRUCT* info = reinterpret_cast<MSLLHOOKSTRUCT*>(lParam); MSLLHOOKSTRUCT* info = reinterpret_cast<MSLLHOOKSTRUCT*>(lParam);
SInt32 x = (SInt32)info->pt.x; SInt32 x = static_cast<SInt32>(info->pt.x);
SInt32 y = (SInt32)info->pt.y; SInt32 y = static_cast<SInt32>(info->pt.y);
SInt32 w = (SInt32)HIWORD(info->mouseData); SInt32 w = static_cast<SInt16>(HIWORD(info->mouseData));
// handle the message // handle the message
if (mouseHookHandler(wParam, x, y, w)) { if (mouseHookHandler(wParam, x, y, w)) {

View File

@ -40,6 +40,10 @@ CServer::CServer(const CConfig& config, CPrimaryClient* primaryClient) :
m_primaryClient(primaryClient), m_primaryClient(primaryClient),
m_active(primaryClient), m_active(primaryClient),
m_seqNum(0), m_seqNum(0),
m_xDelta(0),
m_yDelta(0),
m_xDelta2(0),
m_yDelta2(0),
m_config(config), m_config(config),
m_activeSaver(NULL), m_activeSaver(NULL),
m_switchDir(kNoDirection), m_switchDir(kNoDirection),
@ -374,8 +378,12 @@ CServer::switchScreen(IClient* dst, SInt32 x, SInt32 y, bool forScreensaver)
stopSwitch(); stopSwitch();
// record new position // record new position
m_x = x; m_x = x;
m_y = y; 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. // wrapping means leaving the active screen and entering it again.
// since that's a waste of time we skip that and just warp the // 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 && if (x >= ax + tapZone && x < ax + aw - tapZone &&
y >= ay + tapZone && y < ay + ah - 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; 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 // save position
m_x = x; m_x = x;
m_y = y; m_y = y;
// get screen shape // get screen shape
SInt32 ax, ay, aw, ah; SInt32 ax, ay, aw, ah;
@ -1305,9 +1343,17 @@ CServer::onMouseMoveSecondary(SInt32 dx, SInt32 dy)
const SInt32 xOld = m_x; const SInt32 xOld = m_x;
const SInt32 yOld = m_y; 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 // accumulate motion
m_x += dx; m_x += dx;
m_y += dy; m_y += dy;
// get screen shape // get screen shape
SInt32 ax, ay, aw, ah; SInt32 ax, ay, aw, ah;

View File

@ -278,6 +278,13 @@ private:
// whichever screen is active // whichever screen is active
SInt32 m_x, m_y; 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 // current configuration
CConfig m_config; CConfig m_config;