From faec8a2f84357c05e8ae051c594043e48c47c16b Mon Sep 17 00:00:00 2001 From: walker0643 <> Date: Sat, 3 Feb 2018 16:32:41 -0500 Subject: [PATCH] implement "Immune Keys" which are keys that are ignored by server-to-client key-forwarding. this feature is only implemented for servers running on windows machines. --- src/lib/platform/ImmuneKeysReader.cpp | 53 +++++++++++++++++++++++++++ src/lib/platform/ImmuneKeysReader.h | 34 +++++++++++++++++ src/lib/platform/MSWindowsDesks.cpp | 22 +++++++++++ src/lib/platform/MSWindowsDesks.h | 1 + src/lib/synwinhk/synwinhk.cpp | 39 ++++++++++++++++++++ src/lib/synwinhk/synwinhk.h | 4 ++ 6 files changed, 153 insertions(+) create mode 100644 src/lib/platform/ImmuneKeysReader.cpp create mode 100644 src/lib/platform/ImmuneKeysReader.h diff --git a/src/lib/platform/ImmuneKeysReader.cpp b/src/lib/platform/ImmuneKeysReader.cpp new file mode 100644 index 00000000..72baed3c --- /dev/null +++ b/src/lib/platform/ImmuneKeysReader.cpp @@ -0,0 +1,53 @@ +/* +* barrier -- mouse and keyboard sharing utility +* Copyright (C) 2018 Deuauche Open Source Group +* +* This package is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* found in the file LICENSE that should have accompanied this file. +* +* This package is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include "ImmuneKeysReader.h" + +#include + +const std::size_t AllocatedLineSize = 1024; +const char CommentChar = '#'; + +static void add_key(const char * const buffer, std::vector &keys) +{ + const char *first; + // skip spaces. ignore blank lines and comment lines + for (first = buffer; *first == ' '; ++first); + if (*first != 0 && *first != CommentChar) + keys.emplace_back(std::stoul(first, 0, 0)); +} + +/*static*/ bool ImmuneKeysReader::get_list(const char * const path, std::vector &keys, std::string &badline) +{ + // default values for return params + keys.clear(); + badline.clear(); + std::ifstream stream(path, std::ios::in); + if (stream.is_open()) { + // size includes the null-terminator + char buffer[AllocatedLineSize]; + while (stream.getline(&buffer[0], AllocatedLineSize)) { + try { + add_key(buffer, keys); + } catch (...) { + badline = buffer; + return false; + } + } + } + return true; +} \ No newline at end of file diff --git a/src/lib/platform/ImmuneKeysReader.h b/src/lib/platform/ImmuneKeysReader.h new file mode 100644 index 00000000..b46cbbe8 --- /dev/null +++ b/src/lib/platform/ImmuneKeysReader.h @@ -0,0 +1,34 @@ +/* +* barrier -- mouse and keyboard sharing utility +* Copyright (C) 2018 Deuauche Open Source Group +* +* This package is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* found in the file LICENSE that should have accompanied this file. +* +* This package is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#pragma once + +#include +#include + +// let's not import all of Windows just to get this typedef +typedef unsigned long DWORD; + +class ImmuneKeysReader +{ +public: + static bool get_list(const char * const path, std::vector &keys, std::string &badLine); + +private: + // static class + explicit ImmuneKeysReader() {} +}; diff --git a/src/lib/platform/MSWindowsDesks.cpp b/src/lib/platform/MSWindowsDesks.cpp index 5d4d90af..c5b427ac 100644 --- a/src/lib/platform/MSWindowsDesks.cpp +++ b/src/lib/platform/MSWindowsDesks.cpp @@ -20,6 +20,7 @@ #include "synwinhk/synwinhk.h" #include "platform/MSWindowsScreen.h" +#include "platform/ImmuneKeysReader.h" #include "barrier/IScreenSaver.h" #include "barrier/XScreen.h" #include "mt/Lock.h" @@ -88,6 +89,17 @@ // enable; #define BARRIER_MSG_FAKE_INPUT BARRIER_HOOK_LAST_MSG + 12 +static const std::string ImmuneKeysPath = ArchFileWindows().getProfileDirectory() + "\\ImmuneKeys.txt"; + +static std::vector immune_keys_list() +{ + std::vector keys; + std::string badLine; + if (!ImmuneKeysReader::get_list(ImmuneKeysPath.c_str(), keys, badLine)) + LOG((CLOG_ERR "Reading immune keys stopped at: %s", badLine.c_str())); + return keys; +} + // // MSWindowsDesks // @@ -114,6 +126,8 @@ MSWindowsDesks::MSWindowsDesks( m_events(events), m_stopOnDeskSwitch(stopOnDeskSwitch) { + LOG((CLOG_DEBUG "Immune Keys Path: %s", ImmuneKeysPath)); + if (hookLibrary != NULL) queryHookLibrary(hookLibrary); @@ -355,14 +369,17 @@ MSWindowsDesks::queryHookLibrary(HINSTANCE hookLibrary) if (m_isPrimary && !m_noHooks) { m_install = (InstallFunc)GetProcAddress(hookLibrary, "install"); m_uninstall = (UninstallFunc)GetProcAddress(hookLibrary, "uninstall"); + m_setImmuneKeys = (SetImmuneKeysFunc)GetProcAddress(hookLibrary, "setImmuneKeys"); m_installScreensaver = (InstallScreenSaverFunc)GetProcAddress( hookLibrary, "installScreenSaver"); m_uninstallScreensaver = (UninstallScreenSaverFunc)GetProcAddress( hookLibrary, "uninstallScreenSaver"); + if (m_install == NULL || m_uninstall == NULL || + m_setImmuneKeys == NULL || m_installScreensaver == NULL || m_uninstallScreensaver == NULL) { LOG((CLOG_ERR "Invalid hook library")); @@ -372,6 +389,7 @@ MSWindowsDesks::queryHookLibrary(HINSTANCE hookLibrary) else { m_install = NULL; m_uninstall = NULL; + m_setImmuneKeys = NULL; m_installScreensaver = NULL; m_uninstallScreensaver = NULL; } @@ -696,6 +714,10 @@ MSWindowsDesks::deskThread(void* vdesk) m_uninstallScreensaver(); m_installScreensaver(); } + // populate immune keys list in the DLL's shared memory + // before the hooks are activated + auto list = immune_keys_list(); + m_setImmuneKeys(list.data(), list.size()); switch (m_install()) { case kHOOK_FAILED: // we won't work on this desk diff --git a/src/lib/platform/MSWindowsDesks.h b/src/lib/platform/MSWindowsDesks.h index 37240f8a..6fde3537 100644 --- a/src/lib/platform/MSWindowsDesks.h +++ b/src/lib/platform/MSWindowsDesks.h @@ -286,6 +286,7 @@ private: // hook library stuff InstallFunc m_install; UninstallFunc m_uninstall; + SetImmuneKeysFunc m_setImmuneKeys; InstallScreenSaverFunc m_installScreensaver; UninstallScreenSaverFunc diff --git a/src/lib/synwinhk/synwinhk.cpp b/src/lib/synwinhk/synwinhk.cpp index f45cec31..6d7123c5 100644 --- a/src/lib/synwinhk/synwinhk.cpp +++ b/src/lib/synwinhk/synwinhk.cpp @@ -85,6 +85,18 @@ typedef struct tagMOUSEHOOKSTRUCTWin2000 { #define XBUTTON2 0x0002 #endif +// because all of our global data is shared between processes, +// allocating shared data on-the-fly is tricky. therefore let's +// store all of our immune keys in a pre-allocated array. the +// downside here is that we have to pick a maximum number of +// immune keys to store. who would ever want barrier to ignore +// more than 32 keys on their keyboard?? +struct ImmuneKeys +{ + static const std::size_t MaxKeys = 32; + DWORD list[MaxKeys]; + std::size_t count; +}; // // globals @@ -121,6 +133,7 @@ static BYTE g_deadKeyState[256] = { 0 }; static BYTE g_keyState[256] = { 0 }; static DWORD g_hookThread = 0; static bool g_fakeInput = false; +static ImmuneKeys g_immuneKeys{ {0}, 0 }; #if defined(_MSC_VER) #pragma data_seg() @@ -445,10 +458,23 @@ doKeyboardHookHandler(WPARAM wParam, LPARAM lParam) return false; } +inline static +bool is_immune_key(DWORD target) +{ + for (std::size_t idx = 0; idx < g_immuneKeys.count; ++idx) { + if (g_immuneKeys.list[idx] == target) + return true; + } + return false; +} + static bool keyboardHookHandler(WPARAM wParam, LPARAM lParam) { + // allow all immune keys to pass without filtering + if (is_immune_key(static_cast(wParam))) + return false; return doKeyboardHookHandler(wParam, lParam); } #endif @@ -1123,4 +1149,17 @@ setMode(EHookMode mode) g_mode = mode; } +// do not call this while the hooks are active! +void +setImmuneKeys(const DWORD *list, std::size_t size) +{ + if (size > ImmuneKeys::MaxKeys) + size = ImmuneKeys::MaxKeys; + g_immuneKeys.count = size; + if (size > 0) { + for (std::size_t idx = 0; idx < size; ++idx) + g_immuneKeys.list[idx] = list[idx]; + } +} + } diff --git a/src/lib/synwinhk/synwinhk.h b/src/lib/synwinhk/synwinhk.h index 45f34daf..32d1068c 100644 --- a/src/lib/synwinhk/synwinhk.h +++ b/src/lib/synwinhk/synwinhk.h @@ -76,6 +76,7 @@ typedef int (*UninstallScreenSaverFunc)(void); typedef void (*SetSidesFunc)(UInt32); typedef void (*SetZoneFunc)(SInt32, SInt32, SInt32, SInt32, SInt32); typedef void (*SetModeFunc)(int); +typedef void (*SetImmuneKeysFunc)(const DWORD*, std::size_t); CBARRIERHOOK_API int init(DWORD); CBARRIERHOOK_API int cleanup(void); @@ -88,4 +89,7 @@ CBARRIERHOOK_API void setZone(SInt32 x, SInt32 y, SInt32 w, SInt32 h, SInt32 jumpZoneSize); CBARRIERHOOK_API void setMode(EHookMode mode); +// do not call setImmuneKeys() while the hooks are active! +CBARRIERHOOK_API void setImmuneKeys(const DWORD *list, std::size_t size); + }