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.
This commit is contained in:
walker0643 2018-02-03 16:32:41 -05:00
parent b64512d65f
commit faec8a2f84
6 changed files with 153 additions and 0 deletions

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include "ImmuneKeysReader.h"
#include <fstream>
const std::size_t AllocatedLineSize = 1024;
const char CommentChar = '#';
static void add_key(const char * const buffer, std::vector<DWORD> &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<DWORD> &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;
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vector>
#include <string>
// 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<DWORD> &keys, std::string &badLine);
private:
// static class
explicit ImmuneKeysReader() {}
};

View File

@ -20,6 +20,7 @@
#include "synwinhk/synwinhk.h" #include "synwinhk/synwinhk.h"
#include "platform/MSWindowsScreen.h" #include "platform/MSWindowsScreen.h"
#include "platform/ImmuneKeysReader.h"
#include "barrier/IScreenSaver.h" #include "barrier/IScreenSaver.h"
#include "barrier/XScreen.h" #include "barrier/XScreen.h"
#include "mt/Lock.h" #include "mt/Lock.h"
@ -88,6 +89,17 @@
// enable; <unused> // enable; <unused>
#define BARRIER_MSG_FAKE_INPUT BARRIER_HOOK_LAST_MSG + 12 #define BARRIER_MSG_FAKE_INPUT BARRIER_HOOK_LAST_MSG + 12
static const std::string ImmuneKeysPath = ArchFileWindows().getProfileDirectory() + "\\ImmuneKeys.txt";
static std::vector<DWORD> immune_keys_list()
{
std::vector<DWORD> 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 // MSWindowsDesks
// //
@ -114,6 +126,8 @@ MSWindowsDesks::MSWindowsDesks(
m_events(events), m_events(events),
m_stopOnDeskSwitch(stopOnDeskSwitch) m_stopOnDeskSwitch(stopOnDeskSwitch)
{ {
LOG((CLOG_DEBUG "Immune Keys Path: %s", ImmuneKeysPath));
if (hookLibrary != NULL) if (hookLibrary != NULL)
queryHookLibrary(hookLibrary); queryHookLibrary(hookLibrary);
@ -355,14 +369,17 @@ MSWindowsDesks::queryHookLibrary(HINSTANCE hookLibrary)
if (m_isPrimary && !m_noHooks) { if (m_isPrimary && !m_noHooks) {
m_install = (InstallFunc)GetProcAddress(hookLibrary, "install"); m_install = (InstallFunc)GetProcAddress(hookLibrary, "install");
m_uninstall = (UninstallFunc)GetProcAddress(hookLibrary, "uninstall"); m_uninstall = (UninstallFunc)GetProcAddress(hookLibrary, "uninstall");
m_setImmuneKeys = (SetImmuneKeysFunc)GetProcAddress(hookLibrary, "setImmuneKeys");
m_installScreensaver = m_installScreensaver =
(InstallScreenSaverFunc)GetProcAddress( (InstallScreenSaverFunc)GetProcAddress(
hookLibrary, "installScreenSaver"); hookLibrary, "installScreenSaver");
m_uninstallScreensaver = m_uninstallScreensaver =
(UninstallScreenSaverFunc)GetProcAddress( (UninstallScreenSaverFunc)GetProcAddress(
hookLibrary, "uninstallScreenSaver"); hookLibrary, "uninstallScreenSaver");
if (m_install == NULL || if (m_install == NULL ||
m_uninstall == NULL || m_uninstall == NULL ||
m_setImmuneKeys == NULL ||
m_installScreensaver == NULL || m_installScreensaver == NULL ||
m_uninstallScreensaver == NULL) { m_uninstallScreensaver == NULL) {
LOG((CLOG_ERR "Invalid hook library")); LOG((CLOG_ERR "Invalid hook library"));
@ -372,6 +389,7 @@ MSWindowsDesks::queryHookLibrary(HINSTANCE hookLibrary)
else { else {
m_install = NULL; m_install = NULL;
m_uninstall = NULL; m_uninstall = NULL;
m_setImmuneKeys = NULL;
m_installScreensaver = NULL; m_installScreensaver = NULL;
m_uninstallScreensaver = NULL; m_uninstallScreensaver = NULL;
} }
@ -696,6 +714,10 @@ MSWindowsDesks::deskThread(void* vdesk)
m_uninstallScreensaver(); m_uninstallScreensaver();
m_installScreensaver(); 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()) { switch (m_install()) {
case kHOOK_FAILED: case kHOOK_FAILED:
// we won't work on this desk // we won't work on this desk

View File

@ -286,6 +286,7 @@ private:
// hook library stuff // hook library stuff
InstallFunc m_install; InstallFunc m_install;
UninstallFunc m_uninstall; UninstallFunc m_uninstall;
SetImmuneKeysFunc m_setImmuneKeys;
InstallScreenSaverFunc InstallScreenSaverFunc
m_installScreensaver; m_installScreensaver;
UninstallScreenSaverFunc UninstallScreenSaverFunc

View File

@ -85,6 +85,18 @@ typedef struct tagMOUSEHOOKSTRUCTWin2000 {
#define XBUTTON2 0x0002 #define XBUTTON2 0x0002
#endif #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 // globals
@ -121,6 +133,7 @@ static BYTE g_deadKeyState[256] = { 0 };
static BYTE g_keyState[256] = { 0 }; static BYTE g_keyState[256] = { 0 };
static DWORD g_hookThread = 0; static DWORD g_hookThread = 0;
static bool g_fakeInput = false; static bool g_fakeInput = false;
static ImmuneKeys g_immuneKeys{ {0}, 0 };
#if defined(_MSC_VER) #if defined(_MSC_VER)
#pragma data_seg() #pragma data_seg()
@ -445,10 +458,23 @@ doKeyboardHookHandler(WPARAM wParam, LPARAM lParam)
return false; 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 static
bool bool
keyboardHookHandler(WPARAM wParam, LPARAM lParam) keyboardHookHandler(WPARAM wParam, LPARAM lParam)
{ {
// allow all immune keys to pass without filtering
if (is_immune_key(static_cast<DWORD>(wParam)))
return false;
return doKeyboardHookHandler(wParam, lParam); return doKeyboardHookHandler(wParam, lParam);
} }
#endif #endif
@ -1123,4 +1149,17 @@ setMode(EHookMode mode)
g_mode = 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];
}
}
} }

View File

@ -76,6 +76,7 @@ typedef int (*UninstallScreenSaverFunc)(void);
typedef void (*SetSidesFunc)(UInt32); typedef void (*SetSidesFunc)(UInt32);
typedef void (*SetZoneFunc)(SInt32, SInt32, SInt32, SInt32, SInt32); typedef void (*SetZoneFunc)(SInt32, SInt32, SInt32, SInt32, SInt32);
typedef void (*SetModeFunc)(int); typedef void (*SetModeFunc)(int);
typedef void (*SetImmuneKeysFunc)(const DWORD*, std::size_t);
CBARRIERHOOK_API int init(DWORD); CBARRIERHOOK_API int init(DWORD);
CBARRIERHOOK_API int cleanup(void); CBARRIERHOOK_API int cleanup(void);
@ -88,4 +89,7 @@ CBARRIERHOOK_API void setZone(SInt32 x, SInt32 y, SInt32 w, SInt32 h,
SInt32 jumpZoneSize); SInt32 jumpZoneSize);
CBARRIERHOOK_API void setMode(EHookMode mode); 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);
} }