From 0e5ed7a3051b72f56439190bf1c91d84ea6aa01d Mon Sep 17 00:00:00 2001 From: walker0643 <> Date: Fri, 23 Feb 2018 20:56:12 -0500 Subject: [PATCH] clean up the hook management code --- src/lib/platform/MSWindowsDesks.cpp | 76 ++----- src/lib/platform/MSWindowsHook.cpp | 233 ++++----------------- src/lib/platform/MSWindowsHook.h | 14 +- src/lib/platform/MSWindowsHookResource.cpp | 33 +++ src/lib/platform/MSWindowsHookResource.h | 20 ++ src/lib/platform/MSWindowsScreen.cpp | 4 - src/lib/platform/synwinhk.h | 6 - 7 files changed, 118 insertions(+), 268 deletions(-) create mode 100644 src/lib/platform/MSWindowsHookResource.cpp create mode 100644 src/lib/platform/MSWindowsHookResource.h diff --git a/src/lib/platform/MSWindowsDesks.cpp b/src/lib/platform/MSWindowsDesks.cpp index fa8257d1..8a4f3b7c 100644 --- a/src/lib/platform/MSWindowsDesks.cpp +++ b/src/lib/platform/MSWindowsDesks.cpp @@ -547,7 +547,7 @@ MSWindowsDesks::deskEnter(Desk* desk) AttachThreadInput(thatThread, thisThread, TRUE); SetForegroundWindow(desk->m_foregroundWindow); AttachThreadInput(thatThread, thisThread, FALSE); - EnableWindow(desk->m_window, desk->m_lowLevel ? FALSE : TRUE); + EnableWindow(desk->m_window, FALSE); desk->m_foregroundWindow = NULL; } @@ -560,35 +560,16 @@ MSWindowsDesks::deskLeave(Desk* desk, HKL keyLayout) // layout we choose rather than the keyboard layout of the last // active window. int x, y, w, h; - if (desk->m_lowLevel) { - // with a low level hook the cursor will never budge so - // just a 1x1 window is sufficient. - x = m_xCenter; - y = m_yCenter; - w = 1; - h = 1; - } - else { - // with regular hooks the cursor will jitter as it's moved - // by the user then back to the center by us. to be sure - // we never lose it, cover all the monitors with the window. - x = m_x; - y = m_y; - w = m_w; - h = m_h; - } + // with a low level hook the cursor will never budge so + // just a 1x1 window is sufficient. + x = m_xCenter; + y = m_yCenter; + w = 1; + h = 1; SetWindowPos(desk->m_window, HWND_TOP, x, y, w, h, SWP_NOACTIVATE | SWP_SHOWWINDOW); - // if not using low-level hooks we have to also activate the - // window to ensure we don't lose keyboard focus. - // FIXME -- see if this can be avoided. if so then always - // disable the window (see handling of BARRIER_MSG_SWITCH). - if (!desk->m_lowLevel) { - SetActiveWindow(desk->m_window); - } - - // if using low-level hooks then disable the foreground window + // since we're using low-level hooks, disable the foreground window // so it can't mess up any of our keyboard events. the console // program, for example, will cause characters to be reported as // unshifted, regardless of the shift key state. interestingly @@ -596,19 +577,17 @@ MSWindowsDesks::deskLeave(Desk* desk, HKL keyLayout) // // note that we must enable the window to activate it and we // need to disable the window on deskEnter. - else { - desk->m_foregroundWindow = getForegroundWindow(); - if (desk->m_foregroundWindow != NULL) { - EnableWindow(desk->m_window, TRUE); - SetActiveWindow(desk->m_window); - DWORD thisThread = - GetWindowThreadProcessId(desk->m_window, NULL); - DWORD thatThread = - GetWindowThreadProcessId(desk->m_foregroundWindow, NULL); - AttachThreadInput(thatThread, thisThread, TRUE); - SetForegroundWindow(desk->m_window); - AttachThreadInput(thatThread, thisThread, FALSE); - } + desk->m_foregroundWindow = getForegroundWindow(); + if (desk->m_foregroundWindow != NULL) { + EnableWindow(desk->m_window, TRUE); + SetActiveWindow(desk->m_window); + DWORD thisThread = + GetWindowThreadProcessId(desk->m_window, NULL); + DWORD thatThread = + GetWindowThreadProcessId(desk->m_foregroundWindow, NULL); + AttachThreadInput(thatThread, thisThread, TRUE); + SetForegroundWindow(desk->m_window); + AttachThreadInput(thatThread, thisThread, FALSE); } // switch to requested keyboard layout @@ -683,25 +662,14 @@ MSWindowsDesks::deskThread(void* vdesk) auto list = immune_keys_list(); LOG((CLOG_DEBUG "Found %u immune keys", list.size())); //m_setImmuneKeys(list.data(), list.size()); - switch (MSWindowsHook::install()) { - case kHOOK_FAILED: + if (!MSWindowsHook::install()) { // we won't work on this desk - desk->m_lowLevel = false; - break; - - case kHOOK_OKAY: - desk->m_lowLevel = false; - break; - - case kHOOK_OKAY_LL: - desk->m_lowLevel = true; - break; + LOG((CLOG_DEBUG "Cannot hook on this desk")); } - // a window on the primary screen with low-level hooks // should never activate. if (desk->m_window) - EnableWindow(desk->m_window, desk->m_lowLevel ? FALSE : TRUE); + EnableWindow(desk->m_window, FALSE); } break; diff --git a/src/lib/platform/MSWindowsHook.cpp b/src/lib/platform/MSWindowsHook.cpp index c9952e9d..a27ef981 100644 --- a/src/lib/platform/MSWindowsHook.cpp +++ b/src/lib/platform/MSWindowsHook.cpp @@ -18,6 +18,7 @@ */ #include "platform/MSWindowsHook.h" +#include "platform/MSWindowsHookResource.h" #include "barrier/protocol_types.h" #include "barrier/XScreen.h" #include "base/Log.h" @@ -30,14 +31,11 @@ // #define NO_GRAB_KEYBOARD 0 -static const char* g_name = "synwinhk"; +static const DWORD g_threadID = GetCurrentThreadId(); -static DWORD g_processID = 0; -static DWORD g_threadID = 0; -static HHOOK g_getMessage = NULL; -static HHOOK g_keyboardLL = NULL; -static HHOOK g_mouseLL = NULL; -static bool g_screenSaver = false; +static WindowsHookResource g_hkMessage; +static WindowsHookResource g_hkKeyboard; +static WindowsHookResource g_hkMouse; static EHookMode g_mode = kHOOK_DISABLE; static UInt32 g_zoneSides = 0; static SInt32 g_zoneSize = 0; @@ -50,90 +48,7 @@ static WPARAM g_deadRelease = 0; static LPARAM g_deadLParam = 0; static BYTE g_deadKeyState[256] = { 0 }; static BYTE g_keyState[256] = { 0 }; -static DWORD g_hookThread = 0; static bool g_fakeServerInput = false; -static BOOL g_isPrimary = TRUE; - -MSWindowsHook::MSWindowsHook() -{ -} - -MSWindowsHook::~MSWindowsHook() -{ - cleanup(); - - if (g_processID == GetCurrentProcessId()) { - uninstall(); - uninstallScreenSaver(); - g_processID = 0; - } -} - -void -MSWindowsHook::loadLibrary() -{ - if (g_processID == 0) { - g_processID = GetCurrentProcessId(); - } - if (init(GetCurrentThreadId()) == 0) { - LOG((CLOG_ERR "failed to init hooks handler")); - throw XScreenOpenFailure(); - } -} - -int -MSWindowsHook::init(DWORD threadID) -{ - // try to open process that last called init() to see if it's - // still running or if it died without cleaning up. - if (g_processID != 0 && g_processID != GetCurrentProcessId()) { - HANDLE process = OpenProcess(STANDARD_RIGHTS_REQUIRED, - FALSE, g_processID); - if (process != NULL) { - // old process (probably) still exists so refuse to - // reinitialize this DLL (and thus steal it from the - // old process). - int result = CloseHandle(process); - if (result == false) { - return 0; - } - } - - // clean up after old process. the system should've already - // removed the hooks so we just need to reset our state. - g_processID = GetCurrentProcessId(); - g_threadID = 0; - g_getMessage = NULL; - g_keyboardLL = NULL; - g_mouseLL = NULL; - g_screenSaver = false; - } - - // save thread id. we'll post messages to this thread's - // message queue. - g_threadID = threadID; - - // set defaults - g_mode = kHOOK_DISABLE; - g_zoneSides = 0; - g_zoneSize = 0; - g_xScreen = 0; - g_yScreen = 0; - g_wScreen = 0; - g_hScreen = 0; - - return 1; -} - -int -MSWindowsHook::cleanup() -{ - if (g_processID == GetCurrentProcessId()) { - g_threadID = 0; - } - - return 1; -} void MSWindowsHook::setSides(UInt32 sides) @@ -445,14 +360,9 @@ keyboardHookHandler(WPARAM wParam, LPARAM lParam) // pass event on. we want to let these through to // the window proc because otherwise the keyboard // lights may not stay synchronized. - break; - case VK_HANGUL: - // pass these modifiers if using a low level hook, discard - // them if not. - if (g_hookThread == 0) { - return true; - } + // pass event on because we're using a low level hook + break; default: @@ -493,7 +403,7 @@ keyboardLLHook(int code, WPARAM wParam, LPARAM lParam) } } - return CallNextHookEx(g_keyboardLL, code, wParam, lParam); + return CallNextHookEx(g_hkKeyboard, code, wParam, lParam); } #endif // !NO_GRAB_KEYBOARD @@ -613,19 +523,12 @@ mouseLLHook(int code, WPARAM wParam, LPARAM lParam) } } - return CallNextHookEx(g_mouseLL, code, wParam, lParam); + return CallNextHookEx(g_hkMouse, code, wParam, lParam); } -EHookResult +bool MSWindowsHook::install() { - assert(g_getMessage == NULL || g_screenSaver); - - // must be initialized - if (g_threadID == 0) { - return kHOOK_FAILED; - } - // discard old dead keys g_deadVirtKey = 0; g_deadLParam = 0; @@ -633,68 +536,34 @@ MSWindowsHook::install() // reset fake input flag g_fakeServerInput = false; - // install low-level hooks. we require that they both get installed. - g_mouseLL = SetWindowsHookEx(WH_MOUSE_LL, - &mouseLLHook, - NULL, - 0); -#if !NO_GRAB_KEYBOARD - g_keyboardLL = SetWindowsHookEx(WH_KEYBOARD_LL, - &keyboardLLHook, - NULL, - 0); - if (g_mouseLL == NULL || g_keyboardLL == NULL) { - if (g_keyboardLL != NULL) { - UnhookWindowsHookEx(g_keyboardLL); - g_keyboardLL = NULL; - } - if (g_mouseLL != NULL) { - UnhookWindowsHookEx(g_mouseLL); - g_mouseLL = NULL; - } +#if NO_GRAB_KEYBOARD + // we only need the mouse hook + if (!g_hkMouse.set(WH_MOUSE_LL, &mouseLLHook, NULL, 0)) + return false; +#else + // we need both hooks. if either fails, discard the other + if (!g_hkMouse.set(WH_MOUSE_LL, &mouseLLHook, NULL, 0) || + !g_hkKeyboard.set(WH_KEYBOARD_LL, &keyboardLLHook, NULL, 0)) { + g_hkMouse.unset(); + g_hkKeyboard.unset(); + return false; } #endif - // check that we got all the hooks we wanted - if ((g_mouseLL == NULL) -#if !NO_GRAB_KEYBOARD - || (g_keyboardLL == NULL) -#endif - ) { - uninstall(); - return kHOOK_FAILED; - } - - if (g_keyboardLL != NULL || g_mouseLL != NULL) { - g_hookThread = GetCurrentThreadId(); - return kHOOK_OKAY_LL; - } - - return kHOOK_OKAY; + return true; } -int +void MSWindowsHook::uninstall() { // discard old dead keys g_deadVirtKey = 0; g_deadLParam = 0; - // uninstall hooks - if (g_keyboardLL != NULL) { - UnhookWindowsHookEx(g_keyboardLL); - g_keyboardLL = NULL; - } - if (g_mouseLL != NULL) { - UnhookWindowsHookEx(g_mouseLL); - g_mouseLL = NULL; - } - if (g_getMessage != NULL && !g_screenSaver) { - UnhookWindowsHookEx(g_getMessage); - g_getMessage = NULL; - } + g_hkMouse.unset(); + g_hkKeyboard.unset(); - return 1; + uninstallScreenSaver(); } static @@ -702,53 +571,29 @@ LRESULT CALLBACK getMessageHook(int code, WPARAM wParam, LPARAM lParam) { if (code >= 0) { - if (g_screenSaver) { - MSG* msg = reinterpret_cast(lParam); - if (msg->message == WM_SYSCOMMAND && - msg->wParam == SC_SCREENSAVE) { - // broadcast screen saver started message - PostThreadMessage(g_threadID, - BARRIER_MSG_SCREEN_SAVER, TRUE, 0); - } + MSG* msg = reinterpret_cast(lParam); + if (msg->message == WM_SYSCOMMAND && + msg->wParam == SC_SCREENSAVE) { + // broadcast screen saver started message + PostThreadMessage(g_threadID, + BARRIER_MSG_SCREEN_SAVER, TRUE, 0); } } - return CallNextHookEx(g_getMessage, code, wParam, lParam); + return CallNextHookEx(g_hkMessage, code, wParam, lParam); } -int +bool MSWindowsHook::installScreenSaver() { - // must be initialized - if (g_threadID == 0) { - return 0; - } - - // generate screen saver messages - g_screenSaver = true; - // install hook unless it's already installed - if (g_getMessage == NULL) { - g_getMessage = SetWindowsHookEx(WH_GETMESSAGE, - &getMessageHook, - NULL, - 0); - } - - return (g_getMessage != NULL) ? 1 : 0; + if (g_hkMessage.is_set()) + return true; + return g_hkMessage.set(WH_GETMESSAGE, &getMessageHook, NULL, 0); } -int +void MSWindowsHook::uninstallScreenSaver() { - // uninstall hook unless the mouse wheel hook is installed - if (g_getMessage != NULL) { - UnhookWindowsHookEx(g_getMessage); - g_getMessage = NULL; - } - - // screen saver hook is no longer installed - g_screenSaver = false; - - return 1; + g_hkMessage.unset(); } \ No newline at end of file diff --git a/src/lib/platform/MSWindowsHook.h b/src/lib/platform/MSWindowsHook.h index ba551c7f..7b2121c4 100644 --- a/src/lib/platform/MSWindowsHook.h +++ b/src/lib/platform/MSWindowsHook.h @@ -28,18 +28,12 @@ class MSWindowsHook { public: - MSWindowsHook(); - virtual ~MSWindowsHook(); - - void loadLibrary(); - int init(DWORD threadID); - int cleanup(); void setSides(UInt32 sides); void setZone(SInt32 x, SInt32 y, SInt32 w, SInt32 h, SInt32 jumpZoneSize); void setMode(EHookMode mode); - static EHookResult install(); - static int uninstall(); - static int installScreenSaver(); - static int uninstallScreenSaver(); + static bool install(); + static void uninstall(); + static bool installScreenSaver(); + static void uninstallScreenSaver(); }; diff --git a/src/lib/platform/MSWindowsHookResource.cpp b/src/lib/platform/MSWindowsHookResource.cpp new file mode 100644 index 00000000..ced5ff12 --- /dev/null +++ b/src/lib/platform/MSWindowsHookResource.cpp @@ -0,0 +1,33 @@ +#include "MSWindowsHookResource.h" + +WindowsHookResource::WindowsHookResource() : + _hook(NULL) +{ +} + +WindowsHookResource::~WindowsHookResource() +{ + unset(); +} + +bool WindowsHookResource::set(int idHook, HOOKPROC lpfn, HINSTANCE hmod, DWORD dwThreadId) +{ + if (is_set()) + return false; + _hook = SetWindowsHookEx(idHook, lpfn, hmod, dwThreadId); + return is_set(); +} + +bool WindowsHookResource::unset() +{ + if (is_set()) { + if (UnhookWindowsHookEx(_hook) == 0) { + return false; + } + _hook = NULL; + } + return true; +} + +bool WindowsHookResource::is_set() const { return _hook != NULL; } +WindowsHookResource::operator HHOOK() const { return _hook; } \ No newline at end of file diff --git a/src/lib/platform/MSWindowsHookResource.h b/src/lib/platform/MSWindowsHookResource.h new file mode 100644 index 00000000..b66c4b8c --- /dev/null +++ b/src/lib/platform/MSWindowsHookResource.h @@ -0,0 +1,20 @@ +#pragma once + +#define WIN32_LEAN_AND_MEAN +#include + +class WindowsHookResource +{ +public: + explicit WindowsHookResource(); + ~WindowsHookResource(); + + bool set(int idHook, HOOKPROC lpfn, HINSTANCE hmod, DWORD dwThreadId); + bool unset(); + + bool is_set() const; + operator HHOOK() const; + +private: + HHOOK _hook; +}; \ No newline at end of file diff --git a/src/lib/platform/MSWindowsScreen.cpp b/src/lib/platform/MSWindowsScreen.cpp index 62c6d620..5246f963 100644 --- a/src/lib/platform/MSWindowsScreen.cpp +++ b/src/lib/platform/MSWindowsScreen.cpp @@ -129,10 +129,6 @@ MSWindowsScreen::MSWindowsScreen( s_screen = this; try { - if (m_isPrimary && !m_noHooks) { - m_hook.loadLibrary(); - } - m_screensaver = new MSWindowsScreenSaver(); m_desks = new MSWindowsDesks( m_isPrimary, diff --git a/src/lib/platform/synwinhk.h b/src/lib/platform/synwinhk.h index 57bb9c65..4b2d8e3f 100644 --- a/src/lib/platform/synwinhk.h +++ b/src/lib/platform/synwinhk.h @@ -48,12 +48,6 @@ extern "C" { -enum EHookResult { - kHOOK_FAILED, - kHOOK_OKAY, - kHOOK_OKAY_LL -}; - enum EHookMode { kHOOK_DISABLE, kHOOK_WATCH_JUMP_ZONE,