Merged primary and secondary screens into one class.

This commit is contained in:
crs 2003-09-02 22:05:47 +00:00
parent 4fea7719f3
commit 47ca409ff9
57 changed files with 8263 additions and 9809 deletions

View File

@ -13,7 +13,7 @@
*/ */
#include "CClient.h" #include "CClient.h"
#include "ISecondaryScreenFactory.h" #include "IScreenFactory.h"
#include "ProtocolTypes.h" #include "ProtocolTypes.h"
#include "Version.h" #include "Version.h"
#include "XScreen.h" #include "XScreen.h"
@ -35,14 +35,13 @@
#define DAEMON_RUNNING(running_) #define DAEMON_RUNNING(running_)
#if WINDOWS_LIKE #if WINDOWS_LIKE
#include "CMSWindowsScreen.h" #include "CMSWindowsScreen.h"
#include "CMSWindowsSecondaryScreen.h"
#include "CArchMiscWindows.h" #include "CArchMiscWindows.h"
#include "CMSWindowsClientTaskBarReceiver.h" #include "CMSWindowsClientTaskBarReceiver.h"
#include "resource.h" #include "resource.h"
#undef DAEMON_RUNNING #undef DAEMON_RUNNING
#define DAEMON_RUNNING(running_) CArchMiscWindows::daemonRunning(running_) #define DAEMON_RUNNING(running_) CArchMiscWindows::daemonRunning(running_)
#elif UNIX_LIKE #elif UNIX_LIKE
#include "CXWindowsSecondaryScreen.h" #include "CXWindowsScreen.h"
#include "CXWindowsClientTaskBarReceiver.h" #include "CXWindowsClientTaskBarReceiver.h"
#endif #endif
@ -88,28 +87,28 @@ CArgs* CArgs::s_instance = NULL;
// platform dependent factories // platform dependent factories
// //
//! Factory for creating secondary screens //! Factory for creating screens
/*! /*!
Objects of this type create secondary screens appropriate for the Objects of this type create screens appropriate for the platform.
platform.
*/ */
class CSecondaryScreenFactory : public ISecondaryScreenFactory { class CScreenFactory : public IScreenFactory {
public: public:
CSecondaryScreenFactory() { } CScreenFactory() { }
virtual ~CSecondaryScreenFactory() { } virtual ~CScreenFactory() { }
// ISecondaryScreenFactory overrides // IScreenFactory overrides
virtual CSecondaryScreen* virtual IPlatformScreen*
create(IScreenReceiver*); create(IScreenReceiver*, IPrimaryScreenReceiver*);
}; };
CSecondaryScreen* IPlatformScreen*
CSecondaryScreenFactory::create(IScreenReceiver* receiver) CScreenFactory::create(IScreenReceiver* receiver,
IPrimaryScreenReceiver* primaryReceiver)
{ {
#if WINDOWS_LIKE #if WINDOWS_LIKE
return new CMSWindowsSecondaryScreen(receiver); return new CMSWindowsScreen(receiver, primaryReceiver);
#elif UNIX_LIKE #elif UNIX_LIKE
return new CXWindowsSecondaryScreen(receiver); return new CXWindowsScreen(receiver, primaryReceiver);
#endif #endif
} }
@ -167,7 +166,7 @@ realMain(void)
// create client // create client
s_client = new CClient(ARG->m_name); s_client = new CClient(ARG->m_name);
s_client->setAddress(ARG->m_serverAddress); s_client->setAddress(ARG->m_serverAddress);
s_client->setScreenFactory(new CSecondaryScreenFactory); s_client->setScreenFactory(new CScreenFactory);
s_client->setSocketFactory(new CTCPSocketFactory); s_client->setSocketFactory(new CTCPSocketFactory);
s_client->setStreamFilterFactory(NULL); s_client->setStreamFilterFactory(NULL);

View File

@ -14,7 +14,7 @@
#include "CServer.h" #include "CServer.h"
#include "CConfig.h" #include "CConfig.h"
#include "IPrimaryScreenFactory.h" #include "IScreenFactory.h"
#include "ProtocolTypes.h" #include "ProtocolTypes.h"
#include "Version.h" #include "Version.h"
#include "XScreen.h" #include "XScreen.h"
@ -34,14 +34,13 @@
#define DAEMON_RUNNING(running_) #define DAEMON_RUNNING(running_)
#if WINDOWS_LIKE #if WINDOWS_LIKE
#include "CMSWindowsScreen.h" #include "CMSWindowsScreen.h"
#include "CMSWindowsPrimaryScreen.h"
#include "CArchMiscWindows.h" #include "CArchMiscWindows.h"
#include "CMSWindowsServerTaskBarReceiver.h" #include "CMSWindowsServerTaskBarReceiver.h"
#include "resource.h" #include "resource.h"
#undef DAEMON_RUNNING #undef DAEMON_RUNNING
#define DAEMON_RUNNING(running_) CArchMiscWindows::daemonRunning(running_) #define DAEMON_RUNNING(running_) CArchMiscWindows::daemonRunning(running_)
#elif UNIX_LIKE #elif UNIX_LIKE
#include "CXWindowsPrimaryScreen.h" #include "CXWindowsScreen.h"
#include "CXWindowsServerTaskBarReceiver.h" #include "CXWindowsServerTaskBarReceiver.h"
#endif #endif
@ -100,29 +99,28 @@ CArgs* CArgs::s_instance = NULL;
// platform dependent factories // platform dependent factories
// //
//! Factory for creating primary screens //! Factory for creating screens
/*! /*!
Objects of this type create primary screens appropriate for the Objects of this type create screens appropriate for the platform.
platform.
*/ */
class CPrimaryScreenFactory : public IPrimaryScreenFactory { class CScreenFactory : public IScreenFactory {
public: public:
CPrimaryScreenFactory() { } CScreenFactory() { }
virtual ~CPrimaryScreenFactory() { } virtual ~CScreenFactory() { }
// IPrimaryScreenFactory overrides // IScreenFactory overrides
virtual CPrimaryScreen* virtual IPlatformScreen*
create(IScreenReceiver*, IPrimaryScreenReceiver*); create(IScreenReceiver*, IPrimaryScreenReceiver*);
}; };
CPrimaryScreen* IPlatformScreen*
CPrimaryScreenFactory::create(IScreenReceiver* receiver, CScreenFactory::create(IScreenReceiver* receiver,
IPrimaryScreenReceiver* primaryReceiver) IPrimaryScreenReceiver* primaryReceiver)
{ {
#if WINDOWS_LIKE #if WINDOWS_LIKE
return new CMSWindowsPrimaryScreen(receiver, primaryReceiver); return new CMSWindowsScreen(receiver, primaryReceiver);
#elif UNIX_LIKE #elif UNIX_LIKE
return new CXWindowsPrimaryScreen(receiver, primaryReceiver); return new CXWindowsScreen(receiver, primaryReceiver);
#endif #endif
} }
@ -201,7 +199,7 @@ realMain(void)
// create server // create server
s_server = new CServer(ARG->m_name); s_server = new CServer(ARG->m_name);
s_server->setConfig(ARG->m_config); s_server->setConfig(ARG->m_config);
s_server->setScreenFactory(new CPrimaryScreenFactory); s_server->setScreenFactory(new CScreenFactory);
s_server->setSocketFactory(new CTCPSocketFactory); s_server->setSocketFactory(new CTCPSocketFactory);
s_server->setStreamFilterFactory(NULL); s_server->setStreamFilterFactory(NULL);

View File

@ -96,7 +96,7 @@ dnl checks for system services
dnl adjust variables for X11 and pthreads dnl adjust variables for X11 and pthreads
CXXFLAGS="$CXXFLAGS $SYNERGY_CXXFLAGS $X_CFLAGS $PTHREAD_CFLAGS" CXXFLAGS="$CXXFLAGS $SYNERGY_CXXFLAGS $X_CFLAGS $PTHREAD_CFLAGS -D_BSD_SOURCE -D_XOPEN_SOURCE=500"
LIBS="$NANOSLEEP_LIBS $INET_ATON_LIBS $PTHREAD_LIBS $LIBS" LIBS="$NANOSLEEP_LIBS $INET_ATON_LIBS $PTHREAD_LIBS $LIBS"
AC_OUTPUT([ AC_OUTPUT([

View File

@ -32,6 +32,7 @@
# include "CArchDaemonWindows.h" # include "CArchDaemonWindows.h"
# include "CArchFileWindows.h" # include "CArchFileWindows.h"
# include "CArchLogWindows.h" # include "CArchLogWindows.h"
# include "CArchMiscWindows.h"
# include "CArchMultithreadWindows.h" # include "CArchMultithreadWindows.h"
# include "CArchNetworkWinsock.h" # include "CArchNetworkWinsock.h"
# include "CArchSleepWindows.h" # include "CArchSleepWindows.h"
@ -116,6 +117,10 @@ CArch::CArch(ARCH_ARGS* args)
m_console = new ARCH_CONSOLE; m_console = new ARCH_CONSOLE;
m_daemon = new ARCH_DAEMON; m_daemon = new ARCH_DAEMON;
m_taskbar = new ARCH_TASKBAR(args); m_taskbar = new ARCH_TASKBAR(args);
#if WINDOWS_LIKE
CArchMiscWindows::init();
#endif
} }
CArch::~CArch() CArch::~CArch()

View File

@ -29,6 +29,13 @@ CArchConsoleWindows::CArchConsoleWindows() :
s_thread = ARCH->newCurrentThread(); s_thread = ARCH->newCurrentThread();
m_mutex = ARCH->newMutex(); m_mutex = ARCH->newMutex();
// dummy write to stderr to create locks in stdio from the main
// thread. if we open the console from another thread then we
// can deadlock in stdio when trying to write from a 3rd thread.
// writes to stderr without a console don't go anywhere so the
// user won't notice this.
fprintf(stderr, "\n");
} }
CArchConsoleWindows::~CArchConsoleWindows() CArchConsoleWindows::~CArchConsoleWindows()

View File

@ -19,16 +19,31 @@
// CArchMiscWindows // CArchMiscWindows
// //
void
CArchMiscWindows::init()
{
isWindows95Family();
}
bool bool
CArchMiscWindows::isWindows95Family() CArchMiscWindows::isWindows95Family()
{ {
static bool init = false;
static bool result = false;
if (!init) {
OSVERSIONINFO version; OSVERSIONINFO version;
version.dwOSVersionInfoSize = sizeof(version); version.dwOSVersionInfoSize = sizeof(version);
if (GetVersionEx(&version) == 0) { if (GetVersionEx(&version) == 0) {
// cannot determine OS; assume windows 95 family // cannot determine OS; assume windows 95 family
return true; result = true;
} }
return (version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS); else {
result = (version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
}
init = true;
}
return result;
} }
int int

View File

@ -26,6 +26,9 @@ class CArchMiscWindows {
public: public:
typedef int (*RunFunc)(void); typedef int (*RunFunc)(void);
//! Initialize
static void init();
//! Test if windows 95, et al. //! Test if windows 95, et al.
/*! /*!
Returns true iff the platform is win95/98/me. Returns true iff the platform is win95/98/me.

View File

@ -252,14 +252,12 @@ CArchMultithreadPosix::waitCondVar(CArchCond cond,
CArchMutex CArchMutex
CArchMultithreadPosix::newMutex() CArchMultithreadPosix::newMutex()
{ {
pthread_mutexattr_t attr;
int status = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
assert(status == 0);
CArchMutexImpl* mutex = new CArchMutexImpl; CArchMutexImpl* mutex = new CArchMutexImpl;
int status = pthread_mutex_init(&mutex->m_mutex, NULL); status = pthread_mutex_init(&mutex->m_mutex, &attr);
assert(status == 0); assert(status == 0);
/*
status = pthread_mutexattr_settype(&mutex->m_mutex,
PTHREAD_MUTEX_RECURSIVE);
assert(status == 0);
*/
return mutex; return mutex;
} }

View File

@ -124,11 +124,11 @@ public:
// mutex methods // mutex methods
// //
//! Create a non-recursive mutex //! Create a recursive mutex
/*! /*!
Creates a non-recursive mutex. A thread must not lock a Creates a recursive mutex. A thread may lock a recursive mutex
non-recursive mutex when it already holds a lock on that mutex. when it already holds a lock on that mutex. The mutex is an
If it does it will deadlock. The mutex is an opaque data type. opaque data type.
*/ */
virtual CArchMutex newMutex() = 0; virtual CArchMutex newMutex() = 0;

125
lib/base/CPriorityQueue.h Normal file
View File

@ -0,0 +1,125 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* 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.
*/
#ifndef CPRIORITYQUEUE_H
#define CPRIORITYQUEUE_H
#include "stdvector.h"
#include <algorithm>
#include <functional>
//! A priority queue with an iterator
/*!
This priority queue is the same as a standard priority queue except:
it sorts by std::greater, it has a forward iterator through the elements
(which can appear in any order), and its contents can be swapped.
*/
template <class T, class Container = std::vector<T>,
class Compare = std::greater<typename Container::value_type> >
class CPriorityQueue {
public:
typedef typename Container::value_type value_type;
typedef typename Container::size_type size_type;
typedef typename Container::iterator iterator;
typedef typename Container::const_iterator const_iterator;
typedef Container container_type;
CPriorityQueue() { }
CPriorityQueue(Container& swappedIn) { swap(swappedIn); }
~CPriorityQueue() { }
//! @name manipulators
//@{
//! Add element
void push(const value_type& v)
{
c.push_back(v);
std::push_heap(c.begin(), c.end(), comp);
}
//! Remove head element
void pop()
{
std::pop_heap(c.begin(), c.end(), comp);
c.pop_back();
}
//! Get start iterator
iterator begin()
{
return c.begin();
}
//! Get end iterator
iterator end()
{
return c.end();
}
//! Swap contents with another priority queue
void swap(CPriorityQueue<T, Container, Compare>& q)
{
c.swap(q.c);
}
//! Swap contents with another container
void swap(Container& c2)
{
c.swap(c2);
std::make_heap(c.begin(), c.end(), comp);
}
//@}
//! @name accessors
//@{
//! Returns true if there are no elements
bool empty() const
{
return c.empty();
}
//! Returns the number of elements
size_type size() const
{
return c.size();
}
//! Returns the head element
const value_type& top() const
{
return c.front();
}
//! Get start iterator
const_iterator begin() const
{
return c.begin();
}
//! Get end iterator
const_iterator end() const
{
return c.end();
}
//@}
private:
Container c;
Compare comp;
};
#endif

View File

@ -36,6 +36,7 @@ libbase_a_SOURCES = \
CFunctionJob.h \ CFunctionJob.h \
CJobList.h \ CJobList.h \
CLog.h \ CLog.h \
CPriorityQueue.h \
CStopwatch.h \ CStopwatch.h \
CString.h \ CString.h \
CStringUtil.h \ CStringUtil.h \

View File

@ -14,12 +14,13 @@
#include "CClient.h" #include "CClient.h"
#include "CServerProxy.h" #include "CServerProxy.h"
#include "ISecondaryScreenFactory.h" #include "CScreen.h"
#include "IScreenFactory.h"
#include "CClipboard.h" #include "CClipboard.h"
#include "CInputPacketStream.h" #include "CInputPacketStream.h"
#include "COutputPacketStream.h" #include "COutputPacketStream.h"
#include "CProtocolUtil.h" #include "CProtocolUtil.h"
#include "CSecondaryScreen.h" #include "IPlatformScreen.h"
#include "IServer.h" #include "IServer.h"
#include "ProtocolTypes.h" #include "ProtocolTypes.h"
#include "XScreen.h" #include "XScreen.h"
@ -72,7 +73,7 @@ CClient::setAddress(const CNetworkAddress& serverAddress)
} }
void void
CClient::setScreenFactory(ISecondaryScreenFactory* adopted) CClient::setScreenFactory(IScreenFactory* adopted)
{ {
CLock lock(&m_mutex); CLock lock(&m_mutex);
delete m_screenFactory; delete m_screenFactory;
@ -305,8 +306,9 @@ CClient::enter(SInt32 xAbs, SInt32 yAbs, UInt32, KeyModifierMask mask, bool)
CLock lock(&m_mutex); CLock lock(&m_mutex);
m_active = true; m_active = true;
} }
m_screen->mouseMove(xAbs, yAbs);
m_screen->enter(xAbs, yAbs, mask); m_screen->enter();
m_screen->setToggleState(mask);
} }
bool bool
@ -464,7 +466,10 @@ CClient::openSecondaryScreen()
// create screen // create screen
LOG((CLOG_DEBUG1 "creating secondary screen")); LOG((CLOG_DEBUG1 "creating secondary screen"));
if (m_screenFactory != NULL) { if (m_screenFactory != NULL) {
m_screen = m_screenFactory->create(this); IPlatformScreen* platformScreen = m_screenFactory->create(this, NULL);
if (platformScreen != NULL) {
m_screen = new CScreen(platformScreen, this);
}
} }
if (m_screen == NULL) { if (m_screen == NULL) {
throw XScreenOpenFailure(); throw XScreenOpenFailure();
@ -634,9 +639,11 @@ CClient::runServer()
m_server = proxy; m_server = proxy;
} }
bool enabled = false;
try { try {
// prepare for remote control // enable the screen
m_screen->remoteControl(); m_screen->enable();
enabled = true;
// process messages // process messages
bool rejected = true; bool rejected = true;
@ -647,8 +654,8 @@ CClient::runServer()
setStatus(kNotRunning); setStatus(kNotRunning);
} }
// prepare for local control // disable the screen
m_screen->localControl(); m_screen->disable();
// clean up // clean up
CLock lock(&m_mutex); CLock lock(&m_mutex);
@ -661,7 +668,9 @@ CClient::runServer()
} }
catch (...) { catch (...) {
setStatus(kNotRunning); setStatus(kNotRunning);
m_screen->localControl(); if (enabled) {
m_screen->disable();
}
CLock lock(&m_mutex); CLock lock(&m_mutex);
m_rejected = false; m_rejected = false;
m_server = NULL; m_server = NULL;

View File

@ -22,12 +22,12 @@
#include "CMutex.h" #include "CMutex.h"
#include "CJobList.h" #include "CJobList.h"
class CSecondaryScreen; class CScreen;
class CServerProxy; class CServerProxy;
class CThread; class CThread;
class IDataSocket; class IDataSocket;
class IScreenReceiver; class IScreenReceiver;
class ISecondaryScreenFactory; class IScreenFactory;
class ISocketFactory; class ISocketFactory;
class IStreamFilterFactory; class IStreamFilterFactory;
@ -60,13 +60,12 @@ public:
*/ */
void setAddress(const CNetworkAddress& serverAddress); void setAddress(const CNetworkAddress& serverAddress);
//! Set secondary screen factory //! Set screen factory
/*! /*!
Sets the factory for creating secondary screens. This must be Sets the factory for creating screens. This must be set before
set before calling open(). This object takes ownership of the calling open(). This object takes ownership of the factory.
factory.
*/ */
void setScreenFactory(ISecondaryScreenFactory*); void setScreenFactory(IScreenFactory*);
//! Set socket factory //! Set socket factory
/*! /*!
@ -184,10 +183,10 @@ private:
private: private:
CMutex m_mutex; CMutex m_mutex;
CString m_name; CString m_name;
CSecondaryScreen* m_screen; CScreen* m_screen;
IScreenReceiver* m_server; IScreenReceiver* m_server;
CNetworkAddress m_serverAddress; CNetworkAddress m_serverAddress;
ISecondaryScreenFactory* m_screenFactory; IScreenFactory* m_screenFactory;
ISocketFactory* m_socketFactory; ISocketFactory* m_socketFactory;
IStreamFilterFactory* m_streamFilterFactory; IStreamFilterFactory* m_streamFilterFactory;
CThread* m_session; CThread* m_session;

View File

@ -0,0 +1,75 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* 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.
*/
#include "CMSWindowsDesktop.h"
#include "CLog.h"
#include "CArchMiscWindows.h"
#include <malloc.h>
//
// CMSWindowsDesktop
//
HDESK
CMSWindowsDesktop::openInputDesktop()
{
if (CArchMiscWindows::isWindows95Family()) {
// there's only one desktop on windows 95 et al.
return GetThreadDesktop(GetCurrentThreadId());
}
else {
return OpenInputDesktop(DF_ALLOWOTHERACCOUNTHOOK, TRUE,
DESKTOP_CREATEWINDOW |
DESKTOP_HOOKCONTROL |
GENERIC_WRITE);
}
}
void
CMSWindowsDesktop::closeDesktop(HDESK desk)
{
// on 95/98/me we don't need to close the desktop returned by
// openInputDesktop().
if (desk != NULL && !CArchMiscWindows::isWindows95Family()) {
CloseDesktop(desk);
}
}
bool
CMSWindowsDesktop::setDesktop(HDESK desk)
{
// 95/98/me doesn't support multiple desktops so just return
// true on those platforms.
return (CArchMiscWindows::isWindows95Family() ||
SetThreadDesktop(desk) != 0);
}
CString
CMSWindowsDesktop::getDesktopName(HDESK desk)
{
if (desk == NULL) {
return CString();
}
else if (CArchMiscWindows::isWindows95Family()) {
return "desktop";
}
else {
DWORD size;
GetUserObjectInformation(desk, UOI_NAME, NULL, 0, &size);
TCHAR* name = (TCHAR*)alloca(size + sizeof(TCHAR));
GetUserObjectInformation(desk, UOI_NAME, name, size, &size);
CString result(name);
return result;
}
}

View File

@ -0,0 +1,52 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* 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.
*/
#ifndef CMSWINDOWSDESKTOP_H
#define CMSWINDOWSDESKTOP_H
#include "CString.h"
#include <windows.h>
//! Encapsulate Microsoft Windows desktop
class CMSWindowsDesktop {
public:
//! Open the input desktop
/*!
Opens the input desktop. The caller must close the desktop.
*/
static HDESK openInputDesktop();
//! Close a desktop
/*!
Closes the given desktop.
*/
static void closeDesktop(HDESK);
//! Change current desktop
/*!
Changes the calling thread's desktop, return true iff successful.
The call will fail if the calling thread has any windows or a hooks
on the current desktop.
*/
static bool setDesktop(HDESK);
//! Get the desktop's name.
/*!
Returns the current desktop's name. Returns a constant string
on 95/98/Me.
*/
static CString getDesktopName(HDESK);
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,142 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* 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.
*/
#ifndef CMSWINDOWSKEYMAPPER_H
#define CMSWINDOWSKEYMAPPER_H
#include "IKeyState.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
//! Microsoft Windows key mapper
/*!
This class maps KeyIDs to keystrokes.
*/
class CMSWindowsKeyMapper {
public:
CMSWindowsKeyMapper();
~CMSWindowsKeyMapper();
//! @name manipulators
//@{
//! Update key mapper
/*!
Updates the key mapper's internal tables according to the
current keyboard mapping and updates \c keyState.
*/
void update(IKeyState* keyState);
//! Update shadow key state
/*!
Updates the shadow keyboard state.
*/
void updateKey(KeyButton key, bool pressed);
//@}
//! @name accessors
//@{
//! Map key press/repeat to keystrokes
/*!
Converts a press/repeat of key \c id with the modifiers as given
in \c desiredMask into the keystrokes necessary to synthesize
that key event. Returns the platform specific code of the key
being pressed, or 0 if the key cannot be mapped or \c isAutoRepeat
is true and the key does not auto-repeat.
*/
KeyButton mapKey(IKeyState::Keystrokes&,
const IKeyState& keyState, KeyID id,
KeyModifierMask desiredMask,
bool isAutoRepeat) const;
//! Map key event to a key
/*!
Converts a key event into a KeyID and the shadow modifier state
to a modifier mask. If \c altgr is non-NULL it's set to true if
the key requires AltGr and false otherwise.
*/
KeyID mapKeyFromEvent(WPARAM vkCode, LPARAM info,
KeyModifierMask* maskOut, bool* altgr) const;
//! Test shadow key state
/*!
Returns true iff the shadow state indicates the key is pressed.
*/
bool isPressed(KeyButton key) const;
//! Map key to a scan code
/*!
Returns the scan code for \c key and possibly adjusts \c key.
*/
UINT keyToScanCode(KeyButton* key) const;
//! Check for extended key
/*!
Returns true iff \c key is an extended key
*/
bool isExtendedKey(KeyButton key) const;
//! Get name of key
/*!
Return a string describing the given key.
*/
const char* getKeyName(KeyButton) const;
//@}
private:
// convert a language ID to a code page
UINT getCodePageFromLangID(LANGID langid) const;
// map character \c c given keyboard layout \c hkl to the keystrokes
// to generate it.
KeyButton mapCharacter(IKeyState::Keystrokes& keys,
const IKeyState& keyState, char c, HKL hkl,
bool isAutoRepeat) const;
// map \c virtualKey to the keystrokes to generate it, along with
// keystrokes to update and restore the modifier state.
KeyButton mapToKeystrokes(IKeyState::Keystrokes& keys,
const IKeyState& keyState, KeyButton virtualKey,
KeyModifierMask desiredMask,
KeyModifierMask requiredMask,
bool isAutoRepeat) const;
// get keystrokes to get modifiers in a desired state
bool adjustModifiers(IKeyState::Keystrokes& keys,
IKeyState::Keystrokes& undo,
const IKeyState& keyState,
KeyModifierMask desiredMask,
KeyModifierMask requiredMask) const;
private:
class CModifierKeys {
public:
enum { s_maxKeys = 2 };
KeyModifierMask m_mask;
KeyButton m_keys[s_maxKeys];
};
BYTE m_keys[256];
static const CModifierKeys s_modifiers[];
static const char* s_vkToName[];
static const KeyID s_virtualKey[][2];
static const KeyButton s_mapE000[];
static const KeyButton s_mapEE00[];
static const KeyButton s_mapEF00[];
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,140 +0,0 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* 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.
*/
#ifndef CMSWINDOWSPRIMARYSCREEN_H
#define CMSWINDOWSPRIMARYSCREEN_H
#include "CPrimaryScreen.h"
#include "IMSWindowsScreenEventHandler.h"
#include "CSynergyHook.h"
#include "MouseTypes.h"
#include "CString.h"
class CMSWindowsScreen;
class IScreenReceiver;
class IPrimaryScreenReceiver;
//! Microsoft windows primary screen implementation
class CMSWindowsPrimaryScreen :
public CPrimaryScreen, public IMSWindowsScreenEventHandler {
public:
typedef bool (CMSWindowsPrimaryScreen::*HookMethod)(int, WPARAM, LPARAM);
CMSWindowsPrimaryScreen(IScreenReceiver*, IPrimaryScreenReceiver*);
virtual ~CMSWindowsPrimaryScreen();
// CPrimaryScreen overrides
virtual void reconfigure(UInt32 activeSides);
virtual void warpCursor(SInt32 x, SInt32 y);
virtual void resetOptions();
virtual void setOptions(const COptionsList& options);
virtual UInt32 addOneShotTimer(double timeout);
virtual KeyModifierMask getToggleMask() const;
virtual bool isLockedToScreen() const;
virtual IScreen* getScreen() const;
// IMSWindowsScreenEventHandler overrides
virtual void onScreensaver(bool activated);
virtual bool onPreDispatch(const CEvent* event);
virtual bool onEvent(CEvent* event);
virtual void onOneShotTimerExpired(UInt32 id);
virtual SInt32 getJumpZoneSize() const;
virtual void postCreateWindow(HWND);
virtual void preDestroyWindow(HWND);
virtual void onAccessibleDesktop();
protected:
// CPrimaryScreen overrides
virtual void onPreMainLoop();
virtual void onPreOpen();
virtual void onPostOpen();
virtual void onPostClose();
virtual void onPreEnter();
virtual void onPostEnter();
virtual void onPreLeave();
virtual void onPostLeave(bool);
virtual void createWindow();
virtual void destroyWindow();
virtual bool showWindow();
virtual void hideWindow();
virtual void warpCursorToCenter();
virtual void updateKeys();
private:
void enterNoWarp();
// warp cursor without discarding queued events
void warpCursorNoFlush(SInt32 x, SInt32 y);
// discard posted messages
void nextMark();
// test if event should be ignored
bool ignore() const;
// key and button queries
KeyID mapKey(WPARAM keycode, LPARAM info,
KeyModifierMask* maskOut, bool* altgr);
ButtonID mapButton(WPARAM msg, LPARAM button) const;
void updateKey(UINT vkCode, bool press);
bool isModifier(UINT vkCode) const;
KeyButton mapKeyToScanCode(UINT vk1, UINT vk2) const;
private:
IPrimaryScreenReceiver* m_receiver;
CMSWindowsScreen* m_screen;
// true if windows 95/98/me
bool m_is95Family;
// the main loop's thread id
DWORD m_threadID;
// my window
HWND m_window;
// used to discard queued messages that are no longer needed
UInt32 m_mark;
UInt32 m_markReceived;
// map of key state
BYTE m_keys[256];
// map of button state
BYTE m_buttons[1 + kButtonExtra0 + 1];
// last mouse position
SInt32 m_x, m_y;
// position of center pixel of screen
SInt32 m_xCenter, m_yCenter;
// hook library stuff
HINSTANCE m_hookLibrary;
InitFunc m_init;
CleanupFunc m_cleanup;
InstallFunc m_install;
UninstallFunc m_uninstall;
SetSidesFunc m_setSides;
SetZoneFunc m_setZone;
SetRelayFunc m_setRelay;
bool m_lowLevel;
// stuff for hiding the cursor
DWORD m_cursorThread;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -15,7 +15,8 @@
#ifndef CMSWINDOWSSCREEN_H #ifndef CMSWINDOWSSCREEN_H
#define CMSWINDOWSSCREEN_H #define CMSWINDOWSSCREEN_H
#include "IScreen.h" #include "IPlatformScreen.h"
#include "CMSWindowsKeyMapper.h"
#include "CSynergyHook.h" #include "CSynergyHook.h"
#include "CMutex.h" #include "CMutex.h"
#include "CString.h" #include "CString.h"
@ -23,22 +24,13 @@
#include <windows.h> #include <windows.h>
class CMSWindowsScreenSaver; class CMSWindowsScreenSaver;
class CThread;
// Microsoft windows event
class CEvent {
public:
MSG m_msg;
LRESULT m_result;
};
class IScreenReceiver; class IScreenReceiver;
class IMSWindowsScreenEventHandler; class IPrimaryScreenReceiver;
//! Implementation of IScreen for Microsoft Windows //! Implementation of IPlatformScreen for Microsoft Windows
class CMSWindowsScreen : public IScreen { class CMSWindowsScreen : public IPlatformScreen {
public: public:
CMSWindowsScreen(IScreenReceiver*, IMSWindowsScreenEventHandler*); CMSWindowsScreen(IScreenReceiver*, IPrimaryScreenReceiver*);
virtual ~CMSWindowsScreen(); virtual ~CMSWindowsScreen();
//! @name manipulators //! @name manipulators
@ -51,37 +43,10 @@ public:
*/ */
static void init(HINSTANCE); static void init(HINSTANCE);
//! Open desktop
/*!
Open the desktop and create and return the window. Returns NULL
on failure.
*/
HWND openDesktop();
//! Close desktop
/*!
Close the window and desktop.
*/
void closeDesktop();
//! Install a one-shot timer
/*!
Installs a one-shot timer for \c timeout seconds and returns the
id of the timer (which will be passed to the receiver's
\c onTimerExpired()).
*/
UInt32 addOneShotTimer(double timeout);
//@} //@}
//! @name accessors //! @name accessors
//@{ //@{
//! Test for multiple monitors
/*!
Returns true iff the system appears to have multiple monitors.
*/
bool isMultimon() const;
//! Get instance //! Get instance
/*! /*!
Returns the application instance handle passed to init(). Returns the application instance handle passed to init().
@ -90,53 +55,116 @@ public:
//@} //@}
// IScreen overrides // IPlatformScreen overrides
// note -- this class expects the hook DLL to have been loaded virtual void open(IKeyState*);
// and initialized before open() is called. virtual void close();
void open(); virtual void enable();
void mainLoop(); virtual void disable();
void exitMainLoop(); virtual void mainLoop();
void close(); virtual void exitMainLoop();
bool setClipboard(ClipboardID, const IClipboard*); virtual void enter();
void checkClipboards(); virtual bool leave();
void openScreensaver(bool notify); virtual bool setClipboard(ClipboardID, const IClipboard*);
void closeScreensaver(); virtual void checkClipboards();
void screensaver(bool activate); virtual void openScreensaver(bool notify);
void syncDesktop(); virtual void closeScreensaver();
bool getClipboard(ClipboardID, IClipboard*) const; virtual void screensaver(bool activate);
void getShape(SInt32&, SInt32&, SInt32&, SInt32&) const; virtual void resetOptions();
void getCursorPos(SInt32&, SInt32&) const; virtual void setOptions(const COptionsList& options);
void getCursorCenter(SInt32&, SInt32&) const; virtual void updateKeys();
virtual bool isPrimary() const;
virtual bool getClipboard(ClipboardID, IClipboard*) const;
virtual void getShape(SInt32&, SInt32&, SInt32&, SInt32&) const;
virtual void getCursorPos(SInt32&, SInt32&) const;
// IPrimaryScreen overrides
virtual void reconfigure(UInt32 activeSides);
virtual void warpCursor(SInt32 x, SInt32 y);
virtual UInt32 addOneShotTimer(double timeout);
virtual SInt32 getJumpZoneSize() const;
virtual bool isAnyMouseButtonDown() const;
virtual const char* getKeyName(KeyButton) const;
// ISecondaryScreen overrides
virtual void fakeKeyEvent(KeyButton id, bool press) const;
virtual bool fakeCtrlAltDel() const;
virtual void fakeMouseButton(ButtonID id, bool press) const;
virtual void fakeMouseMove(SInt32 x, SInt32 y) const;
virtual void fakeMouseWheel(SInt32 delta) const;
virtual KeyButton mapKey(IKeyState::Keystrokes&,
const IKeyState& keyState, KeyID id,
KeyModifierMask desiredMask,
bool isAutoRepeat) const;
private: private:
// update screen size cache // update screen size cache
void updateScreenShape(); void updateScreenShape();
// internal pre-dispatch event processing
bool onPreDispatch(const CEvent* event);
// internal (post-dispatch) event processing
bool onEvent(CEvent* event);
// create the transparent cursor
void createBlankCursor();
// switch to the given desktop. this destroys the window and unhooks // switch to the given desktop. this destroys the window and unhooks
// all hooks, switches the desktop, then creates the window and rehooks // all hooks, switches the desktop, then creates the window and rehooks
// all hooks (because you can't switch the thread's desktop if it has // all hooks (because you can't switch the thread's desktop if it has
// any windows or hooks). // any windows or hooks).
bool switchDesktop(HDESK desk); bool switchDesktop(HDESK desk);
// get the input desktop. caller must CloseDesktop() the result. // make sure we're on the expected desktop
// do not call under windows 95/98/me. void syncDesktop() const;
HDESK openInputDesktop() const;
// get the desktop's name. do not call under windows 95/98/me. // handle message before it gets dispatched. returns true iff
CString getDesktopName(HDESK) const; // the message should not be dispatched.
bool onPreDispatch(HWND, UINT, WPARAM, LPARAM);
// returns true iff desk is the current desk. do not call under // handle message before it gets dispatched. returns true iff
// windows 95/98/me. // the message should not be dispatched.
bool isCurrentDesktop(HDESK desk) const; bool onPreDispatchPrimary(HWND, UINT, WPARAM, LPARAM);
// handle message. returns true iff handled and optionally sets
// \c *result (which defaults to 0).
bool onEvent(HWND, UINT, WPARAM, LPARAM, LRESULT* result);
// message handlers
bool onMark(UInt32 mark);
bool onKey(WPARAM, LPARAM);
bool onMouseButton(WPARAM, LPARAM);
bool onMouseMove(SInt32 x, SInt32 y);
bool onMouseWheel(SInt32 delta);
bool onScreensaver(bool activated);
bool onTimer(UINT timerID);
bool onDisplayChange();
bool onClipboardChange();
bool onActivate(bool activated);
// XXX
// warp cursor without discarding queued events
void warpCursorNoFlush(SInt32 x, SInt32 y);
// discard posted messages
void nextMark();
// test if event should be ignored
bool ignore() const;
// XXX
// create the transparent cursor
HCURSOR createBlankCursor() const;
// show/hide the cursor
void showCursor(bool) const;
// enable/disable special key combinations so we can catch/pass them
void enableSpecialKeys(bool) const;
// map a button ID and action to a mouse event
DWORD mapButtonToEvent(ButtonID button,
bool press, DWORD* inData) const;
// map a button event to a button ID
ButtonID mapButtonFromEvent(WPARAM msg, LPARAM button) const;
// return true iff the given virtual key is a modifier
bool isModifier(UINT vkCode) const;
// send ctrl+alt+del hotkey event
static void ctrlAltDelThread(void*);
// our window proc // our window proc
static LRESULT CALLBACK wndProc(HWND, UINT, WPARAM, LPARAM); static LRESULT CALLBACK wndProc(HWND, UINT, WPARAM, LPARAM);
@ -144,53 +172,63 @@ private:
private: private:
static HINSTANCE s_instance; static HINSTANCE s_instance;
IScreenReceiver* m_receiver; // true if screen is being used as a primary screen, false otherwise
IMSWindowsScreenEventHandler* m_eventHandler; bool m_isPrimary;
ATOM m_class;
HICON m_icon;
HCURSOR m_cursor;
// true if windows 95/98/me // true if windows 95/98/me
bool m_is95Family; bool m_is95Family;
// our window // receivers
IScreenReceiver* m_receiver;
IPrimaryScreenReceiver* m_primaryReceiver;
// true if mouse has entered the screen
bool m_isOnScreen;
// our resources
ATOM m_class;
HCURSOR m_cursor;
HWND m_window; HWND m_window;
// screen shape // screen shape stuff
SInt32 m_x, m_y; SInt32 m_x, m_y;
SInt32 m_w, m_h; SInt32 m_w, m_h;
SInt32 m_xCenter, m_yCenter;
// true if system appears to have multiple monitors // true if system appears to have multiple monitors
bool m_multimon; bool m_multimon;
// last mouse position
SInt32 m_xCursor, m_yCursor;
// used to discard queued messages that are no longer needed
UInt32 m_mark;
UInt32 m_markReceived;
// the main loop's thread id // the main loop's thread id
DWORD m_threadID; DWORD m_threadID;
// the thread id of the last attached thread // the thread id of the last attached thread
DWORD m_lastThreadID; DWORD m_lastThreadID;
// clipboard stuff
HWND m_nextClipboardWindow;
bool m_ownClipboard;
// the timer used to check for desktop switching // the timer used to check for desktop switching
UINT m_timer; UINT m_timer;
// the one shot timer // the one shot timer
UINT m_oneShotTimer; UINT m_oneShotTimer;
// screen saver stuff
CMSWindowsScreenSaver* m_screensaver;
bool m_screensaverNotify;
// clipboard stuff
HWND m_nextClipboardWindow;
bool m_ownClipboard;
// the current desk and it's name // the current desk and it's name
HDESK m_desk; HDESK m_desk;
CString m_deskName; CString m_deskName;
// screen saver stuff
HINSTANCE m_hookLibrary;
InstallScreenSaverFunc m_installScreensaver;
UninstallScreenSaverFunc m_uninstallScreensaver;
CMSWindowsScreenSaver* m_screensaver;
bool m_screensaverNotify;
// true when the current desktop is inaccessible. while // true when the current desktop is inaccessible. while
// the desktop is inaccessible we won't receive user input // the desktop is inaccessible we won't receive user input
// and we'll lose track of the keyboard state. when the // and we'll lose track of the keyboard state. when the
@ -198,6 +236,29 @@ private:
// handler of that. // handler of that.
bool m_inaccessibleDesktop; bool m_inaccessibleDesktop;
// hook library stuff
HINSTANCE m_hookLibrary;
InitFunc m_init;
CleanupFunc m_cleanup;
InstallFunc m_install;
UninstallFunc m_uninstall;
SetSidesFunc m_setSides;
SetZoneFunc m_setZone;
SetModeFunc m_setMode;
InstallScreenSaverFunc m_installScreensaver;
UninstallScreenSaverFunc m_uninstallScreensaver;
bool m_lowLevel;
// keyboard stuff
IKeyState* m_keyState;
CMSWindowsKeyMapper m_keyMapper;
// map of button state
BYTE m_buttons[1 + kButtonExtra0 + 1];
// stuff for hiding the cursor
DWORD m_cursorThread;
static CMSWindowsScreen* s_screen; static CMSWindowsScreen* s_screen;
}; };

File diff suppressed because it is too large Load Diff

View File

@ -1,137 +0,0 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* 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.
*/
#ifndef CMSWINDOWSSECONDARYSCREEN_H
#define CMSWINDOWSSECONDARYSCREEN_H
// ensure that we get SendInput()
#if _WIN32_WINNT <= 0x400
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x401
#endif
#include "CSecondaryScreen.h"
#include "IMSWindowsScreenEventHandler.h"
#include "CMutex.h"
#include "CString.h"
class CMSWindowsScreen;
class IScreenReceiver;
//! Microsoft windows secondary screen implementation
class CMSWindowsSecondaryScreen :
public CSecondaryScreen, public IMSWindowsScreenEventHandler {
public:
CMSWindowsSecondaryScreen(IScreenReceiver*);
virtual ~CMSWindowsSecondaryScreen();
// CSecondaryScreen overrides
virtual IScreen* getScreen() const;
// IMSWindowsScreenEventHandler overrides
virtual void onScreensaver(bool activated);
virtual bool onPreDispatch(const CEvent* event);
virtual bool onEvent(CEvent* event);
virtual void onOneShotTimerExpired(UInt32 id);
virtual void postCreateWindow(HWND);
virtual void preDestroyWindow(HWND);
virtual void onAccessibleDesktop();
protected:
// CSecondaryScreen overrides
virtual void onPreMainLoop();
virtual void onPreOpen();
virtual void onPreEnter();
virtual void onPreLeave();
virtual void createWindow();
virtual void destroyWindow();
virtual void showWindow(SInt32 x, SInt32 y);
virtual void hideWindow();
virtual void updateKeys(KeyState* sysKeyStates);
virtual KeyModifierMask getModifiers() const;
virtual SysKeyID getUnhanded(SysKeyID) const;
virtual SysKeyID getOtherHanded(SysKeyID) const;
virtual bool isAutoRepeating(SysKeyID) const;
virtual KeyModifierMask getModifierKeyMask(SysKeyID) const;
virtual bool isModifierActive(SysKeyID) const;
virtual SysKeyID getToggleSysKey(KeyID keyID) const;
virtual bool synthesizeCtrlAltDel(EKeyAction);
virtual void sync() const;
virtual KeyModifierMask
mapKey(Keystrokes&, SysKeyID& sysKeyID, KeyID,
KeyModifierMask, KeyModifierMask, EKeyAction) const;
virtual void fakeKeyEvent(SysKeyID, bool press) const;
virtual void fakeMouseButton(ButtonID, bool press) const;
virtual void fakeMouseMove(SInt32 x, SInt32 y) const;
virtual void fakeMouseWheel(SInt32 delta) const;
private:
class CModifierInfo {
public:
KeyModifierMask m_mask;
UINT m_virtualKey;
UINT m_virtualKey2;
bool m_isToggle;
};
// open/close desktop (for windows 95/98/me)
bool openDesktop();
void closeDesktop();
// make desk the thread desktop (for windows NT/2000/XP)
bool switchDesktop(HDESK desk);
// returns true iff there appear to be multiple monitors
bool isMultimon() const;
// key and button queries and operations
DWORD mapButton(ButtonID button,
bool press, DWORD* data) const;
UINT mapCharacter(Keystrokes& keys,
char c, HKL hkl,
KeyModifierMask currentMask,
KeyModifierMask desiredMask,
EKeyAction action) const;
KeyModifierMask mapToKeystrokes(Keystrokes& keys,
UINT virtualKey,
KeyModifierMask currentMask,
KeyModifierMask desiredMask,
EKeyAction action) const;
const CModifierInfo* getModifierInfo(UINT virtualKey) const;
KeyState getKeyState(UINT virtualKey) const;
UINT virtualKeyToScanCode(UINT& virtualKey) const;
bool isExtendedKey(UINT virtualKey) const;
UINT getCodePageFromLangID(LANGID) const;
// thread that generates fake ctrl+alt+del
static void ctrlAltDelThread(void*);
private:
CMutex m_mutex;
CMSWindowsScreen* m_screen;
// true if windows 95/98/me
bool m_is95Family;
// our window
HWND m_window;
// modifier table
static const CModifierInfo s_modifier[];
};
#endif

View File

@ -82,7 +82,7 @@ static HANDLE g_hookEventLL = NULL;
static HHOOK g_keyboardLL = NULL; static HHOOK g_keyboardLL = NULL;
static HHOOK g_mouseLL = NULL; static HHOOK g_mouseLL = NULL;
static bool g_screenSaver = false; static bool g_screenSaver = false;
static bool g_relay = false; static EHookMode g_mode = kHOOK_WATCH_JUMP_ZONE;
static UInt32 g_zoneSides = 0; static UInt32 g_zoneSides = 0;
static SInt32 g_zoneSize = 0; static SInt32 g_zoneSize = 0;
static SInt32 g_xScreen = 0; static SInt32 g_xScreen = 0;
@ -151,7 +151,7 @@ keyboardHookHandler(WPARAM wParam, LPARAM lParam)
// the scroll lock toggle state. // the scroll lock toggle state.
PostThreadMessage(g_threadID, SYNERGY_MSG_KEY, wParam, lParam); PostThreadMessage(g_threadID, SYNERGY_MSG_KEY, wParam, lParam);
if (g_relay) { if (g_mode == kHOOK_RELAY_EVENTS) {
// let certain keys pass through // let certain keys pass through
switch (wParam) { switch (wParam) {
case VK_CAPITAL: case VK_CAPITAL:
@ -202,18 +202,18 @@ mouseHookHandler(WPARAM wParam, SInt32 x, SInt32 y, SInt32 data)
case WM_NCXBUTTONUP: case WM_NCXBUTTONUP:
// always relay the event. eat it if relaying. // always relay the event. eat it if relaying.
PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_BUTTON, wParam, data); PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_BUTTON, wParam, data);
return g_relay; return (g_mode == kHOOK_RELAY_EVENTS);
case WM_MOUSEWHEEL: case WM_MOUSEWHEEL:
if (g_relay) { if (g_mode == kHOOK_RELAY_EVENTS) {
// relay event // relay event
PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_WHEEL, data, 0); PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_WHEEL, data, 0);
} }
return g_relay; return (g_mode == kHOOK_RELAY_EVENTS);
case WM_NCMOUSEMOVE: case WM_NCMOUSEMOVE:
case WM_MOUSEMOVE: case WM_MOUSEMOVE:
if (g_relay) { if (g_mode == kHOOK_RELAY_EVENTS) {
// we want the cursor to be hidden at all times so we // we want the cursor to be hidden at all times so we
// hide the cursor on whatever window has it. but then // hide the cursor on whatever window has it. but then
// we have to show the cursor whenever we leave that // we have to show the cursor whenever we leave that
@ -329,7 +329,7 @@ getMessageHook(int code, WPARAM wParam, LPARAM lParam)
SYNERGY_MSG_SCREEN_SAVER, TRUE, 0); SYNERGY_MSG_SCREEN_SAVER, TRUE, 0);
} }
} }
if (g_relay) { if (g_mode == kHOOK_RELAY_EVENTS) {
MSG* msg = reinterpret_cast<MSG*>(lParam); MSG* msg = reinterpret_cast<MSG*>(lParam);
if (msg->message == g_wmMouseWheel) { if (msg->message == g_wmMouseWheel) {
// post message to our window // post message to our window
@ -614,7 +614,7 @@ init(DWORD threadID)
g_threadID = threadID; g_threadID = threadID;
// set defaults // set defaults
g_relay = false; g_mode = kHOOK_WATCH_JUMP_ZONE;
g_zoneSides = 0; g_zoneSides = 0;
g_zoneSize = 0; g_zoneSize = 0;
g_xScreen = 0; g_xScreen = 0;
@ -827,14 +827,14 @@ setZone(SInt32 x, SInt32 y, SInt32 w, SInt32 h, SInt32 jumpZoneSize)
} }
void void
setRelay(int enable) setMode(EHookMode mode)
{ {
if ((enable != 0) == g_relay) { if (mode == g_mode) {
// no change // no change
return; return;
} }
g_relay = (enable != 0); g_mode = mode;
if (!g_relay) { if (g_mode != kHOOK_RELAY_EVENTS) {
restoreCursor(); restoreCursor();
} }
} }

View File

@ -49,6 +49,11 @@ enum EHookResult {
kHOOK_OKAY_LL kHOOK_OKAY_LL
}; };
enum EHookMode {
kHOOK_WATCH_JUMP_ZONE,
kHOOK_RELAY_EVENTS
};
typedef int (*InitFunc)(DWORD targetQueueThreadID); typedef int (*InitFunc)(DWORD targetQueueThreadID);
typedef int (*CleanupFunc)(void); typedef int (*CleanupFunc)(void);
typedef EHookResult (*InstallFunc)(void); typedef EHookResult (*InstallFunc)(void);
@ -57,7 +62,7 @@ typedef int (*InstallScreenSaverFunc)(void);
typedef int (*UninstallScreenSaverFunc)(void); typedef int (*UninstallScreenSaverFunc)(void);
typedef void (*SetSidesFunc)(UInt32); typedef void (*SetSidesFunc)(UInt32);
typedef void (*SetZoneFunc)(SInt32, SInt32, SInt32, SInt32, SInt32); typedef void (*SetZoneFunc)(SInt32, SInt32, SInt32, SInt32, SInt32);
typedef void (*SetRelayFunc)(int); typedef void (*SetModeFunc)(int);
CSYNERGYHOOK_API int init(DWORD); CSYNERGYHOOK_API int init(DWORD);
CSYNERGYHOOK_API int cleanup(void); CSYNERGYHOOK_API int cleanup(void);
@ -68,7 +73,7 @@ CSYNERGYHOOK_API int uninstallScreenSaver(void);
CSYNERGYHOOK_API void setSides(UInt32 sides); CSYNERGYHOOK_API void setSides(UInt32 sides);
CSYNERGYHOOK_API void setZone(SInt32 x, SInt32 y, SInt32 w, SInt32 h, CSYNERGYHOOK_API void setZone(SInt32 x, SInt32 y, SInt32 w, SInt32 h,
SInt32 jumpZoneSize); SInt32 jumpZoneSize);
CSYNERGYHOOK_API void setRelay(int enable); // relay iff enable != 0 CSYNERGYHOOK_API void setMode(EHookMode mode);
} }

View File

@ -0,0 +1,910 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* 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.
*/
#include "CXWindowsKeyMapper.h"
#include "CXWindowsUtil.h"
#include "CLog.h"
#if defined(X_DISPLAY_MISSING)
# error X11 is required to build synergy
#else
# include <X11/X.h>
# include <X11/Xutil.h>
# define XK_MISCELLANY
# define XK_XKB_KEYS
# include <X11/keysymdef.h>
# if defined(HAVE_X11_XF86KEYSYM_H)
# include <X11/XF86keysym.h>
# endif
# if !defined(XF86XK_Launch0)
# define XF86XK_Launch0 0x1008FF40
# endif
# if !defined(XF86XK_Launch1)
# define XF86XK_Launch1 0x1008FF41
# endif
#endif
// map special KeyID keys to KeySyms
#if defined(HAVE_X11_XF86KEYSYM_H)
static const KeySym g_mapE000[] =
{
/* 0x00 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x08 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x10 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x18 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x20 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x28 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x30 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x38 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x40 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x48 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x50 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x58 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x60 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x68 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x70 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x78 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x80 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x88 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x90 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x98 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xa0 */ 0, 0, 0, 0,
/* 0xa4 */ 0, 0,
/* 0xa6 */ XF86XK_Back, XF86XK_Forward,
/* 0xa8 */ XF86XK_Refresh, XF86XK_Stop,
/* 0xaa */ XF86XK_Search, XF86XK_Favorites,
/* 0xac */ XF86XK_HomePage, XF86XK_AudioMute,
/* 0xae */ XF86XK_AudioLowerVolume, XF86XK_AudioRaiseVolume,
/* 0xb0 */ XF86XK_AudioNext, XF86XK_AudioPrev,
/* 0xb2 */ XF86XK_AudioStop, XF86XK_AudioPlay,
/* 0xb4 */ XF86XK_Mail, XF86XK_AudioMedia,
/* 0xb6 */ XF86XK_Launch0, XF86XK_Launch1,
/* 0xb8 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xc0 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xc8 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xd0 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xd8 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xe0 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xe8 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xf0 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xf8 */ 0, 0, 0, 0, 0, 0, 0, 0
};
#endif
CXWindowsKeyMapper::CXWindowsKeyMapper()
{
// do nothing
}
CXWindowsKeyMapper::~CXWindowsKeyMapper()
{
// do nothing
}
void
CXWindowsKeyMapper::update(Display* display, IKeyState* keyState)
{
// query which keys are pressed
char keys[32];
XQueryKeymap(display, keys);
// query the pointer to get the keyboard state
Window root = DefaultRootWindow(display), window;
int xRoot, yRoot, xWindow, yWindow;
unsigned int state;
if (!XQueryPointer(display, root, &root, &window,
&xRoot, &yRoot, &xWindow, &yWindow, &state)) {
state = 0;
}
// update mappings
updateKeysymMap(display, keyState);
updateModifiers();
// transfer to our state
for (UInt32 i = 0, j = 0; i < 32; j += 8, ++i) {
if ((keys[i] & 0x01) != 0)
keyState->setKeyDown(j + 0);
if ((keys[i] & 0x02) != 0)
keyState->setKeyDown(j + 1);
if ((keys[i] & 0x04) != 0)
keyState->setKeyDown(j + 2);
if ((keys[i] & 0x08) != 0)
keyState->setKeyDown(j + 3);
if ((keys[i] & 0x10) != 0)
keyState->setKeyDown(j + 4);
if ((keys[i] & 0x20) != 0)
keyState->setKeyDown(j + 5);
if ((keys[i] & 0x40) != 0)
keyState->setKeyDown(j + 6);
if ((keys[i] & 0x80) != 0)
keyState->setKeyDown(j + 7);
}
// set toggle modifier states
if ((state & LockMask) != 0)
keyState->setToggled(KeyModifierCapsLock);
if ((state & m_numLockMask) != 0)
keyState->setToggled(KeyModifierNumLock);
if ((state & m_scrollLockMask) != 0)
keyState->setToggled(KeyModifierScrollLock);
}
KeyButton
CXWindowsKeyMapper::mapKey(IKeyState::Keystrokes& keys,
const IKeyState& keyState, KeyID id,
KeyModifierMask desiredMask,
bool isAutoRepeat) const
{
// the system translates key events into characters depending
// on the modifier key state at the time of the event. to
// generate the right keysym we need to set the modifier key
// states appropriately.
//
// desiredMask is the mask desired by the caller. however, there
// may not be a keycode mapping to generate the desired keysym
// with that mask. we override the bits in the mask that cannot
// be accomodated.
// convert KeyID to a KeySym
KeySym keysym = keyIDToKeySym(id, desiredMask);
if (keysym == NoSymbol) {
// unknown key
return 0;
}
// get the mapping for this keysym
KeySymIndex keyIndex = m_keysymMap.find(keysym);
// if the mapping isn't found and keysym is caps lock sensitive
// then convert the case of the keysym and try again.
if (keyIndex == m_keysymMap.end()) {
KeySym lKey, uKey;
XConvertCase(keysym, &lKey, &uKey);
if (lKey != uKey) {
if (lKey == keysym) {
keyIndex = m_keysymMap.find(uKey);
}
else {
keyIndex = m_keysymMap.find(lKey);
}
}
}
if (keyIndex != m_keysymMap.end()) {
// the keysym is mapped to some keycode. create the keystrokes
// for this keysym.
return mapToKeystrokes(keys, keyState, keyIndex, isAutoRepeat);
}
// we can't find the keysym mapped to any keycode. this doesn't
// necessarily mean we can't generate the keysym, though. if the
// keysym can be created by combining keysyms then we may still
// be okay.
CXWindowsUtil::KeySyms decomposition;
if (!CXWindowsUtil::decomposeKeySym(keysym, decomposition)) {
return 0;
}
LOG((CLOG_DEBUG2 "decomposed keysym 0x%08x into %d keysyms", keysym, decomposition.size()));
// map each decomposed keysym to keystrokes. we want the mask
// and the keycode from the last keysym (which should be the
// only non-dead key). the dead keys are not sensitive to
// anything but shift and mode switch.
KeyButton keycode = 0;
for (CXWindowsUtil::KeySyms::const_iterator i = decomposition.begin();
i != decomposition.end(); ++i) {
// lookup the key
keysym = *i;
keyIndex = m_keysymMap.find(keysym);
if (keyIndex == m_keysymMap.end()) {
// missing a required keysym
return 0;
}
// the keysym is mapped to some keycode
keycode = mapToKeystrokes(keys, keyState, keyIndex, isAutoRepeat);
if (keycode == 0) {
return 0;
}
}
return keycode;
}
KeyModifierMask
CXWindowsKeyMapper::mapModifier(unsigned int state) const
{
KeyModifierMask mask = 0;
if (state & ShiftMask)
mask |= KeyModifierShift;
if (state & LockMask)
mask |= KeyModifierCapsLock;
if (state & ControlMask)
mask |= KeyModifierControl;
if (state & m_altMask)
mask |= KeyModifierAlt;
if (state & m_metaMask)
mask |= KeyModifierMeta;
if (state & m_superMask)
mask |= KeyModifierSuper;
if (state & m_modeSwitchMask)
mask |= KeyModifierModeSwitch;
if (state & m_numLockMask)
mask |= KeyModifierNumLock;
if (state & m_scrollLockMask)
mask |= KeyModifierScrollLock;
return mask;
}
void
CXWindowsKeyMapper::updateKeysymMap(Display* display, IKeyState* keyState)
{
// there are up to 4 keysyms per keycode
static const unsigned int maxKeysyms = 4;
// get the number of keycodes
int minKeycode, maxKeycode;
XDisplayKeycodes(display, &minKeycode, &maxKeycode);
const int numKeycodes = maxKeycode - minKeycode + 1;
// get the keyboard mapping for all keys
int keysymsPerKeycode;
KeySym* keysyms = XGetKeyboardMapping(display,
minKeycode, numKeycodes,
&keysymsPerKeycode);
// we only understand up to maxKeysyms keysyms per keycodes
unsigned int numKeysyms = keysymsPerKeycode;
if (numKeysyms > maxKeysyms) {
numKeysyms = maxKeysyms;
}
// determine shift and mode switch sensitivity. a keysym is shift
// or mode switch sensitive if its keycode is. a keycode is mode
// mode switch sensitive if it has keysyms for indices 2 or 3.
// it's shift sensitive if the keysym for index 1 (if any) is
// different from the keysym for index 0 and, if the keysym for
// for index 3 (if any) is different from the keysym for index 2.
// that is, if shift changes the generated keysym for the keycode.
std::vector<bool> usesShift(numKeycodes);
std::vector<bool> usesModeSwitch(numKeycodes);
for (int i = 0; i < numKeycodes; ++i) {
// check mode switch first
if (numKeysyms > 2 &&
keysyms[i * keysymsPerKeycode + 2] != NoSymbol ||
keysyms[i * keysymsPerKeycode + 3] != NoSymbol) {
usesModeSwitch[i] = true;
}
// check index 0 with index 1 keysyms
if (keysyms[i * keysymsPerKeycode + 0] != NoSymbol &&
keysyms[i * keysymsPerKeycode + 1] != NoSymbol &&
keysyms[i * keysymsPerKeycode + 1] !=
keysyms[i * keysymsPerKeycode + 0]) {
usesShift[i] = true;
}
else if (numKeysyms >= 4 &&
keysyms[i * keysymsPerKeycode + 2] != NoSymbol &&
keysyms[i * keysymsPerKeycode + 3] != NoSymbol &&
keysyms[i * keysymsPerKeycode + 3] !=
keysyms[i * keysymsPerKeycode + 2]) {
usesShift[i] = true;
}
}
// get modifier map from server
XModifierKeymap* modifiers = XGetModifierMapping(display);
int keysPerModifier = modifiers->max_keypermod;
// clear state
m_keysymMap.clear();
m_modeSwitchKeysym = NoSymbol;
m_altMask = 0;
m_metaMask = 0;
m_superMask = 0;
m_modeSwitchMask = 0;
m_numLockMask = 0;
m_scrollLockMask = 0;
// work around for my system, which reports this state bit when
// mode switch is down, instead of the appropriate modifier bit.
// should have no effect on other systems. -crs 9/02.
m_modeSwitchMask |= (1 << 13);
// for each modifier keycode, get the index 0 keycode and add it to
// the keysym map. also collect all keycodes for each modifier.
for (unsigned int i = 0; i < 8; ++i) {
// no keycodes for this modifier yet
bool hasKeycode = false;
KeyModifierMask mask = 0;
IKeyState::KeyButtons modifierKeys;
// add each keycode for modifier
for (unsigned int j = 0; j < keysPerModifier; ++j) {
// get keycode and ignore unset keycodes
KeyCode keycode = modifiers->modifiermap[i * keysPerModifier + j];
if (keycode == 0) {
continue;
}
// get keysym and get/create key mapping
const int keycodeIndex = keycode - minKeycode;
const KeySym keysym = keysyms[keycodeIndex *
keysymsPerKeycode + 0];
// get modifier mask if we haven't yet. this has the side
// effect of setting the m_*Mask members.
if (mask == 0) {
mask = mapToModifierMask(i, keysym);
if (mask == 0) {
continue;
}
}
// save keycode for modifier
modifierKeys.push_back(keycode);
// skip if we already have a keycode for this index
KeyMapping& mapping = m_keysymMap[keysym];
if (mapping.m_keycode[0] != 0) {
continue;
}
// fill in keysym info
mapping.m_keycode[0] = keycode;
mapping.m_shiftSensitive[0] = usesShift[keycodeIndex];
mapping.m_modeSwitchSensitive[0] = usesModeSwitch[keycodeIndex];
mapping.m_modifierMask = mask;
mapping.m_capsLockSensitive = false;
mapping.m_numLockSensitive = false;
}
// tell keyState about this modifier
if (mask != 0 && keyState != NULL) {
keyState->addModifier(mask, modifierKeys);
}
}
// create a convenient NoSymbol entry (if it doesn't exist yet).
// sometimes it's useful to handle NoSymbol like a normal keysym.
// remove any entry for NoSymbol. that keysym doesn't count.
{
KeyMapping& mapping = m_keysymMap[NoSymbol];
for (unsigned int i = 0; i < numKeysyms; ++i) {
mapping.m_keycode[i] = 0;
mapping.m_shiftSensitive[i] = false;
mapping.m_modeSwitchSensitive[i] = false;
}
mapping.m_modifierMask = 0;
mapping.m_capsLockSensitive = false;
mapping.m_numLockSensitive = false;
}
// add each keysym to the map, unless we've already inserted a key
// for that keysym index.
for (int i = 0; i < numKeycodes; ++i) {
for (unsigned int j = 0; j < numKeysyms; ++j) {
// lookup keysym
const KeySym keysym = keysyms[i * keysymsPerKeycode + j];
if (keysym == NoSymbol) {
continue;
}
KeyMapping& mapping = m_keysymMap[keysym];
// skip if we already have a keycode for this index
if (mapping.m_keycode[j] != 0) {
continue;
}
// fill in keysym info
if (mapping.m_keycode[0] == 0) {
mapping.m_modifierMask = 0;
}
mapping.m_keycode[j] = static_cast<KeyCode>(
minKeycode + i);
mapping.m_shiftSensitive[j] = usesShift[i];
mapping.m_modeSwitchSensitive[j] = usesModeSwitch[i];
mapping.m_numLockSensitive = isNumLockSensitive(keysym);
mapping.m_capsLockSensitive = isCapsLockSensitive(keysym);
}
}
// clean up
XFreeModifiermap(modifiers);
XFree(keysyms);
}
KeyModifierMask
CXWindowsKeyMapper::mapToModifierMask(unsigned int i, KeySym keysym)
{
// some modifier indices (0,1,2) are dedicated to particular uses,
// the rest depend on the keysyms bound.
switch (i) {
case 0:
return KeyModifierShift;
case 1:
return KeyModifierCapsLock;
case 2:
return KeyModifierControl;
default:
switch (keysym) {
case XK_Shift_L:
case XK_Shift_R:
return KeyModifierShift;
case XK_Control_L:
case XK_Control_R:
return KeyModifierControl;
case XK_Alt_L:
case XK_Alt_R:
m_altMask = (1 << i);
return KeyModifierAlt;
case XK_Meta_L:
case XK_Meta_R:
m_metaMask = (1 << i);
return KeyModifierMeta;
case XK_Super_L:
case XK_Super_R:
m_superMask = (1 << i);
return KeyModifierSuper;
case XK_Mode_switch:
m_modeSwitchMask = (1 << i);
return KeyModifierModeSwitch;
case XK_Caps_Lock:
return KeyModifierCapsLock;
case XK_Num_Lock:
m_numLockMask = (1 << i);
return KeyModifierNumLock;
case XK_Scroll_Lock:
m_scrollLockMask = (1 << i);
return KeyModifierScrollLock;
default:
return 0;
}
}
}
void
CXWindowsKeyMapper::updateModifiers()
{
struct CModifierBitInfo {
public:
KeySym CXWindowsKeyMapper::*m_keysym;
KeySym m_left;
KeySym m_right;
};
static const CModifierBitInfo s_modifierBitTable[] = {
{ &CXWindowsKeyMapper::m_modeSwitchKeysym, XK_Mode_switch, NoSymbol },
};
// choose the keysym to use for some modifiers. if a modifier has
// both left and right versions then (arbitrarily) prefer the left.
for (size_t i = 0; i < sizeof(s_modifierBitTable) /
sizeof(s_modifierBitTable[0]); ++i) {
const CModifierBitInfo& info = s_modifierBitTable[i];
// find available keysym
KeySymIndex keyIndex = m_keysymMap.find(info.m_left);
if (keyIndex == m_keysymMap.end() && info.m_right != NoSymbol) {
keyIndex = m_keysymMap.find(info.m_right);
}
// save modifier info
if (keyIndex != m_keysymMap.end() &&
keyIndex->second.m_modifierMask != 0) {
this->*(info.m_keysym) = keyIndex->first;
}
}
// if there's no mode switch key mapped then remove all keycodes
// that depend on it and no keycode can be mode switch sensitive.
if (m_modeSwitchKeysym == NoSymbol) {
LOG((CLOG_DEBUG2 "no mode switch in keymap"));
for (KeySymMap::iterator i = m_keysymMap.begin();
i != m_keysymMap.end(); ) {
i->second.m_keycode[2] = 0;
i->second.m_keycode[3] = 0;
i->second.m_modeSwitchSensitive[0] = false;
i->second.m_modeSwitchSensitive[1] = false;
i->second.m_modeSwitchSensitive[2] = false;
i->second.m_modeSwitchSensitive[3] = false;
// if this keysym no has no keycodes then remove it
// except for the NoSymbol keysym mapping.
if (i->second.m_keycode[0] == 0 && i->second.m_keycode[1] == 0) {
m_keysymMap.erase(i++);
}
else {
++i;
}
}
}
}
KeySym
CXWindowsKeyMapper::keyIDToKeySym(KeyID id, KeyModifierMask mask) const
{
// convert id to keysym
KeySym keysym = NoSymbol;
if ((id & 0xfffff000) == 0xe000) {
// special character
switch (id & 0x0000ff00) {
#if defined(HAVE_X11_XF86KEYSYM_H)
case 0xe000:
return g_mapE000[id & 0xff];
#endif
case 0xee00:
// ISO 9995 Function and Modifier Keys
if (id == kKeyLeftTab) {
keysym = XK_ISO_Left_Tab;
}
break;
case 0xef00:
// MISCELLANY
keysym = static_cast<KeySym>(id - 0xef00 + 0xff00);
break;
}
}
else if ((id >= 0x0020 && id <= 0x007e) ||
(id >= 0x00a0 && id <= 0x00ff)) {
// Latin-1 maps directly
return static_cast<KeySym>(id);
}
else {
// lookup keysym in table
return CXWindowsUtil::mapUCS4ToKeySym(id);
}
// fail if unknown key
if (keysym == NoSymbol) {
return keysym;
}
// if kKeyTab is requested with shift active then try XK_ISO_Left_Tab
// instead. if that doesn't work, we'll fall back to XK_Tab with
// shift active. this is to handle primary screens that don't map
// XK_ISO_Left_Tab sending events to secondary screens that do.
if (keysym == XK_Tab && (mask & KeyModifierShift) != 0) {
keysym = XK_ISO_Left_Tab;
}
// some keysyms have emergency backups (particularly the numpad
// keys since most laptops don't have a separate numpad and the
// numpad overlaying the main keyboard may not have movement
// key bindings). figure out the emergency backup.
KeySym backupKeysym;
switch (keysym) {
case XK_KP_Home:
backupKeysym = XK_Home;
break;
case XK_KP_Left:
backupKeysym = XK_Left;
break;
case XK_KP_Up:
backupKeysym = XK_Up;
break;
case XK_KP_Right:
backupKeysym = XK_Right;
break;
case XK_KP_Down:
backupKeysym = XK_Down;
break;
case XK_KP_Prior:
backupKeysym = XK_Prior;
break;
case XK_KP_Next:
backupKeysym = XK_Next;
break;
case XK_KP_End:
backupKeysym = XK_End;
break;
case XK_KP_Insert:
backupKeysym = XK_Insert;
break;
case XK_KP_Delete:
backupKeysym = XK_Delete;
break;
case XK_ISO_Left_Tab:
backupKeysym = XK_Tab;
break;
default:
backupKeysym = keysym;
break;
}
// see if the keysym is assigned to any keycode. if not and the
// backup keysym is then use the backup keysym.
if (backupKeysym != keysym &&
m_keysymMap.find(keysym) == m_keysymMap.end() &&
m_keysymMap.find(backupKeysym) != m_keysymMap.end()) {
keysym = backupKeysym;
}
return keysym;
}
KeyButton
CXWindowsKeyMapper::mapToKeystrokes(IKeyState::Keystrokes& keys,
const IKeyState& keyState,
KeySymIndex keyIndex,
bool isAutoRepeat) const
{
// keyIndex must be valid
assert(keyIndex != m_keysymMap.end());
KeyModifierMask currentMask = keyState.getActiveModifiers();
// get the keysym we're trying to generate and possible keycodes
const KeySym keysym = keyIndex->first;
const KeyMapping& mapping = keyIndex->second;
LOG((CLOG_DEBUG2 "keysym = 0x%08x", keysym));
// get the best keycode index for the keysym and modifiers. note
// that (bestIndex & 1) == 0 if the keycode is a shift modifier
// and (bestIndex & 2) == 0 if the keycode is a mode switch
// modifier. this is important later because we don't want
// adjustModifiers() to adjust a modifier if that's the key we're
// mapping.
unsigned int bestIndex = findBestKeyIndex(keyIndex, currentMask);
// get the keycode
KeyButton keycode = mapping.m_keycode[bestIndex];
// flip low bit of bestIndex if shift is inverted. if there's a
// keycode for this new index then use it. otherwise use the old
// keycode. you'd think we should fail if there isn't a keycode
// for the new index but some keymaps only include the upper case
// keysyms (notably those on Sun Solaris) so to handle the missing
// lower case keysyms we just use the old keycode. note that
// isShiftInverted() will always return false for a shift modifier.
if (isShiftInverted(keyIndex, currentMask)) {
LOG((CLOG_DEBUG2 "shift is inverted"));
bestIndex ^= 1;
if (mapping.m_keycode[bestIndex] != 0) {
keycode = mapping.m_keycode[bestIndex];
}
}
LOG((CLOG_DEBUG2 "bestIndex = %d, keycode = %d", bestIndex, keycode));
// if this for auto-repeat and this key does not auto-repeat
// then return 0.
if (isAutoRepeat &&
(m_keyControl.auto_repeats[keycode >> 3] &
static_cast<char>(1 << (keycode & 7))) == 0) {
return 0;
}
// compute desired mask. the desired mask is the one that matches
// bestIndex, except if the key being synthesized is a shift key
// where we desire what we already have or if it's the mode switch
// key where we only desire to adjust shift. also, if the keycode
// is not sensitive to shift then don't adjust it, otherwise
// something like shift+home would become just home. similiarly
// for mode switch.
KeyModifierMask desiredMask = currentMask;
if (keyIndex->second.m_modifierMask != KeyModifierShift) {
if (keyIndex->second.m_shiftSensitive[bestIndex]) {
if ((bestIndex & 1) != 0) {
desiredMask |= KeyModifierShift;
}
else {
desiredMask &= ~KeyModifierShift;
}
}
if (keyIndex->second.m_modifierMask != KeyModifierModeSwitch) {
if (keyIndex->second.m_modeSwitchSensitive[bestIndex]) {
if ((bestIndex & 2) != 0) {
desiredMask |= KeyModifierModeSwitch;
}
else {
desiredMask &= ~KeyModifierModeSwitch;
}
}
}
}
// adjust the modifiers to match the desired modifiers
IKeyState::Keystrokes undo;
if (!adjustModifiers(keys, undo, keyState, desiredMask)) {
LOG((CLOG_DEBUG2 "failed to adjust modifiers"));
return 0;
}
// add the key event
IKeyState::Keystroke keystroke;
keystroke.m_key = keycode;
if (!isAutoRepeat) {
keystroke.m_press = true;
keystroke.m_repeat = false;
keys.push_back(keystroke);
}
else {
keystroke.m_press = false;
keystroke.m_repeat = true;
keys.push_back(keystroke);
keystroke.m_press = true;
keys.push_back(keystroke);
}
// put undo keystrokes at end of keystrokes in reverse order
while (!undo.empty()) {
keys.push_back(undo.back());
undo.pop_back();
}
return keycode;
}
unsigned int
CXWindowsKeyMapper::findBestKeyIndex(KeySymIndex keyIndex,
KeyModifierMask /*currentMask*/) const
{
// there are up to 4 keycodes per keysym to choose from. the
// best choice is the one that requires the fewest adjustments
// to the modifier state. for example, the letter A normally
// requires shift + a. if shift isn't already down we'd have
// to synthesize a shift press before the a press. however,
// if A could also be created with some other keycode without
// shift then we'd prefer that when shift wasn't down.
//
// if the action is an auto-repeat then we don't call this
// method since we just need to synthesize a key repeat on the
// same keycode that we pressed.
// XXX -- do this right
for (unsigned int i = 0; i < 4; ++i) {
if (keyIndex->second.m_keycode[i] != 0) {
return i;
}
}
assert(0 && "no keycode found for keysym");
return 0;
}
bool
CXWindowsKeyMapper::isShiftInverted(KeySymIndex keyIndex,
KeyModifierMask currentMask) const
{
// each keycode has up to 4 keysym associated with it, one each for:
// no modifiers, shift, mode switch, and shift and mode switch. if
// a keysym is modified by num lock and num lock is active then you
// get the shifted keysym when shift is not down and the unshifted
// keysym when it is. that is, num lock inverts the sense of the
// shift modifier when active. similarly for caps lock. this
// method returns true iff the sense of shift should be inverted
// for this key given a modifier state.
if (keyIndex->second.m_numLockSensitive) {
if ((currentMask & KeyModifierNumLock) != 0) {
return true;
}
}
// if a keysym is num lock sensitive it is never caps lock
// sensitive, thus the else here.
else if (keyIndex->second.m_capsLockSensitive) {
if ((currentMask & KeyModifierCapsLock) != 0) {
return true;
}
}
return false;
}
bool
CXWindowsKeyMapper::adjustModifiers(IKeyState::Keystrokes& keys,
IKeyState::Keystrokes& undo,
const IKeyState& keyState,
KeyModifierMask desiredMask) const
{
KeyModifierMask currentMask = keyState.getActiveModifiers();
// get mode switch set correctly. do this before shift because
// mode switch may be sensitive to the shift modifier and will
// set/reset it as necessary.
const bool wantModeSwitch = ((desiredMask & KeyModifierModeSwitch) != 0);
const bool haveModeSwitch = ((currentMask & KeyModifierModeSwitch) != 0);
if (wantModeSwitch != haveModeSwitch) {
LOG((CLOG_DEBUG2 "fix mode switch"));
// adjust shift if necessary
KeySymIndex modeSwitchIndex = m_keysymMap.find(m_modeSwitchKeysym);
assert(modeSwitchIndex != m_keysymMap.end());
if (modeSwitchIndex->second.m_shiftSensitive[0]) {
const bool wantShift = false;
const bool haveShift = ((currentMask & KeyModifierShift) != 0);
if (wantShift != haveShift) {
// add shift keystrokes
LOG((CLOG_DEBUG2 "fix shift for mode switch"));
if (!keyState.mapModifier(keys, undo,
KeyModifierShift, wantShift)) {
return false;
}
currentMask ^= KeyModifierShift;
}
}
// add mode switch keystrokes
if (!keyState.mapModifier(keys, undo,
KeyModifierModeSwitch, wantModeSwitch)) {
return false;
}
currentMask ^= KeyModifierModeSwitch;
}
// get shift set correctly
const bool wantShift = ((desiredMask & KeyModifierShift) != 0);
const bool haveShift = ((currentMask & KeyModifierShift) != 0);
if (wantShift != haveShift) {
// add shift keystrokes
LOG((CLOG_DEBUG2 "fix shift"));
if (!keyState.mapModifier(keys, undo, KeyModifierShift, wantShift)) {
return false;
}
currentMask ^= KeyModifierShift;
}
return true;
}
bool
CXWindowsKeyMapper::isNumLockSensitive(KeySym keysym) const
{
return (IsKeypadKey(keysym) || IsPrivateKeypadKey(keysym));
}
bool
CXWindowsKeyMapper::isCapsLockSensitive(KeySym keysym) const
{
KeySym lKey, uKey;
XConvertCase(keysym, &lKey, &uKey);
return (lKey != uKey);
}
//
// CXWindowsKeyMapper::KeyMapping
//
CXWindowsKeyMapper::KeyMapping::KeyMapping()
{
m_keycode[0] = 0;
m_keycode[1] = 0;
m_keycode[2] = 0;
m_keycode[3] = 0;
}

View File

@ -0,0 +1,153 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* 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.
*/
#ifndef CXWINDOWSKEYMAPPER_H
#define CXWINDOWSKEYMAPPER_H
#include "IKeyState.h"
#include "stdmap.h"
#if defined(X_DISPLAY_MISSING)
# error X11 is required to build synergy
#else
# include <X11/Xlib.h>
#endif
//! X Windows key mapper
/*!
This class maps KeyIDs to keystrokes.
*/
class CXWindowsKeyMapper {
public:
CXWindowsKeyMapper();
~CXWindowsKeyMapper();
//! @name manipulators
//@{
//! Update key mapper
/*!
Updates the key mapper's internal tables according to the display's
current keyboard mapping and updates \c keyState.
*/
void update(Display*, IKeyState* keyState);
//@}
//! @name accessors
//@{
//! Map key press/repeat to keystrokes
/*!
Converts a press/repeat of key \c id with the modifiers as given
in \c desiredMask into the keystrokes necessary to synthesize
that key event. Returns the platform specific code of the key
being pressed, or 0 if the key cannot be mapped or \c isAutoRepeat
is true and the key does not auto-repeat.
*/
KeyButton mapKey(IKeyState::Keystrokes&,
const IKeyState& keyState, KeyID id,
KeyModifierMask desiredMask,
bool isAutoRepeat) const;
//! Convert X modifier mask to synergy mask
/*!
Returns the synergy modifier mask corresponding to the given X
modifier mask.
*/
KeyModifierMask mapModifier(unsigned int state) const;
//@}
private:
class KeyMapping {
public:
KeyMapping();
public:
// KeyCode to generate keysym and whether keycode[i] is
// sensitive to shift and mode switch.
KeyCode m_keycode[4];
bool m_shiftSensitive[4];
bool m_modeSwitchSensitive[4];
// the modifier mask of keysym or 0 if not a modifier
KeyModifierMask m_modifierMask;
// whether keysym is sensitive to caps and num lock
bool m_numLockSensitive;
bool m_capsLockSensitive;
};
typedef std::map<KeySym, KeyMapping> KeySymMap;
typedef KeySymMap::const_iterator KeySymIndex;
// save the current keyboard mapping and note the currently
// pressed keys in \c keyState.
void updateKeysymMap(Display* display, IKeyState* keyState);
// note interesting modifier KeySyms
void updateModifiers();
// map a modifier index and its KeySym to a modifier mask. also
// save the modifier mask in one of m_*Mask.
KeyModifierMask mapToModifierMask(unsigned int, KeySym);
// convert a KeyID to a KeySym
KeySym keyIDToKeySym(KeyID id, KeyModifierMask mask) const;
// map a KeySym into the keystrokes to produce it
KeyButton mapToKeystrokes(IKeyState::Keystrokes& keys,
const IKeyState& keyState,
KeySymIndex keyIndex,
bool isAutoRepeat) const;
// choose the best set of modifiers to generate the KeySym
unsigned int findBestKeyIndex(KeySymIndex keyIndex,
KeyModifierMask currentMask) const;
// returns true if the sense of shift is inverted for KeySym
bool isShiftInverted(KeySymIndex keyIndex,
KeyModifierMask currentMask) const;
// returns the keystrokes to adjust the modifiers into the desired
// state the keystrokes to get back to the current state.
bool adjustModifiers(IKeyState::Keystrokes& keys,
IKeyState::Keystrokes& undo,
const IKeyState& keyState,
KeyModifierMask desiredMask) const;
// returns true if keysym is sensitive to the NumLock state
bool isNumLockSensitive(KeySym keysym) const;
// returns true if keysym is sensitive to the CapsLock state
bool isCapsLockSensitive(KeySym keysym) const;
private:
// keysym to keycode mapping
KeySymMap m_keysymMap;
// the keyboard control state the last time this screen was entered
XKeyboardState m_keyControl;
// modifier keysyms
KeySym m_modeSwitchKeysym;
// modifier masks
unsigned int m_altMask;
unsigned int m_metaMask;
unsigned int m_superMask;
unsigned int m_modeSwitchMask;
unsigned int m_numLockMask;
unsigned int m_scrollLockMask;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,126 +0,0 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* 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.
*/
#ifndef CXWINDOWSPRIMARYSCREEN_H
#define CXWINDOWSPRIMARYSCREEN_H
#include "CPrimaryScreen.h"
#include "IScreenEventHandler.h"
#include "MouseTypes.h"
#if defined(X_DISPLAY_MISSING)
# error X11 is required to build synergy
#else
# include <X11/Xlib.h>
#endif
class CXWindowsScreen;
class IScreenReceiver;
class IPrimaryScreenReceiver;
//! X11 primary screen implementation
class CXWindowsPrimaryScreen :
public CPrimaryScreen, public IScreenEventHandler {
public:
CXWindowsPrimaryScreen(IScreenReceiver*, IPrimaryScreenReceiver*);
virtual ~CXWindowsPrimaryScreen();
// CPrimaryScreen overrides
virtual void reconfigure(UInt32 activeSides);
virtual void warpCursor(SInt32 x, SInt32 y);
virtual void resetOptions();
virtual void setOptions(const COptionsList& options);
virtual UInt32 addOneShotTimer(double timeout);
virtual KeyModifierMask getToggleMask() const;
virtual bool isLockedToScreen() const;
virtual IScreen* getScreen() const;
// IScreenEventHandler overrides
virtual void onScreensaver(bool activated);
virtual bool onPreDispatch(const CEvent* event);
virtual bool onEvent(CEvent* event);
virtual void onOneShotTimerExpired(UInt32 id);
virtual SInt32 getJumpZoneSize() const;
protected:
// CPrimaryScreen overrides
virtual void onPreMainLoop();
virtual void onPreOpen();
virtual void onPostOpen();
virtual void onPreClose();
virtual void onPreEnter();
virtual void onPreLeave();
virtual void onEnterScreenSaver();
virtual void createWindow();
virtual void destroyWindow();
virtual bool showWindow();
virtual void hideWindow();
virtual void warpCursorToCenter();
virtual void updateKeys();
private:
void warpCursorNoFlush(Display*,
SInt32 xAbsolute, SInt32 yAbsolute);
void selectEvents(Display*, Window) const;
void doSelectEvents(Display*, Window) const;
KeyModifierMask mapModifier(unsigned int state) const;
KeyID mapKey(XKeyEvent*) const;
ButtonID mapButton(unsigned int button) const;
class CKeyEventInfo {
public:
int m_event;
Window m_window;
Time m_time;
KeyCode m_keycode;
};
static Bool findKeyEvent(Display*, XEvent* xevent, XPointer arg);
private:
CXWindowsScreen* m_screen;
IPrimaryScreenReceiver* m_receiver;
// our window
Window m_window;
// note toggle keys that toggle on up/down (false) or on
// transition (true)
bool m_numLockHalfDuplex;
bool m_capsLockHalfDuplex;
// modifier masks
unsigned int m_altMask;
unsigned int m_metaMask;
unsigned int m_superMask;
unsigned int m_modeSwitchMask;
unsigned int m_numLockMask;
unsigned int m_capsLockMask;
unsigned int m_scrollLockMask;
// last mouse position
SInt32 m_x, m_y;
// position of center pixel of screen
SInt32 m_xCenter, m_yCenter;
// input method stuff
XIM m_im;
XIC m_ic;
KeyCode m_lastKeycode;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -15,40 +15,28 @@
#ifndef CXWINDOWSSCREEN_H #ifndef CXWINDOWSSCREEN_H
#define CXWINDOWSSCREEN_H #define CXWINDOWSSCREEN_H
#include "IScreen.h" #include "IPlatformScreen.h"
#include "CXWindowsKeyMapper.h"
#include "CMutex.h" #include "CMutex.h"
#include "CStopwatch.h" #include "CStopwatch.h"
#include "CPriorityQueue.h"
#include "stdvector.h" #include "stdvector.h"
#if defined(X_DISPLAY_MISSING) #if defined(X_DISPLAY_MISSING)
# error X11 is required to build synergy # error X11 is required to build synergy
#else #else
# include <X11/Xlib.h> # include <X11/Xlib.h>
#endif #endif
#include <algorithm>
#include <functional>
class IJob;
class IScreenEventHandler;
class IScreenReceiver;
class CXWindowsClipboard; class CXWindowsClipboard;
class CXWindowsScreenSaver; class CXWindowsScreenSaver;
class IJob;
class IScreenReceiver;
class IPrimaryScreenReceiver;
/*! //! Implementation of IPlatformScreen for X11
\class CEvent class CXWindowsScreen : public IPlatformScreen {
\brief User event data
An architecture dependent type holding user event data.
*/
// X11 event
class CEvent {
public: public:
XEvent m_event; CXWindowsScreen(IScreenReceiver*, IPrimaryScreenReceiver*);
SInt32 m_result;
};
//! Implementation of IScreen for X11
class CXWindowsScreen : public IScreen {
public:
CXWindowsScreen(IScreenReceiver*, IScreenEventHandler*);
virtual ~CXWindowsScreen(); virtual ~CXWindowsScreen();
//! @name manipulators //! @name manipulators
@ -56,10 +44,10 @@ public:
//! Add timer //! Add timer
/*! /*!
Add a job to invoke every timeout seconds. The job is Add a job to invoke every timeout seconds. The job is called
called with the display locked. If a job timeout expires twice with the display locked. If a job timeout expires twice or
or more before the job can be called then the job is called more before the job can be called then the job is called just
just once. The caller retains ownership of the job. once. The caller retains ownership of the job.
*/ */
void addTimer(IJob*, double timeout); void addTimer(IJob*, double timeout);
@ -69,64 +57,55 @@ public:
*/ */
void removeTimer(IJob*); void removeTimer(IJob*);
//! Install a one-shot timer
/*!
Installs a one-shot timer for \c timeout seconds and returns the
id of the timer (which will be passed to the receiver's
\c onTimerExpired()).
*/
UInt32 addOneShotTimer(double timeout);
//! Set window
/*!
Set the window (created by the subclass). This performs some
initialization and saves the window in case it's needed later.
*/
void setWindow(Window);
//@}
//! @name accessors
//@{
//! Get window
/*!
Returns the root window of the screen.
*/
Window getRoot() const;
//! Get transparent cursor
/*!
Returns a cursor that is transparent everywhere.
*/
Cursor getBlankCursor() const;
//@} //@}
// IScreen overrides // IPlatformScreen overrides
void open(); virtual void open(IKeyState*);
void mainLoop(); virtual void close();
void exitMainLoop(); virtual void enable();
void close(); virtual void disable();
bool setClipboard(ClipboardID, const IClipboard*); virtual void mainLoop();
void checkClipboards(); virtual void exitMainLoop();
void openScreensaver(bool notify); virtual void enter();
void closeScreensaver(); virtual bool leave();
void screensaver(bool activate); virtual bool setClipboard(ClipboardID, const IClipboard*);
void syncDesktop(); virtual void checkClipboards();
bool getClipboard(ClipboardID, IClipboard*) const; virtual void openScreensaver(bool notify);
void getShape(SInt32&, SInt32&, SInt32&, SInt32&) const; virtual void closeScreensaver();
void getCursorPos(SInt32&, SInt32&) const; virtual void screensaver(bool activate);
void getCursorCenter(SInt32&, SInt32&) const; virtual void resetOptions();
virtual void setOptions(const COptionsList& options);
virtual void updateKeys();
virtual bool isPrimary() const;
virtual bool getClipboard(ClipboardID, IClipboard*) const;
virtual void getShape(SInt32&, SInt32&, SInt32&, SInt32&) const;
virtual void getCursorPos(SInt32&, SInt32&) const;
// IPrimaryScreen overrides
virtual void reconfigure(UInt32 activeSides);
virtual void warpCursor(SInt32 x, SInt32 y);
virtual UInt32 addOneShotTimer(double timeout);
virtual SInt32 getJumpZoneSize() const;
virtual bool isAnyMouseButtonDown() const;
virtual const char* getKeyName(KeyButton) const;
// ISecondaryScreen overrides
virtual void fakeKeyEvent(KeyButton id, bool press) const;
virtual bool fakeCtrlAltDel() const;
virtual void fakeMouseButton(ButtonID id, bool press) const;
virtual void fakeMouseMove(SInt32 x, SInt32 y) const;
virtual void fakeMouseWheel(SInt32 delta) const;
virtual KeyButton mapKey(IKeyState::Keystrokes&,
const IKeyState& keyState, KeyID id,
KeyModifierMask desiredMask,
bool isAutoRepeat) const;
private: private:
// update screen size cache
void updateScreenShape();
// process events before dispatching to receiver // process events before dispatching to receiver
bool onPreDispatch(CEvent* event); void onEvent(XEvent* event);
// create the transparent cursor // create the transparent cursor
void createBlankCursor(); Cursor createBlankCursor() const;
// remove a timer without locking // remove a timer without locking
void removeTimerNoLock(IJob*); void removeTimerNoLock(IJob*);
@ -149,78 +128,6 @@ private:
static int ioErrorHandler(Display*); static int ioErrorHandler(Display*);
private: private:
// a priority queue will direct access to the elements
template <class T, class Container = std::vector<T>,
class Compare = std::greater<typename Container::value_type> >
class CPriorityQueue {
public:
typedef typename Container::value_type value_type;
typedef typename Container::size_type size_type;
typedef typename Container::iterator iterator;
typedef Container container_type;
CPriorityQueue() { }
CPriorityQueue(Container& swappedIn);
~CPriorityQueue() { }
// manipulators
void push(const value_type& v)
{
c.push_back(v);
std::push_heap(c.begin(), c.end(), comp);
}
void pop()
{
std::pop_heap(c.begin(), c.end(), comp);
c.pop_back();
}
iterator begin()
{
return c.begin();
}
iterator end()
{
return c.end();
}
void swap(CPriorityQueue<T, Container, Compare>& q)
{
c.swap(q.c);
}
void swap(Container& c2)
{
c.swap(c2);
std::make_heap(c.begin(), c.end(), comp);
}
// accessors
bool empty() const
{
return c.empty();
}
size_type size() const
{
return c.size();
}
const value_type&
top() const
{
return c.front();
}
private:
Container c;
Compare comp;
};
// a timer priority queue element // a timer priority queue element
class CTimer { class CTimer {
public: public:
@ -252,32 +159,80 @@ private:
double m_time; double m_time;
double m_startTime; double m_startTime;
}; };
class CKeyEventInfo {
public:
int m_event;
Window m_window;
Time m_time;
KeyCode m_keycode;
};
bool isQuitEvent(XEvent*) const;
Window createWindow() const;
void openIM();
bool grabMouseAndKeyboard();
void onKeyPress(XKeyEvent&);
void onKeyRelease(XKeyEvent&);
void onMousePress(const XButtonEvent&);
void onMouseRelease(const XButtonEvent&);
void onMouseMove(const XMotionEvent&);
void selectEvents(Window) const;
void doSelectEvents(Window) const;
KeyID mapKeyFromX(XKeyEvent*) const;
ButtonID mapButtonFromX(const XButtonEvent*) const;
unsigned int mapButtonToX(ButtonID id) const;
void warpCursorNoFlush(SInt32 x, SInt32 y);
void updateButtons();
static Bool findKeyEvent(Display*, XEvent* xevent, XPointer arg);
private: private:
friend class CDisplayLock;
typedef CPriorityQueue<CTimer> CTimerPriorityQueue; typedef CPriorityQueue<CTimer> CTimerPriorityQueue;
// true if screen is being used as a primary screen, false otherwise
bool m_isPrimary;
// X is not thread safe // X is not thread safe
CMutex m_mutex; CMutex m_mutex;
Display* m_display; Display* m_display;
Window m_root; Window m_root;
bool m_stop;
IScreenReceiver* m_receiver;
IScreenEventHandler* m_eventHandler;
Window m_window; Window m_window;
IScreenReceiver* m_receiver;
IPrimaryScreenReceiver* m_primaryReceiver;
// true if mouse has entered the screen
bool m_isOnScreen;
// screen shape stuff
SInt32 m_x, m_y; SInt32 m_x, m_y;
SInt32 m_w, m_h; SInt32 m_w, m_h;
SInt32 m_xCenter, m_yCenter; SInt32 m_xCenter, m_yCenter;
// last mouse position
SInt32 m_xCursor, m_yCursor;
// keyboard stuff
IKeyState* m_keyState;
CXWindowsKeyMapper m_keyMapper;
// input method stuff
XIM m_im;
XIC m_ic;
KeyCode m_lastKeycode;
// clipboards // clipboards
CXWindowsClipboard* m_clipboard[kClipboardEnd]; CXWindowsClipboard* m_clipboard[kClipboardEnd];
// the transparent cursor // the quit message
Cursor m_cursor; Atom m_atomQuit;
// screen saver stuff // screen saver stuff
CXWindowsScreenSaver* m_screensaver; CXWindowsScreenSaver* m_screensaver;
@ -290,22 +245,23 @@ private:
CMutex m_timersMutex; CMutex m_timersMutex;
CTimer* m_oneShotTimer; CTimer* m_oneShotTimer;
// logical to physical button mapping. m_buttons[i] gives the
// physical button for logical button i+1.
std::vector<unsigned char> m_buttons;
// true if global auto-repeat was enabled before we turned it off
bool m_autoRepeat;
// stuff to workaround xtest being xinerama unaware. attempting
// to fake a mouse motion under xinerama may behave strangely,
// especially if screen 0 is not at 0,0 or if faking a motion on
// a screen other than screen 0.
bool m_xtestIsXineramaUnaware;
bool m_xinerama;
// pointer to (singleton) screen. this is only needed by // pointer to (singleton) screen. this is only needed by
// ioErrorHandler(). // ioErrorHandler().
static CXWindowsScreen* s_screen; static CXWindowsScreen* s_screen;
}; };
//! Convenience object to lock/unlock a CXWindowsScreen
class CDisplayLock {
public:
CDisplayLock(const CXWindowsScreen*);
~CDisplayLock();
operator Display*() const;
private:
const CMutex* m_mutex;
Display* m_display;
};
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -1,195 +0,0 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* 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.
*/
#ifndef CXWINDOWSSECONDARYSCREEN_H
#define CXWINDOWSSECONDARYSCREEN_H
#include "CSecondaryScreen.h"
#include "IScreenEventHandler.h"
#include "stdmap.h"
#include "stdvector.h"
#if defined(X_DISPLAY_MISSING)
# error X11 is required to build synergy
#else
# include <X11/Xlib.h>
#endif
class CXWindowsScreen;
class IScreenReceiver;
//! X11 secondary screen implementation
class CXWindowsSecondaryScreen :
public CSecondaryScreen, public IScreenEventHandler {
public:
CXWindowsSecondaryScreen(IScreenReceiver*);
virtual ~CXWindowsSecondaryScreen();
// CSecondaryScreen overrides
virtual void resetOptions();
virtual void setOptions(const COptionsList& options);
virtual IScreen* getScreen() const;
// IScreenEventHandler overrides
virtual void onScreensaver(bool activated);
virtual bool onPreDispatch(const CEvent* event);
virtual bool onEvent(CEvent* event);
virtual void onOneShotTimerExpired(UInt32 id);
protected:
// CSecondaryScreen overrides
virtual void onPreMainLoop();
virtual void onPreOpen();
virtual void onPostOpen();
virtual void onPreClose();
virtual void onPreEnter();
virtual void onPostEnter();
virtual void onPreLeave();
virtual void createWindow();
virtual void destroyWindow();
virtual void showWindow(SInt32 x, SInt32 y);
virtual void hideWindow();
virtual void updateKeys(KeyState* sysKeyStates);
virtual KeyModifierMask getModifiers() const;
virtual bool isAutoRepeating(SysKeyID) const;
virtual KeyModifierMask getModifierKeyMask(SysKeyID) const;
virtual bool isModifierActive(SysKeyID) const;
virtual SysKeyID getToggleSysKey(KeyID keyID) const;
virtual void flush();
virtual KeyModifierMask
mapKey(Keystrokes&, SysKeyID& sysKeyID, KeyID,
KeyModifierMask, KeyModifierMask, EKeyAction) const;
virtual void fakeKeyEvent(SysKeyID, bool press) const;
virtual void fakeMouseButton(ButtonID, bool press) const;
virtual void fakeMouseMove(SInt32 x, SInt32 y) const;
virtual void fakeMouseWheel(SInt32 delta) const;
private:
typedef unsigned int ModifierIndex;
class KeyMapping {
public:
KeyMapping();
public:
// KeyCode to generate keysym and whether keycode[i] is
// sensitive to shift and mode switch.
KeyCode m_keycode[4];
bool m_shiftSensitive[4];
bool m_modeSwitchSensitive[4];
// the modifier mask of keysym or 0 if not a modifier
KeyModifierMask m_modifierMask;
// whether keysym is sensitive to caps and num lock
bool m_numLockSensitive;
bool m_capsLockSensitive;
};
typedef std::vector<KeyCode> KeyCodes;
typedef std::map<KeyCode, ModifierIndex> KeyCodeToModifierMap;
typedef std::map<KeySym, KeyMapping> KeySymMap;
typedef KeySymMap::const_iterator KeySymIndex;
typedef std::vector<KeySym> KeySyms;
typedef std::map<KeySym, KeySyms> KeySymsMap;
unsigned int mapButton(ButtonID button) const;
bool mapToKeystrokes(Keystrokes& keys,
SysKeyID& keycode,
KeyModifierMask& finalMask,
KeySymIndex keyIndex,
KeyModifierMask currentMask,
EKeyAction action,
bool isHalfDuplex) const;
bool adjustModifiers(Keystrokes& keys,
Keystrokes& undo,
KeyModifierMask& inOutMask,
KeyModifierMask desiredMask) const;
bool adjustModifier(Keystrokes& keys,
Keystrokes& undo,
KeySym keysym,
bool desireActive) const;
KeyModifierMask mapToModifierMask(ModifierIndex, KeySym) const;
unsigned int findBestKeyIndex(KeySymIndex keyIndex,
KeyModifierMask currentMask) const;
bool isShiftInverted(KeySymIndex keyIndex,
KeyModifierMask currentMask) const;
void doUpdateKeys(Display*);
void updateKeysymMap(Display* display);
void updateModifiers(Display* display);
ModifierIndex keySymToModifierIndex(KeySym) const;
static bool isToggleKeysym(KeySym);
KeySym keyIDToKeySym(KeyID id, KeyModifierMask mask) const;
bool adjustForNumLock(KeySym) const;
bool adjustForCapsLock(KeySym) const;
bool decomposeKeySym(KeySym keysym,
KeySyms& decomposed) const;
static const KeySymsMap& getDecomposedKeySymTable();
private:
CXWindowsScreen* m_screen;
Window m_window;
// logical to physical button mapping. m_buttons[i] gives the
// physical button for logical button i+1.
std::vector<unsigned char> m_buttons;
// the modifiers that have keys bound to them
KeyModifierMask m_modifierMask;
// set bits indicate modifiers that toggle (e.g. caps-lock)
KeyModifierMask m_toggleModifierMask;
// keysym to keycode mapping
KeySymMap m_keysymMap;
// modifier index to keycodes
KeyCodes m_modifierKeycodes[8];
// modifier index to modifier mask
KeyModifierMask m_modifierIndexToMask[8];
// keycode to modifier index
KeyCodeToModifierMap m_keycodeToModifier;
// modifier keysyms
KeySym m_shiftKeysym;
KeySym m_ctrlKeysym;
KeySym m_altKeysym;
KeySym m_metaKeysym;
KeySym m_superKeysym;
KeySym m_modeSwitchKeysym;
KeySym m_numLockKeysym;
KeySym m_capsLockKeysym;
KeySym m_scrollLockKeysym;
// the keyboard control state the last time this screen was entered
XKeyboardState m_keyControl;
// stuff to workaround xtest being xinerama unaware. attempting
// to fake a mouse motion under xinerama may behave strangely,
// especially if screen 0 is not at 0,0 or if faking a motion on
// a screen other than screen 0.
bool m_xtestIsXineramaUnaware;
bool m_xinerama;
// a table of keysym decompositions
static KeySymsMap s_decomposedKeySyms;
};
#endif

View File

@ -16,6 +16,14 @@
#include "CThread.h" #include "CThread.h"
#include "CLog.h" #include "CLog.h"
#include <X11/Xatom.h> #include <X11/Xatom.h>
#define XK_XKB_KEYS
#define XK_LATIN1
#define XK_LATIN2
#define XK_LATIN3
#define XK_LATIN4
#define XK_LATIN8
#define XK_LATIN9
#include <X11/keysymdef.h>
/* /*
* This table maps keysym values into the corresponding ISO 10646 * This table maps keysym values into the corresponding ISO 10646
@ -805,6 +813,218 @@ struct codepair {
{ 0x20ac, 0x20ac } /* EuroSign EURO SIGN */ { 0x20ac, 0x20ac } /* EuroSign EURO SIGN */
}; };
static const KeySym s_rawDecomposeTable[] = {
// non-dead version of dead keys
XK_grave, XK_dead_grave, XK_space, 0,
XK_acute, XK_dead_acute, XK_space, 0,
XK_asciicircum, XK_dead_circumflex, XK_space, 0,
XK_asciitilde, XK_dead_tilde, XK_space, 0,
XK_cedilla, XK_dead_cedilla, XK_space, 0,
XK_ogonek, XK_dead_ogonek, XK_space, 0,
XK_caron, XK_dead_caron, XK_space, 0,
XK_abovedot, XK_dead_abovedot, XK_space, 0,
XK_doubleacute, XK_dead_doubleacute, XK_space, 0,
XK_breve, XK_dead_breve, XK_space, 0,
XK_macron, XK_dead_macron, XK_space, 0,
// Latin-1 (ISO 8859-1)
XK_Agrave, XK_dead_grave, XK_A, 0,
XK_Aacute, XK_dead_acute, XK_A, 0,
XK_Acircumflex, XK_dead_circumflex, XK_A, 0,
XK_Atilde, XK_dead_tilde, XK_A, 0,
XK_Adiaeresis, XK_dead_diaeresis, XK_A, 0,
XK_Aring, XK_dead_abovering, XK_A, 0,
XK_Ccedilla, XK_dead_cedilla, XK_C, 0,
XK_Egrave, XK_dead_grave, XK_E, 0,
XK_Eacute, XK_dead_acute, XK_E, 0,
XK_Ecircumflex, XK_dead_circumflex, XK_E, 0,
XK_Ediaeresis, XK_dead_diaeresis, XK_E, 0,
XK_Igrave, XK_dead_grave, XK_I, 0,
XK_Iacute, XK_dead_acute, XK_I, 0,
XK_Icircumflex, XK_dead_circumflex, XK_I, 0,
XK_Idiaeresis, XK_dead_diaeresis, XK_I, 0,
XK_Ntilde, XK_dead_tilde, XK_N, 0,
XK_Ograve, XK_dead_grave, XK_O, 0,
XK_Oacute, XK_dead_acute, XK_O, 0,
XK_Ocircumflex, XK_dead_circumflex, XK_O, 0,
XK_Otilde, XK_dead_tilde, XK_O, 0,
XK_Odiaeresis, XK_dead_diaeresis, XK_O, 0,
XK_Ugrave, XK_dead_grave, XK_U, 0,
XK_Uacute, XK_dead_acute, XK_U, 0,
XK_Ucircumflex, XK_dead_circumflex, XK_U, 0,
XK_Udiaeresis, XK_dead_diaeresis, XK_U, 0,
XK_Yacute, XK_dead_acute, XK_Y, 0,
XK_agrave, XK_dead_grave, XK_a, 0,
XK_aacute, XK_dead_acute, XK_a, 0,
XK_acircumflex, XK_dead_circumflex, XK_a, 0,
XK_atilde, XK_dead_tilde, XK_a, 0,
XK_adiaeresis, XK_dead_diaeresis, XK_a, 0,
XK_aring, XK_dead_abovering, XK_a, 0,
XK_ccedilla, XK_dead_cedilla, XK_c, 0,
XK_egrave, XK_dead_grave, XK_e, 0,
XK_eacute, XK_dead_acute, XK_e, 0,
XK_ecircumflex, XK_dead_circumflex, XK_e, 0,
XK_ediaeresis, XK_dead_diaeresis, XK_e, 0,
XK_igrave, XK_dead_grave, XK_i, 0,
XK_iacute, XK_dead_acute, XK_i, 0,
XK_icircumflex, XK_dead_circumflex, XK_i, 0,
XK_idiaeresis, XK_dead_diaeresis, XK_i, 0,
XK_ntilde, XK_dead_tilde, XK_n, 0,
XK_ograve, XK_dead_grave, XK_o, 0,
XK_oacute, XK_dead_acute, XK_o, 0,
XK_ocircumflex, XK_dead_circumflex, XK_o, 0,
XK_otilde, XK_dead_tilde, XK_o, 0,
XK_odiaeresis, XK_dead_diaeresis, XK_o, 0,
XK_ugrave, XK_dead_grave, XK_u, 0,
XK_uacute, XK_dead_acute, XK_u, 0,
XK_ucircumflex, XK_dead_circumflex, XK_u, 0,
XK_udiaeresis, XK_dead_diaeresis, XK_u, 0,
XK_yacute, XK_dead_acute, XK_y, 0,
XK_ydiaeresis, XK_dead_diaeresis, XK_y, 0,
// Latin-2 (ISO 8859-2)
XK_Aogonek, XK_dead_ogonek, XK_A, 0,
XK_Lcaron, XK_dead_caron, XK_L, 0,
XK_Sacute, XK_dead_acute, XK_S, 0,
XK_Scaron, XK_dead_caron, XK_S, 0,
XK_Scedilla, XK_dead_cedilla, XK_S, 0,
XK_Tcaron, XK_dead_caron, XK_T, 0,
XK_Zacute, XK_dead_acute, XK_Z, 0,
XK_Zcaron, XK_dead_caron, XK_Z, 0,
XK_Zabovedot, XK_dead_abovedot, XK_Z, 0,
XK_aogonek, XK_dead_ogonek, XK_a, 0,
XK_lcaron, XK_dead_caron, XK_l, 0,
XK_sacute, XK_dead_acute, XK_s, 0,
XK_scaron, XK_dead_caron, XK_s, 0,
XK_scedilla, XK_dead_cedilla, XK_s, 0,
XK_tcaron, XK_dead_caron, XK_t, 0,
XK_zacute, XK_dead_acute, XK_z, 0,
XK_zcaron, XK_dead_caron, XK_z, 0,
XK_zabovedot, XK_dead_abovedot, XK_z, 0,
XK_Racute, XK_dead_acute, XK_R, 0,
XK_Abreve, XK_dead_breve, XK_A, 0,
XK_Lacute, XK_dead_acute, XK_L, 0,
XK_Cacute, XK_dead_acute, XK_C, 0,
XK_Ccaron, XK_dead_caron, XK_C, 0,
XK_Eogonek, XK_dead_ogonek, XK_E, 0,
XK_Ecaron, XK_dead_caron, XK_E, 0,
XK_Dcaron, XK_dead_caron, XK_D, 0,
XK_Nacute, XK_dead_acute, XK_N, 0,
XK_Ncaron, XK_dead_caron, XK_N, 0,
XK_Odoubleacute, XK_dead_doubleacute, XK_O, 0,
XK_Rcaron, XK_dead_caron, XK_R, 0,
XK_Uring, XK_dead_abovering, XK_U, 0,
XK_Udoubleacute, XK_dead_doubleacute, XK_U, 0,
XK_Tcedilla, XK_dead_cedilla, XK_T, 0,
XK_racute, XK_dead_acute, XK_r, 0,
XK_abreve, XK_dead_breve, XK_a, 0,
XK_lacute, XK_dead_acute, XK_l, 0,
XK_cacute, XK_dead_acute, XK_c, 0,
XK_ccaron, XK_dead_caron, XK_c, 0,
XK_eogonek, XK_dead_ogonek, XK_e, 0,
XK_ecaron, XK_dead_caron, XK_e, 0,
XK_dcaron, XK_dead_caron, XK_d, 0,
XK_nacute, XK_dead_acute, XK_n, 0,
XK_ncaron, XK_dead_caron, XK_n, 0,
XK_odoubleacute, XK_dead_doubleacute, XK_o, 0,
XK_rcaron, XK_dead_caron, XK_r, 0,
XK_uring, XK_dead_abovering, XK_u, 0,
XK_udoubleacute, XK_dead_doubleacute, XK_u, 0,
XK_tcedilla, XK_dead_cedilla, XK_t, 0,
// Latin-3 (ISO 8859-3)
XK_Hcircumflex, XK_dead_circumflex, XK_H, 0,
XK_Iabovedot, XK_dead_abovedot, XK_I, 0,
XK_Gbreve, XK_dead_breve, XK_G, 0,
XK_Jcircumflex, XK_dead_circumflex, XK_J, 0,
XK_hcircumflex, XK_dead_circumflex, XK_h, 0,
XK_gbreve, XK_dead_breve, XK_g, 0,
XK_jcircumflex, XK_dead_circumflex, XK_j, 0,
XK_Cabovedot, XK_dead_abovedot, XK_C, 0,
XK_Ccircumflex, XK_dead_circumflex, XK_C, 0,
XK_Gabovedot, XK_dead_abovedot, XK_G, 0,
XK_Gcircumflex, XK_dead_circumflex, XK_G, 0,
XK_Ubreve, XK_dead_breve, XK_U, 0,
XK_Scircumflex, XK_dead_circumflex, XK_S, 0,
XK_cabovedot, XK_dead_abovedot, XK_c, 0,
XK_ccircumflex, XK_dead_circumflex, XK_c, 0,
XK_gabovedot, XK_dead_abovedot, XK_g, 0,
XK_gcircumflex, XK_dead_circumflex, XK_g, 0,
XK_ubreve, XK_dead_breve, XK_u, 0,
XK_scircumflex, XK_dead_circumflex, XK_s, 0,
// Latin-4 (ISO 8859-4)
XK_scircumflex, XK_dead_circumflex, XK_s, 0,
XK_Rcedilla, XK_dead_cedilla, XK_R, 0,
XK_Itilde, XK_dead_tilde, XK_I, 0,
XK_Lcedilla, XK_dead_cedilla, XK_L, 0,
XK_Emacron, XK_dead_macron, XK_E, 0,
XK_Gcedilla, XK_dead_cedilla, XK_G, 0,
XK_rcedilla, XK_dead_cedilla, XK_r, 0,
XK_itilde, XK_dead_tilde, XK_i, 0,
XK_lcedilla, XK_dead_cedilla, XK_l, 0,
XK_emacron, XK_dead_macron, XK_e, 0,
XK_gcedilla, XK_dead_cedilla, XK_g, 0,
XK_Amacron, XK_dead_macron, XK_A, 0,
XK_Iogonek, XK_dead_ogonek, XK_I, 0,
XK_Eabovedot, XK_dead_abovedot, XK_E, 0,
XK_Imacron, XK_dead_macron, XK_I, 0,
XK_Ncedilla, XK_dead_cedilla, XK_N, 0,
XK_Omacron, XK_dead_macron, XK_O, 0,
XK_Kcedilla, XK_dead_cedilla, XK_K, 0,
XK_Uogonek, XK_dead_ogonek, XK_U, 0,
XK_Utilde, XK_dead_tilde, XK_U, 0,
XK_Umacron, XK_dead_macron, XK_U, 0,
XK_amacron, XK_dead_macron, XK_a, 0,
XK_iogonek, XK_dead_ogonek, XK_i, 0,
XK_eabovedot, XK_dead_abovedot, XK_e, 0,
XK_imacron, XK_dead_macron, XK_i, 0,
XK_ncedilla, XK_dead_cedilla, XK_n, 0,
XK_omacron, XK_dead_macron, XK_o, 0,
XK_kcedilla, XK_dead_cedilla, XK_k, 0,
XK_uogonek, XK_dead_ogonek, XK_u, 0,
XK_utilde, XK_dead_tilde, XK_u, 0,
XK_umacron, XK_dead_macron, XK_u, 0,
// Latin-8 (ISO 8859-14)
#if defined(XK_Babovedot)
XK_Babovedot, XK_dead_abovedot, XK_B, 0,
XK_babovedot, XK_dead_abovedot, XK_b, 0,
XK_Dabovedot, XK_dead_abovedot, XK_D, 0,
XK_Wgrave, XK_dead_grave, XK_W, 0,
XK_Wacute, XK_dead_acute, XK_W, 0,
XK_dabovedot, XK_dead_abovedot, XK_d, 0,
XK_Ygrave, XK_dead_grave, XK_Y, 0,
XK_Fabovedot, XK_dead_abovedot, XK_F, 0,
XK_fabovedot, XK_dead_abovedot, XK_f, 0,
XK_Mabovedot, XK_dead_abovedot, XK_M, 0,
XK_mabovedot, XK_dead_abovedot, XK_m, 0,
XK_Pabovedot, XK_dead_abovedot, XK_P, 0,
XK_wgrave, XK_dead_grave, XK_w, 0,
XK_pabovedot, XK_dead_abovedot, XK_p, 0,
XK_wacute, XK_dead_acute, XK_w, 0,
XK_Sabovedot, XK_dead_abovedot, XK_S, 0,
XK_ygrave, XK_dead_grave, XK_y, 0,
XK_Wdiaeresis, XK_dead_diaeresis, XK_W, 0,
XK_wdiaeresis, XK_dead_diaeresis, XK_w, 0,
XK_sabovedot, XK_dead_abovedot, XK_s, 0,
XK_Wcircumflex, XK_dead_circumflex, XK_W, 0,
XK_Tabovedot, XK_dead_abovedot, XK_T, 0,
XK_Ycircumflex, XK_dead_circumflex, XK_Y, 0,
XK_wcircumflex, XK_dead_circumflex, XK_w, 0,
XK_tabovedot, XK_dead_abovedot, XK_t, 0,
XK_ycircumflex, XK_dead_circumflex, XK_y, 0,
#endif
// Latin-9 (ISO 8859-15)
#if defined(XK_Ydiaeresis)
XK_Ydiaeresis, XK_dead_diaeresis, XK_Y, 0,
#endif
// end of table
0
};
// //
// CXWindowsUtil // CXWindowsUtil
@ -812,6 +1032,7 @@ struct codepair {
CXWindowsUtil::CKeySymMap CXWindowsUtil::s_keySymToUCS4; CXWindowsUtil::CKeySymMap CXWindowsUtil::s_keySymToUCS4;
CXWindowsUtil::CUCS4Map CXWindowsUtil::s_UCS4ToKeySym; CXWindowsUtil::CUCS4Map CXWindowsUtil::s_UCS4ToKeySym;
CXWindowsUtil::CKeySymsMap CXWindowsUtil::s_decomposedKeySyms;
bool bool
CXWindowsUtil::getWindowProperty(Display* display, Window window, CXWindowsUtil::getWindowProperty(Display* display, Window window,
@ -1008,6 +1229,21 @@ CXWindowsUtil::mapUCS4ToKeySym(UInt32 c)
} }
} }
bool
CXWindowsUtil::decomposeKeySym(KeySym keysym, KeySyms& decomposed)
{
// unfortunately, X11 doesn't appear to have any way of
// decomposing a keysym into its component keysyms. we'll
// use a lookup table for certain character sets.
initKeyMaps();
CKeySymsMap::const_iterator i = s_decomposedKeySyms.find(keysym);
if (i == s_decomposedKeySyms.end()) {
return false;
}
decomposed = i->second;
return true;
}
Bool Bool
CXWindowsUtil::propertyNotifyPredicate(Display*, XEvent* xevent, XPointer arg) CXWindowsUtil::propertyNotifyPredicate(Display*, XEvent* xevent, XPointer arg)
{ {
@ -1031,6 +1267,19 @@ CXWindowsUtil::initKeyMaps()
s_UCS4ToKeySym[s_keymap[i].ucs4] = s_keymap[i].keysym; s_UCS4ToKeySym[s_keymap[i].ucs4] = s_keymap[i].keysym;
} }
} }
// fill decomposed key table if not filled yet
if (s_decomposedKeySyms.empty()) {
for (const KeySym* scan = s_rawDecomposeTable; *scan != 0; ++scan) {
// add an entry for this keysym
KeySyms& entry = s_decomposedKeySyms[*scan];
// add the decomposed keysyms for the keysym
while (*++scan != 0) {
entry.push_back(*scan);
}
}
}
} }

View File

@ -18,6 +18,7 @@
#include "CString.h" #include "CString.h"
#include "BasicTypes.h" #include "BasicTypes.h"
#include "stdmap.h" #include "stdmap.h"
#include "stdvector.h"
#if defined(X_DISPLAY_MISSING) #if defined(X_DISPLAY_MISSING)
# error X11 is required to build synergy # error X11 is required to build synergy
#else #else
@ -27,6 +28,8 @@
//! X11 utility functions //! X11 utility functions
class CXWindowsUtil { class CXWindowsUtil {
public: public:
typedef std::vector<KeySym> KeySyms;
//! Get property //! Get property
/*! /*!
Gets property \c property on \c window. \b Appends the data to Gets property \c property on \c window. \b Appends the data to
@ -70,6 +73,14 @@ public:
*/ */
static KeySym mapUCS4ToKeySym(UInt32); static KeySym mapUCS4ToKeySym(UInt32);
//! Decompose a KeySym
/*!
Decomposes \c keysym into its component keysyms. All but the last
decomposed KeySym are dead keys. Returns true iff the decomposition
was successful.
*/
static bool decomposeKeySym(KeySym keysym, KeySyms& decomposed);
//! X11 error handler //! X11 error handler
/*! /*!
This class sets an X error handler in the c'tor and restores the This class sets an X error handler in the c'tor and restores the
@ -133,9 +144,11 @@ private:
private: private:
typedef std::map<KeySym, UInt32> CKeySymMap; typedef std::map<KeySym, UInt32> CKeySymMap;
typedef std::map<UInt32, KeySym> CUCS4Map; typedef std::map<UInt32, KeySym> CUCS4Map;
typedef std::map<KeySym, KeySyms> CKeySymsMap;
static CKeySymMap s_keySymToUCS4; static CKeySymMap s_keySymToUCS4;
static CUCS4Map s_UCS4ToKeySym; static CUCS4Map s_UCS4ToKeySym;
static CKeySymsMap s_decomposedKeySyms;
}; };
#endif #endif

View File

@ -1,55 +0,0 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* 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.
*/
#ifndef IMSWINDOWSSCREENEVENTHANDLER_H
#define IMSWINDOWSSCREENEVENTHANDLER_H
#include "IScreenEventHandler.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
//! MS Windows screen event handler interface
class IMSWindowsScreenEventHandler : public IScreenEventHandler {
public:
//! @name manipulators
//@{
//! Notify of window creation
/*!
This is called after the window is created.
*/
virtual void postCreateWindow(HWND) = 0;
//! Notify of window destruction
/*!
This is called before the window is destroyed.
*/
virtual void preDestroyWindow(HWND) = 0;
//! Notify of newly accessible desktop
/*!
This is called when the user switched from an inaccessible desktop
to an accessible desktop.
*/
virtual void onAccessibleDesktop() = 0;
//@}
// IScreenEventHandler overrides
virtual void onScreensaver(bool activated) = 0;
virtual bool onPreDispatch(const CEvent* event) = 0;
virtual bool onEvent(CEvent* event) = 0;
};
#endif

View File

@ -23,21 +23,20 @@ EXTRA_DIST = \
CMSWindowsClipboardAnyTextConverter.cpp \ CMSWindowsClipboardAnyTextConverter.cpp \
CMSWindowsClipboardTextConverter.cpp \ CMSWindowsClipboardTextConverter.cpp \
CMSWindowsClipboardUTF16Converter.cpp \ CMSWindowsClipboardUTF16Converter.cpp \
CMSWindowsPrimaryScreen.cpp \ CMSWindowsDesktop.cpp \
CMSWindowsKeyMapper.cpp \
CMSWindowsScreen.cpp \ CMSWindowsScreen.cpp \
CMSWindowsScreenSaver.cpp \ CMSWindowsScreenSaver.cpp \
CMSWindowsSecondaryScreen.cpp \
CSynergyHook.cpp \ CSynergyHook.cpp \
CMSWindowsClipboard.h \ CMSWindowsClipboard.h \
CMSWindowsClipboardAnyTextConverter.h \ CMSWindowsClipboardAnyTextConverter.h \
CMSWindowsClipboardTextConverter.h \ CMSWindowsClipboardTextConverter.h \
CMSWindowsClipboardUTF16Converter.h \ CMSWindowsClipboardUTF16Converter.h \
CMSWindowsPrimaryScreen.h \ CMSWindowsDesktop.h \
CMSWindowsKeyMapper.h \
CMSWindowsScreen.h \ CMSWindowsScreen.h \
CMSWindowsScreenSaver.h \ CMSWindowsScreenSaver.h \
CMSWindowsSecondaryScreen.h \
CSynergyHook.h \ CSynergyHook.h \
IMSWindowsScreenEventHandler.h \
$(NULL) $(NULL)
MAINTAINERCLEANFILES = \ MAINTAINERCLEANFILES = \
@ -50,19 +49,17 @@ libplatform_a_SOURCES = \
CXWindowsClipboardTextConverter.cpp \ CXWindowsClipboardTextConverter.cpp \
CXWindowsClipboardUCS2Converter.cpp \ CXWindowsClipboardUCS2Converter.cpp \
CXWindowsClipboardUTF8Converter.cpp \ CXWindowsClipboardUTF8Converter.cpp \
CXWindowsPrimaryScreen.cpp \ CXWindowsKeyMapper.cpp \
CXWindowsScreen.cpp \ CXWindowsScreen.cpp \
CXWindowsScreenSaver.cpp \ CXWindowsScreenSaver.cpp \
CXWindowsSecondaryScreen.cpp \
CXWindowsUtil.cpp \ CXWindowsUtil.cpp \
CXWindowsClipboard.h \ CXWindowsClipboard.h \
CXWindowsClipboardTextConverter.h \ CXWindowsClipboardTextConverter.h \
CXWindowsClipboardUCS2Converter.h \ CXWindowsClipboardUCS2Converter.h \
CXWindowsClipboardUTF8Converter.h \ CXWindowsClipboardUTF8Converter.h \
CXWindowsPrimaryScreen.h \ CXWindowsKeyMapper.h \
CXWindowsScreen.h \ CXWindowsScreen.h \
CXWindowsScreenSaver.h \ CXWindowsScreenSaver.h \
CXWindowsSecondaryScreen.h \
CXWindowsUtil.h \ CXWindowsUtil.h \
$(NULL) $(NULL)
INCLUDES = \ INCLUDES = \

View File

@ -103,7 +103,11 @@ SOURCE=.\CMSWindowsClipboardUTF16Converter.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\CMSWindowsPrimaryScreen.cpp SOURCE=.\CMSWindowsDesktop.cpp
# End Source File
# Begin Source File
SOURCE=.\CMSWindowsKeyMapper.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
@ -113,10 +117,6 @@ SOURCE=.\CMSWindowsScreen.cpp
SOURCE=.\CMSWindowsScreenSaver.cpp SOURCE=.\CMSWindowsScreenSaver.cpp
# End Source File # End Source File
# Begin Source File
SOURCE=.\CMSWindowsSecondaryScreen.cpp
# End Source File
# End Group # End Group
# Begin Group "Header Files" # Begin Group "Header Files"
@ -139,7 +139,11 @@ SOURCE=.\CMSWindowsClipboardUTF16Converter.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\CMSWindowsPrimaryScreen.h SOURCE=.\CMSWindowsDesktop.h
# End Source File
# Begin Source File
SOURCE=.\CMSWindowsKeyMapper.h
# End Source File # End Source File
# Begin Source File # Begin Source File
@ -149,14 +153,6 @@ SOURCE=.\CMSWindowsScreen.h
SOURCE=.\CMSWindowsScreenSaver.h SOURCE=.\CMSWindowsScreenSaver.h
# End Source File # End Source File
# Begin Source File
SOURCE=.\CMSWindowsSecondaryScreen.h
# End Source File
# Begin Source File
SOURCE=.\IMSWindowsScreenEventHandler.h
# End Source File
# End Group # End Group
# End Target # End Target
# End Project # End Project

View File

@ -13,11 +13,11 @@
*/ */
#include "CPrimaryClient.h" #include "CPrimaryClient.h"
#include "IPrimaryScreenFactory.h" #include "CScreen.h"
#include "IScreenFactory.h"
#include "IServer.h" #include "IServer.h"
#include "XScreen.h" #include "XScreen.h"
#include "XSynergy.h" #include "XSynergy.h"
#include "CPrimaryScreen.h"
#include "CClipboard.h" #include "CClipboard.h"
#include "CLog.h" #include "CLog.h"
@ -25,7 +25,7 @@
// CPrimaryClient // CPrimaryClient
// //
CPrimaryClient::CPrimaryClient(IPrimaryScreenFactory* screenFactory, CPrimaryClient::CPrimaryClient(IScreenFactory* screenFactory,
IServer* server, IServer* server,
IPrimaryScreenReceiver* receiver, IPrimaryScreenReceiver* receiver,
const CString& name) : const CString& name) :
@ -38,7 +38,11 @@ CPrimaryClient::CPrimaryClient(IPrimaryScreenFactory* screenFactory,
// create screen // create screen
LOG((CLOG_DEBUG1 "creating primary screen")); LOG((CLOG_DEBUG1 "creating primary screen"));
if (screenFactory != NULL) { if (screenFactory != NULL) {
m_screen = screenFactory->create(this, receiver); IPlatformScreen* platformScreen =
screenFactory->create(this, receiver);
if (platformScreen != NULL) {
m_screen = new CScreen(platformScreen, this);
}
} }
if (m_screen == NULL) { if (m_screen == NULL) {
throw XScreenOpenFailure(); throw XScreenOpenFailure();
@ -86,7 +90,7 @@ CPrimaryClient::isLockedToScreen() const
KeyModifierMask KeyModifierMask
CPrimaryClient::getToggleMask() const CPrimaryClient::getToggleMask() const
{ {
return m_screen->getToggleMask(); return m_screen->getActiveModifiers();
} }
void void
@ -149,13 +153,28 @@ CPrimaryClient::close()
m_screen->close(); m_screen->close();
} }
void
CPrimaryClient::enable()
{
m_screen->enable();
}
void
CPrimaryClient::disable()
{
m_screen->disable();
}
void void
CPrimaryClient::enter(SInt32 xAbs, SInt32 yAbs, CPrimaryClient::enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask, bool screensaver) UInt32 seqNum, KeyModifierMask, bool screensaver)
{ {
// note -- we must not call any server methods except onError(). // note -- we must not call any server methods except onError().
m_seqNum = seqNum; m_seqNum = seqNum;
m_screen->enter(xAbs, yAbs, screensaver); if (!screensaver) {
m_screen->warpCursor(xAbs, yAbs);
}
m_screen->enter();
} }
bool bool

View File

@ -19,9 +19,9 @@
#include "IScreenReceiver.h" #include "IScreenReceiver.h"
#include "ProtocolTypes.h" #include "ProtocolTypes.h"
class CScreen;
class IClipboard; class IClipboard;
class CPrimaryScreen; class IScreenFactory;
class IPrimaryScreenFactory;
class IPrimaryScreenReceiver; class IPrimaryScreenReceiver;
class IServer; class IServer;
@ -38,7 +38,7 @@ public:
\c factory. Throws XScreenOpenFailure or whatever the factory can \c factory. Throws XScreenOpenFailure or whatever the factory can
throw if the screen cannot be created. throw if the screen cannot be created.
*/ */
CPrimaryClient(IPrimaryScreenFactory* factory, IServer*, CPrimaryClient(IScreenFactory* factory, IServer*,
IPrimaryScreenReceiver*, const CString& name); IPrimaryScreenReceiver*, const CString& name);
~CPrimaryClient(); ~CPrimaryClient();
@ -96,6 +96,9 @@ public:
virtual bool onGrabClipboard(ClipboardID); virtual bool onGrabClipboard(ClipboardID);
virtual void onClipboardChanged(ClipboardID, const CString&); virtual void onClipboardChanged(ClipboardID, const CString&);
// XXX -- these go in IClient
virtual void enable();
virtual void disable();
// IClient overrides // IClient overrides
virtual void open(); virtual void open();
virtual void mainLoop(); virtual void mainLoop();
@ -127,7 +130,7 @@ public:
private: private:
IServer* m_server; IServer* m_server;
CPrimaryScreen* m_screen; CScreen* m_screen;
CString m_name; CString m_name;
UInt32 m_seqNum; UInt32 m_seqNum;
CClientInfo m_info; CClientInfo m_info;

View File

@ -15,7 +15,7 @@
#include "CServer.h" #include "CServer.h"
#include "CHTTPServer.h" #include "CHTTPServer.h"
#include "CPrimaryClient.h" #include "CPrimaryClient.h"
#include "IPrimaryScreenFactory.h" #include "IScreenFactory.h"
#include "CInputPacketStream.h" #include "CInputPacketStream.h"
#include "COutputPacketStream.h" #include "COutputPacketStream.h"
#include "CProtocolUtil.h" #include "CProtocolUtil.h"
@ -89,6 +89,7 @@ CServer::open()
LOG((CLOG_INFO "opening screen")); LOG((CLOG_INFO "opening screen"));
openPrimaryScreen(); openPrimaryScreen();
setStatus(kNotRunning); setStatus(kNotRunning);
m_primaryClient->enable();
} }
catch (XScreen& e) { catch (XScreen& e) {
// can't open screen // can't open screen
@ -212,6 +213,7 @@ void
CServer::close() CServer::close()
{ {
if (m_primaryClient != NULL) { if (m_primaryClient != NULL) {
m_primaryClient->disable();
closePrimaryScreen(); closePrimaryScreen();
} }
LOG((CLOG_INFO "closed screen")); LOG((CLOG_INFO "closed screen"));
@ -280,7 +282,7 @@ CServer::setConfig(const CConfig& config)
} }
void void
CServer::setScreenFactory(IPrimaryScreenFactory* adopted) CServer::setScreenFactory(IScreenFactory* adopted)
{ {
CLock lock(&m_mutex); CLock lock(&m_mutex);
delete m_screenFactory; delete m_screenFactory;
@ -1601,7 +1603,7 @@ CServer::runClient(void* vsocket)
try { try {
CProtocolUtil::writef(proxy->getOutputStream(), kMsgEBusy); CProtocolUtil::writef(proxy->getOutputStream(), kMsgEBusy);
} }
catch (XSocket&) { catch (XIO&) {
// ignore // ignore
} }
delete proxy; delete proxy;
@ -1614,7 +1616,7 @@ CServer::runClient(void* vsocket)
try { try {
CProtocolUtil::writef(proxy->getOutputStream(), kMsgEUnknown); CProtocolUtil::writef(proxy->getOutputStream(), kMsgEUnknown);
} }
catch (XSocket&) { catch (XIO&) {
// ignore // ignore
} }
delete proxy; delete proxy;
@ -1646,7 +1648,7 @@ CServer::runClient(void* vsocket)
try { try {
CProtocolUtil::writef(proxy->getOutputStream(), kMsgEBad); CProtocolUtil::writef(proxy->getOutputStream(), kMsgEBad);
} }
catch (XSocket&) { catch (XIO&) {
// ignore. client probably aborted the connection. // ignore. client probably aborted the connection.
} }
} }
@ -1766,7 +1768,7 @@ CServer::handshakeClient(IDataSocket* socket)
CProtocolUtil::writef(output, kMsgEIncompatible, CProtocolUtil::writef(output, kMsgEIncompatible,
kProtocolMajorVersion, kProtocolMinorVersion); kProtocolMajorVersion, kProtocolMinorVersion);
} }
catch (XSocket&) { catch (XIO&) {
// ignore // ignore
} }
} }
@ -1776,7 +1778,7 @@ CServer::handshakeClient(IDataSocket* socket)
try { try {
CProtocolUtil::writef(output, kMsgEBad); CProtocolUtil::writef(output, kMsgEBad);
} }
catch (XSocket&) { catch (XIO&) {
// ignore. client probably aborted the connection. // ignore. client probably aborted the connection.
} }
} }

View File

@ -33,7 +33,7 @@ class CHTTPServer;
class CPrimaryClient; class CPrimaryClient;
class IClient; class IClient;
class IDataSocket; class IDataSocket;
class IPrimaryScreenFactory; class IScreenFactory;
class IServerProtocol; class IServerProtocol;
class ISocketFactory; class ISocketFactory;
class IStreamFilterFactory; class IStreamFilterFactory;
@ -102,13 +102,12 @@ public:
*/ */
bool setConfig(const CConfig&); bool setConfig(const CConfig&);
//! Set primary screen factory //! Set screen factory
/*! /*!
Sets the factory for creating primary screens. This must be Sets the factory for creating screens. This must be set before
set before calling open(). This object takes ownership of the calling open(). This object takes ownership of the factory.
factory.
*/ */
void setScreenFactory(IPrimaryScreenFactory*); void setScreenFactory(IScreenFactory*);
//! Set socket factory //! Set socket factory
/*! /*!
@ -341,7 +340,7 @@ private:
double m_bindTimeout; double m_bindTimeout;
// factories // factories
IPrimaryScreenFactory* m_screenFactory; IScreenFactory* m_screenFactory;
ISocketFactory* m_socketFactory; ISocketFactory* m_socketFactory;
IStreamFilterFactory* m_streamFilterFactory; IStreamFilterFactory* m_streamFilterFactory;

View File

@ -1,281 +0,0 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* 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.
*/
#include "CPrimaryScreen.h"
#include "IScreen.h"
#include "IScreenReceiver.h"
#include "ProtocolTypes.h"
#include "CLock.h"
#include "CThread.h"
#include "CLog.h"
//
// CPrimaryScreen
//
CPrimaryScreen::CPrimaryScreen(IScreenReceiver* receiver) :
m_receiver(receiver),
m_active(false)
{
// do nothing
}
CPrimaryScreen::~CPrimaryScreen()
{
// do nothing
}
void
CPrimaryScreen::mainLoop()
{
// change our priority
CThread::getCurrentThread().setPriority(-14);
// run event loop
try {
LOG((CLOG_DEBUG "entering event loop"));
onPreMainLoop();
getScreen()->mainLoop();
onPostMainLoop();
LOG((CLOG_DEBUG "exiting event loop"));
}
catch (...) {
onPostMainLoop();
LOG((CLOG_DEBUG "exiting event loop"));
throw;
}
}
void
CPrimaryScreen::exitMainLoop()
{
getScreen()->exitMainLoop();
}
void
CPrimaryScreen::open()
{
CClientInfo info;
try {
// subclass hook
onPreOpen();
// open the screen
getScreen()->open();
// create and prepare our window
createWindow();
// collect screen info
getScreen()->getShape(info.m_x, info.m_y, info.m_w, info.m_h);
getScreen()->getCursorPos(info.m_mx, info.m_my);
info.m_zoneSize = getJumpZoneSize();
// update keyboard state
updateKeys();
// get notified of screen saver activation/deactivation
getScreen()->openScreensaver(true);
// subclass hook
onPostOpen();
// reset options
resetOptions();
}
catch (...) {
close();
throw;
}
// enter the screen
{
CLock lock(&m_mutex);
enterNoWarp();
}
// send screen info
m_receiver->onInfoChanged(info);
}
void
CPrimaryScreen::close()
{
onPreClose();
getScreen()->closeScreensaver();
destroyWindow();
getScreen()->close();
onPostClose();
}
void
CPrimaryScreen::enter(SInt32 x, SInt32 y, bool forScreensaver)
{
LOG((CLOG_INFO "entering primary at %d,%d%s", x, y, forScreensaver ? " for screen saver" : ""));
CLock lock(&m_mutex);
assert(m_active == true);
if (!forScreensaver) {
warpCursor(x, y);
}
else {
onEnterScreensaver();
}
enterNoWarp();
}
void
CPrimaryScreen::enterNoWarp()
{
// note -- must be locked on entry
// not active anymore
m_active = false;
// subclass hook
onPreEnter();
// restore active window and hide our window
hideWindow();
// subclass hook
onPostEnter();
}
bool
CPrimaryScreen::leave()
{
LOG((CLOG_INFO "leaving primary"));
CLock lock(&m_mutex);
assert(m_active == false);
// subclass hook
onPreLeave();
// show our window
if (!showWindow()) {
onPostLeave(false);
return false;
}
// get keyboard state as we leave
updateKeys();
// warp mouse to center
warpCursorToCenter();
// subclass hook
onPostLeave(true);
// local client now active
m_active = true;
// make sure our idea of clipboard ownership is correct
getScreen()->checkClipboards();
return true;
}
void
CPrimaryScreen::setClipboard(ClipboardID id,
const IClipboard* clipboard)
{
getScreen()->setClipboard(id, clipboard);
}
void
CPrimaryScreen::grabClipboard(ClipboardID id)
{
getScreen()->setClipboard(id, NULL);
}
bool
CPrimaryScreen::isActive() const
{
CLock lock(&m_mutex);
return m_active;
}
void
CPrimaryScreen::getClipboard(ClipboardID id,
IClipboard* clipboard) const
{
getScreen()->getClipboard(id, clipboard);
}
void
CPrimaryScreen::onPreMainLoop()
{
// do nothing
}
void
CPrimaryScreen::onPostMainLoop()
{
// do nothing
}
void
CPrimaryScreen::onPreOpen()
{
// do nothing
}
void
CPrimaryScreen::onPostOpen()
{
// do nothing
}
void
CPrimaryScreen::onPreClose()
{
// do nothing
}
void
CPrimaryScreen::onPostClose()
{
// do nothing
}
void
CPrimaryScreen::onPreEnter()
{
// do nothing
}
void
CPrimaryScreen::onPostEnter()
{
// do nothing
}
void
CPrimaryScreen::onEnterScreensaver()
{
// do nothing
}
void
CPrimaryScreen::onPreLeave()
{
// do nothing
}
void
CPrimaryScreen::onPostLeave(bool)
{
// do nothing
}

View File

@ -1,349 +0,0 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* 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.
*/
#ifndef CPRIMARYSCREEN_H
#define CPRIMARYSCREEN_H
#include "ClipboardTypes.h"
#include "KeyTypes.h"
#include "OptionTypes.h"
#include "CMutex.h"
class IClipboard;
class IScreen;
class IScreenReceiver;
//! Generic server-side screen
/*!
This is a platform independent base class for primary screen
implementations. A primary screen is a server-side screen.
Each platform will derive a class from CPrimaryScreen to handle
platform dependent operations.
*/
class CPrimaryScreen {
public:
CPrimaryScreen(IScreenReceiver*);
virtual ~CPrimaryScreen();
//! @name manipulators
//@{
//! Open screen
/*!
Opens the screen. This includes initializing the screen, opening
the screen saver, synchronizing keyboard state, and causing events
to be reported to an IPrimaryScreenReceiver (set through another
interface). Calls close() before returning (rethrowing) if it
fails for any reason.
*/
void open();
//! Run event loop
/*!
Run the screen's event loop. This returns when it detects
the application should terminate or when exitMainLoop() is called.
mainLoop() may only be called between open() and close().
*/
void mainLoop();
//! Exit event loop
/*!
Force mainLoop() to return. This call can return before
mainLoop() does (i.e. asynchronously).
*/
void exitMainLoop();
//! Close screen
/*!
Closes the screen. This close the screen saver and the screen.
*/
void close();
//! Enter screen
/*!
Called when the user navigates to the primary screen. Warps
the cursor to the absolute coordinates \c x,y and unhides
it. If \c forScreensaver is true then we're entering because
the screen saver started and the cursor is not warped.
*/
void enter(SInt32 x, SInt32 y, bool forScreensaver);
//! Leave screen
/*!
Called when the user navigates off the primary screen. Returns
true iff successful.
*/
bool leave();
//! Update configuration
/*!
This is called when the configuration has changed. \c activeSides
is a bitmask of EDirectionMask indicating which sides of the
primary screen are linked to clients. Override to handle the
possible change in jump zones.
*/
virtual void reconfigure(UInt32 activeSides) = 0;
//! Warp cursor
/*!
Warp the cursor to the absolute coordinates \c x,y. Also
discard input events up to and including the warp before
returning.
*/
virtual void warpCursor(SInt32 x, SInt32 y) = 0;
//! Set clipboard
/*!
Sets the system's clipboard contents. This is usually called
soon after an enter().
*/
void setClipboard(ClipboardID, const IClipboard*);
//! Grab clipboard
/*!
Grabs (i.e. take ownership of) the system clipboard.
*/
void grabClipboard(ClipboardID);
//! Notify of options changes
/*!
Reset all options to their default values.
*/
virtual void resetOptions() = 0;
//! Notify of options changes
/*!
Set options to given values. Ignore unknown options and don't
modify our options that aren't given in \c options.
*/
virtual void setOptions(const COptionsList& options) = 0;
//! Install a one-shot timer
/*!
Installs a one-shot timer for \c timeout seconds and returns the
id of the timer.
*/
virtual UInt32 addOneShotTimer(double timeout) = 0;
//@}
//! @name accessors
//@{
//! Test if active
/*!
Returns true iff the screen is active (i.e. the user has left
the screen). Note this is the reverse of a secdonary screen.
*/
bool isActive() const;
//! Get clipboard
/*!
Saves the contents of the system clipboard indicated by \c id.
*/
void getClipboard(ClipboardID, IClipboard*) const;
//! Get jump zone size
/*!
Return the jump zone size, the size of the regions on the edges of
the screen that cause the cursor to jump to another screen.
*/
virtual SInt32 getJumpZoneSize() const = 0;
//! Get toggle key state
/*!
Return the primary screen's current toggle modifier key state.
The returned mask should have the corresponding bit set for
each toggle key that is active. For example, if caps lock is
on then the returned mask should have \c KeyModifierCapsLock set.
*/
virtual KeyModifierMask getToggleMask() const = 0;
//! Get screen lock state
/*!
Return true if any key or button is being pressed or if there's
any other reason that the user should not be allowed to switch
screens. Active toggle keys (including the scroll lock key)
should not be counted as reasons to lock to the screen.
If this method returns true it should log a message on why at
the CLOG_DEBUG level.
*/
virtual bool isLockedToScreen() const = 0;
//! Get screen
/*!
Return the platform dependent screen.
*/
virtual IScreen* getScreen() const = 0;
//@}
protected:
//! Pre-mainLoop() hook
/*!
Called on entry to mainLoop(). Override to perform platform specific
operations. Default does nothing. May throw.
*/
virtual void onPreMainLoop();
//! Post-mainLoop() hook
/*!
Called on exit from mainLoop(). Override to perform platform specific
operations. Default does nothing. May \b not throw.
*/
virtual void onPostMainLoop();
//! Pre-open() hook
/*!
Called on entry to open(). Override to perform platform specific
operations. Default does nothing. May throw.
*/
virtual void onPreOpen();
//! Post-open() hook
/*!
Called on exit from open() iff the open was successful. Default
does nothing. May throw.
*/
virtual void onPostOpen();
//! Pre-close() hook
/*!
Called on entry to close(). Override to perform platform specific
operations. Default does nothing. May \b not throw.
*/
virtual void onPreClose();
//! Post-close() hook
/*!
Called on exit from close(). Override to perform platform specific
operations. Default does nothing. May \b not throw.
*/
virtual void onPostClose();
//! Pre-enter() hook
/*!
Called from enter() after the cursor has been warped or, if
\c forScreensaver is true, onEnterScreensaver() was called. Override
to perform platform specific operations. Default does nothing. May
\b not throw.
*/
virtual void onPreEnter();
//! Post-enter() hook
/*!
Called on exit from enter(). Override to perform platform specific
operations. Default does nothing. May \b not throw.
*/
virtual void onPostEnter();
//! Pre-enter() for screen saver hook
/*!
Called on entry to enter() if the \c forScreensaver passed to it was
true. Override to perform platform specific operations. Default
does nothing. May \b not throw.
*/
virtual void onEnterScreensaver();
//! Pre-leave() hook
/*!
Called on entry to leave() after desktop synchronization. Override
to perform platform specific operations. Default does nothing. May
\b not throw.
*/
virtual void onPreLeave();
//! Post-leave() hook
/*!
Called on exit from leave(). \c success is the value returned by
showWindow(). Override to perform platform specific operations.
Default does nothing. May \b not throw.
*/
virtual void onPostLeave(bool success);
//! Create window
/*!
Called to create the window. This window is generally used to
receive events, hide the cursor, and to capture keyboard and mouse
input.
*/
virtual void createWindow() = 0;
//! Destroy window
/*!
Called to destroy the window created by createWindow().
*/
virtual void destroyWindow() = 0;
//! Show window
/*!
Called when the user navigates off the primary screen. Hide the
cursor and grab exclusive access to the input devices. Every call
to showWindow() has a matching call to hideWindow() which preceeds
it. Return true iff successful (in particular, iff the input
devices were grabbed).
After a successful showWindow(), user input events and
screensaver activation/deactivation should be reported to an
IPrimaryScreenReceiver (set through another interface) until
hideWindow() is called. Report mouse motion to its
onMouseMoveSecondary(). User input should not be delivered to
any application except this one.
*/
virtual bool showWindow() = 0;
//! Hide window
/*!
Called when the user navigates back to the primary screen. Show
the cursor and ungrab the input devices.
After hideWindow(), user input events should be delivered normally
to other applications. Mouse motion over (at least) the jump zones
must be reported to an IPrimaryScreenReceiver's onMouseMovePrimary().
*/
virtual void hideWindow() = 0;
//! Warp cursor for relative motion
/*!
Prepare the cursor to report relative motion. When the user has
navigated to another screen, synergy requires the cursor motion
deltas, not the absolute coordinates. Typically this is done by
warping the cursor to the center of the primary screen and then
every time it moves compute the motion and warp back to the
center (but without reporting that warp as motion). This is
only called after a successful showWindow().
*/
virtual void warpCursorToCenter() = 0;
//! Synchronize key state
/*!
Check the current keyboard state. Normally a screen will save
the keyboard state in this method and use this shadow state
when handling user input and in methods like isLockedToScreen().
*/
virtual void updateKeys() = 0;
private:
void enterNoWarp();
private:
CMutex m_mutex;
// object to notify of changes
IScreenReceiver* m_receiver;
// m_active is true if this screen has been left
bool m_active;
};
#endif

1001
lib/synergy/CScreen.cpp Normal file

File diff suppressed because it is too large Load Diff

357
lib/synergy/CScreen.h Normal file
View File

@ -0,0 +1,357 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* 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.
*/
#ifndef CSECONDARYSCREEN_H
#define CSECONDARYSCREEN_H
#include "IKeyState.h"
#include "ClipboardTypes.h"
#include "MouseTypes.h"
#include "OptionTypes.h"
#include "CMutex.h"
#include "stdmap.h"
class IClipboard;
class IPlatformScreen;
class IScreenReceiver;
//! Platform independent screen
/*!
This is a platform independent screen. It can work as either a
primary or secondary screen.
*/
class CScreen : public IKeyState {
public:
CScreen(IPlatformScreen* platformScreen, IScreenReceiver*);
virtual ~CScreen();
//! @name manipulators
//@{
//! Open screen
/*!
Opens the screen.
*/
void open();
//! Close screen
/*!
Closes the screen.
*/
void close();
//! Activate screen
/*!
Activate the screen, preparing it to report system and user events.
For a secondary screen it also means disabling the screen saver if
synchronizing it and preparing to synthesize events.
*/
void enable();
//! Deactivate screen
/*!
Undoes the operations in activate() and events are no longer
reported. It also releases keys that are logically pressed.
*/
void disable();
//! Run event loop
/*!
Run the screen's event loop. This returns when it detects
the application should terminate or when exitMainLoop() is called.
mainLoop() may only be called between open() and close().
*/
void mainLoop();
//! Exit event loop
/*!
Force mainLoop() to return. This call can return before
mainLoop() does (i.e. asynchronously).
*/
void exitMainLoop();
//! Enter screen
/*!
Called when the user navigates to this screen.
*/
void enter();
//! Leave screen
/*!
Called when the user navigates off this screen.
*/
bool leave();
//! Update configuration
/*!
This is called when the configuration has changed. \c activeSides
is a bitmask of EDirectionMask indicating which sides of the
primary screen are linked to clients.
*/
void reconfigure(UInt32 activeSides);
//! Warp cursor
/*!
Warps the cursor to the absolute coordinates \c x,y. Also
discards input events up to and including the warp before
returning.
*/
void warpCursor(SInt32 x, SInt32 y);
//! Set clipboard
/*!
Sets the system's clipboard contents. This is usually called
soon after an enter().
*/
void setClipboard(ClipboardID, const IClipboard*);
//! Grab clipboard
/*!
Grabs (i.e. take ownership of) the system clipboard.
*/
void grabClipboard(ClipboardID);
//! Activate/deactivate screen saver
/*!
Forcibly activates the screen saver if \c activate is true otherwise
forcibly deactivates it.
*/
void screensaver(bool activate);
//! Notify of key press
/*!
Synthesize key events to generate a press of key \c id. If possible
match the given modifier mask. The KeyButton identifies the physical
key on the server that generated this key down. The client must
ensure that a key up or key repeat that uses the same KeyButton will
synthesize an up or repeat for the same client key synthesized by
keyDown().
*/
void keyDown(KeyID id, KeyModifierMask, KeyButton);
//! Notify of key repeat
/*!
Synthesize key events to generate a press and release of key \c id
\c count times. If possible match the given modifier mask.
*/
void keyRepeat(KeyID id, KeyModifierMask,
SInt32 count, KeyButton);
//! Notify of key release
/*!
Synthesize key events to generate a release of key \c id. If possible
match the given modifier mask.
*/
void keyUp(KeyID id, KeyModifierMask, KeyButton);
//! Notify of mouse press
/*!
Synthesize mouse events to generate a press of mouse button \c id.
*/
void mouseDown(ButtonID id);
//! Notify of mouse release
/*!
Synthesize mouse events to generate a release of mouse button \c id.
*/
void mouseUp(ButtonID id);
//! Notify of mouse motion
/*!
Synthesize mouse events to generate mouse motion to the absolute
screen position \c xAbs,yAbs.
*/
void mouseMove(SInt32 xAbs, SInt32 yAbs);
//! Notify of mouse wheel motion
/*!
Synthesize mouse events to generate mouse wheel motion of \c delta.
\c delta is positive for motion away from the user and negative for
motion towards the user. Each wheel click should generate a delta
of +/-120.
*/
void mouseWheel(SInt32 delta);
//! Notify of options changes
/*!
Resets all options to their default values.
*/
void resetOptions();
//! Notify of options changes
/*!
Set options to given values. Ignores unknown options and doesn't
modify options that aren't given in \c options.
*/
void setOptions(const COptionsList& options);
//! Install a one-shot timer
/*!
Installs a one-shot timer for \c timeout seconds and returns the
id of the timer.
*/
UInt32 addOneShotTimer(double timeout);
//@}
//! @name accessors
//@{
//! Test if cursor on screen
/*!
Returns true iff the cursor is on the screen.
*/
bool isOnScreen() const;
//! Get clipboard
/*!
Saves the contents of the system clipboard indicated by \c id.
*/
void getClipboard(ClipboardID id, IClipboard*) const;
//! Get jump zone size
/*!
Returns the jump zone size, the size of the regions on the edges of
the screen that cause the cursor to jump to another screen.
*/
SInt32 getJumpZoneSize() const;
//! Get screen lock state
/*!
Returns true if there's any reason that the user should not be
allowed to leave the screen. Active toggle keys (excluding the
scroll lock key) are not be counted as reasons to lock to the
screen. If this method returns true it logs a message on why at
the CLOG_DEBUG level.
*/
bool isLockedToScreen() const;
//! Get screen shape
/*!
Returns the position of the upper-left corner of the screen in \c x
and \c y and the size of the screen in \c width and \c height.
*/
void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const;
//! Get cursor position
/*!
Returns the current position of the cursor in \c x,y.
*/
void getCursorPos(SInt32& x, SInt32& y) const;
//@}
// IKeyState overrides
virtual void updateKeys();
virtual void releaseKeys();
virtual void setKeyDown(KeyButton key);
virtual void setToggled(KeyModifierMask);
virtual void addModifier(KeyModifierMask, KeyButtons&);
virtual void setToggleState(KeyModifierMask);
virtual KeyButton isAnyKeyDown() const;
virtual bool isKeyDown(KeyButton) const;
virtual bool isToggle(KeyModifierMask) const;
virtual bool isHalfDuplex(KeyModifierMask) const;
virtual bool isModifierActive(KeyModifierMask) const;
virtual KeyModifierMask
getActiveModifiers() const;
virtual bool mapModifier(Keystrokes& keys, Keystrokes& undo,
KeyModifierMask mask, bool desireActive) const;
virtual KeyModifierMask
getMaskForKey(KeyButton) const;
protected:
void enablePrimary();
void enableSecondary();
void disablePrimary();
void disableSecondary();
void enterPrimary();
void enterSecondary();
void leavePrimary();
void leaveSecondary();
private:
// Get the modifier mask for the current key state
KeyModifierMask getModifierMask() const;
// Send fake keystrokes
void doKeystrokes(const Keystrokes&, SInt32 count);
// Send a fake key event
void fakeKeyEvent(KeyButton, bool press, bool repeat) const;
// Update the shadow state for a key
void updateKeyState(KeyButton button,
KeyButton key, bool press);
// Toggle a modifier
void toggleKey(KeyModifierMask);
// Test if a modifier is toggled
bool isKeyToggled(KeyButton) const;
private:
typedef std::map<KeyButton, KeyButton> ServerKeyMap;
typedef std::map<KeyModifierMask, KeyButtons> MaskToKeys;
typedef std::map<KeyButton, KeyModifierMask> KeyToMask;
CMutex m_mutex;
// our platform dependent screen
IPlatformScreen* m_screen;
// our screen receiver
IScreenReceiver* m_receiver;
// true if screen is being used as a primary screen, false otherwise
bool m_isPrimary;
// true if screen is enabled
bool m_enabled;
// true if the cursor is on this screen
bool m_entered;
// true if screen saver should be synchronized to server
bool m_screenSaverSync;
// note toggle keys that toggles on up/down (false) or on
// transition (true)
bool m_numLockHalfDuplex;
bool m_capsLockHalfDuplex;
// keyboard state
// map server key buttons to local system keys
ServerKeyMap m_serverKeyMap;
// system key states as set by us or the user
KeyState m_keys[256];
// system key states as set by us
KeyState m_fakeKeys[256];
// modifier info
MaskToKeys m_maskToKeys;
KeyToMask m_keyToMask;
// current active modifiers
KeyModifierMask m_mask;
// the toggle key state when this screen was last entered
KeyModifierMask m_toggleKeys;
};
#endif

View File

@ -1,781 +0,0 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* 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.
*/
#include "CSecondaryScreen.h"
#include "IScreen.h"
#include "CLock.h"
#include "CThread.h"
#include "CLog.h"
//
// CSecondaryScreen
//
CSecondaryScreen::CSecondaryScreen() :
m_remoteReady(false),
m_active(false),
m_toggleKeys(0),
m_screenSaverSync(true)
{
// do nothing
}
CSecondaryScreen::~CSecondaryScreen()
{
// do nothing
}
void
CSecondaryScreen::mainLoop()
{
// change our priority
CThread::getCurrentThread().setPriority(-14);
// run event loop
try {
LOG((CLOG_DEBUG "entering event loop"));
onPreMainLoop();
getScreen()->mainLoop();
onPostMainLoop();
LOG((CLOG_DEBUG "exiting event loop"));
}
catch (...) {
onPostMainLoop();
LOG((CLOG_DEBUG "exiting event loop"));
throw;
}
}
void
CSecondaryScreen::exitMainLoop()
{
getScreen()->exitMainLoop();
}
void
CSecondaryScreen::open()
{
try {
// subclass hook
onPreOpen();
// open the screen
getScreen()->open();
// create and prepare our window. pretend we're active so
// we don't try to show our window until later.
{
CLock lock(&m_mutex);
assert(m_active == false);
m_active = true;
}
createWindow();
{
CLock lock(&m_mutex);
m_active = false;
}
// subclass hook
onPostOpen();
// reset options
resetOptions();
}
catch (...) {
close();
throw;
}
}
void
CSecondaryScreen::close()
{
onPreClose();
destroyWindow();
getScreen()->close();
onPostClose();
}
void
CSecondaryScreen::remoteControl()
{
// assume primary has all clipboards
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
grabClipboard(id);
}
// update keyboard state
{
CLock lock(&m_mutex);
updateKeys();
}
// now remote ready. fake being active for call to leave().
bool screenSaverSync;
{
CLock lock(&m_mutex);
m_remoteReady = true;
m_active = true;
// copy screen saver synchronization state
screenSaverSync = m_screenSaverSync;
}
// disable the screen saver if synchronization is enabled
if (screenSaverSync) {
getScreen()->openScreensaver(false);
}
// hide the cursor
leave();
}
void
CSecondaryScreen::localControl()
{
getScreen()->closeScreensaver();
// not remote ready anymore
CLock lock(&m_mutex);
m_remoteReady = false;
}
void
CSecondaryScreen::enter(SInt32 x, SInt32 y, KeyModifierMask mask)
{
CLock lock(&m_mutex);
assert(m_active == false);
LOG((CLOG_INFO "entering screen at %d,%d mask=%04x", x, y, mask));
sync();
// now active
m_active = true;
// subclass hook
onPreEnter();
// update our keyboard state to reflect the local state
updateKeys();
// toggle modifiers that don't match the desired state and
// remember previous toggle key state.
m_toggleKeys = m_mask;
setToggleState(mask);
// warp to requested location
fakeMouseMove(x, y);
// show mouse
hideWindow();
// subclass hook
onPostEnter();
}
void
CSecondaryScreen::leave()
{
LOG((CLOG_INFO "leaving screen"));
CLock lock(&m_mutex);
assert(m_active == true);
sync();
// subclass hook
onPreLeave();
// restore toggle key state
setToggleState(m_toggleKeys);
// hide mouse
SInt32 x, y;
getScreen()->getCursorCenter(x, y);
showWindow(x, y);
// subclass hook
onPostLeave();
// not active anymore
m_active = false;
// make sure our idea of clipboard ownership is correct
getScreen()->checkClipboards();
}
void
CSecondaryScreen::setClipboard(ClipboardID id,
const IClipboard* clipboard)
{
getScreen()->setClipboard(id, clipboard);
}
void
CSecondaryScreen::grabClipboard(ClipboardID id)
{
getScreen()->setClipboard(id, NULL);
}
void
CSecondaryScreen::screensaver(bool activate)
{
// get screen saver synchronization flag
bool screenSaverSync;
{
CLock lock(&m_mutex);
screenSaverSync = m_screenSaverSync;
}
// activate/deactivation screen saver iff synchronization enabled
if (screenSaverSync) {
getScreen()->screensaver(activate);
}
}
CSecondaryScreen::SysKeyID
CSecondaryScreen::getUnhanded(SysKeyID) const
{
// no key represents both left and right sides of any key
return 0;
}
CSecondaryScreen::SysKeyID
CSecondaryScreen::getOtherHanded(SysKeyID) const
{
// no key represents both left and right sides of any key
return 0;
}
bool
CSecondaryScreen::synthesizeCtrlAltDel(EKeyAction)
{
// pass keys through unchanged
return false;
}
void
CSecondaryScreen::sync() const
{
// do nothing
}
void
CSecondaryScreen::flush()
{
// do nothing
}
void
CSecondaryScreen::doKeystrokes(const Keystrokes& keys, SInt32 count)
{
// do nothing if no keys or no repeats
if (count < 1 || keys.empty()) {
return;
}
// generate key events
LOG((CLOG_DEBUG2 "keystrokes:"));
for (Keystrokes::const_iterator k = keys.begin(); k != keys.end(); ) {
if (k->m_repeat) {
// repeat from here up to but not including the next key
// with m_repeat == false count times.
Keystrokes::const_iterator start = k;
for (; count > 0; --count) {
// send repeating events
for (k = start; k != keys.end() && k->m_repeat; ++k) {
LOG((CLOG_DEBUG2 " %d %s repeat", k->m_sysKeyID, k->m_press ? "down" : "up"));
fakeKeyEvent(k->m_sysKeyID, k->m_press);
}
}
// note -- k is now on the first non-repeat key after the
// repeat keys, exactly where we'd like to continue from.
}
else {
// send event
LOG((CLOG_DEBUG2 " %d %s", k->m_sysKeyID, k->m_press ? "down" : "up"));
fakeKeyEvent(k->m_sysKeyID, k->m_press);
// next key
++k;
}
}
flush();
}
void
CSecondaryScreen::keyDown(KeyID key,
KeyModifierMask mask, KeyButton button)
{
CLock lock(&m_mutex);
sync();
// check for ctrl+alt+del emulation
if (key == kKeyDelete &&
(mask & (KeyModifierControl | KeyModifierAlt)) ==
(KeyModifierControl | KeyModifierAlt)) {
LOG((CLOG_DEBUG "emulating ctrl+alt+del press"));
if (synthesizeCtrlAltDel(kPress)) {
return;
}
}
// get the sequence of keys to simulate key press and the final
// modifier state.
Keystrokes keys;
SysKeyID sysKeyID;
m_mask = mapKey(keys, sysKeyID, key, m_mask, mask, kPress);
if (keys.empty()) {
// do nothing if there are no associated keys (i.e. lookup failed)
return;
}
sysKeyID &= 0xffu;
// generate key events
doKeystrokes(keys, 1);
// do not record button down if button or system key is 0 (invalid)
if (button != 0 && sysKeyID != 0) {
// note that key is now down
SysKeyID unhandedSysKeyID = getUnhanded(sysKeyID);
m_serverKeyMap[button] = sysKeyID;
m_keys[sysKeyID] |= kDown;
m_fakeKeys[sysKeyID] |= kDown;
if (unhandedSysKeyID != 0) {
m_keys[unhandedSysKeyID] |= kDown;
m_fakeKeys[unhandedSysKeyID] |= kDown;
}
}
}
void
CSecondaryScreen::keyRepeat(KeyID key,
KeyModifierMask mask, SInt32 count, KeyButton button)
{
CLock lock(&m_mutex);
sync();
// if we haven't seen this button go down then ignore it
ServerKeyMap::iterator index = m_serverKeyMap.find(button);
if (index == m_serverKeyMap.end()) {
return;
}
// get the sequence of keys to simulate key repeat and the final
// modifier state.
Keystrokes keys;
SysKeyID sysKeyID;
m_mask = mapKey(keys, sysKeyID, key, m_mask, mask, kRepeat);
if (keys.empty()) {
return;
}
sysKeyID &= 0xffu;
// if this key shouldn't auto-repeat then ignore
if (!isAutoRepeating(sysKeyID)) {
return;
}
// if the keycode for the auto-repeat is not the same as for the
// initial press then mark the initial key as released and the new
// key as pressed. this can happen when we auto-repeat after a
// dead key. for example, a dead accent followed by 'a' will
// generate an 'a with accent' followed by a repeating 'a'. the
// keycodes for the two keysyms might be different.
if (sysKeyID != index->second) {
// replace key up with previous key id but leave key down
// alone so it uses the new keycode and store that keycode
// in the server key map.
for (Keystrokes::iterator index2 = keys.begin();
index2 != keys.end(); ++index2) {
if ((index2->m_sysKeyID & 0xffu) == sysKeyID) {
index2->m_sysKeyID = index->second;
break;
}
}
// note that old key is now up
m_keys[index->second] &= ~kDown;
m_fakeKeys[index->second] &= ~kDown;
// map server key to new key
index->second = sysKeyID;
// note that new key is now down
m_keys[index->second] |= kDown;
m_fakeKeys[index->second] |= kDown;
}
// generate key events
doKeystrokes(keys, count);
}
void
CSecondaryScreen::keyUp(KeyID key, KeyModifierMask mask, KeyButton button)
{
CLock lock(&m_mutex);
sync();
// if we haven't seen this button go down then ignore it
ServerKeyMap::iterator index = m_serverKeyMap.find(button);
if (index == m_serverKeyMap.end()) {
return;
}
SysKeyID sysKeyID = index->second;
// check for ctrl+alt+del emulation
if (key == kKeyDelete &&
(mask & (KeyModifierControl | KeyModifierAlt)) ==
(KeyModifierControl | KeyModifierAlt)) {
LOG((CLOG_DEBUG "emulating ctrl+alt+del release"));
if (synthesizeCtrlAltDel(kRelease)) {
return;
}
}
// get the sequence of keys to simulate key release
Keystrokes keys;
Keystroke keystroke;
keystroke.m_sysKeyID = sysKeyID;
keystroke.m_press = false;
keystroke.m_repeat = false;
keys.push_back(keystroke);
// generate key events
doKeystrokes(keys, 1);
// note that key is now up
SysKeyID unhandedSysKeyID = getUnhanded(sysKeyID);
m_serverKeyMap.erase(index);
m_keys[sysKeyID] &= ~kDown;
m_fakeKeys[sysKeyID] &= ~kDown;
if (unhandedSysKeyID != 0) {
SysKeyID otherHandedSysKeyID = getOtherHanded(sysKeyID);
if ((m_keys[otherHandedSysKeyID] & kDown) == 0) {
m_keys[unhandedSysKeyID] &= ~kDown;
m_fakeKeys[unhandedSysKeyID] &= ~kDown;
}
}
// get the new modifier state
mask = getModifierKeyMask(sysKeyID);
if (mask != 0) {
// key is a modifier key
if ((mask & (KeyModifierCapsLock |
KeyModifierNumLock |
KeyModifierScrollLock)) != 0) {
// modifier is a toggle
m_mask ^= mask;
}
else if (!isModifierActive(sysKeyID)) {
// all keys for this modifier are released
m_mask &= ~mask;
}
}
}
void
CSecondaryScreen::mouseDown(ButtonID button)
{
CLock lock(&m_mutex);
sync();
fakeMouseButton(button, true);
flush();
}
void
CSecondaryScreen::mouseUp(ButtonID button)
{
CLock lock(&m_mutex);
sync();
fakeMouseButton(button, false);
flush();
}
void
CSecondaryScreen::mouseMove(SInt32 x, SInt32 y)
{
CLock lock(&m_mutex);
sync();
fakeMouseMove(x, y);
flush();
}
void
CSecondaryScreen::mouseWheel(SInt32 delta)
{
CLock lock(&m_mutex);
sync();
fakeMouseWheel(delta);
flush();
}
void
CSecondaryScreen::setToggleState(KeyModifierMask mask)
{
// toggle modifiers that don't match the desired state
KeyModifierMask different = (m_mask ^ mask);
if ((different & KeyModifierCapsLock) != 0) {
toggleKey(kKeyCapsLock, KeyModifierCapsLock);
}
if ((different & KeyModifierNumLock) != 0) {
toggleKey(kKeyNumLock, KeyModifierNumLock);
}
if ((different & KeyModifierScrollLock) != 0) {
toggleKey(kKeyScrollLock, KeyModifierScrollLock);
}
}
void
CSecondaryScreen::resetOptions()
{
// set screen saver synchronization flag and see if we need to
// update the screen saver synchronization. reset other options.
bool screenSaverSyncOn;
{
CLock lock(&m_mutex);
screenSaverSyncOn = (!m_screenSaverSync && m_remoteReady);
m_screenSaverSync = true;
m_numLockHalfDuplex = false;
m_capsLockHalfDuplex = false;
}
// update screen saver synchronization
if (screenSaverSyncOn) {
getScreen()->openScreensaver(false);
}
}
void
CSecondaryScreen::setOptions(const COptionsList& options)
{
// update options
bool updateScreenSaverSync = false;
bool oldScreenSaverSync;
{
CLock lock(&m_mutex);
oldScreenSaverSync = m_screenSaverSync;
for (UInt32 i = 0, n = options.size(); i < n; i += 2) {
if (options[i] == kOptionScreenSaverSync) {
updateScreenSaverSync = true;
m_screenSaverSync = (options[i + 1] != 0);
LOG((CLOG_DEBUG1 "screen saver synchronization %s", m_screenSaverSync ? "on" : "off"));
}
else if (options[i] == kOptionHalfDuplexCapsLock) {
m_capsLockHalfDuplex = (options[i + 1] != 0);
LOG((CLOG_DEBUG1 "half-duplex caps-lock %s", m_capsLockHalfDuplex ? "on" : "off"));
}
else if (options[i] == kOptionHalfDuplexNumLock) {
m_numLockHalfDuplex = (options[i + 1] != 0);
LOG((CLOG_DEBUG1 "half-duplex num-lock %s", m_numLockHalfDuplex ? "on" : "off"));
}
}
if (!m_remoteReady || oldScreenSaverSync == m_screenSaverSync) {
updateScreenSaverSync = false;
}
}
// update screen saver synchronization
if (updateScreenSaverSync) {
if (oldScreenSaverSync) {
getScreen()->closeScreensaver();
}
else {
getScreen()->openScreensaver(false);
}
}
}
bool
CSecondaryScreen::isActive() const
{
CLock lock(&m_mutex);
return m_active;
}
void
CSecondaryScreen::getClipboard(ClipboardID id,
IClipboard* clipboard) const
{
getScreen()->getClipboard(id, clipboard);
}
SInt32
CSecondaryScreen::getJumpZoneSize() const
{
return 0;
}
void
CSecondaryScreen::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
{
sync();
getScreen()->getShape(x, y, w, h);
}
void
CSecondaryScreen::getCursorPos(SInt32& x, SInt32& y) const
{
sync();
getScreen()->getCursorPos(x, y);
}
void
CSecondaryScreen::onPreMainLoop()
{
// do nothing
}
void
CSecondaryScreen::onPostMainLoop()
{
// do nothing
}
void
CSecondaryScreen::onPreOpen()
{
// do nothing
}
void
CSecondaryScreen::onPostOpen()
{
// do nothing
}
void
CSecondaryScreen::onPreClose()
{
// do nothing
}
void
CSecondaryScreen::onPostClose()
{
// do nothing
}
void
CSecondaryScreen::onPreEnter()
{
// do nothing
}
void
CSecondaryScreen::onPostEnter()
{
// do nothing
}
void
CSecondaryScreen::onPreLeave()
{
// do nothing
}
void
CSecondaryScreen::onPostLeave()
{
// do nothing
}
void
CSecondaryScreen::updateKeys()
{
sync();
// clear key state
memset(m_keys, 0, sizeof(m_keys));
memset(m_fakeKeys, 0, sizeof(m_fakeKeys));
// let subclass set m_keys
updateKeys(m_keys);
// get m_mask from subclass
m_mask = getModifiers();
LOG((CLOG_DEBUG2 "modifiers on update: 0x%04x", m_mask));
}
void
CSecondaryScreen::releaseKeys()
{
CLock lock(&m_mutex);
sync();
// release keys that we've synthesized a press for and only those
// keys. we don't want to synthesize a release on a key the user
// is still physically pressing.
for (UInt32 i = 1; i < 256; ++i) {
if ((m_fakeKeys[i] & kDown) != 0) {
fakeKeyEvent(i, false);
m_keys[i] &= ~kDown;
m_fakeKeys[i] &= ~kDown;
}
}
flush();
}
void
CSecondaryScreen::toggleKey(KeyID keyID, KeyModifierMask mask)
{
// get the system key ID for this toggle key ID
SysKeyID sysKeyID = getToggleSysKey(keyID);
if (sysKeyID == 0) {
return;
}
// toggle the key
if (isKeyHalfDuplex(keyID)) {
// "half-duplex" toggle
fakeKeyEvent(sysKeyID, (m_mask & mask) == 0);
}
else {
// normal toggle
fakeKeyEvent(sysKeyID, true);
fakeKeyEvent(sysKeyID, false);
}
flush();
// toggle shadow state
m_mask ^= mask;
sysKeyID &= 0xffu;
m_keys[sysKeyID] ^= kToggled;
m_fakeKeys[sysKeyID] ^= kToggled;
}
bool
CSecondaryScreen::isKeyDown(SysKeyID sysKeyID) const
{
sysKeyID &= 0xffu;
return (sysKeyID != 0 && ((m_keys[sysKeyID] & kDown) != 0));
}
bool
CSecondaryScreen::isKeyToggled(SysKeyID sysKeyID) const
{
sysKeyID &= 0xffu;
return (sysKeyID != 0 && ((m_keys[sysKeyID] & kToggled) != 0));
}
bool
CSecondaryScreen::isKeyHalfDuplex(KeyID keyID) const
{
return ((keyID == kKeyCapsLock && m_capsLockHalfDuplex) ||
(keyID == kKeyNumLock && m_numLockHalfDuplex));
}

View File

@ -1,446 +0,0 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* 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.
*/
#ifndef CSECONDARYSCREEN_H
#define CSECONDARYSCREEN_H
#include "ClipboardTypes.h"
#include "KeyTypes.h"
#include "MouseTypes.h"
#include "OptionTypes.h"
#include "CMutex.h"
#include "stdmap.h"
#include "stdvector.h"
class IClipboard;
class IScreen;
//! Generic client-side screen
/*!
This is a platform independent base class for secondary screen
implementations. A secondary screen is a client-side screen.
Each platform will derive a class from CSecondaryScreen to handle
platform dependent operations.
*/
class CSecondaryScreen {
public:
CSecondaryScreen();
virtual ~CSecondaryScreen();
//! @name manipulators
//@{
//! Open screen
/*!
Opens the screen. It also causes events to the reported to an
IScreenReceiver (which is set through some other interface).
Calls close() before returning (rethrowing) if it fails for any
reason.
*/
void open();
//! Run event loop
/*!
Run the screen's event loop. This returns when it detects
the application should terminate or when exitMainLoop() is called.
mainLoop() may only be called between open() and close().
*/
void mainLoop();
//! Exit event loop
/*!
Force mainLoop() to return. This call can return before
mainLoop() does (i.e. asynchronously).
*/
void exitMainLoop();
//! Prepare for remote control
/*!
Prepares the screen for remote control by the server. In
particular, it disables the screen saver.
*/
void remoteControl();
//! Release from remote control
/*!
Cleans up the screen from remote control by the server. In
particular, it enables the screen saver. It also synthesizes
key up events for any keys that are logically down; without
this the client will leave its keyboard in the wrong logical
state.
*/
void localControl();
//! Close screen
/*!
Closes the screen.
*/
void close();
//! Enter screen
/*!
Called when the user navigates to this secondary screen. Warps
the cursor to the absolute coordinates \c x,y and unhides
it. Also prepares to synthesize input events.
*/
void enter(SInt32 x, SInt32 y, KeyModifierMask mask);
//! Leave screen
/*!
Called when the user navigates off the secondary screen. Cleans
up input event synthesis and hides the cursor.
*/
void leave();
//! Set clipboard
/*!
Sets the system's clipboard contents. This is usually called
soon after an enter().
*/
void setClipboard(ClipboardID, const IClipboard*);
//! Grab clipboard
/*!
Grabs (i.e. take ownership of) the system clipboard.
*/
void grabClipboard(ClipboardID);
//! Activate/deactivate screen saver
/*!
Forcibly activates the screen saver if \c activate is true otherwise
forcibly deactivates it.
*/
void screensaver(bool activate);
//! Notify of key press
/*!
Synthesize key events to generate a press of key \c id. If possible
match the given modifier mask. The KeyButton identifies the physical
key on the server that generated this key down. The client must
ensure that a key up or key repeat that uses the same KeyButton will
synthesize an up or repeat for the same client key synthesized by
keyDown().
*/
void keyDown(KeyID id, KeyModifierMask, KeyButton);
//! Notify of key repeat
/*!
Synthesize key events to generate a press and release of key \c id
\c count times. If possible match the given modifier mask.
*/
void keyRepeat(KeyID id, KeyModifierMask,
SInt32 count, KeyButton);
//! Notify of key release
/*!
Synthesize key events to generate a release of key \c id. If possible
match the given modifier mask.
*/
void keyUp(KeyID id, KeyModifierMask, KeyButton);
//! Notify of mouse press
/*!
Synthesize mouse events to generate a press of mouse button \c id.
*/
void mouseDown(ButtonID id);
//! Notify of mouse release
/*!
Synthesize mouse events to generate a release of mouse button \c id.
*/
void mouseUp(ButtonID id);
//! Notify of mouse motion
/*!
Synthesize mouse events to generate mouse motion to the absolute
screen position \c xAbs,yAbs.
*/
void mouseMove(SInt32 xAbs, SInt32 yAbs);
//! Notify of mouse wheel motion
/*!
Synthesize mouse events to generate mouse wheel motion of \c delta.
\c delta is positive for motion away from the user and negative for
motion towards the user. Each wheel click should generate a delta
of +/-120.
*/
void mouseWheel(SInt32 delta);
//! Notify of options changes
/*!
Reset all options to their default values. Overrides should call
the superclass's method.
*/
virtual void resetOptions();
//! Notify of options changes
/*!
Set options to given values. Ignore unknown options and don't
modify our options that aren't given in \c options. Overrides
should call the superclass's method.
*/
virtual void setOptions(const COptionsList& options);
//@}
//! @name accessors
//@{
//! Test if active
/*!
Returns true iff the screen is active (i.e. the user has entered
the screen). Note this is the reverse of a primary screen.
*/
bool isActive() const;
//! Get clipboard
/*!
Saves the contents of the system clipboard indicated by \c id.
*/
void getClipboard(ClipboardID id, IClipboard*) const;
//! Get jump zone size
/*!
Return the jump zone size, the size of the regions on the edges of
the screen that cause the cursor to jump to another screen.
*/
SInt32 getJumpZoneSize() const;
//! Get screen shape
/*!
Return the position of the upper-left corner of the screen in \c x and
\c y and the size of the screen in \c width and \c height.
*/
virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const;
//! Get cursor position
/*!
Return the current position of the cursor in \c x,y.
*/
virtual void getCursorPos(SInt32& x, SInt32& y) const;
//! Get screen
/*!
Return the platform dependent screen.
*/
virtual IScreen* getScreen() const = 0;
//@}
protected:
typedef UInt8 KeyState;
typedef UInt32 SysKeyID;
enum EKeyState { kDown = 0x01, kToggled = 0x80 };
enum EKeyAction { kPress, kRelease, kRepeat };
class Keystroke {
public:
SysKeyID m_sysKeyID;
bool m_press;
bool m_repeat;
};
typedef std::vector<Keystroke> Keystrokes;
typedef std::map<KeyButton, SysKeyID> ServerKeyMap;
void updateKeys();
void releaseKeys();
void doKeystrokes(const Keystrokes&, SInt32 count);
bool isKeyDown(SysKeyID) const;
bool isKeyToggled(SysKeyID) const;
bool isKeyHalfDuplex(KeyID) const;
//! Pre-mainLoop() hook
/*!
Called on entry to mainLoop(). Override to perform platform specific
operations. Default does nothing. May throw.
*/
virtual void onPreMainLoop();
//! Post-mainLoop() hook
/*!
Called on exit from mainLoop(). Override to perform platform specific
operations. Default does nothing. May \b not throw.
*/
virtual void onPostMainLoop();
//! Pre-open() hook
/*!
Called on entry to open(). Override to perform platform specific
operations. Default does nothing. May throw.
*/
virtual void onPreOpen();
//! Post-open() hook
/*!
Called on exit from open() iff the open was successful. Default
does nothing. May throw.
*/
virtual void onPostOpen();
//! Pre-close() hook
/*!
Called on entry to close(). Override to perform platform specific
operations. Default does nothing. May \b not throw.
*/
virtual void onPreClose();
//! Post-close() hook
/*!
Called on exit from close(). Override to perform platform specific
operations. Default does nothing. May \b not throw.
*/
virtual void onPostClose();
//! Pre-enter() hook
/*!
Called on entry to enter() after desktop synchronization. Override
to perform platform specific operations. Default does nothing. May
\b not throw.
*/
virtual void onPreEnter();
//! Post-enter() hook
/*!
Called on exit from enter(). Override to perform platform specific
operations. Default does nothing. May \b not throw.
*/
virtual void onPostEnter();
//! Pre-leave() hook
/*!
Called on entry to leave() after desktop synchronization. Override
to perform platform specific operations. Default does nothing. May
\b not throw.
*/
virtual void onPreLeave();
//! Post-leave() hook
/*!
Called on exit from leave(). Override to perform platform specific
operations. Default does nothing. May \b not throw.
*/
virtual void onPostLeave();
//! Create window
/*!
Called to create the window. This window is generally used to
receive events and hide the cursor.
*/
virtual void createWindow() = 0;
//! Destroy window
/*!
Called to destroy the window created by createWindow().
*/
virtual void destroyWindow() = 0;
//! Show window
/*!
Called when the user navigates off this secondary screen. It needn't
actually show the window created by createWindow() but it must move
the cursor to x,y, hide it, and clean up event synthesis.
*/
virtual void showWindow(SInt32 x, SInt32 y) = 0;
//! Hide window
/*!
Called when the user navigates to this secondary screen. It should
hide the window (if shown), show the cursor, and prepare to synthesize
input events.
*/
virtual void hideWindow() = 0;
//! Synchronize key state
/*!
Save the current keyboard state. Normally a screen will save
the keyboard state in this method and use this shadow state,
available through isKeyDown() and getKeyState(), when
synthesizing events.
*/
virtual void updateKeys(KeyState* sysKeyStates) = 0;
//! Get modifier key state
/*!
Return the current keyboard modifier state.
*/
virtual KeyModifierMask getModifiers() const = 0;
//! Synchronize toggle key state
/*!
Toggles modifiers that don't match the given state so that they do.
*/
void setToggleState(KeyModifierMask);
virtual SysKeyID getUnhanded(SysKeyID) const;
virtual SysKeyID getOtherHanded(SysKeyID) const;
virtual bool isAutoRepeating(SysKeyID) const = 0;
virtual KeyModifierMask getModifierKeyMask(SysKeyID) const = 0;
virtual bool isModifierActive(SysKeyID) const = 0;
virtual SysKeyID getToggleSysKey(KeyID keyID) const = 0;
virtual bool synthesizeCtrlAltDel(EKeyAction);
virtual void sync() const;
virtual void flush();
virtual KeyModifierMask
mapKey(Keystrokes&, SysKeyID& sysKeyID, KeyID,
KeyModifierMask currentMask,
KeyModifierMask desiredMask, EKeyAction) const = 0;
virtual void fakeKeyEvent(SysKeyID, bool press) const = 0;
virtual void fakeMouseButton(ButtonID, bool press) const = 0;
//! Warp cursor
/*!
Warp the cursor to the absolute coordinates \c x,y.
*/
virtual void fakeMouseMove(SInt32 x, SInt32 y) const = 0;
virtual void fakeMouseWheel(SInt32 delta) const = 0;
private:
void toggleKey(KeyID, KeyModifierMask);
private:
CMutex m_mutex;
// true if ready for remote control
bool m_remoteReady;
// m_active is true if this screen has been entered
bool m_active;
// true if screen saver should be synchronized to server
bool m_screenSaverSync;
// map server key buttons to local system keys
ServerKeyMap m_serverKeyMap;
// system key states as set by us or the user
KeyState m_keys[256];
// system key states as set by us
KeyState m_fakeKeys[256];
// current active modifiers
// XXX -- subclasses still have and use this
KeyModifierMask m_mask;
// the toggle key state when this screen was last entered
KeyModifierMask m_toggleKeys;
// note toggle keys that toggles on up/down (false) or on
// transition (true)
bool m_numLockHalfDuplex;
bool m_capsLockHalfDuplex;
};
#endif

156
lib/synergy/IKeyState.h Normal file
View File

@ -0,0 +1,156 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* 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.
*/
#ifndef IKEYSTATE_H
#define IKEYSTATE_H
#include "IInterface.h"
#include "KeyTypes.h"
#include "CString.h"
#include "stdvector.h"
class IKeyState : public IInterface {
public:
class Keystroke {
public:
KeyButton m_key;
bool m_press;
bool m_repeat;
};
typedef std::vector<Keystroke> Keystrokes;
typedef std::vector<KeyButton> KeyButtons;
//! @name manipulators
//@{
//! Update the key state
/*!
Causes the key state to get updated to reflect the physical keyboard
state and current keyboard mapping.
*/
virtual void updateKeys() = 0;
//! Release fake pressed keys
/*!
Send fake key events to release keys that aren't physically pressed
but are logically pressed.
*/
virtual void releaseKeys() = 0;
//! Mark key as being down
/*!
Sets the state of \c key to down.
*/
virtual void setKeyDown(KeyButton key) = 0;
//! Mark modifier as being toggled on
/*!
Sets the state of the keys for the given (single) modifier to be
toggled on.
*/
virtual void setToggled(KeyModifierMask) = 0;
//! Add keys for modifier
/*!
Sets the keys that are mapped to the given (single) modifier. For
example, if buttons 5 and 23 were mapped to KeyModifierShift (perhaps
as left and right shift keys) then the mask would be KeyModifierShift
and \c keys would contain 5 and 23. A modifier with no keys is
ignored. All keys must be valid (not zero). \c keys may be modified
by the call.
*/
virtual void addModifier(KeyModifierMask, KeyButtons& keys) = 0;
//! Set toggle key state
/*!
Update the local toggle key state to match the given state.
*/
virtual void setToggleState(KeyModifierMask) = 0;
//@}
//! @name accessors
//@{
//! Test if any key is down
/*!
If any key is down then returns one of those keys. Otherwise returns 0.
*/
virtual KeyButton isAnyKeyDown() const = 0;
//! Test if key is pressed
/*!
Returns true iff the given key is down. Half-duplex toggles
should always return false.
*/
virtual bool isKeyDown(KeyButton) const = 0;
//! Test if modifier is a toggle
/*!
Returns true iff the given (single) modifier is a toggle.
*/
virtual bool isToggle(KeyModifierMask) const = 0;
//! Test if modifier is half-duplex
/*!
Returns true iff the given (single) modifier is a half-duplex
toggle key.
*/
virtual bool isHalfDuplex(KeyModifierMask) const = 0;
//! Test if modifier is active
/*!
Returns true iff the given (single) modifier is currently active.
*/
virtual bool isModifierActive(KeyModifierMask) const = 0;
//! Get the active modifiers
/*!
Returns the modifiers that are currently active.
*/
virtual KeyModifierMask
getActiveModifiers() const = 0;
//! Get key events to change modifier state
/*!
Retrieves the key events necessary to activate (\c desireActive is true)
or deactivate (\c desireActive is false) the modifier given by \c mask
by pushing them onto the back of \c keys. \c mask must specify exactly
one modifier. \c undo receives the key events necessary to restore the
modifier's previous state. They're pushed onto \c undo in the reverse
order they should be executed. Returns true if the modifier can be
adjusted, false otherwise.
*/
virtual bool mapModifier(Keystrokes& keys, Keystrokes& undo,
KeyModifierMask mask, bool desireActive) const = 0;
//! Get modifier mask for key
/*!
Returns the modifier mask for \c key. If \c key is not a modifier
key then returns 0.
*/
virtual KeyModifierMask
getMaskForKey(KeyButton) const = 0;
//@}
protected:
typedef UInt8 KeyState;
enum EKeyState {
kDown = 0x01, //!< Key is down
kToggled = 0x80 //!< Key is toggled on
};
};
#endif

View File

@ -12,21 +12,24 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#ifndef ISCREEN_H #ifndef IPLATFORMSCREEN_H
#define ISCREEN_H #define IPLATFORMSCREEN_H
#include "IInterface.h" #include "IPrimaryScreen.h"
#include "ISecondaryScreen.h"
#include "ClipboardTypes.h" #include "ClipboardTypes.h"
#include "OptionTypes.h"
class IClipboard; class IClipboard;
class IKeyState;
//! Screen interface //! Screen interface
/*! /*!
This interface defines the methods common to all platform dependent This interface defines the methods common to all platform dependent
screen implementations that are use by both primary and secondary screen implementations that are used by both primary and secondary
screens. screens.
*/ */
class IScreen : public IInterface { class IPlatformScreen : public IPrimaryScreen, public ISecondaryScreen {
public: public:
//! @name manipulators //! @name manipulators
//@{ //@{
@ -37,7 +40,29 @@ public:
if the screen cannot be opened but retrying later may succeed. if the screen cannot be opened but retrying later may succeed.
Otherwise throw some other XScreenOpenFailure exception. Otherwise throw some other XScreenOpenFailure exception.
*/ */
virtual void open() = 0; virtual void open(IKeyState*) = 0;
//! Close screen
/*!
Called to close the screen. close() should quietly ignore calls
that don't have a matching successful call to open().
*/
virtual void close() = 0;
//! Enable screen
/*!
Enable the screen, preparing it to report system and user events.
For a secondary screen it also means preparing to synthesize events
and hiding the cursor.
*/
virtual void enable() = 0;
//! Disable screen
/*!
Undoes the operations in enable() and events should no longer
be reported.
*/
virtual void disable() = 0;
//! Run event loop //! Run event loop
/*! /*!
@ -54,12 +79,20 @@ public:
*/ */
virtual void exitMainLoop() = 0; virtual void exitMainLoop() = 0;
//! Close screen //! Enter screen
/*! /*!
Called to close the screen. close() should quietly ignore calls Called when the user navigates to this screen.
that don't have a matching successful call to open().
*/ */
virtual void close() = 0; virtual void enter() = 0;
//! Leave screen
/*!
Called when the user navigates off the screen. Returns true on
success, false on failure. A typical reason for failure is being
unable to install the keyboard and mouse snoopers on a primary
screen. Secondary screens should not fail.
*/
virtual bool leave() = 0;
//! Set clipboard //! Set clipboard
/*! /*!
@ -84,6 +117,7 @@ public:
it's closed. If \c notify is false then the screen saver is it's closed. If \c notify is false then the screen saver is
disabled on open and restored on close. disabled on open and restored on close.
*/ */
// XXX -- pass an interface pointer, not a notify flag
virtual void openScreensaver(bool notify) = 0; virtual void openScreensaver(bool notify) = 0;
//! Close screen saver //! Close screen saver
@ -101,20 +135,35 @@ public:
*/ */
virtual void screensaver(bool activate) = 0; virtual void screensaver(bool activate) = 0;
//! Attach to desktop //! Notify of options changes
/*! /*!
Called to ensure that this thread is attached to the visible desktop. Reset all options to their default values.
This is mainly intended for microsoft windows which has an artificial
distinction between desktops where a thread cannot interact with the
visible desktop unless the thread is attached to that desktop. Since
it doesn't report when the visible desktop changes we must poll.
*/ */
virtual void syncDesktop() = 0; virtual void resetOptions() = 0;
//! Notify of options changes
/*!
Set options to given values. Ignore unknown options and don't
modify options that aren't given in \c options.
*/
virtual void setOptions(const COptionsList& options) = 0;
//! Get keyboard state
/*!
Put the current keyboard state into the IKeyState passed to \c open().
*/
virtual void updateKeys() = 0;
//@} //@}
//! @name accessors //! @name accessors
//@{ //@{
//! Test if is primary screen
/*!
Return true iff this screen is a primary screen.
*/
virtual bool isPrimary() const = 0;
//! Get clipboard //! Get clipboard
/*! /*!
Save the contents of the clipboard indicated by \c id and return Save the contents of the clipboard indicated by \c id and return
@ -136,15 +185,26 @@ public:
*/ */
virtual void getCursorPos(SInt32& x, SInt32& y) const = 0; virtual void getCursorPos(SInt32& x, SInt32& y) const = 0;
//! Get cursor center position
/*!
Return the cursor center position which is where we park the
cursor to compute cursor motion deltas and should be far from
the edges of the screen, typically the center.
*/
virtual void getCursorCenter(SInt32& x, SInt32& y) const = 0;
//@} //@}
// IPrimaryScreen overrides
virtual void reconfigure(UInt32 activeSides) = 0;
virtual void warpCursor(SInt32 x, SInt32 y) = 0;
virtual UInt32 addOneShotTimer(double timeout) = 0;
virtual SInt32 getJumpZoneSize() const = 0;
virtual bool isAnyMouseButtonDown() const = 0;
virtual const char* getKeyName(KeyButton) const = 0;
// ISecondaryScreen overrides
virtual void fakeKeyEvent(KeyButton id, bool press) const = 0;
virtual bool fakeCtrlAltDel() const = 0;
virtual void fakeMouseButton(ButtonID id, bool press) const = 0;
virtual void fakeMouseMove(SInt32 x, SInt32 y) const = 0;
virtual void fakeMouseWheel(SInt32 delta) const = 0;
virtual KeyButton mapKey(IKeyState::Keystrokes&,
const IKeyState& keyState, KeyID id,
KeyModifierMask desiredMask,
bool isAutoRepeat) const = 0;
}; };
#endif #endif

View File

@ -0,0 +1,84 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* 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.
*/
#ifndef IPRIMARYSCREEN_H
#define IPRIMARYSCREEN_H
#include "IInterface.h"
#include "IKeyState.h"
//! Primary screen interface
/*!
This interface defines the methods common to all platform dependent
primary screen implementations.
*/
class IPrimaryScreen : public IInterface {
public:
// XXX -- may need an interface for sending events
//! @name manipulators
//@{
//! Update configuration
/*!
This is called when the configuration has changed. \c activeSides
is a bitmask of EDirectionMask indicating which sides of the
primary screen are linked to clients. Override to handle the
possible change in jump zones.
*/
virtual void reconfigure(UInt32 activeSides) = 0;
//! Warp cursor
/*!
Warp the cursor to the absolute coordinates \c x,y. Also
discard input events up to and including the warp before
returning.
*/
virtual void warpCursor(SInt32 x, SInt32 y) = 0;
//! Install a one-shot timer
/*!
Installs a one-shot timer for \c timeout seconds and returns the
id of the timer.
*/
// XXX -- need to specify the receiver of the event. or we should
// pass a job. need a method to remove the timer?
virtual UInt32 addOneShotTimer(double timeout) = 0;
//@}
//! @name accessors
//@{
//! Get jump zone size
/*!
Return the jump zone size, the size of the regions on the edges of
the screen that cause the cursor to jump to another screen.
*/
virtual SInt32 getJumpZoneSize() const = 0;
//! Test if mouse is pressed
/*!
Return true if any mouse button is currently pressed.
*/
virtual bool isAnyMouseButtonDown() const = 0;
//! Get name of key
/*!
Return a string describing the given key.
*/
virtual const char* getKeyName(KeyButton) const = 0;
//@}
};
#endif

View File

@ -1,69 +0,0 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* 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.
*/
#ifndef ISCREENEVENTHANDLER_H
#define ISCREENEVENTHANDLER_H
#include "IInterface.h"
// the platform screen should define this
class CEvent;
class IScreen;
//! Screen event handler interface
/*!
This is the interface through which IScreen sends notification of events.
Each platform will derive two types from IScreenEventHandler, one
for handling events on the primary screen and one for the
secondary screen. The header file with the IScreen subclass for
each platform should define the CEvent type, which depends on the
type of native events for that platform.
*/
class IScreenEventHandler : public IInterface {
public:
//! @name manipulators
//@{
//! Notify of screen saver change
/*!
Called when the screensaver is activated or deactivated.
*/
virtual void onScreensaver(bool activated) = 0;
//! Event filtering
/*!
Called for each event before event translation and dispatch. Return
true to skip translation and dispatch. Subclasses should call the
superclass's version first and return true if it returns true.
*/
virtual bool onPreDispatch(const CEvent* event) = 0;
//! Event handling
/*!
Called to handle an event. Iff the event was handled return true and
store the result, if any, in event->m_result, which defaults to zero.
*/
virtual bool onEvent(CEvent* event) = 0;
//! Notify of one-shot timer expiration
/*!
Called when a one-shot timer expires.
*/
virtual void onOneShotTimerExpired(UInt32 id) = 0;
//@}
};
#endif

View File

@ -1,6 +1,6 @@
/* /*
* synergy -- mouse and keyboard sharing utility * synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman * Copyright (C) 2003 Chris Schoeneman
* *
* This package is free software; you can redistribute it and/or * This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -12,27 +12,29 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#ifndef IPRIMARYSCREENFACTORY_H #ifndef ISCREENFACTORY_H
#define IPRIMARYSCREENFACTORY_H #define ISCREENFACTORY_H
#include "IInterface.h" #include "IInterface.h"
class CPrimaryScreen;
class IPrimaryScreenReceiver; class IPrimaryScreenReceiver;
class IPlatformScreen;
class IScreenReceiver; class IScreenReceiver;
//! Primary screen factory interface //! Primary screen factory interface
/*! /*!
This interface provides factory methods to create primary screens. This interface provides factory methods to create primary and
secondary screens.
*/ */
class IPrimaryScreenFactory : public IInterface { class IScreenFactory : public IInterface {
public: public:
//! Create screen //! Create screen
/*! /*!
Create and return a primary screen. The caller must delete the Create and return a screen. The caller must delete the returned
returned object. object. The screen is a primary screen iff the IPrimaryScreenReceiver
is not NULL.
*/ */
virtual CPrimaryScreen* virtual IPlatformScreen*
create(IScreenReceiver*, IPrimaryScreenReceiver*) = 0; create(IScreenReceiver*, IPrimaryScreenReceiver*) = 0;
}; };

View File

@ -0,0 +1,82 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* 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.
*/
#ifndef ISECONDARYSCREEN_H
#define ISECONDARYSCREEN_H
#include "IInterface.h"
#include "IKeyState.h"
#include "MouseTypes.h"
//! Secondary screen interface
/*!
This interface defines the methods common to all platform dependent
secondary screen implementations.
*/
class ISecondaryScreen : public IInterface {
public:
//! @name accessors
//@{
//! Fake key press/release
/*!
Synthesize a press or release of key \c id.
*/
virtual void fakeKeyEvent(KeyButton id, bool press) const = 0;
//! Fake ctrl+alt+del
/*!
Synthesize a press of ctrl+alt+del. Return true if processing is
complete and false if normal key processing should continue.
*/
virtual bool fakeCtrlAltDel() const = 0;
//! Fake mouse press/release
/*!
Synthesize a press or release of mouse button \c id.
*/
virtual void fakeMouseButton(ButtonID id, bool press) const = 0;
//! Fake mouse move
/*!
Synthesize a mouse move to the absolute coordinates \c x,y.
*/
virtual void fakeMouseMove(SInt32 x, SInt32 y) const = 0;
//! Fake mouse wheel
/*!
Synthesize a mouse wheel event of amount \c delta.
*/
virtual void fakeMouseWheel(SInt32 delta) const = 0;
//! Map key press/repeat to keystrokes
/*!
Convert a press/repeat of key \c id with the modifiers as given
in \c desiredMask into the keystrokes necessary to synthesize
that key event. This may expand into multiple keys due to modifiers
that don't match the current modifier state from \c keyState, or to
needing to compose a character using dead key, or to other reasons.
Return the platform specific code of the key being pressed. If \c id
cannot be mapped or if \c isAutoRepeat is true and the key does not
auto-repeat then return 0.
*/
virtual KeyButton mapKey(IKeyState::Keystrokes&,
const IKeyState& keyState, KeyID id,
KeyModifierMask desiredMask,
bool isAutoRepeat) const = 0;
//@}
};
#endif

View File

@ -1,38 +0,0 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* 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.
*/
#ifndef ISECONDARYSCREENFACTORY_H
#define ISECONDARYSCREENFACTORY_H
#include "IInterface.h"
class CSecondaryScreen;
class IScreenReceiver;
//! Secondary screen factory interface
/*!
This interface provides factory methods to create secondary screens.
*/
class ISecondaryScreenFactory : public IInterface {
public:
//! Create screen
/*!
Create and return a secondary screen. The caller must delete the
returned object.
*/
virtual CSecondaryScreen*
create(IScreenReceiver*) = 0;
};
#endif

View File

@ -28,27 +28,26 @@ libsynergy_a_SOURCES = \
CClipboard.cpp \ CClipboard.cpp \
CInputPacketStream.cpp \ CInputPacketStream.cpp \
COutputPacketStream.cpp \ COutputPacketStream.cpp \
CPrimaryScreen.cpp \
CProtocolUtil.cpp \ CProtocolUtil.cpp \
CSecondaryScreen.cpp \ CScreen.cpp \
XScreen.cpp \ XScreen.cpp \
XSynergy.cpp \ XSynergy.cpp \
CClipboard.h \ CClipboard.h \
CInputPacketStream.h \ CInputPacketStream.h \
COutputPacketStream.h \ COutputPacketStream.h \
CPrimaryScreen.h \
CProtocolUtil.h \ CProtocolUtil.h \
CSecondaryScreen.h \ CScreen.h \
ClipboardTypes.h \ ClipboardTypes.h \
IClient.h \ IClient.h \
IClipboard.h \ IClipboard.h \
IPrimaryScreenFactory.h \ IKeyState.h \
IPlatformScreen.h \
IPrimaryScreen.h \
IPrimaryScreenReceiver.h \ IPrimaryScreenReceiver.h \
IScreen.h \ IScreenFactory.h \
IScreenEventHandler.h \
IScreenReceiver.h \ IScreenReceiver.h \
IScreenSaver.h \ IScreenSaver.h \
ISecondaryScreenFactory.h \ ISecondaryScreen.h \
IServer.h \ IServer.h \
KeyTypes.h \ KeyTypes.h \
MouseTypes.h \ MouseTypes.h \

View File

@ -99,15 +99,11 @@ SOURCE=.\COutputPacketStream.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\CPrimaryScreen.cpp
# End Source File
# Begin Source File
SOURCE=.\CProtocolUtil.cpp SOURCE=.\CProtocolUtil.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\CSecondaryScreen.cpp SOURCE=.\CScreen.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
@ -139,15 +135,11 @@ SOURCE=.\COutputPacketStream.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\CPrimaryScreen.h
# End Source File
# Begin Source File
SOURCE=.\CProtocolUtil.h SOURCE=.\CProtocolUtil.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\CSecondaryScreen.h SOURCE=.\CScreen.h
# End Source File # End Source File
# Begin Source File # Begin Source File
@ -159,7 +151,15 @@ SOURCE=.\IClipboard.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\IPrimaryScreenFactory.h SOURCE=.\IKeyState.h
# End Source File
# Begin Source File
SOURCE=.\IPlatformScreen.h
# End Source File
# Begin Source File
SOURCE=.\IPrimaryScreen.h
# End Source File # End Source File
# Begin Source File # Begin Source File
@ -167,11 +167,7 @@ SOURCE=.\IPrimaryScreenReceiver.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\IScreen.h SOURCE=.\IScreenFactory.h
# End Source File
# Begin Source File
SOURCE=.\IScreenEventHandler.h
# End Source File # End Source File
# Begin Source File # Begin Source File
@ -183,7 +179,7 @@ SOURCE=.\IScreenSaver.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\ISecondaryScreenFactory.h SOURCE=.\ISecondaryScreen.h
# End Source File # End Source File
# Begin Source File # Begin Source File