From e277e6e74a8812cef550d68da615cfa187ab60ec Mon Sep 17 00:00:00 2001 From: crs Date: Thu, 23 May 2002 18:35:08 +0000 Subject: [PATCH] added support for mouse wheel on win32. --- server/CMSWindowsPrimaryScreen.cpp | 8 ++ server/CSynergyHook.cpp | 188 ++++++++++++++++++++++++----- server/CSynergyHook.h | 1 + 3 files changed, 170 insertions(+), 27 deletions(-) diff --git a/server/CMSWindowsPrimaryScreen.cpp b/server/CMSWindowsPrimaryScreen.cpp index 5d3a36b6..43136b07 100644 --- a/server/CMSWindowsPrimaryScreen.cpp +++ b/server/CMSWindowsPrimaryScreen.cpp @@ -406,6 +406,14 @@ bool CMSWindowsPrimaryScreen::onPreTranslate(MSG* msg) } return true; + case SYNERGY_MSG_MOUSE_WHEEL: + // ignore if not at current mark + if (m_mark == m_markReceived) { + log((CLOG_ERR "event: button wheel delta=%d %d", msg->wParam, msg->lParam)); + m_server->onMouseWheel(msg->wParam); + } + return true; + case SYNERGY_MSG_MOUSE_MOVE: // ignore if not at current mark if (m_mark == m_markReceived) { diff --git a/server/CSynergyHook.cpp b/server/CSynergyHook.cpp index 7c7dc293..ef3b052a 100644 --- a/server/CSynergyHook.cpp +++ b/server/CSynergyHook.cpp @@ -1,6 +1,29 @@ #include "CSynergyHook.h" #include "CScreenMap.h" #include +#include + +// +// extra mouse wheel stuff +// + +enum EWheelSupport { + kWheelNone, + kWheelOld, + kWheelWin2000, + kWheelModern +}; + +// declare extended mouse hook struct. useable on win2k +typedef struct tagMOUSEHOOKSTRUCTWin2000 { + MOUSEHOOKSTRUCT mhs; + DWORD mouseData; +} MOUSEHOOKSTRUCTWin2000; + +#if !defined(SM_MOUSEWHEELPRESENT) +#define SM_MOUSEWHEELPRESENT 75 +#endif + // // globals @@ -12,10 +35,13 @@ static HINSTANCE g_hinstance = NULL; static DWORD g_process = NULL; +static EWheelSupport g_wheelSupport = kWheelNone; +static UINT g_wmMouseWheel = 0; static HWND g_hwnd = NULL; static HHOOK g_keyboard = NULL; static HHOOK g_mouse = NULL; static HHOOK g_cbt = NULL; +static HHOOK g_getMessage = NULL; static bool g_relay = false; static SInt32 g_zoneSize = 0; static UInt32 g_zoneSides = 0; @@ -24,6 +50,8 @@ static SInt32 g_hScreen = 0; static HCURSOR g_cursor = NULL; static DWORD g_cursorThread = 0; +static int foo = 0; + #pragma data_seg() // @@ -58,27 +86,29 @@ static LRESULT CALLBACK keyboardHook(int code, WPARAM wParam, LPARAM lParam) { if (code >= 0) { if (g_relay) { - if (code == HC_ACTION) { - // forward message to our window - PostMessage(g_hwnd, SYNERGY_MSG_KEY, wParam, lParam); + // forward message to our window + PostMessage(g_hwnd, SYNERGY_MSG_KEY, wParam, lParam); - // if the active window isn't our window then make it - // active. - const bool wrongFocus = (GetActiveWindow() != g_hwnd); - if (wrongFocus) { - SetForegroundWindow(g_hwnd); - } +/* XXX -- this doesn't seem to work/help with lost key events + // if the active window isn't our window then make it + // active. + const bool wrongFocus = (GetActiveWindow() != g_hwnd); + if (wrongFocus) { + SetForegroundWindow(g_hwnd); + } +*/ - // let non-system keyboard messages through to our window. - // this allows DefWindowProc() to do normal processing. - // for most keys that means do nothing. for toggle keys - // it means updating the thread's toggle state. discard - // system messages (i.e. keys pressed when alt is down) to - // prevent unexpected or undesired processing. also - // discard messages if not destined for our window - if (wrongFocus || (lParam & 0x20000000lu) != 0) { - return 1; - } + // let certain keys pass through + switch (wParam) { + case VK_CAPITAL: + case VK_NUMLOCK: + case VK_SCROLL: + // pass event + break; + + default: + // discard event + return 1; } } } @@ -100,6 +130,33 @@ static LRESULT CALLBACK mouseHook(int code, WPARAM wParam, LPARAM lParam) PostMessage(g_hwnd, SYNERGY_MSG_MOUSE_BUTTON, wParam, 0); return 1; + case WM_MOUSEWHEEL: { + // win2k and other systems supporting WM_MOUSEWHEEL in + // the mouse hook are gratuitously different (and poorly + // documented). + switch (g_wheelSupport) { + case kWheelModern: { + const MOUSEHOOKSTRUCT* info = + (const MOUSEHOOKSTRUCT*)lParam; + PostMessage(g_hwnd, SYNERGY_MSG_MOUSE_WHEEL, + static_cast(LOWORD(info->dwExtraInfo)), 0); + break; + } + + case kWheelWin2000: { + const MOUSEHOOKSTRUCTWin2000* info = + (const MOUSEHOOKSTRUCTWin2000*)lParam; + PostMessage(g_hwnd, SYNERGY_MSG_MOUSE_WHEEL, + static_cast(HIWORD(info->mouseData)), 0); + break; + } + + default: + break; + } + return 1; + } + case WM_MOUSEMOVE: { const MOUSEHOOKSTRUCT* info = (const MOUSEHOOKSTRUCT*)lParam; SInt32 x = (SInt32)info->pt.x; @@ -174,6 +231,66 @@ static LRESULT CALLBACK cbtHook(int code, WPARAM wParam, LPARAM lParam) return CallNextHookEx(g_cbt, code, wParam, lParam); } +static LRESULT CALLBACK getMessageHook(int code, WPARAM wParam, LPARAM lParam) +{ + if (code >= 0) { + if (g_relay) { + MSG* msg = reinterpret_cast(lParam); + if (msg->message == g_wmMouseWheel) { + // post message to our window + PostMessage(g_hwnd, SYNERGY_MSG_MOUSE_WHEEL, msg->wParam, 0); + + // zero out the delta in the message so it's (hopefully) + // ignored + msg->wParam = 0; + } + } + } + + return CallNextHookEx(g_getMessage, code, wParam, lParam); +} + +static EWheelSupport GetWheelSupport() +{ + // get operating system + OSVERSIONINFO info; + info.dwOSVersionInfoSize = sizeof(info); + if (!GetVersionEx(&info)) { + return kWheelNone; + } + + // see if modern wheel is present + if (GetSystemMetrics(SM_MOUSEWHEELPRESENT)) { + // note if running on win2k + if (info.dwPlatformId == VER_PLATFORM_WIN32_NT && + info.dwMajorVersion == 5 && + info.dwMinorVersion == 0) { + return kWheelWin2000; + } + return kWheelModern; + } + + // not modern. see if we've got old-style support. + UINT wheelSupportMsg = RegisterWindowMessage(MSH_WHEELSUPPORT); + HWND wheelSupportWindow = FindWindow(MSH_WHEELMODULE_CLASS, + MSH_WHEELMODULE_TITLE); + if (wheelSupportWindow != NULL && wheelSupportMsg != 0) { + if (SendMessage(wheelSupportWindow, wheelSupportMsg, 0, 0) != 0) { + g_wmMouseWheel = RegisterWindowMessage(MSH_MOUSEWHEEL); + if (g_wmMouseWheel != 0) { + return kWheelOld; + } + } + } + + // assume modern. we don't do anything special in this case + // except respond to WM_MOUSEWHEEL messages. GetSystemMetrics() + // can apparently return FALSE even if a mouse wheel is present + // though i'm not sure exactly when it does that (but WinME does + // for my logitech usb trackball). + return kWheelModern; +} + // // external functions @@ -202,10 +319,11 @@ extern "C" { int install(HWND hwnd) { - assert(g_hinstance != NULL); - assert(g_keyboard == NULL); - assert(g_mouse == NULL); - assert(g_cbt == NULL); + assert(g_hinstance != NULL); + assert(g_keyboard == NULL); + assert(g_mouse == NULL); + assert(g_cbt == NULL); + assert(g_wheelSupport != kWheelOld || g_getMessage == NULL); // save window g_hwnd = hwnd; @@ -219,6 +337,9 @@ int install(HWND hwnd) g_cursor = NULL; g_cursorThread = 0; + // check for mouse wheel support + g_wheelSupport = GetWheelSupport(); + // install keyboard hook g_keyboard = SetWindowsHookEx(WH_KEYBOARD, &keyboardHook, @@ -257,6 +378,15 @@ int install(HWND hwnd) return 0; } + // install GetMessage hook + if (g_wheelSupport == kWheelOld) { + g_getMessage = SetWindowsHookEx(WH_GETMESSAGE, + &getMessageHook, + g_hinstance, + 0); + // ignore failure; we just won't get mouse wheel messages + } + return 1; } @@ -270,10 +400,14 @@ int uninstall(void) UnhookWindowsHookEx(g_keyboard); UnhookWindowsHookEx(g_mouse); UnhookWindowsHookEx(g_cbt); - g_keyboard = NULL; - g_mouse = NULL; - g_cbt = NULL; - g_hwnd = NULL; + if (g_getMessage != NULL) { + UnhookWindowsHookEx(g_getMessage); + } + g_keyboard = NULL; + g_mouse = NULL; + g_cbt = NULL; + g_getMessage = NULL; + g_hwnd = NULL; // show the cursor restoreCursor(); diff --git a/server/CSynergyHook.h b/server/CSynergyHook.h index 5cdf9c12..ec99afa2 100644 --- a/server/CSynergyHook.h +++ b/server/CSynergyHook.h @@ -18,6 +18,7 @@ #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_MOUSE_WHEEL WM_APP + 0x0015 // delta; typedef int (*InstallFunc)(HWND); typedef int (*UninstallFunc)(void);