Added low-level mouse hook to support mouse wheel on NT (>=SP3).
Thanks to karsten for the patch used as a starting point.
This commit is contained in:
parent
f832bdaf12
commit
1fd7ce14f3
|
@ -55,10 +55,11 @@ static HHOOK g_keyboard = NULL;
|
||||||
static HHOOK g_mouse = NULL;
|
static HHOOK g_mouse = NULL;
|
||||||
static HHOOK g_cbt = NULL;
|
static HHOOK g_cbt = NULL;
|
||||||
static HHOOK g_getMessage = NULL;
|
static HHOOK g_getMessage = NULL;
|
||||||
static HANDLE g_keyHookThread = NULL;
|
static HANDLE g_hookThreadLL = NULL;
|
||||||
static DWORD g_keyHookThreadID = 0;
|
static DWORD g_hookThreadIDLL = 0;
|
||||||
static HANDLE g_keyHookEvent = NULL;
|
static HANDLE g_hookEventLL = NULL;
|
||||||
static HHOOK g_keyboardLL = NULL;
|
static HHOOK g_keyboardLL = NULL;
|
||||||
|
static HHOOK g_mouseLL = NULL;
|
||||||
static bool g_screenSaver = false;
|
static bool g_screenSaver = false;
|
||||||
static bool g_relay = false;
|
static bool g_relay = false;
|
||||||
static UInt32 g_zoneSides = 0;
|
static UInt32 g_zoneSides = 0;
|
||||||
|
@ -162,7 +163,9 @@ mouseHook(int code, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
// win2k and other systems supporting WM_MOUSEWHEEL in
|
// win2k and other systems supporting WM_MOUSEWHEEL in
|
||||||
// the mouse hook are gratuitously different (and poorly
|
// the mouse hook are gratuitously different (and poorly
|
||||||
// documented).
|
// documented). if a low-level mouse hook is in place
|
||||||
|
// it should capture these events so we'll never see
|
||||||
|
// them.
|
||||||
switch (g_wheelSupport) {
|
switch (g_wheelSupport) {
|
||||||
case kWheelModern: {
|
case kWheelModern: {
|
||||||
const MOUSEHOOKSTRUCT* info =
|
const MOUSEHOOKSTRUCT* info =
|
||||||
|
@ -342,12 +345,55 @@ keyboardLLHook(int code, WPARAM wParam, LPARAM lParam)
|
||||||
return CallNextHookEx(g_keyboardLL, code, wParam, lParam);
|
return CallNextHookEx(g_keyboardLL, code, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// low-level mouse hook -- this allows us to capture and handle mouse
|
||||||
|
// wheel events on all windows NT platforms from NT SP3 and up. this
|
||||||
|
// is both simpler than using the mouse hook but also supports windows
|
||||||
|
// windows NT which does not report mouse wheel events. we need to
|
||||||
|
// keep the mouse hook handling of mouse wheel events because the
|
||||||
|
// windows 95 family doesn't support low-level hooks.
|
||||||
|
//
|
||||||
|
|
||||||
|
static
|
||||||
|
LRESULT CALLBACK
|
||||||
|
mouseLLHook(int code, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
if (code >= 0) {
|
||||||
|
if (g_relay) {
|
||||||
|
MSLLHOOKSTRUCT* info = reinterpret_cast<MSLLHOOKSTRUCT*>(lParam);
|
||||||
|
|
||||||
|
switch (wParam) {
|
||||||
|
case WM_MOUSEWHEEL:
|
||||||
|
// mouse wheel events are the same for entire NT family
|
||||||
|
// (>=SP3, prior versions have no low level hooks) for
|
||||||
|
// low-level mouse hook messages, unlike (regular) mouse
|
||||||
|
// hook messages which are gratuitously different on
|
||||||
|
// win2k and not sent at all for windows NT.
|
||||||
|
|
||||||
|
// forward message to our window
|
||||||
|
PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_WHEEL,
|
||||||
|
HIWORD(info->mouseData), 0);
|
||||||
|
|
||||||
|
// discard event
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// all other events are passed through
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CallNextHookEx(g_mouseLL, code, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
DWORD WINAPI
|
DWORD WINAPI
|
||||||
getKeyboardLLProc(void*)
|
getLowLevelProc(void*)
|
||||||
{
|
{
|
||||||
// thread proc for low-level keyboard hook. this does nothing but
|
// thread proc for low-level keyboard/mouse hooks. this does
|
||||||
// install the hook, process events, and uninstall the hook.
|
// nothing but install the hook, process events, and uninstall
|
||||||
|
// the hook.
|
||||||
|
|
||||||
// force this thread to have a message queue
|
// force this thread to have a message queue
|
||||||
MSG msg;
|
MSG msg;
|
||||||
|
@ -360,13 +406,27 @@ getKeyboardLLProc(void*)
|
||||||
0);
|
0);
|
||||||
if (g_keyboardLL == NULL) {
|
if (g_keyboardLL == NULL) {
|
||||||
// indicate failure and exit
|
// indicate failure and exit
|
||||||
g_keyHookThreadID = 0;
|
g_hookThreadIDLL = 0;
|
||||||
SetEvent(g_keyHookEvent);
|
SetEvent(g_hookEventLL);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// install low-level mouse hook
|
||||||
|
g_mouseLL = SetWindowsHookEx(WH_MOUSE_LL,
|
||||||
|
&mouseLLHook,
|
||||||
|
g_hinstance,
|
||||||
|
0);
|
||||||
|
if (g_mouseLL == NULL) {
|
||||||
|
// indicate failure and exit
|
||||||
|
UnhookWindowsHookEx(g_keyboardLL);
|
||||||
|
g_keyboardLL = NULL;
|
||||||
|
g_hookThreadIDLL = 0;
|
||||||
|
SetEvent(g_hookEventLL);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ready
|
// ready
|
||||||
SetEvent(g_keyHookEvent);
|
SetEvent(g_hookEventLL);
|
||||||
|
|
||||||
// message loop
|
// message loop
|
||||||
bool done = false;
|
bool done = false;
|
||||||
|
@ -387,7 +447,9 @@ getKeyboardLLProc(void*)
|
||||||
}
|
}
|
||||||
|
|
||||||
// uninstall hook
|
// uninstall hook
|
||||||
|
UnhookWindowsHookEx(g_mouseLL);
|
||||||
UnhookWindowsHookEx(g_keyboardLL);
|
UnhookWindowsHookEx(g_keyboardLL);
|
||||||
|
g_mouseLL = NULL;
|
||||||
g_keyboardLL = NULL;
|
g_keyboardLL = NULL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -397,10 +459,10 @@ getKeyboardLLProc(void*)
|
||||||
|
|
||||||
static
|
static
|
||||||
DWORD WINAPI
|
DWORD WINAPI
|
||||||
getKeyboardLLProc(void*)
|
getLowLevelProc(void*)
|
||||||
{
|
{
|
||||||
g_keyHookThreadID = 0;
|
g_hookThreadIDLL = 0;
|
||||||
SetEvent(g_keyHookEvent);
|
SetEvent(g_hookEventLL);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -506,10 +568,11 @@ init(DWORD threadID)
|
||||||
g_mouse = NULL;
|
g_mouse = NULL;
|
||||||
g_cbt = NULL;
|
g_cbt = NULL;
|
||||||
g_getMessage = NULL;
|
g_getMessage = NULL;
|
||||||
g_keyHookThread = NULL;
|
g_hookThreadLL = NULL;
|
||||||
g_keyHookThreadID = 0;
|
g_hookThreadIDLL = 0;
|
||||||
g_keyHookEvent = NULL;
|
g_hookEventLL = NULL;
|
||||||
g_keyboardLL = NULL;
|
g_keyboardLL = NULL;
|
||||||
|
g_mouseLL = NULL;
|
||||||
g_screenSaver = false;
|
g_screenSaver = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -607,31 +670,31 @@ install()
|
||||||
// ignore failure; we just won't get mouse wheel messages
|
// ignore failure; we just won't get mouse wheel messages
|
||||||
}
|
}
|
||||||
|
|
||||||
// install low-level keyboard hook, if possible. since this hook
|
// install low-level keyboard/mouse hooks, if possible. since these
|
||||||
// is called in the context of the installing thread and that
|
// hook are called in the context of the installing thread and that
|
||||||
// thread must have a message loop but we don't want the caller's
|
// thread must have a message loop but we don't want the caller's
|
||||||
// message loop to do the work, we'll fire up a separate thread
|
// message loop to do the work, we'll fire up a separate thread
|
||||||
// just for the hook. note that low-level keyboard hooks are only
|
// just for the hooks. note that low-level hooks are only available
|
||||||
// available on windows NT SP3 and above.
|
// on windows NT SP3 and above.
|
||||||
g_keyHookEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
g_hookEventLL = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
if (g_keyHookEvent != NULL) {
|
if (g_hookEventLL != NULL) {
|
||||||
g_keyHookThread = CreateThread(NULL, 0, &getKeyboardLLProc, 0,
|
g_hookThreadLL = CreateThread(NULL, 0, &getLowLevelProc, 0,
|
||||||
CREATE_SUSPENDED, &g_keyHookThreadID);
|
CREATE_SUSPENDED, &g_hookThreadIDLL);
|
||||||
if (g_keyHookThread != NULL) {
|
if (g_hookThreadLL != NULL) {
|
||||||
// start the thread and wait for it to initialize
|
// start the thread and wait for it to initialize
|
||||||
ResumeThread(g_keyHookThread);
|
ResumeThread(g_hookThreadLL);
|
||||||
WaitForSingleObject(g_keyHookEvent, INFINITE);
|
WaitForSingleObject(g_hookEventLL, INFINITE);
|
||||||
ResetEvent(g_keyHookEvent);
|
ResetEvent(g_hookEventLL);
|
||||||
|
|
||||||
// the thread clears g_keyHookThreadID if it failed
|
// the thread clears g_hookThreadIDLL if it failed
|
||||||
if (g_keyHookThreadID == 0) {
|
if (g_hookThreadIDLL == 0) {
|
||||||
CloseHandle(g_keyHookThread);
|
CloseHandle(g_hookThreadLL);
|
||||||
g_keyHookThread = NULL;
|
g_hookThreadLL = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (g_keyHookThread == NULL) {
|
if (g_hookThreadLL == NULL) {
|
||||||
CloseHandle(g_keyHookEvent);
|
CloseHandle(g_hookEventLL);
|
||||||
g_keyHookEvent = NULL;
|
g_hookEventLL = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -644,14 +707,14 @@ uninstall(void)
|
||||||
assert(g_hinstance != NULL);
|
assert(g_hinstance != NULL);
|
||||||
|
|
||||||
// uninstall hooks
|
// uninstall hooks
|
||||||
if (g_keyHookThread != NULL) {
|
if (g_hookThreadLL != NULL) {
|
||||||
PostThreadMessage(g_keyHookThreadID, WM_QUIT, 0, 0);
|
PostThreadMessage(g_hookThreadIDLL, WM_QUIT, 0, 0);
|
||||||
WaitForSingleObject(g_keyHookThread, INFINITE);
|
WaitForSingleObject(g_hookThreadLL, INFINITE);
|
||||||
CloseHandle(g_keyHookEvent);
|
CloseHandle(g_hookEventLL);
|
||||||
CloseHandle(g_keyHookThread);
|
CloseHandle(g_hookThreadLL);
|
||||||
g_keyHookEvent = NULL;
|
g_hookEventLL = NULL;
|
||||||
g_keyHookThread = NULL;
|
g_hookThreadLL = NULL;
|
||||||
g_keyHookThreadID = 0;
|
g_hookThreadIDLL = 0;
|
||||||
}
|
}
|
||||||
if (g_keyboard != NULL) {
|
if (g_keyboard != NULL) {
|
||||||
UnhookWindowsHookEx(g_keyboard);
|
UnhookWindowsHookEx(g_keyboard);
|
||||||
|
|
Loading…
Reference in New Issue