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);
+
}