diff --git a/src/lib/platform/CMSWindowsHookLibraryLoader.cpp b/src/lib/platform/CMSWindowsHookLibraryLoader.cpp
new file mode 100644
index 00000000..33e8ee79
--- /dev/null
+++ b/src/lib/platform/CMSWindowsHookLibraryLoader.cpp
@@ -0,0 +1,68 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2011 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
+ *
+ * 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 COPYING 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 "CMSWindowsHookLibraryLoader.h"
+#include "XScreen.h"
+#include "CLog.h"
+
+CMSWindowsHookLibraryLoader::CMSWindowsHookLibraryLoader() :
+ m_init(NULL),
+ m_cleanup(NULL),
+ m_setSides(NULL),
+ m_setZone(NULL),
+ m_setMode(NULL)
+{
+}
+
+CMSWindowsHookLibraryLoader::~CMSWindowsHookLibraryLoader()
+{
+ // TODO: take ownership of m_ and delete them.
+}
+
+HINSTANCE
+CMSWindowsHookLibraryLoader::openHookLibrary(const char* name)
+{
+ // load the hook library
+ HINSTANCE hookLibrary = LoadLibrary(name);
+ if (hookLibrary == NULL) {
+ LOG((CLOG_ERR "Failed to load hook library; %s.dll is missing", name));
+ throw XScreenOpenFailure();
+ }
+
+ // look up functions
+ m_setSides = (SetSidesFunc)GetProcAddress(hookLibrary, "setSides");
+ m_setZone = (SetZoneFunc)GetProcAddress(hookLibrary, "setZone");
+ m_setMode = (SetModeFunc)GetProcAddress(hookLibrary, "setMode");
+ m_init = (InitFunc)GetProcAddress(hookLibrary, "init");
+ m_cleanup = (CleanupFunc)GetProcAddress(hookLibrary, "cleanup");
+ if (m_setSides == NULL ||
+ m_setZone == NULL ||
+ m_setMode == NULL ||
+ m_init == NULL ||
+ m_cleanup == NULL) {
+ LOG((CLOG_ERR "Invalid hook library; use a newer %s.dll", name));
+ throw XScreenOpenFailure();
+ }
+
+ // initialize hook library
+ if (m_init(GetCurrentThreadId()) == 0) {
+ LOG((CLOG_ERR "Cannot initialize hook library; is synergy already running?"));
+ throw XScreenOpenFailure();
+ }
+
+ return hookLibrary;
+}
\ No newline at end of file
diff --git a/src/lib/platform/CMSWindowsHookLibraryLoader.h b/src/lib/platform/CMSWindowsHookLibraryLoader.h
new file mode 100644
index 00000000..e37fd6e0
--- /dev/null
+++ b/src/lib/platform/CMSWindowsHookLibraryLoader.h
@@ -0,0 +1,45 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2011 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
+ *
+ * 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 COPYING 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 .
+ */
+
+#ifndef CMSWINDOWSHOOKLIBRARYLOADER_H
+#define CMSWINDOWSHOOKLIBRARYLOADER_H
+
+#define WIN32_LEAN_AND_MEAN
+#include
+#include "CSynergyHook.h"
+
+//! Loads Windows hook DLLs.
+class CMSWindowsHookLibraryLoader
+{
+public:
+ CMSWindowsHookLibraryLoader();
+ virtual ~CMSWindowsHookLibraryLoader();
+
+ HINSTANCE openHookLibrary(const char* name);
+
+ // TODO: either make these private or expose properly
+ InitFunc m_init;
+ CleanupFunc m_cleanup;
+ SetSidesFunc m_setSides;
+ SetZoneFunc m_setZone;
+ SetModeFunc m_setMode;
+
+private:
+ HINSTANCE m_hookLibrary;
+};
+
+#endif
\ No newline at end of file
diff --git a/src/lib/platform/CMSWindowsKeyState.cpp b/src/lib/platform/CMSWindowsKeyState.cpp
index b615a071..13b62d7d 100644
--- a/src/lib/platform/CMSWindowsKeyState.cpp
+++ b/src/lib/platform/CMSWindowsKeyState.cpp
@@ -574,8 +574,8 @@ static const CWin32Modifiers s_modifiers[] =
{ VK_RWIN, KeyModifierSuper }
};
-CMSWindowsKeyState::CMSWindowsKeyState(CMSWindowsDesks* desks,
- void* eventTarget) :
+CMSWindowsKeyState::CMSWindowsKeyState(
+ CMSWindowsDesks* desks, void* eventTarget) :
m_is95Family(CArchMiscWindows::isWindows95Family()),
m_eventTarget(eventTarget),
m_desks(desks),
@@ -584,11 +584,27 @@ CMSWindowsKeyState::CMSWindowsKeyState(CMSWindowsDesks* desks,
m_lastDown(0),
m_useSavedModifiers(false),
m_savedModifiers(0),
- m_originalSavedModifiers(0)
+ m_originalSavedModifiers(0),
+ m_eventQueue(*EVENTQUEUE)
{
- // look up symbol that's available on winNT family but not win95
- HMODULE userModule = GetModuleHandle("user32.dll");
- m_ToUnicodeEx = (ToUnicodeEx_t)GetProcAddress(userModule, "ToUnicodeEx");
+ init();
+}
+
+CMSWindowsKeyState::CMSWindowsKeyState(
+ CMSWindowsDesks* desks, void* eventTarget, IEventQueue& eventQueue, CKeyMap& keyMap) :
+ CKeyState(eventQueue, keyMap),
+ m_is95Family(CArchMiscWindows::isWindows95Family()),
+ m_eventTarget(eventTarget),
+ m_desks(desks),
+ m_keyLayout(GetKeyboardLayout(0)),
+ m_fixTimer(NULL),
+ m_lastDown(0),
+ m_useSavedModifiers(false),
+ m_savedModifiers(0),
+ m_originalSavedModifiers(0),
+ m_eventQueue(eventQueue)
+{
+ init();
}
CMSWindowsKeyState::~CMSWindowsKeyState()
@@ -596,12 +612,20 @@ CMSWindowsKeyState::~CMSWindowsKeyState()
disable();
}
+void
+CMSWindowsKeyState::init()
+{
+ // look up symbol that's available on winNT family but not win95
+ HMODULE userModule = GetModuleHandle("user32.dll");
+ m_ToUnicodeEx = (ToUnicodeEx_t)GetProcAddress(userModule, "ToUnicodeEx");
+}
+
void
CMSWindowsKeyState::disable()
{
if (m_fixTimer != NULL) {
- EVENTQUEUE->removeHandler(CEvent::kTimer, m_fixTimer);
- EVENTQUEUE->deleteTimer(m_fixTimer);
+ getEventQueue().removeHandler(CEvent::kTimer, m_fixTimer);
+ getEventQueue().deleteTimer(m_fixTimer);
m_fixTimer = NULL;
}
m_lastDown = 0;
@@ -773,11 +797,11 @@ CMSWindowsKeyState::fakeKeyDown(KeyID id, KeyModifierMask mask,
CKeyState::fakeKeyDown(id, mask, button);
}
-void
+bool
CMSWindowsKeyState::fakeKeyRepeat(KeyID id, KeyModifierMask mask,
SInt32 count, KeyButton button)
{
- CKeyState::fakeKeyRepeat(id, mask, count, button);
+ return CKeyState::fakeKeyRepeat(id, mask, count, button);
}
bool
diff --git a/src/lib/platform/CMSWindowsKeyState.h b/src/lib/platform/CMSWindowsKeyState.h
index 5196cf57..ee57474d 100644
--- a/src/lib/platform/CMSWindowsKeyState.h
+++ b/src/lib/platform/CMSWindowsKeyState.h
@@ -27,6 +27,7 @@
class CEvent;
class CEventQueueTimer;
class CMSWindowsDesks;
+class IEventQueue;
//! Microsoft Windows key mapper
/*!
@@ -35,6 +36,7 @@ This class maps KeyIDs to keystrokes.
class CMSWindowsKeyState : public CKeyState {
public:
CMSWindowsKeyState(CMSWindowsDesks* desks, void* eventTarget);
+ CMSWindowsKeyState(CMSWindowsDesks* desks, void* eventTarget, IEventQueue& eventQueue, CKeyMap& keyMap);
virtual ~CMSWindowsKeyState();
//! @name manipulators
@@ -126,7 +128,7 @@ public:
// IKeyState overrides
virtual void fakeKeyDown(KeyID id, KeyModifierMask mask,
KeyButton button);
- virtual void fakeKeyRepeat(KeyID id, KeyModifierMask mask,
+ virtual bool fakeKeyRepeat(KeyID id, KeyModifierMask mask,
SInt32 count, KeyButton button);
virtual bool fakeCtrlAltDel();
virtual KeyModifierMask
@@ -142,6 +144,12 @@ public:
KeyID key, KeyModifierMask mask,
SInt32 count, KeyButton button);
+ // Unit test accessors
+ KeyButton getLastDown() const { return m_lastDown; }
+ void setLastDown(KeyButton value) { m_lastDown = value; }
+ KeyModifierMask getSavedModifiers() const { return m_savedModifiers; }
+ void setSavedModifiers(KeyModifierMask value) { m_savedModifiers = value; }
+
protected:
// CKeyState overrides
virtual void getKeyMap(CKeyMap& keyMap);
@@ -167,6 +175,8 @@ private:
void addKeyEntry(CKeyMap& keyMap, CKeyMap::KeyItem& item);
+ void init();
+
private:
// not implemented
CMSWindowsKeyState(const CMSWindowsKeyState&);
@@ -184,6 +194,7 @@ private:
UINT m_buttonToNumpadVK[512];
KeyButton m_virtualKeyToButton[256];
KeyToVKMap m_keyToVKMap;
+ IEventQueue& m_eventQueue;
// the timer used to check for fixing key state
CEventQueueTimer* m_fixTimer;
diff --git a/src/lib/platform/CMSWindowsScreen.cpp b/src/lib/platform/CMSWindowsScreen.cpp
index 4005b157..b491d267 100644
--- a/src/lib/platform/CMSWindowsScreen.cpp
+++ b/src/lib/platform/CMSWindowsScreen.cpp
@@ -104,11 +104,6 @@ CMSWindowsScreen::CMSWindowsScreen(bool isPrimary, bool noHooks) :
m_ownClipboard(false),
m_desks(NULL),
m_hookLibrary(NULL),
- m_init(NULL),
- m_cleanup(NULL),
- m_setSides(NULL),
- m_setZone(NULL),
- m_setMode(NULL),
m_keyState(NULL),
m_hasMouse(GetSystemMetrics(SM_MOUSEPRESENT) != 0),
m_showingMouse(false)
@@ -205,10 +200,10 @@ CMSWindowsScreen::enable()
if (m_isPrimary) {
// set jump zones
- m_setZone(m_x, m_y, m_w, m_h, getJumpZoneSize());
+ m_hookLibraryLoader.m_setZone(m_x, m_y, m_w, m_h, getJumpZoneSize());
// watch jump zones
- m_setMode(kHOOK_WATCH_JUMP_ZONE);
+ m_hookLibraryLoader.m_setMode(kHOOK_WATCH_JUMP_ZONE);
}
else {
// prevent the system from entering power saving modes. if
@@ -226,7 +221,7 @@ CMSWindowsScreen::disable()
if (m_isPrimary) {
// disable hooks
- m_setMode(kHOOK_DISABLE);
+ m_hookLibraryLoader.m_setMode(kHOOK_DISABLE);
// enable special key sequences on win95 family
enableSpecialKeys(true);
@@ -264,7 +259,7 @@ CMSWindowsScreen::enter()
enableSpecialKeys(true);
// watch jump zones
- m_setMode(kHOOK_WATCH_JUMP_ZONE);
+ m_hookLibraryLoader.m_setMode(kHOOK_WATCH_JUMP_ZONE);
// all messages prior to now are invalid
nextMark();
@@ -317,7 +312,7 @@ CMSWindowsScreen::leave()
m_keyState->saveModifiers();
// capture events
- m_setMode(kHOOK_RELAY_EVENTS);
+ m_hookLibraryLoader.m_setMode(kHOOK_RELAY_EVENTS);
}
// now off screen
@@ -471,7 +466,7 @@ CMSWindowsScreen::reconfigure(UInt32 activeSides)
assert(m_isPrimary);
LOG((CLOG_DEBUG "active sides: %x", activeSides));
- m_setSides(activeSides);
+ m_hookLibraryLoader.m_setSides(activeSides);
}
void
@@ -697,19 +692,21 @@ CMSWindowsScreen::fakeKeyDown(KeyID id, KeyModifierMask mask,
updateForceShowCursor();
}
-void
+bool
CMSWindowsScreen::fakeKeyRepeat(KeyID id, KeyModifierMask mask,
SInt32 count, KeyButton button)
{
- CPlatformScreen::fakeKeyRepeat(id, mask, count, button);
+ bool result = CPlatformScreen::fakeKeyRepeat(id, mask, count, button);
updateForceShowCursor();
+ return result;
}
-void
+bool
CMSWindowsScreen::fakeKeyUp(KeyButton button)
{
- CPlatformScreen::fakeKeyUp(button);
+ bool result = CPlatformScreen::fakeKeyUp(button);
updateForceShowCursor();
+ return result;
}
void
@@ -722,42 +719,14 @@ CMSWindowsScreen::fakeAllKeysUp()
HINSTANCE
CMSWindowsScreen::openHookLibrary(const char* name)
{
- // load the hook library
- HINSTANCE hookLibrary = LoadLibrary(name);
- if (hookLibrary == NULL) {
- LOG((CLOG_ERR "Failed to load hook library; %s.dll is missing", name));
- throw XScreenOpenFailure();
- }
-
- // look up functions
- m_setSides = (SetSidesFunc)GetProcAddress(hookLibrary, "setSides");
- m_setZone = (SetZoneFunc)GetProcAddress(hookLibrary, "setZone");
- m_setMode = (SetModeFunc)GetProcAddress(hookLibrary, "setMode");
- m_init = (InitFunc)GetProcAddress(hookLibrary, "init");
- m_cleanup = (CleanupFunc)GetProcAddress(hookLibrary, "cleanup");
- if (m_setSides == NULL ||
- m_setZone == NULL ||
- m_setMode == NULL ||
- m_init == NULL ||
- m_cleanup == NULL) {
- LOG((CLOG_ERR "Invalid hook library; use a newer %s.dll", name));
- throw XScreenOpenFailure();
- }
-
- // initialize hook library
- if (m_init(GetCurrentThreadId()) == 0) {
- LOG((CLOG_ERR "Cannot initialize hook library; is synergy already running?"));
- throw XScreenOpenFailure();
- }
-
- return hookLibrary;
+ return m_hookLibraryLoader.openHookLibrary(name);
}
void
CMSWindowsScreen::closeHookLibrary(HINSTANCE hookLibrary) const
{
if (hookLibrary != NULL) {
- m_cleanup();
+ m_hookLibraryLoader.m_cleanup();
FreeLibrary(hookLibrary);
}
}
@@ -1427,7 +1396,7 @@ CMSWindowsScreen::onDisplayChange()
// tell hook about resize if on screen
else {
- m_setZone(m_x, m_y, m_w, m_h, getJumpZoneSize());
+ m_hookLibraryLoader.m_setZone(m_x, m_y, m_w, m_h, getJumpZoneSize());
}
}
diff --git a/src/lib/platform/CMSWindowsScreen.h b/src/lib/platform/CMSWindowsScreen.h
index 0af50d39..9809f9a1 100644
--- a/src/lib/platform/CMSWindowsScreen.h
+++ b/src/lib/platform/CMSWindowsScreen.h
@@ -25,6 +25,7 @@
#include "CString.h"
#define WIN32_LEAN_AND_MEAN
#include
+#include "CMSWindowsHookLibraryLoader.h"
class CEventQueueTimer;
class CMSWindowsDesks;
@@ -89,9 +90,9 @@ public:
virtual void updateKeys();
virtual void fakeKeyDown(KeyID id, KeyModifierMask mask,
KeyButton button);
- virtual void fakeKeyRepeat(KeyID id, KeyModifierMask mask,
+ virtual bool fakeKeyRepeat(KeyID id, KeyModifierMask mask,
SInt32 count, KeyButton button);
- virtual void fakeKeyUp(KeyButton button);
+ virtual bool fakeKeyUp(KeyButton button);
virtual void fakeAllKeysUp();
// IPlatformScreen overrides
@@ -274,11 +275,6 @@ private:
// hook library stuff
HINSTANCE m_hookLibrary;
- InitFunc m_init;
- CleanupFunc m_cleanup;
- SetSidesFunc m_setSides;
- SetZoneFunc m_setZone;
- SetModeFunc m_setMode;
// keyboard stuff
CMSWindowsKeyState* m_keyState;
@@ -308,6 +304,10 @@ private:
MOUSEKEYS m_mouseKeys;
MOUSEKEYS m_oldMouseKeys;
+ // loads synrgyhk.dll
+ CMSWindowsHookLibraryLoader
+ m_hookLibraryLoader;
+
static CMSWindowsScreen* s_screen;
// save last position of mouse to compute next delta movement
diff --git a/src/lib/platform/CMakeLists.txt b/src/lib/platform/CMakeLists.txt
index 8be5e3f2..f5bdd7af 100644
--- a/src/lib/platform/CMakeLists.txt
+++ b/src/lib/platform/CMakeLists.txt
@@ -29,6 +29,7 @@ if (WIN32)
CMSWindowsScreenSaver.h
CMSWindowsUtil.h
CMSWindowsRelauncher.h
+ CMSWindowsHookLibraryLoader.h
IMSWindowsClipboardFacade.h
)
@@ -48,6 +49,7 @@ if (WIN32)
CMSWindowsScreenSaver.cpp
CMSWindowsUtil.cpp
CMSWindowsRelauncher.cpp
+ CMSWindowsHookLibraryLoader.cpp
)
set(inc_hook
diff --git a/src/lib/platform/COSXKeyState.cpp b/src/lib/platform/COSXKeyState.cpp
index 2757b1ae..262357bf 100644
--- a/src/lib/platform/COSXKeyState.cpp
+++ b/src/lib/platform/COSXKeyState.cpp
@@ -121,6 +121,23 @@ static const CKeyEntry s_controlKeys[] = {
COSXKeyState::COSXKeyState() :
m_deadKeyState(0)
+{
+ init();
+}
+
+COSXKeyState::COSXKeyState(IEventQueue& eventQueue, CKeyMap& keyMap) :
+ CKeyState(eventQueue, keyMap),
+ m_deadKeyState(0)
+{
+ init();
+}
+
+COSXKeyState::~COSXKeyState()
+{
+}
+
+void
+COSXKeyState::init()
{
// initialize modifier key values
shiftPressed = false;
@@ -137,33 +154,31 @@ COSXKeyState::COSXKeyState() :
}
}
-COSXKeyState::~COSXKeyState()
-{
- // do nothing
-}
-
KeyModifierMask
COSXKeyState::mapModifiersFromOSX(UInt32 mask) const
{
-LOG((CLOG_DEBUG1 "mask: %04x", mask));
- // convert
+ LOG((CLOG_DEBUG1 "mask: %04x", mask));
+
+ // previously this used the kCGEventFlagMask* enums, which would
+ // not work, since GetCurrentKeyModifiers doesn't return a mask
+ // containing those values; instead *Key enums should be used.
KeyModifierMask outMask = 0;
- if ((mask & kCGEventFlagMaskShift) != 0) {
+ if ((mask & shiftKey) != 0) {
outMask |= KeyModifierShift;
}
- if ((mask & kCGEventFlagMaskControl) != 0) {
+ if ((mask & controlKey) != 0) {
outMask |= KeyModifierControl;
}
- if ((mask & kCGEventFlagMaskAlternate) != 0) {
+ if ((mask & cmdKey) != 0) {
outMask |= KeyModifierAlt;
}
- if ((mask & kCGEventFlagMaskCommand) != 0) {
+ if ((mask & optionKey) != 0) {
outMask |= KeyModifierSuper;
}
- if ((mask & kCGEventFlagMaskAlphaShift) != 0) {
+ if ((mask & alphaLock) != 0) {
outMask |= KeyModifierCapsLock;
}
- if ((mask & kCGEventFlagMaskNumericPad) != 0) {
+ if ((mask & s_osxNumLock) != 0) {
outMask |= KeyModifierNumLock;
}
diff --git a/src/lib/platform/COSXKeyState.h b/src/lib/platform/COSXKeyState.h
index 3c9f4275..0d90b1a0 100644
--- a/src/lib/platform/COSXKeyState.h
+++ b/src/lib/platform/COSXKeyState.h
@@ -39,6 +39,7 @@ public:
typedef std::vector CKeyIDs;
COSXKeyState();
+ COSXKeyState(IEventQueue& eventQueue, CKeyMap& keyMap);
virtual ~COSXKeyState();
//! @name modifiers
@@ -147,6 +148,8 @@ private:
// mapVirtualKeyToKeyButton.
static UInt32 mapKeyButtonToVirtualKey(KeyButton keyButton);
+ void init();
+
private:
class CKeyResource : public IInterface {
public:
diff --git a/src/lib/platform/CXWindowsKeyState.cpp b/src/lib/platform/CXWindowsKeyState.cpp
index d8b4eee7..2956f440 100644
--- a/src/lib/platform/CXWindowsKeyState.cpp
+++ b/src/lib/platform/CXWindowsKeyState.cpp
@@ -20,6 +20,8 @@
#include "CLog.h"
#include "CStringUtil.h"
#include "stdmap.h"
+#include
+#include
#if X_DISPLAY_MISSING
# error X11 is required to build synergy
#else
@@ -33,8 +35,36 @@
#endif
#endif
+static const size_t ModifiersFromXDefaultSize = 32;
+
CXWindowsKeyState::CXWindowsKeyState(Display* display, bool useXKB) :
- m_display(display)
+ m_display(display),
+ m_modifierFromX(ModifiersFromXDefaultSize)
+{
+ init(display, useXKB);
+}
+
+CXWindowsKeyState::CXWindowsKeyState(
+ Display* display, bool useXKB,
+ IEventQueue& eventQueue, CKeyMap& keyMap) :
+ CKeyState(eventQueue, keyMap),
+ m_display(display),
+ m_modifierFromX(ModifiersFromXDefaultSize)
+{
+ init(display, useXKB);
+}
+
+CXWindowsKeyState::~CXWindowsKeyState()
+{
+#if HAVE_XKB_EXTENSION
+ if (m_xkb != NULL) {
+ XkbFreeKeyboard(m_xkb, 0, True);
+ }
+#endif
+}
+
+void
+CXWindowsKeyState::init(Display* display, bool useXKB)
{
XGetKeyboardControl(m_display, &m_keyboardState);
#if HAVE_XKB_EXTENSION
@@ -49,19 +79,12 @@ CXWindowsKeyState::CXWindowsKeyState(Display* display, bool useXKB) :
setActiveGroup(kGroupPollAndSet);
}
-CXWindowsKeyState::~CXWindowsKeyState()
-{
-#if HAVE_XKB_EXTENSION
- if (m_xkb != NULL) {
- XkbFreeKeyboard(m_xkb, 0, True);
- }
-#endif
-}
-
void
CXWindowsKeyState::setActiveGroup(SInt32 group)
{
if (group == kGroupPollAndSet) {
+ // we need to set the group to -1 in order for pollActiveGroup() to
+ // actually poll for the group
m_group = -1;
m_group = pollActiveGroup();
}
@@ -83,11 +106,18 @@ CXWindowsKeyState::setAutoRepeat(const XKeyboardState& state)
KeyModifierMask
CXWindowsKeyState::mapModifiersFromX(unsigned int state) const
{
+ LOG((CLOG_DEBUG2 "mapping state: %i", state));
UInt32 offset = 8 * getGroupFromState(state);
KeyModifierMask mask = 0;
for (int i = 0; i < 8; ++i) {
if ((state & (1u << i)) != 0) {
- mask |= m_modifierFromX[offset + i];
+ LOG((CLOG_DEBUG2 "|= modifier: %i", offset + i));
+ if (offset + i >= m_modifierFromX.size()) {
+ LOG((CLOG_ERR "m_modifierFromX is too small (%d) for the "
+ "requested offset (%d)", m_modifierFromX.size(), offset+i));
+ } else {
+ mask |= m_modifierFromX[offset + i];
+ }
}
}
return mask;
@@ -140,9 +170,9 @@ CXWindowsKeyState::pollActiveModifiers() const
{
Window root = DefaultRootWindow(m_display), window;
int xRoot, yRoot, xWindow, yWindow;
- unsigned int state;
- if (!XQueryPointer(m_display, root, &root, &window,
- &xRoot, &yRoot, &xWindow, &yWindow, &state)) {
+ unsigned int state = 0;
+ if (XQueryPointer(m_display, root, &root, &window,
+ &xRoot, &yRoot, &xWindow, &yWindow, &state) == False) {
state = 0;
}
return mapModifiersFromX(state);
@@ -151,15 +181,15 @@ CXWindowsKeyState::pollActiveModifiers() const
SInt32
CXWindowsKeyState::pollActiveGroup() const
{
- if (m_group != -1) {
- assert(m_group >= 0);
+ // fixed condition where any group < -1 would have undetermined behaviour
+ if (m_group >= 0) {
return m_group;
}
#if HAVE_XKB_EXTENSION
if (m_xkb != NULL) {
XkbStateRec state;
- if (XkbGetState(m_display, XkbUseCoreKbd, &state)) {
+ if (XkbGetState(m_display, XkbUseCoreKbd, &state) == Success) {
return state.group;
}
}
@@ -192,15 +222,14 @@ CXWindowsKeyState::getKeyMap(CKeyMap& keyMap)
#if HAVE_XKB_EXTENSION
if (m_xkb != NULL) {
- XkbGetUpdatedMap(m_display, XkbKeyActionsMask | XkbKeyBehaviorsMask |
- XkbAllClientInfoMask, m_xkb);
- updateKeysymMapXKB(keyMap);
+ if (XkbGetUpdatedMap(m_display, XkbKeyActionsMask |
+ XkbKeyBehaviorsMask | XkbAllClientInfoMask, m_xkb) == Success) {
+ updateKeysymMapXKB(keyMap);
+ return;
+ }
}
- else
#endif
- {
- updateKeysymMap(keyMap);
- }
+ updateKeysymMap(keyMap);
}
void
@@ -229,8 +258,10 @@ CXWindowsKeyState::fakeKey(const Keystroke& keystroke)
LOG((CLOG_DEBUG1 " group %d", keystroke.m_data.m_group.m_group));
#if HAVE_XKB_EXTENSION
if (m_xkb != NULL) {
- XkbLockGroup(m_display, XkbUseCoreKbd,
- keystroke.m_data.m_group.m_group);
+ if (XkbLockGroup(m_display, XkbUseCoreKbd,
+ keystroke.m_data.m_group.m_group) == False) {
+ LOG((CLOG_DEBUG1 "XkbLockGroup request not sent"));
+ }
}
else
#endif
@@ -242,9 +273,11 @@ CXWindowsKeyState::fakeKey(const Keystroke& keystroke)
LOG((CLOG_DEBUG1 " group %+d", keystroke.m_data.m_group.m_group));
#if HAVE_XKB_EXTENSION
if (m_xkb != NULL) {
- XkbLockGroup(m_display, XkbUseCoreKbd,
+ if (XkbLockGroup(m_display, XkbUseCoreKbd,
getEffectiveGroup(pollActiveGroup(),
- keystroke.m_data.m_group.m_group));
+ keystroke.m_data.m_group.m_group)) == False) {
+ LOG((CLOG_DEBUG1 "XkbLockGroup request not sent"));
+ }
}
else
#endif
@@ -267,8 +300,7 @@ CXWindowsKeyState::updateKeysymMap(CKeyMap& keyMap)
// prepare map from X modifier to KeyModifierMask. certain bits
// are predefined.
- m_modifierFromX.clear();
- m_modifierFromX.resize(8);
+ std::fill(m_modifierFromX.begin(), m_modifierFromX.end(), 0);
m_modifierFromX[ShiftMapIndex] = KeyModifierShift;
m_modifierFromX[LockMapIndex] = KeyModifierCapsLock;
m_modifierFromX[ControlMapIndex] = KeyModifierControl;
@@ -610,7 +642,7 @@ CXWindowsKeyState::updateKeysymMapXKB(CKeyMap& keyMap)
item.m_lock = false;
bool isModifier = false;
UInt32 modifierMask = m_xkb->map->modmap[keycode];
- if (XkbKeyHasActions(m_xkb, keycode)) {
+ if (XkbKeyHasActions(m_xkb, keycode) == True) {
XkbAction* action =
XkbKeyActionEntry(m_xkb, keycode, level, eGroup);
if (action->type == XkbSA_SetMods ||
@@ -761,7 +793,7 @@ CXWindowsKeyState::hasModifiersXKB() const
// iterate over all keycodes
for (int i = m_xkb->min_key_code; i <= m_xkb->max_key_code; ++i) {
KeyCode keycode = static_cast(i);
- if (XkbKeyHasActions(m_xkb, keycode)) {
+ if (XkbKeyHasActions(m_xkb, keycode) == True) {
// iterate over all groups
int numGroups = XkbKeyNumGroups(m_xkb, keycode);
for (int group = 0; group < numGroups; ++group) {
diff --git a/src/lib/platform/CXWindowsKeyState.h b/src/lib/platform/CXWindowsKeyState.h
index 79045e32..37a5d082 100644
--- a/src/lib/platform/CXWindowsKeyState.h
+++ b/src/lib/platform/CXWindowsKeyState.h
@@ -48,6 +48,8 @@ public:
};
CXWindowsKeyState(Display*, bool useXKB);
+ CXWindowsKeyState(Display*, bool useXKB,
+ IEventQueue& eventQueue, CKeyMap& keyMap);
~CXWindowsKeyState();
//! @name modifiers
@@ -111,6 +113,7 @@ protected:
virtual void fakeKey(const Keystroke& keystroke);
private:
+ void init(Display* display, bool useXKB);
void updateKeysymMap(CKeyMap&);
void updateKeysymMapXKB(CKeyMap&);
bool hasModifiersXKB() const;
diff --git a/src/lib/synergy/CKeyMap.h b/src/lib/synergy/CKeyMap.h
index c1982587..de5961fe 100644
--- a/src/lib/synergy/CKeyMap.h
+++ b/src/lib/synergy/CKeyMap.h
@@ -215,7 +215,7 @@ public:
event in \p keys. It returns the \c KeyItem of the key being
pressed/repeated, or NULL if the key cannot be mapped.
*/
- const KeyItem* mapKey(Keystrokes& keys, KeyID id, SInt32 group,
+ virtual const KeyItem* mapKey(Keystrokes& keys, KeyID id, SInt32 group,
ModifierToKeys& activeModifiers,
KeyModifierMask& currentState,
KeyModifierMask desiredMask,
diff --git a/src/lib/synergy/CKeyState.cpp b/src/lib/synergy/CKeyState.cpp
index 1b36bf8d..d9d3ea6c 100644
--- a/src/lib/synergy/CKeyState.cpp
+++ b/src/lib/synergy/CKeyState.cpp
@@ -583,7 +583,7 @@ CKeyState::fakeKeyDown(KeyID id, KeyModifierMask mask, KeyButton serverID)
fakeKeys(keys, 1);
}
-void
+bool
CKeyState::fakeKeyRepeat(
KeyID id, KeyModifierMask mask,
SInt32 count, KeyButton serverID)
@@ -593,7 +593,7 @@ CKeyState::fakeKeyRepeat(
// if we haven't seen this button go down then ignore it
KeyButton oldLocalID = m_serverKeys[serverID];
if (oldLocalID == 0) {
- return;
+ return false;
}
// get keys for key repeat
@@ -603,11 +603,11 @@ CKeyState::fakeKeyRepeat(
m_keyMap.mapKey(keys, id, pollActiveGroup(), m_activeModifiers,
getActiveModifiersRValue(), mask, true);
if (keyItem == NULL) {
- return;
+ return false;
}
KeyButton localID = (KeyButton)(keyItem->m_button & kButtonMask);
if (localID == 0) {
- return;
+ return false;
}
// if the KeyButton for the auto-repeat is not the same as for the
@@ -642,15 +642,16 @@ CKeyState::fakeKeyRepeat(
// generate key events
fakeKeys(keys, count);
+ return true;
}
-void
+bool
CKeyState::fakeKeyUp(KeyButton serverID)
{
// if we haven't seen this button go down then ignore it
KeyButton localID = m_serverKeys[serverID & kButtonMask];
if (localID == 0) {
- return;
+ return false;
}
// get the sequence of keys to simulate key release
@@ -682,6 +683,7 @@ CKeyState::fakeKeyUp(KeyButton serverID)
// generate key events
fakeKeys(keys, 1);
+ return true;
}
void
diff --git a/src/lib/synergy/CKeyState.h b/src/lib/synergy/CKeyState.h
index 9536bd2f..bc6d2e69 100644
--- a/src/lib/synergy/CKeyState.h
+++ b/src/lib/synergy/CKeyState.h
@@ -68,9 +68,9 @@ public:
virtual void setHalfDuplexMask(KeyModifierMask);
virtual void fakeKeyDown(KeyID id, KeyModifierMask mask,
KeyButton button);
- virtual void fakeKeyRepeat(KeyID id, KeyModifierMask mask,
+ virtual bool fakeKeyRepeat(KeyID id, KeyModifierMask mask,
SInt32 count, KeyButton button);
- virtual void fakeKeyUp(KeyButton button);
+ virtual bool fakeKeyUp(KeyButton button);
virtual void fakeAllKeysUp();
virtual bool fakeCtrlAltDel() = 0;
virtual bool isKeyDown(KeyButton) const;
diff --git a/src/lib/synergy/CPlatformScreen.cpp b/src/lib/synergy/CPlatformScreen.cpp
index 7b640849..f74cc03c 100644
--- a/src/lib/synergy/CPlatformScreen.cpp
+++ b/src/lib/synergy/CPlatformScreen.cpp
@@ -53,17 +53,17 @@ CPlatformScreen::fakeKeyDown(KeyID id, KeyModifierMask mask,
getKeyState()->fakeKeyDown(id, mask, button);
}
-void
+bool
CPlatformScreen::fakeKeyRepeat(KeyID id, KeyModifierMask mask,
SInt32 count, KeyButton button)
{
- getKeyState()->fakeKeyRepeat(id, mask, count, button);
+ return getKeyState()->fakeKeyRepeat(id, mask, count, button);
}
-void
+bool
CPlatformScreen::fakeKeyUp(KeyButton button)
{
- getKeyState()->fakeKeyUp(button);
+ return getKeyState()->fakeKeyUp(button);
}
void
diff --git a/src/lib/synergy/CPlatformScreen.h b/src/lib/synergy/CPlatformScreen.h
index 355a9da4..eabdabae 100644
--- a/src/lib/synergy/CPlatformScreen.h
+++ b/src/lib/synergy/CPlatformScreen.h
@@ -62,9 +62,9 @@ public:
virtual void setHalfDuplexMask(KeyModifierMask);
virtual void fakeKeyDown(KeyID id, KeyModifierMask mask,
KeyButton button);
- virtual void fakeKeyRepeat(KeyID id, KeyModifierMask mask,
+ virtual bool fakeKeyRepeat(KeyID id, KeyModifierMask mask,
SInt32 count, KeyButton button);
- virtual void fakeKeyUp(KeyButton button);
+ virtual bool fakeKeyUp(KeyButton button);
virtual void fakeAllKeysUp();
virtual bool fakeCtrlAltDel();
virtual bool isKeyDown(KeyButton) const;
diff --git a/src/lib/synergy/Global.h b/src/lib/synergy/Global.h
new file mode 100644
index 00000000..6da57d61
--- /dev/null
+++ b/src/lib/synergy/Global.h
@@ -0,0 +1,28 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2011 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
+ *
+ * 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 COPYING 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 .
+ */
+
+#ifndef GLOBAL_H
+#define GLOBAL_H
+
+// Makes everything public for unit tests
+#ifdef TEST_ENV
+#define protected public
+#define private public
+#endif
+
+#endif
+
diff --git a/src/lib/synergy/IKeyState.h b/src/lib/synergy/IKeyState.h
index f12d1b10..2966da84 100644
--- a/src/lib/synergy/IKeyState.h
+++ b/src/lib/synergy/IKeyState.h
@@ -100,14 +100,14 @@ public:
/*!
Synthesizes a key repeat event and updates the key state.
*/
- virtual void fakeKeyRepeat(KeyID id, KeyModifierMask mask,
+ virtual bool fakeKeyRepeat(KeyID id, KeyModifierMask mask,
SInt32 count, KeyButton button) = 0;
//! Fake a key release
/*!
Synthesizes a key release event and updates the key state.
*/
- virtual void fakeKeyUp(KeyButton button) = 0;
+ virtual bool fakeKeyUp(KeyButton button) = 0;
//! Fake key releases for all fake pressed keys
/*!
diff --git a/src/lib/synergy/IPlatformScreen.h b/src/lib/synergy/IPlatformScreen.h
index 76058bb2..87682ff6 100644
--- a/src/lib/synergy/IPlatformScreen.h
+++ b/src/lib/synergy/IPlatformScreen.h
@@ -169,9 +169,9 @@ public:
virtual void setHalfDuplexMask(KeyModifierMask) = 0;
virtual void fakeKeyDown(KeyID id, KeyModifierMask mask,
KeyButton button) = 0;
- virtual void fakeKeyRepeat(KeyID id, KeyModifierMask mask,
+ virtual bool fakeKeyRepeat(KeyID id, KeyModifierMask mask,
SInt32 count, KeyButton button) = 0;
- virtual void fakeKeyUp(KeyButton button) = 0;
+ virtual bool fakeKeyUp(KeyButton button) = 0;
virtual void fakeAllKeysUp() = 0;
virtual bool fakeCtrlAltDel() = 0;
virtual bool isKeyDown(KeyButton) const = 0;
diff --git a/src/test/integtests/CMakeLists.txt b/src/test/integtests/CMakeLists.txt
index 3711a382..ddc6f6b1 100644
--- a/src/test/integtests/CMakeLists.txt
+++ b/src/test/integtests/CMakeLists.txt
@@ -22,6 +22,7 @@ if (WIN32)
# windows
list(APPEND src
platform/CMSWindowsClipboardTests.cpp
+ platform/CMSWindowsKeyStateTests.cpp
)
elseif (APPLE)
@@ -29,6 +30,7 @@ elseif (APPLE)
# mac
list(APPEND src
platform/COSXClipboardTests.cpp
+ platform/COSXKeyStateTests.cpp
)
elseif (UNIX)
@@ -36,6 +38,7 @@ elseif (UNIX)
# unix/linux
list(APPEND src
platform/CXWindowsClipboardTests.cpp
+ platform/CXWindowsKeyStateTests.cpp
)
endif()
@@ -52,6 +55,8 @@ set(inc
../../lib/synergy
../../../tools/gtest-1.6.0/include
../../../tools/gmock-1.6.0/include
+ ../unittests
+ ../unittests/synergy
)
if (UNIX)
diff --git a/src/test/integtests/Main.cpp b/src/test/integtests/Main.cpp
index c778e67a..c1e6e0f3 100644
--- a/src/test/integtests/Main.cpp
+++ b/src/test/integtests/Main.cpp
@@ -36,9 +36,6 @@
using namespace std;
-int
-ensureSingleInstance();
-
#if SYSAPI_UNIX
void
@@ -52,15 +49,12 @@ removeLock();
int
main(int argc, char **argv)
{
- // make sure integ tests don't run in parallel.
- int err = ensureSingleInstance();
- if (err != 0)
- return err;
-
-#if SYSAPI_UNIX
- // register SIGINT handling (to delete lock file)
- signal(SIGINT, signalHandler);
- atexit(removeLock);
+#if SYSAPI_WIN32
+ if (CArchMiscWindows::isWindows95Family())
+ {
+ std::cerr << "Windows 95 family not supported." << std::endl;
+ return 1;
+ }
#endif
#if SYSAPI_WIN32
@@ -76,87 +70,3 @@ main(int argc, char **argv)
return RUN_ALL_TESTS();
}
-
-int
-ensureSingleInstance()
-{
-#if SYSAPI_WIN32
-
- // get info for current process (we'll use the name later).
- PROCESSENTRY32 selfEntry;
- if (!CArchMiscWindows::getSelfProcessEntry(selfEntry))
- cerr << "could not process info for self "
- << "(error: " << GetLastError() << ")" << endl;
-
- // get current task list.
- HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
- if (snapshot == INVALID_HANDLE_VALUE)
- cerr << "could not get process snapshot "
- << "(error: " << GetLastError() << ")" << endl;
-
- PROCESSENTRY32 entry;
- BOOL gotEntry = Process32First(snapshot, &entry);
- if (!gotEntry)
- cerr << "could not get first process entry "
- << "(error: " << GetLastError() << ")" << endl;
-
- while (gotEntry)
- {
- string checkName(entry.szExeFile);
-
- // if entry has the same name as this process, but is not
- // the current process...
- if ((checkName.find(selfEntry.szExeFile) != string::npos) &&
- (entry.th32ProcessID != selfEntry.th32ProcessID))
- {
- cerr << "error: process already running: "
- << entry.th32ProcessID << " -> " << entry.szExeFile << endl;
-
- return ERROR_ALREADY_RUNNING;
- }
-
- gotEntry = Process32Next(snapshot, &entry);
- }
-
-#elif SYSAPI_UNIX
-
- // fail if lock file exists
- struct stat info;
- int statResult = stat(LOCK_FILE, &info);
- if (statResult == 0)
- {
- cerr << "error: lock file exists: " << LOCK_FILE << endl;
- return ERROR_ALREADY_RUNNING;
- }
-
- // write an empty lock file
- cout << "creating lock: " << LOCK_FILE << endl;
-
- ofstream stream;
- stream.open(LOCK_FILE);
- if (!stream.is_open())
- cerr << "error: could not create lock" << endl;
-
- stream << "";
- stream.close();
-
-#endif
-
- return 0;
-}
-
-#if SYSAPI_UNIX
-void
-signalHandler(int signal)
-{
- removeLock();
-}
-
-void
-removeLock()
-{
- // remove lock file so other instances can run.
- cout << "removing lock: " << LOCK_FILE << endl;
- unlink(LOCK_FILE);
-}
-#endif
diff --git a/src/test/integtests/platform/CMSWindowsKeyStateTests.cpp b/src/test/integtests/platform/CMSWindowsKeyStateTests.cpp
new file mode 100644
index 00000000..43a330e8
--- /dev/null
+++ b/src/test/integtests/platform/CMSWindowsKeyStateTests.cpp
@@ -0,0 +1,130 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2011 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
+ *
+ * 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 COPYING 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
+#include
+#include "CMSWindowsKeyState.h"
+#include "CMSWindowsDesks.h"
+#include "CMSWindowsScreen.h"
+#include "CMSWindowsScreenSaver.h"
+#include "TMethodJob.h"
+#include "CMockEventQueue.h"
+#include "CMockKeyMap.h"
+
+// wParam = flags, HIBYTE(lParam) = virtual key, LOBYTE(lParam) = scan code
+#define SYNERGY_MSG_FAKE_KEY SYNERGY_HOOK_LAST_MSG + 4
+
+using ::testing::_;
+using ::testing::NiceMock;
+
+class CMSWindowsKeyStateTests : public ::testing::Test
+{
+protected:
+ virtual void SetUp()
+ {
+ // load synrgyhk.dll
+ m_hookLibrary = m_hookLibraryLoader.openHookLibrary("synrgyhk");
+ m_screensaver = new CMSWindowsScreenSaver();
+ m_desks = new CMSWindowsDesks(
+ true, false, m_hookLibrary, m_screensaver,
+ new TMethodJob(
+ this, &CMSWindowsKeyStateTests::updateKeysCB));
+ }
+
+ virtual void TearDown()
+ {
+ delete m_screensaver;
+ delete m_desks;
+ }
+
+ CMSWindowsDesks* getDesks() const
+ {
+ return m_desks;
+ }
+
+ void* getEventTarget() const
+ {
+ return const_cast(this);
+ }
+
+private:
+ void updateKeysCB(void*) { }
+ HINSTANCE m_hookLibrary;
+ IScreenSaver* m_screensaver;
+ CMSWindowsDesks* m_desks;
+ CMSWindowsHookLibraryLoader m_hookLibraryLoader;
+};
+
+TEST_F(CMSWindowsKeyStateTests, disable_nonWin95OS_eventQueueNotUsed)
+{
+ NiceMock eventQueue;
+ CMockKeyMap keyMap;
+ CMSWindowsKeyState keyState(getDesks(), getEventTarget(), eventQueue, keyMap);
+
+ // in anything above win95-family, event handler should not be called.
+ EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(0);
+
+ keyState.disable();
+}
+
+TEST_F(CMSWindowsKeyStateTests, testAutoRepeat_noRepeatAndButtonIsZero_resultIsTrue)
+{
+ NiceMock eventQueue;
+ CMockKeyMap keyMap;
+ CMSWindowsKeyState keyState(getDesks(), getEventTarget(), eventQueue, keyMap);
+ keyState.setLastDown(1);
+
+ bool actual = keyState.testAutoRepeat(true, false, 1);
+
+ ASSERT_TRUE(actual);
+}
+
+TEST_F(CMSWindowsKeyStateTests, testAutoRepeat_pressFalse_lastDownIsZero)
+{
+ NiceMock eventQueue;
+ CMockKeyMap keyMap;
+ CMSWindowsKeyState keyState(getDesks(), getEventTarget(), eventQueue, keyMap);
+ keyState.setLastDown(1);
+
+ keyState.testAutoRepeat(false, false, 1);
+
+ ASSERT_EQ(0, keyState.getLastDown());
+}
+
+TEST_F(CMSWindowsKeyStateTests, saveModifiers_noModifiers_savedModifiers0)
+{
+ NiceMock eventQueue;
+ CMockKeyMap keyMap;
+ CMSWindowsKeyState keyState(getDesks(), getEventTarget(), eventQueue, keyMap);
+
+ keyState.saveModifiers();
+
+ ASSERT_EQ(0, keyState.getSavedModifiers());
+}
+
+TEST_F(CMSWindowsKeyStateTests, saveModifiers_shiftKeyDown_savedModifiers4)
+{
+ NiceMock eventQueue;
+ CMockKeyMap keyMap;
+ CMSWindowsKeyState keyState(getDesks(), getEventTarget(), eventQueue, keyMap);
+ getDesks()->enable();
+ getDesks()->fakeKeyEvent(1, 1, true, false);
+
+ keyState.saveModifiers();
+
+ ASSERT_EQ(1, keyState.getSavedModifiers());
+}
diff --git a/src/test/integtests/platform/COSXKeyStateTests.cpp b/src/test/integtests/platform/COSXKeyStateTests.cpp
new file mode 100644
index 00000000..7d8952b8
--- /dev/null
+++ b/src/test/integtests/platform/COSXKeyStateTests.cpp
@@ -0,0 +1,95 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2011 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
+ *
+ * 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 COPYING 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
+#include
+
+#include "COSXKeyState.h"
+#include "CMockKeyMap.h"
+#include "CMockEventQueue.h"
+
+CGKeyCode escKeyCode = 53;
+CGKeyCode shiftKeyCode = 56;
+CGKeyCode controlKeyCode = 59;
+
+TEST(COSXKeyStateTests, pollActiveModifiers_shiftKeyDownThenUp_masksAreCorrect)
+{
+ CMockKeyMap keyMap;
+ CMockEventQueue eventQueue;
+ COSXKeyState keyState((IEventQueue&)keyMap, (CKeyMap&)eventQueue);
+
+ // fake shift key down (without using synergy). this is a bit weird;
+ // looks like you need to create a shift down event *and* set the
+ // shift modifier.
+ CGEventRef shiftDown = CGEventCreateKeyboardEvent(NULL, shiftKeyCode, true);
+ CGEventSetFlags(shiftDown, kCGEventFlagMaskShift);
+ CGEventPost(kCGHIDEventTap, shiftDown);
+ CFRelease(shiftDown);
+
+ // function under test (1st call)
+ KeyModifierMask downMask = keyState.pollActiveModifiers();
+
+ // fake shift key up (without using synergy). also as weird as the
+ // shift down; use a non-shift key down and reset the pressed modifiers.
+ CGEventRef shiftUp = CGEventCreateKeyboardEvent(NULL, escKeyCode, true);
+ CGEventSetFlags(shiftUp, 0);
+ CGEventPost(kCGHIDEventTap, shiftUp);
+ CFRelease(shiftUp);
+
+ // function under test (2nd call)
+ KeyModifierMask upMask = keyState.pollActiveModifiers();
+
+ EXPECT_TRUE((downMask & KeyModifierShift) == KeyModifierShift)
+ << "shift key not in mask (" << downMask << ") - key was not pressed";
+
+ EXPECT_TRUE((upMask & KeyModifierShift) == 0)
+ << "shift key still in mask (" << upMask << ") - make sure no keys are being held down";
+}
+
+TEST(COSXKeyStateTests, pollActiveModifiers_controlKeyDownThenUp_masksAreCorrect)
+{
+ CMockKeyMap keyMap;
+ CMockEventQueue eventQueue;
+ COSXKeyState keyState((IEventQueue&)keyMap, (CKeyMap&)eventQueue);
+
+ // fake control key down (without using synergy). this is a bit weird;
+ // looks like you need to create a shift down event *and* set the
+ // shift modifier.
+ CGEventRef controlDown = CGEventCreateKeyboardEvent(NULL, controlKeyCode, true);
+ CGEventSetFlags(controlDown, kCGEventFlagMaskControl);
+ CGEventPost(kCGHIDEventTap, controlDown);
+ CFRelease(controlDown);
+
+ // function under test (1st call)
+ KeyModifierMask downMask = keyState.pollActiveModifiers();
+
+ // fake control key up (without using synergy). also as weird as the
+ // shift down; use a non-shift key down and reset the pressed modifiers.
+ CGEventRef controlUp = CGEventCreateKeyboardEvent(NULL, escKeyCode, true);
+ CGEventSetFlags(controlUp, 0);
+ CGEventPost(kCGHIDEventTap, controlUp);
+ CFRelease(controlUp);
+
+ // function under test (2nd call)
+ KeyModifierMask upMask = keyState.pollActiveModifiers();
+
+ EXPECT_TRUE((downMask & KeyModifierControl) == KeyModifierControl)
+ << "control key not in mask (" << downMask << ") - key was not pressed";
+
+ EXPECT_TRUE((upMask & KeyModifierControl) == 0)
+ << "control key still in mask (" << upMask << ") - make sure no keys are being held down";
+}
diff --git a/src/test/integtests/platform/CXWindowsKeyStateTests.cpp b/src/test/integtests/platform/CXWindowsKeyStateTests.cpp
new file mode 100644
index 00000000..f2e9650e
--- /dev/null
+++ b/src/test/integtests/platform/CXWindowsKeyStateTests.cpp
@@ -0,0 +1,245 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2011 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
+ *
+ * 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 COPYING 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
+#include
+
+#define TEST_ENV
+#include "Global.h"
+
+#include "CMockKeyMap.h"
+#include "CMockEventQueue.h"
+#include "CXWindowsKeyState.h"
+#include "CLog.h"
+#include
+
+#define XK_LATIN1
+#define XK_MISCELLANY
+#include "X11/keysymdef.h"
+
+#if HAVE_XKB_EXTENSION
+# include
+#endif
+
+class CXWindowsKeyStateTests : public ::testing::Test
+{
+protected:
+ CXWindowsKeyStateTests() :
+ m_display(NULL)
+ {
+ }
+
+ ~CXWindowsKeyStateTests()
+ {
+ if (m_display != NULL) {
+ LOG((CLOG_DEBUG "closing display"));
+ XCloseDisplay(m_display);
+ }
+ }
+
+ virtual void
+ SetUp()
+ {
+ // open the display only once for the entire test suite
+ if (this->m_display == NULL) {
+ LOG((CLOG_DEBUG "opening display"));
+ this->m_display = XOpenDisplay(NULL);
+
+ ASSERT_TRUE(this->m_display != NULL)
+ << "unable to open display: " << errno;
+ }
+ }
+
+ virtual void
+ TearDown()
+ {
+ }
+
+ Display* m_display;
+};
+
+TEST_F(CXWindowsKeyStateTests, setActiveGroup_pollAndSet_groupIsZero)
+{
+ CMockKeyMap keyMap;
+ CMockEventQueue eventQueue;
+ CXWindowsKeyState keyState(
+ m_display, true, (IEventQueue&)keyMap, (CKeyMap&)eventQueue);
+
+ keyState.setActiveGroup(CXWindowsKeyState::kGroupPollAndSet);
+
+ ASSERT_EQ(0, keyState.m_group);
+}
+
+TEST_F(CXWindowsKeyStateTests, setActiveGroup_poll_groupIsNotSet)
+{
+ CMockKeyMap keyMap;
+ CMockEventQueue eventQueue;
+ CXWindowsKeyState keyState(
+ m_display, true, (IEventQueue&)keyMap, (CKeyMap&)eventQueue);
+
+ keyState.setActiveGroup(CXWindowsKeyState::kGroupPoll);
+
+ ASSERT_LE(-1, keyState.m_group);
+}
+
+TEST_F(CXWindowsKeyStateTests, setActiveGroup_customGroup_groupWasSet)
+{
+ CMockKeyMap keyMap;
+ CMockEventQueue eventQueue;
+ CXWindowsKeyState keyState(
+ m_display, true, (IEventQueue&)keyMap, (CKeyMap&)eventQueue);
+
+ keyState.setActiveGroup(1);
+
+ ASSERT_EQ(1, keyState.m_group);
+}
+
+TEST_F(CXWindowsKeyStateTests, mapModifiersFromX_zeroState_zeroMask)
+{
+ CMockKeyMap keyMap;
+ CMockEventQueue eventQueue;
+ CXWindowsKeyState keyState(
+ m_display, true, (IEventQueue&)keyMap, (CKeyMap&)eventQueue);
+
+ int mask = keyState.mapModifiersFromX(0);
+
+ ASSERT_EQ(0, mask);
+}
+
+TEST_F(CXWindowsKeyStateTests, mapModifiersToX_zeroMask_resultIsTrue)
+{
+ CMockKeyMap keyMap;
+ CMockEventQueue eventQueue;
+ CXWindowsKeyState keyState(
+ m_display, true, (IEventQueue&)keyMap, (CKeyMap&)eventQueue);
+
+ unsigned int modifiers = 0;
+ bool result = keyState.mapModifiersToX(0, modifiers);
+
+ ASSERT_TRUE(result);
+}
+
+TEST_F(CXWindowsKeyStateTests, fakeCtrlAltDel_default_returnsFalse)
+{
+ CMockKeyMap keyMap;
+ CMockEventQueue eventQueue;
+ CXWindowsKeyState keyState(
+ m_display, true, (IEventQueue&)keyMap, (CKeyMap&)eventQueue);
+
+ bool result = keyState.fakeCtrlAltDel();
+
+ ASSERT_FALSE(result);
+}
+
+TEST_F(CXWindowsKeyStateTests, pollActiveModifiers_defaultState_returnsZero)
+{
+ CMockKeyMap keyMap;
+ CMockEventQueue eventQueue;
+ CXWindowsKeyState keyState(
+ m_display, true, (IEventQueue&)keyMap, (CKeyMap&)eventQueue);
+
+ KeyModifierMask actual = keyState.pollActiveModifiers();
+
+ ASSERT_EQ(0, actual);
+}
+
+TEST_F(CXWindowsKeyStateTests, pollActiveModifiers_shiftKeyDownThenUp_masksAreCorrect)
+{
+ CMockKeyMap keyMap;
+ CMockEventQueue eventQueue;
+ CXWindowsKeyState keyState(
+ m_display, true, (IEventQueue&)keyMap, (CKeyMap&)eventQueue);
+
+ // set mock modifier mapping
+ std::fill(
+ keyState.m_modifierFromX.begin(), keyState.m_modifierFromX.end(), 0);
+ keyState.m_modifierFromX[ShiftMapIndex] = KeyModifierShift;
+
+ KeyCode key = XKeysymToKeycode(m_display, XK_Shift_L);
+
+ // fake shift key down (without using synergy)
+ XTestFakeKeyEvent(m_display, key, true, CurrentTime);
+
+ // function under test (1st call)
+ KeyModifierMask modDown = keyState.pollActiveModifiers();
+
+ // fake shift key up (without using synergy)
+ XTestFakeKeyEvent(m_display, key, false, CurrentTime);
+
+ // function under test (2nd call)
+ KeyModifierMask modUp = keyState.pollActiveModifiers();
+
+ EXPECT_TRUE((modDown & KeyModifierShift) == KeyModifierShift)
+ << "shift key not in mask - key was not pressed";
+
+ EXPECT_TRUE((modUp & KeyModifierShift) == 0)
+ << "shift key still in mask - make sure no keys are being held down";
+}
+
+TEST_F(CXWindowsKeyStateTests, pollActiveGroup_defaultState_returnsZero)
+{
+ CMockKeyMap keyMap;
+ CMockEventQueue eventQueue;
+ CXWindowsKeyState keyState(
+ m_display, true, (IEventQueue&)keyMap, (CKeyMap&)eventQueue);
+
+ SInt32 actual = keyState.pollActiveGroup();
+
+ ASSERT_EQ(0, actual);
+}
+
+TEST_F(CXWindowsKeyStateTests, pollActiveGroup_positiveGroup_returnsGroup)
+{
+ CMockKeyMap keyMap;
+ CMockEventQueue eventQueue;
+ CXWindowsKeyState keyState(
+ m_display, true, (IEventQueue&)keyMap, (CKeyMap&)eventQueue);
+
+ keyState.m_group = 3;
+
+ SInt32 actual = keyState.pollActiveGroup();
+
+ ASSERT_EQ(3, actual);
+}
+
+TEST_F(CXWindowsKeyStateTests, pollActiveGroup_xkb_areEqual)
+{
+#if HAVE_XKB_EXTENSION
+ CMockKeyMap keyMap;
+ CMockEventQueue eventQueue;
+ CXWindowsKeyState keyState(
+ m_display, true, (IEventQueue&)keyMap, (CKeyMap&)eventQueue);
+
+ // reset the group
+ keyState.m_group = -1;
+
+ XkbStateRec state;
+
+ // compare pollActiveGroup() with XkbGetState()
+ if (XkbGetState(m_display, XkbUseCoreKbd, &state) == Success) {
+ SInt32 actual = keyState.pollActiveGroup();
+
+ ASSERT_EQ(state.group, actual);
+ }
+ else {
+ FAIL() << "XkbGetState() returned error " << errno;
+ }
+#else
+ SUCCEED() << "Xkb extension not installed";
+#endif
+}
+
diff --git a/src/test/unittests/CMakeLists.txt b/src/test/unittests/CMakeLists.txt
index c98f9cf6..78e73e1b 100644
--- a/src/test/unittests/CMakeLists.txt
+++ b/src/test/unittests/CMakeLists.txt
@@ -14,7 +14,7 @@
# along with this program. If not, see .
set(h
- synergy/CKeyStateImpl.h
+ synergy/CKeyStateTests.h
synergy/CMockEventQueue.h
synergy/CMockKeyMap.h
)
diff --git a/src/test/unittests/synergy/CKeyStateTests.cpp b/src/test/unittests/synergy/CKeyStateTests.cpp
index f73cff28..51e1caf5 100644
--- a/src/test/unittests/synergy/CKeyStateTests.cpp
+++ b/src/test/unittests/synergy/CKeyStateTests.cpp
@@ -17,7 +17,7 @@
#include
#include
-#include "CKeyStateImpl.h"
+#include "CKeyStateTests.h"
#include "CMockEventQueue.h"
#include "CMockKeyMap.h"
@@ -27,19 +27,15 @@ using ::testing::Invoke;
using ::testing::Return;
using ::testing::SaveArg;
-enum {
- kAKey = 30
-};
-
TEST(CKeyStateTests, onKey_aKeyDown_keyStateOne)
{
CMockKeyMap keyMap;
CMockEventQueue eventQueue;
CKeyStateImpl keyState(eventQueue, keyMap);
- keyState.onKey(kAKey, true, KeyModifierAlt);
+ keyState.onKey(1, true, KeyModifierAlt);
- EXPECT_EQ(1, keyState.getKeyState(kAKey));
+ EXPECT_EQ(1, keyState.getKeyState(1));
}
TEST(CKeyStateTests, onKey_aKeyUp_keyStateZero)
@@ -48,9 +44,9 @@ TEST(CKeyStateTests, onKey_aKeyUp_keyStateZero)
CMockEventQueue eventQueue;
CKeyStateImpl keyState(eventQueue, keyMap);
- keyState.onKey(kAKey, false, KeyModifierAlt);
+ keyState.onKey(1, false, KeyModifierAlt);
- EXPECT_EQ(0, keyState.getKeyState(kAKey));
+ EXPECT_EQ(0, keyState.getKeyState(1));
}
TEST(CKeyStateTests, onKey_invalidKey_keyStateZero)
@@ -78,7 +74,7 @@ TEST(CKeyStateTests, sendKeyEvent_halfDuplexAndRepeat_addEventNotCalled)
TEST(CKeyStateTests, sendKeyEvent_halfDuplex_addEventCalledTwice)
{
- CMockKeyMap keyMap;
+ NiceMock keyMap;
NiceMock eventQueue;
CKeyStateImpl keyState(eventQueue, keyMap);
ON_CALL(keyMap, isHalfDuplex(_, _)).WillByDefault(Return(true));
@@ -90,55 +86,49 @@ TEST(CKeyStateTests, sendKeyEvent_halfDuplex_addEventCalledTwice)
TEST(CKeyStateTests, sendKeyEvent_keyRepeat_addEventCalledOnce)
{
- CMockKeyMap keyMap;
+ NiceMock keyMap;
NiceMock eventQueue;
CKeyStateImpl keyState(eventQueue, keyMap);
EXPECT_CALL(eventQueue, addEvent(_)).Times(1);
- keyState.sendKeyEvent(NULL, false, true, kAKey, 0, 0, 0);
+ keyState.sendKeyEvent(NULL, false, true, 1, 0, 0, 0);
}
TEST(CKeyStateTests, sendKeyEvent_keyDown_addEventCalledOnce)
{
- CMockKeyMap keyMap;
+ NiceMock keyMap;
NiceMock eventQueue;
CKeyStateImpl keyState(eventQueue, keyMap);
EXPECT_CALL(eventQueue, addEvent(_)).Times(1);
- keyState.sendKeyEvent(NULL, true, false, kAKey, 0, 0, 0);
+ keyState.sendKeyEvent(NULL, true, false, 1, 0, 0, 0);
}
TEST(CKeyStateTests, sendKeyEvent_keyUp_addEventCalledOnce)
{
- CMockKeyMap keyMap;
+ NiceMock keyMap;
NiceMock eventQueue;
CKeyStateImpl keyState(eventQueue, keyMap);
EXPECT_CALL(eventQueue, addEvent(_)).Times(1);
- keyState.sendKeyEvent(NULL, false, false, kAKey, 0, 0, 0);
+ keyState.sendKeyEvent(NULL, false, false, 1, 0, 0, 0);
}
TEST(CKeyStateTests, updateKeyMap_mockKeyMap_keyMapGotMock)
{
- CMockKeyMap keyMap;
+ NiceMock keyMap;
CMockEventQueue eventQueue;
CKeyStateImpl keyState(eventQueue, keyMap);
+ // key map member gets a new key map via swap()
EXPECT_CALL(keyMap, swap(_));
- EXPECT_CALL(keyMap, finish());
keyState.updateKeyMap();
}
-void
-stubPollPressedKeys(IKeyState::KeyButtonSet& pressedKeys)
-{
- pressedKeys.insert(kAKey);
-}
-
TEST(CKeyStateTests, updateKeyState_pollInsertsSingleKey_keyIsDown)
{
NiceMock keyMap;
@@ -148,7 +138,7 @@ TEST(CKeyStateTests, updateKeyState_pollInsertsSingleKey_keyIsDown)
keyState.updateKeyState();
- bool actual = keyState.isKeyDown(kAKey);
+ bool actual = keyState.isKeyDown(1);
ASSERT_TRUE(actual);
}
@@ -160,7 +150,7 @@ TEST(CKeyStateTests, updateKeyState_pollDoesNothing_keyNotSet)
keyState.updateKeyState();
- bool actual = keyState.isKeyDown(kAKey);
+ bool actual = keyState.isKeyDown(1);
ASSERT_FALSE(actual);
}
@@ -189,22 +179,17 @@ TEST(CKeyStateTests, updateKeyState_activeModifiers_maskNotSet)
ASSERT_EQ(0, actual);
}
-void
-assertMaskIsOne(ForeachKeyCallback cb, void* userData)
-{
- ASSERT_EQ(1, ((CKeyState::CAddActiveModifierContext*)userData)->m_mask);
-}
-
TEST(CKeyStateTests, updateKeyState_activeModifiers_keyMapGotModifers)
{
CMockKeyMap keyMap;
CMockEventQueue eventQueue;
CKeyStateImpl keyState(eventQueue, keyMap);
- EXPECT_CALL(keyMap, foreachKey(_, _));
-
ON_CALL(keyState, pollActiveModifiers()).WillByDefault(Return(1));
ON_CALL(keyMap, foreachKey(_, _)).WillByDefault(Invoke(assertMaskIsOne));
+ // key map gets new modifiers via foreachKey()
+ EXPECT_CALL(keyMap, foreachKey(_, _));
+
keyState.updateKeyState();
}
@@ -218,3 +203,249 @@ TEST(CKeyStateTests, setHalfDuplexMask_capsLock_halfDuplexCapsLockAdded)
keyState.setHalfDuplexMask(KeyModifierCapsLock);
}
+
+TEST(CKeyStateTests, setHalfDuplexMask_numLock_halfDuplexNumLockAdded)
+{
+ CMockKeyMap keyMap;
+ CMockEventQueue eventQueue;
+ CKeyStateImpl keyState(eventQueue, keyMap);
+
+ EXPECT_CALL(keyMap, addHalfDuplexModifier(kKeyNumLock));
+
+ keyState.setHalfDuplexMask(KeyModifierNumLock);
+}
+
+TEST(CKeyStateTests, setHalfDuplexMask_scrollLock_halfDuplexScollLockAdded)
+{
+ CMockKeyMap keyMap;
+ CMockEventQueue eventQueue;
+ CKeyStateImpl keyState(eventQueue, keyMap);
+
+ EXPECT_CALL(keyMap, addHalfDuplexModifier(kKeyScrollLock));
+
+ keyState.setHalfDuplexMask(KeyModifierScrollLock);
+}
+
+TEST(CKeyStateTests, fakeKeyDown_serverKeyAlreadyDown_fakeKeyCalledTwice)
+{
+ NiceMock keyMap;
+ CMockEventQueue eventQueue;
+ CKeyStateImpl keyState(eventQueue, keyMap);
+ s_stubKeyItem.m_client = 0;
+ s_stubKeyItem.m_button = 1;
+ ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Invoke(stubMapKey));
+
+ // 2 calls to fakeKeyDown should still call fakeKey, even though
+ // repeated keys are handled differently.
+ EXPECT_CALL(keyState, fakeKey(_)).Times(2);
+
+ // call twice to simulate server key already down (a misreported autorepeat).
+ keyState.fakeKeyDown(1, 0, 0);
+ keyState.fakeKeyDown(1, 0, 0);
+}
+
+TEST(CKeyStateTests, fakeKeyDown_isIgnoredKey_fakeKeyNotCalled)
+{
+ CMockKeyMap keyMap;
+ CMockEventQueue eventQueue;
+ CKeyStateImpl keyState(eventQueue, keyMap);
+
+ EXPECT_CALL(keyState, fakeKey(_)).Times(0);
+
+ keyState.fakeKeyDown(kKeyCapsLock, 0, 0);
+}
+
+TEST(CKeyStateTests, fakeKeyDown_mapReturnsKeystrokes_fakeKeyCalled)
+{
+ NiceMock keyMap;
+ CMockEventQueue eventQueue;
+ CKeyStateImpl keyState(eventQueue, keyMap);
+ s_stubKeyItem.m_button = 0;
+ s_stubKeyItem.m_client = 0;
+ ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Invoke(stubMapKey));
+
+ EXPECT_CALL(keyState, fakeKey(_)).Times(1);
+
+ keyState.fakeKeyDown(1, 0, 0);
+}
+
+TEST(CKeyStateTests, fakeKeyRepeat_invalidKey_returnsFalse)
+{
+ CMockKeyMap keyMap;
+ CMockEventQueue eventQueue;
+ CKeyStateImpl keyState(eventQueue, keyMap);
+
+ bool actual = keyState.fakeKeyRepeat(0, 0, 0, 0);
+
+ ASSERT_FALSE(actual);
+}
+
+TEST(CKeyStateTests, fakeKeyRepeat_nullKey_returnsFalse)
+{
+ NiceMock keyMap;
+ CMockEventQueue eventQueue;
+ CKeyStateImpl keyState(eventQueue, keyMap);
+
+ // set the key to down (we need to make mapKey return a valid key to do this).
+ CKeyMap::KeyItem keyItem;
+ keyItem.m_client = 0;
+ keyItem.m_button = 1;
+ ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Return(&keyItem));
+ keyState.fakeKeyDown(1, 0, 0);
+
+ // change mapKey to return NULL so that fakeKeyRepeat exits early.
+ CKeyMap::KeyItem* nullKeyItem = NULL;
+ ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Return(nullKeyItem));
+
+ bool actual = keyState.fakeKeyRepeat(1, 0, 0, 0);
+
+ ASSERT_FALSE(actual);
+}
+
+TEST(CKeyStateTests, fakeKeyRepeat_invalidButton_returnsFalse)
+{
+ NiceMock keyMap;
+ CMockEventQueue eventQueue;
+ CKeyStateImpl keyState(eventQueue, keyMap);
+
+ // set the key to down (we need to make mapKey return a valid key to do this).
+ CKeyMap::KeyItem keyItem;
+ keyItem.m_client = 0;
+ keyItem.m_button = 1; // set to 1 to make fakeKeyDown work.
+ ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Return(&keyItem));
+ keyState.fakeKeyDown(1, 0, 0);
+
+ // change button to 0 so that fakeKeyRepeat will return early.
+ keyItem.m_button = 0;
+ ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Return(&keyItem));
+
+ bool actual = keyState.fakeKeyRepeat(1, 0, 0, 0);
+
+ ASSERT_FALSE(actual);
+}
+
+TEST(CKeyStateTests, fakeKeyRepeat_validKey_returnsTrue)
+{
+ NiceMock keyMap;
+ CMockEventQueue eventQueue;
+ CKeyStateImpl keyState(eventQueue, keyMap);
+ s_stubKeyItem.m_client = 0;
+ s_stubKeystroke.m_type = CKeyMap::Keystroke::kButton;
+ s_stubKeystroke.m_data.m_button.m_button = 2;
+
+ // set the button to 1 for fakeKeyDown call
+ s_stubKeyItem.m_button = 1;
+ ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Invoke(stubMapKey));
+ keyState.fakeKeyDown(1, 0, 0);
+
+ // change the button to 2
+ s_stubKeyItem.m_button = 2;
+ ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Invoke(stubMapKey));
+
+ bool actual = keyState.fakeKeyRepeat(1, 0, 0, 0);
+
+ ASSERT_TRUE(actual);
+}
+
+TEST(CKeyStateTests, fakeKeyUp_buttonNotDown_returnsFalse)
+{
+ CMockKeyMap keyMap;
+ CMockEventQueue eventQueue;
+ CKeyStateImpl keyState(eventQueue, keyMap);
+
+ bool actual = keyState.fakeKeyUp(0);
+
+ ASSERT_FALSE(actual);
+}
+
+TEST(CKeyStateTests, fakeKeyUp_buttonAlreadyDown_returnsTrue)
+{
+ NiceMock keyMap;
+ CMockEventQueue eventQueue;
+ CKeyStateImpl keyState(eventQueue, keyMap);
+
+ // press alt down so we get full coverage.
+ ON_CALL(keyState, pollActiveModifiers()).WillByDefault(Return(KeyModifierAlt));
+ keyState.updateKeyState();
+
+ // press button 1 down.
+ s_stubKeyItem.m_button = 1;
+ ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Invoke(stubMapKey));
+ keyState.fakeKeyDown(1, 0, 1);
+
+ // this takes the button id, which is the 3rd arg of fakeKeyDown
+ bool actual = keyState.fakeKeyUp(1);
+
+ ASSERT_TRUE(actual);
+}
+
+TEST(CKeyStateTests, fakeAllKeysUp_keysWereDown_keysAreUp)
+{
+ NiceMock keyMap;
+ CMockEventQueue eventQueue;
+ CKeyStateImpl keyState(eventQueue, keyMap);
+
+ // press button 1 down.
+ s_stubKeyItem.m_button = 1;
+ ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Invoke(stubMapKey));
+ keyState.fakeKeyDown(1, 0, 1);
+
+ // method under test
+ keyState.fakeAllKeysUp();
+
+ bool actual = keyState.isKeyDown(1);
+ ASSERT_FALSE(actual);
+}
+
+TEST(CKeyStateTests, isKeyDown_keyDown_returnsTrue)
+{
+ NiceMock keyMap;
+ CMockEventQueue eventQueue;
+ CKeyStateImpl keyState(eventQueue, keyMap);
+
+ // press button 1 down.
+ s_stubKeyItem.m_button = 1;
+ ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Invoke(stubMapKey));
+ keyState.fakeKeyDown(1, 0, 1);
+
+ // method under test
+ bool actual = keyState.isKeyDown(1);
+
+ ASSERT_TRUE(actual);
+}
+
+TEST(CKeyStateTests, isKeyDown_noKeysDown_returnsFalse)
+{
+ CMockKeyMap keyMap;
+ CMockEventQueue eventQueue;
+ CKeyStateImpl keyState(eventQueue, keyMap);
+
+ // method under test
+ bool actual = keyState.isKeyDown(1);
+
+ ASSERT_FALSE(actual);
+}
+
+void
+stubPollPressedKeys(IKeyState::KeyButtonSet& pressedKeys)
+{
+ pressedKeys.insert(1);
+}
+
+void
+assertMaskIsOne(ForeachKeyCallback cb, void* userData)
+{
+ ASSERT_EQ(1, ((CKeyState::CAddActiveModifierContext*)userData)->m_mask);
+}
+
+const CKeyMap::KeyItem*
+stubMapKey(
+ CKeyMap::Keystrokes& keys, KeyID id, SInt32 group,
+ CKeyMap::ModifierToKeys& activeModifiers,
+ KeyModifierMask& currentState,
+ KeyModifierMask desiredMask,
+ bool isAutoRepeat)
+{
+ keys.push_back(s_stubKeystroke);
+ return &s_stubKeyItem;
+}
diff --git a/src/test/unittests/synergy/CKeyStateImpl.h b/src/test/unittests/synergy/CKeyStateTests.h
similarity index 71%
rename from src/test/unittests/synergy/CKeyStateImpl.h
rename to src/test/unittests/synergy/CKeyStateTests.h
index 81bc2edd..fea2f6f8 100644
--- a/src/test/unittests/synergy/CKeyStateImpl.h
+++ b/src/test/unittests/synergy/CKeyStateTests.h
@@ -15,8 +15,8 @@
* along with this program. If not, see .
*/
-#ifndef CKEYSTATEIMPL_H
-#define CKEYSTATEIMPL_H
+#ifndef CKEYSTATETESTS_H
+#define CKEYSTATETESTS_H
#include "CKeyState.h"
#include "gmock/gmock.h"
@@ -24,9 +24,8 @@
class CMockKeyMap;
class CMockEventQueue;
-// while the class name indicates that this is actually a mock, we use a
-// typedef later to rename it (so the name matches the compilation unit)
-// so the tests are less confusing.
+// NOTE: do not mock methods that are not pure virtual. this mock exists only
+// to provide an implementation of the CKeyState abstract class.
class CMockKeyState : public CKeyState
{
public:
@@ -47,9 +46,6 @@ public:
MOCK_CONST_METHOD1(pollPressedKeys, void(KeyButtonSet&));
};
-// hide that we're actually testing a mock to make the unit tests less
-// confusing. use NiceMock so that we don't get warnings for unexpected
-// calls.
typedef ::testing::NiceMock CKeyStateImpl;
typedef UInt32 KeyID;
@@ -57,4 +53,21 @@ typedef UInt32 KeyID;
typedef void (*ForeachKeyCallback)(
KeyID, SInt32 group, CKeyMap::KeyItem&, void* userData);
+void
+stubPollPressedKeys(IKeyState::KeyButtonSet& pressedKeys);
+
+void
+assertMaskIsOne(ForeachKeyCallback cb, void* userData);
+
+const CKeyMap::KeyItem*
+stubMapKey(
+ CKeyMap::Keystrokes& keys, KeyID id, SInt32 group,
+ CKeyMap::ModifierToKeys& activeModifiers,
+ KeyModifierMask& currentState,
+ KeyModifierMask desiredMask,
+ bool isAutoRepeat);
+
+CKeyMap::Keystroke s_stubKeystroke(1, false, false);
+CKeyMap::KeyItem s_stubKeyItem;
+
#endif
diff --git a/src/test/unittests/synergy/CMockKeyMap.h b/src/test/unittests/synergy/CMockKeyMap.h
index d5a8ac78..2fbf88d7 100644
--- a/src/test/unittests/synergy/CMockKeyMap.h
+++ b/src/test/unittests/synergy/CMockKeyMap.h
@@ -29,6 +29,9 @@ public:
MOCK_METHOD2(foreachKey, void(ForeachKeyCallback, void*));
MOCK_METHOD1(addHalfDuplexModifier, void(KeyID));
MOCK_CONST_METHOD2(isHalfDuplex, bool(KeyID, KeyButton));
+ MOCK_CONST_METHOD7(mapKey, const CKeyMap::KeyItem*(
+ Keystrokes&, KeyID, SInt32, ModifierToKeys&, KeyModifierMask&,
+ KeyModifierMask, bool));
};
#endif