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;
}
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<SInt32>(LOWORD(info->dwExtraInfo));
w = static_cast<SInt16>(LOWORD(info->dwExtraInfo));
break;
case kWheelWin2000: {
const MOUSEHOOKSTRUCTWin2000* info2k =
(const MOUSEHOOKSTRUCTWin2000*)lParam;
w = static_cast<SInt32>(HIWORD(info2k->mouseData));
w = static_cast<SInt16>(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<SInt16>(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<MSLLHOOKSTRUCT*>(lParam);
SInt32 x = (SInt32)info->pt.x;
SInt32 y = (SInt32)info->pt.y;
SInt32 w = (SInt32)HIWORD(info->mouseData);
SInt32 x = static_cast<SInt32>(info->pt.x);
SInt32 y = static_cast<SInt32>(info->pt.y);
SInt32 w = static_cast<SInt16>(HIWORD(info->mouseData));
// handle the message
if (mouseHookHandler(wParam, x, y, w)) {

View File

@ -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),
@ -376,6 +380,10 @@ CServer::switchScreen(IClient* dst, SInt32 x, SInt32 y, bool forScreensaver)
// record new position
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,6 +1272,14 @@ 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;
@ -1305,6 +1343,14 @@ 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;

View File

@ -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;