From 76cc62d133210b2ff64f79df8c86dfa0b3f56ea3 Mon Sep 17 00:00:00 2001 From: crs Date: Wed, 17 Jul 2002 17:27:41 +0000 Subject: [PATCH] attempt to fix stuttering when leaving win32 screen. seems to work but will let testers make the final call. also fixed desktop synchronization by setting a variable that was mistakenly left unset. and tried to work around an apparent bug in MsgWaitForMultipleObjects() that prevented the service from closing down properly. start/pause/continue/stop sequence still doesn't shut down correctly. start/pause/stop and start/stop work fine. --- platform/CMSWindowsScreen.cpp | 6 ++ platform/CSynergyHook.cpp | 9 +- platform/CSynergyHook.h | 11 ++- server/CMSWindowsPrimaryScreen.cpp | 152 ++++++++++++++++------------- server/CMSWindowsPrimaryScreen.h | 9 +- server/CPrimaryScreen.cpp | 13 +-- server/CPrimaryScreen.h | 4 +- 7 files changed, 108 insertions(+), 96 deletions(-) diff --git a/platform/CMSWindowsScreen.cpp b/platform/CMSWindowsScreen.cpp index 9cc1a096..63e34d1f 100644 --- a/platform/CMSWindowsScreen.cpp +++ b/platform/CMSWindowsScreen.cpp @@ -1,6 +1,7 @@ #include "CMSWindowsScreen.h" #include "CMSWindowsClipboard.h" #include "CMSWindowsScreenSaver.h" +#include "CPlatform.h" #include "CClipboard.h" #include "IMSWindowsScreenEventHandler.h" #include "IScreenReceiver.h" @@ -35,6 +36,7 @@ CMSWindowsScreen::CMSWindowsScreen(IScreenReceiver* receiver, m_class(NULL), m_icon(NULL), m_cursor(NULL), + m_is95Family(CPlatform::isWindows95Family()), m_window(NULL), m_x(0), m_y(0), m_w(0), m_h(0), @@ -206,7 +208,11 @@ CMSWindowsScreen::mainLoop() void CMSWindowsScreen::exitMainLoop() { + // post an arbitrary message after the quit because + // MsgWaitForMultipleObjects() is broken and might not wake up if + // just WM_QUIT is in the queue. PostThreadMessage(m_threadID, WM_QUIT, 0, 0); + PostThreadMessage(m_threadID, WM_APP + 1, 0, 0); } void diff --git a/platform/CSynergyHook.cpp b/platform/CSynergyHook.cpp index 83857454..2f602de6 100644 --- a/platform/CSynergyHook.cpp +++ b/platform/CSynergyHook.cpp @@ -187,14 +187,7 @@ mouseHook(int code, WPARAM wParam, LPARAM lParam) // relay the motion SInt32 x = (SInt32)info->pt.x; SInt32 y = (SInt32)info->pt.y; - if (info->dwExtraInfo == 0x12345678) { - PostThreadMessage(g_threadID, - SYNERGY_MSG_POST_WARP, x, y); - } - else { - PostThreadMessage(g_threadID, - SYNERGY_MSG_MOUSE_MOVE, x, y); - } + PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_MOVE, x, y); } return 1; } diff --git a/platform/CSynergyHook.h b/platform/CSynergyHook.h index 893f2242..4466c5f7 100644 --- a/platform/CSynergyHook.h +++ b/platform/CSynergyHook.h @@ -19,10 +19,13 @@ #define SYNERGY_MSG_MARK WM_APP + 0x0011 // mark id; #define SYNERGY_MSG_KEY WM_APP + 0x0012 // vk code; key data #define SYNERGY_MSG_MOUSE_BUTTON WM_APP + 0x0013 // button msg; -#define SYNERGY_MSG_MOUSE_MOVE WM_APP + 0x0014 // x; y -#define SYNERGY_MSG_POST_WARP WM_APP + 0x0015 // x; y -#define SYNERGY_MSG_MOUSE_WHEEL WM_APP + 0x0016 // delta; -#define SYNERGY_MSG_SCREEN_SAVER WM_APP + 0x0017 // activated; +#define SYNERGY_MSG_MOUSE_WHEEL WM_APP + 0x0014 // delta; +#define SYNERGY_MSG_MOUSE_MOVE WM_APP + 0x0015 // x; y +#define SYNERGY_MSG_POST_WARP WM_APP + 0x0016 // ; +#define SYNERGY_MSG_PRE_WARP WM_APP + 0x0017 // x; y +#define SYNERGY_MSG_SCREEN_SAVER WM_APP + 0x0018 // activated; +#define SYNERGY_MSG_INPUT_FIRST SYNERGY_MSG_KEY +#define SYNERGY_MSG_INPUT_LAST SYNERGY_MSG_PRE_WARP extern "C" { diff --git a/server/CMSWindowsPrimaryScreen.cpp b/server/CMSWindowsPrimaryScreen.cpp index d2e53b6f..2a4f8715 100644 --- a/server/CMSWindowsPrimaryScreen.cpp +++ b/server/CMSWindowsPrimaryScreen.cpp @@ -19,8 +19,7 @@ CMSWindowsPrimaryScreen::CMSWindowsPrimaryScreen( m_threadID(0), m_window(NULL), m_mark(0), - m_markReceived(0), - m_mouseMoveIgnore(0) + m_markReceived(0) { assert(m_receiver != NULL); @@ -71,9 +70,15 @@ CMSWindowsPrimaryScreen::reconfigure(UInt32 activeSides) void CMSWindowsPrimaryScreen::warpCursor(SInt32 x, SInt32 y) { - // set the cursor position without generating an event -// FIXME -- doesn't this generate an event anyway? - SetCursorPos(x, y); + // warp mouse + warpCursorNoFlush(x, y); + + // remove all input events before and including warp + MSG msg; + while (PeekMessage(&msg, NULL, SYNERGY_MSG_INPUT_FIRST, + SYNERGY_MSG_INPUT_LAST, PM_REMOVE)) { + // do nothing + } // save position as last position m_x = x; @@ -165,7 +170,7 @@ CMSWindowsPrimaryScreen::onPreDispatch(const CEvent* event) case SYNERGY_MSG_KEY: // ignore message if posted prior to last mark change - if (m_markReceived == m_mark) { + if (!ignore()) { KeyModifierMask mask; const KeyID key = mapKey(msg->wParam, msg->lParam, &mask); if (key != kKeyNone) { @@ -201,7 +206,7 @@ CMSWindowsPrimaryScreen::onPreDispatch(const CEvent* event) case SYNERGY_MSG_MOUSE_BUTTON: // ignore message if posted prior to last mark change - if (m_markReceived == m_mark) { + if (!ignore()) { static const int s_vkButton[] = { 0, // kButtonNone VK_LBUTTON, // kButtonLeft, etc. @@ -236,53 +241,65 @@ CMSWindowsPrimaryScreen::onPreDispatch(const CEvent* event) case SYNERGY_MSG_MOUSE_WHEEL: // ignore message if posted prior to last mark change - if (m_markReceived == m_mark) { - log((CLOG_ERR "event: button wheel delta=%d %d", msg->wParam, msg->lParam)); + if (!ignore()) { + log((CLOG_DEBUG1 "event: button wheel delta=%d %d", msg->wParam, msg->lParam)); m_receiver->onMouseWheel(msg->wParam); } return true; + case SYNERGY_MSG_PRE_WARP: + { + // save position to compute delta of next motion + m_x = static_cast(msg->wParam); + m_y = static_cast(msg->lParam); + + // we warped the mouse. discard events until we find the + // matching post warp event. see warpCursorNoFlush() for + // where the events are sent. we discard the matching + // post warp event and can be sure we've skipped the warp + // event. + MSG msg; + do { + GetMessage(&msg, NULL, SYNERGY_MSG_MOUSE_MOVE, + SYNERGY_MSG_POST_WARP); + } while (msg.message != SYNERGY_MSG_POST_WARP); + + return true; + } + + case SYNERGY_MSG_POST_WARP: + log((CLOG_WARN "unmatched post warp")); + return true; + case SYNERGY_MSG_MOUSE_MOVE: // ignore message if posted prior to last mark change - if (m_markReceived == m_mark) { - SInt32 x = static_cast(msg->wParam); - SInt32 y = static_cast(msg->lParam); + if (!ignore()) { + // compute motion delta (relative to the last known + // mouse position) + SInt32 x = static_cast(msg->wParam) - m_x; + SInt32 y = static_cast(msg->lParam) - m_y; + + // save position to compute delta of next motion + m_x = static_cast(msg->wParam); + m_y = static_cast(msg->lParam); + if (!isActive()) { - m_receiver->onMouseMovePrimary(x, y); + // motion on primary screen + m_receiver->onMouseMovePrimary(m_x, m_y); } else { - // compute motion delta. this is relative to the - // last known mouse position. - x -= m_x; - y -= m_y; + // motion on secondary screen. warp mouse back to + // center. + if (x != 0 || y != 0) { + // back to center + warpCursorNoFlush(m_xCenter, m_yCenter); - // save position to compute delta of next motion - m_x = static_cast(msg->wParam); - m_y = static_cast(msg->lParam); - - // ignore if the mouse didn't move or we're ignoring - // motion. - if (m_mouseMoveIgnore == 0) { - if (x != 0 || y != 0) { - // back to center - warpCursorToCenter(); - - // send motion - m_receiver->onMouseMoveSecondary(x, y); - } - } - else { - // ignored one more motion event - --m_mouseMoveIgnore; + // send motion + m_receiver->onMouseMoveSecondary(x, y); } } } return true; - - case SYNERGY_MSG_POST_WARP: - m_x = static_cast(msg->wParam); - m_y = static_cast(msg->lParam); - return true; } return false; @@ -414,9 +431,6 @@ CMSWindowsPrimaryScreen::onPreEnter() { assert(m_window != NULL); - // reset motion ignore count - m_mouseMoveIgnore = 0; - // enable ctrl+alt+del, alt+tab, etc if (m_is95Family) { DWORD dummy = 0; @@ -450,23 +464,11 @@ CMSWindowsPrimaryScreen::onPostLeave(bool success) // relay all mouse and keyboard events m_setRelay(true); - // ignore this many mouse motion events (not including the already - // queued events). on (at least) the win2k login desktop, one - // motion event is reported using a position from before the above - // warpCursor(). i don't know why it does that and other desktops - // don't have the same problem. anyway, simply ignoring that event - // works around it. -// FIXME -- is this true now that we're using mouse_event? - m_mouseMoveIgnore = 1; - // disable ctrl+alt+del, alt+tab, etc if (m_is95Family) { DWORD dummy = 0; SystemParametersInfo(SPI_SETSCREENSAVERRUNNING, TRUE, &dummy, 0); } - - // discard messages until after the warp - nextMark(); } } @@ -550,16 +552,21 @@ CMSWindowsPrimaryScreen::hideWindow() void CMSWindowsPrimaryScreen::warpCursorToCenter() { - // warp to center. the extra info tells the hook DLL to send - // SYNERGY_MSG_POST_WARP instead of SYNERGY_MSG_MOUSE_MOVE. - SInt32 x, y, w, h; - m_screen->getShape(x, y, w, h); - mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE, - (DWORD)((65535.99 * (m_xCenter - x)) / (w - 1)), - (DWORD)((65535.99 * (m_yCenter - y)) / (h - 1)), - 0, - 0x12345678); -// FIXME -- ignore mouse until we get warp notification? + warpCursor(m_xCenter, m_yCenter); +} + +void +CMSWindowsPrimaryScreen::warpCursorNoFlush(SInt32 x, SInt32 y) +{ + // send an event that we can recognize before the mouse warp + PostThreadMessage(m_threadID, SYNERGY_MSG_PRE_WARP, x, y); + + // warp mouse. hopefully this inserts a mouse motion event + // between the previous message and the following message. + SetCursorPos(x, y); + + // send an event that we can recognize after the mouse warp + PostThreadMessage(m_threadID, SYNERGY_MSG_POST_WARP, 0, 0); } void @@ -572,6 +579,12 @@ CMSWindowsPrimaryScreen::nextMark() PostThreadMessage(m_threadID, SYNERGY_MSG_MARK, m_mark, 0); } +bool +CMSWindowsPrimaryScreen::ignore() const +{ + return (m_mark != m_markReceived); +} + static const KeyID g_virtualKey[] = { /* 0x00 */ kKeyNone, // reserved @@ -984,15 +997,14 @@ CMSWindowsPrimaryScreen::mapKey( // set shift state required to generate key BYTE keys[256]; memset(keys, 0, sizeof(keys)); -// FIXME -- surely these masks should be different in each if expression if (vkCode & 0x0100) { - keys[VK_SHIFT] = 0x80; + keys[VK_SHIFT] = 0x80; } - if (vkCode & 0x0100) { + if (vkCode & 0x0200) { keys[VK_CONTROL] = 0x80; } - if (vkCode & 0x0100) { - keys[VK_MENU] = 0x80; + if (vkCode & 0x0400) { + keys[VK_MENU] = 0x80; } // strip shift state off of virtual key code diff --git a/server/CMSWindowsPrimaryScreen.h b/server/CMSWindowsPrimaryScreen.h index 0b8af7b1..3dc2d161 100644 --- a/server/CMSWindowsPrimaryScreen.h +++ b/server/CMSWindowsPrimaryScreen.h @@ -56,9 +56,15 @@ protected: private: void enterNoWarp(); + // warp cursor without discarding queued events + void warpCursorNoFlush(SInt32 x, SInt32 y); + // discard posted messages void nextMark(); + // test if event should be ignored + bool ignore() const; + // key and button queries KeyID mapKey(WPARAM keycode, LPARAM info, KeyModifierMask* maskOut); @@ -91,9 +97,6 @@ private: // position of center pixel of screen SInt32 m_xCenter, m_yCenter; - // used to ignore mouse motion - SInt32 m_mouseMoveIgnore; - // hook library stuff HINSTANCE m_hookLibrary; InitFunc m_init; diff --git a/server/CPrimaryScreen.cpp b/server/CPrimaryScreen.cpp index 4184c7fd..cfe7d014 100644 --- a/server/CPrimaryScreen.cpp +++ b/server/CPrimaryScreen.cpp @@ -155,19 +155,12 @@ CPrimaryScreen::leave() // get keyboard state as we leave updateKeys(); - // warp mouse to center - warpCursorToCenter(); - // FIXME -- this doesn't match the win32 version. that just does - // the warp while we flush the input queue until we find the warp - // and we discard that too. would prefer to at least match our - // own warping when we receive MotionNotify; that just does the - // warp. however, the win32 version sometimes stutters when - // leaving and perhaps this is why. hmm, win32 does ignore the - // events until after the warp (via the mark). - // subclass hook onPostLeave(true); + // warp mouse to center + warpCursorToCenter(); + // local client now active m_active = true; diff --git a/server/CPrimaryScreen.h b/server/CPrimaryScreen.h index 5df1987c..7fab4eba 100644 --- a/server/CPrimaryScreen.h +++ b/server/CPrimaryScreen.h @@ -47,7 +47,9 @@ public: // primary screen are linked to clients. virtual void reconfigure(UInt32 activeSides) = 0; - // warp the cursor to the given absolute coordinates + // warp the cursor to the given absolute coordinates. also + // discard input events up to and including the warp before + // returning. virtual void warpCursor(SInt32 x, SInt32 y) = 0; // set the screen's clipboard contents. this is usually called