merged 1.4 r1043:1044 into trunk
This commit is contained in:
parent
7f4138a376
commit
2fe11744cf
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CMSWINDOWSHOOKLIBRARYLOADER_H
|
||||
#define CMSWINDOWSHOOKLIBRARYLOADER_H
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#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
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "CString.h"
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ public:
|
|||
typedef std::vector<KeyID> 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:
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include "CLog.h"
|
||||
#include "CStringUtil.h"
|
||||
#include "stdmap.h"
|
||||
#include <cstddef>
|
||||
#include <algorithm>
|
||||
#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<KeyCode>(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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GLOBAL_H
|
||||
#define GLOBAL_H
|
||||
|
||||
// Makes everything public for unit tests
|
||||
#ifdef TEST_ENV
|
||||
#define protected public
|
||||
#define private public
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -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
|
||||
/*!
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
#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<CMSWindowsKeyStateTests>(
|
||||
this, &CMSWindowsKeyStateTests::updateKeysCB));
|
||||
}
|
||||
|
||||
virtual void TearDown()
|
||||
{
|
||||
delete m_screensaver;
|
||||
delete m_desks;
|
||||
}
|
||||
|
||||
CMSWindowsDesks* getDesks() const
|
||||
{
|
||||
return m_desks;
|
||||
}
|
||||
|
||||
void* getEventTarget() const
|
||||
{
|
||||
return const_cast<CMSWindowsKeyStateTests*>(this);
|
||||
}
|
||||
|
||||
private:
|
||||
void updateKeysCB(void*) { }
|
||||
HINSTANCE m_hookLibrary;
|
||||
IScreenSaver* m_screensaver;
|
||||
CMSWindowsDesks* m_desks;
|
||||
CMSWindowsHookLibraryLoader m_hookLibraryLoader;
|
||||
};
|
||||
|
||||
TEST_F(CMSWindowsKeyStateTests, disable_nonWin95OS_eventQueueNotUsed)
|
||||
{
|
||||
NiceMock<CMockEventQueue> 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<CMockEventQueue> 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<CMockEventQueue> 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<CMockEventQueue> eventQueue;
|
||||
CMockKeyMap keyMap;
|
||||
CMSWindowsKeyState keyState(getDesks(), getEventTarget(), eventQueue, keyMap);
|
||||
|
||||
keyState.saveModifiers();
|
||||
|
||||
ASSERT_EQ(0, keyState.getSavedModifiers());
|
||||
}
|
||||
|
||||
TEST_F(CMSWindowsKeyStateTests, saveModifiers_shiftKeyDown_savedModifiers4)
|
||||
{
|
||||
NiceMock<CMockEventQueue> eventQueue;
|
||||
CMockKeyMap keyMap;
|
||||
CMSWindowsKeyState keyState(getDesks(), getEventTarget(), eventQueue, keyMap);
|
||||
getDesks()->enable();
|
||||
getDesks()->fakeKeyEvent(1, 1, true, false);
|
||||
|
||||
keyState.saveModifiers();
|
||||
|
||||
ASSERT_EQ(1, keyState.getSavedModifiers());
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#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";
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#define TEST_ENV
|
||||
#include "Global.h"
|
||||
|
||||
#include "CMockKeyMap.h"
|
||||
#include "CMockEventQueue.h"
|
||||
#include "CXWindowsKeyState.h"
|
||||
#include "CLog.h"
|
||||
#include <errno.h>
|
||||
|
||||
#define XK_LATIN1
|
||||
#define XK_MISCELLANY
|
||||
#include "X11/keysymdef.h"
|
||||
|
||||
#if HAVE_XKB_EXTENSION
|
||||
# include <X11/XKBlib.h>
|
||||
#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
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
set(h
|
||||
synergy/CKeyStateImpl.h
|
||||
synergy/CKeyStateTests.h
|
||||
synergy/CMockEventQueue.h
|
||||
synergy/CMockKeyMap.h
|
||||
)
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
#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<CMockKeyMap> keyMap;
|
||||
NiceMock<CMockEventQueue> 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<CMockKeyMap> keyMap;
|
||||
NiceMock<CMockEventQueue> 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<CMockKeyMap> keyMap;
|
||||
NiceMock<CMockEventQueue> 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<CMockKeyMap> keyMap;
|
||||
NiceMock<CMockEventQueue> 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<CMockKeyMap> 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<CMockKeyMap> 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<CMockKeyMap> 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<CMockKeyMap> 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<CMockKeyMap> 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<CMockKeyMap> 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<CMockKeyMap> 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<CMockKeyMap> 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<CMockKeyMap> 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<CMockKeyMap> 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;
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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<CMockKeyState> 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
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue