mirror of
https://github.com/debauchee/barrier.git
synced 2024-11-23 20:12:39 +03:00
Merged primary and secondary screens into one class.
This commit is contained in:
parent
4fea7719f3
commit
47ca409ff9
@ -13,7 +13,7 @@
|
||||
*/
|
||||
|
||||
#include "CClient.h"
|
||||
#include "ISecondaryScreenFactory.h"
|
||||
#include "IScreenFactory.h"
|
||||
#include "ProtocolTypes.h"
|
||||
#include "Version.h"
|
||||
#include "XScreen.h"
|
||||
@ -35,14 +35,13 @@
|
||||
#define DAEMON_RUNNING(running_)
|
||||
#if WINDOWS_LIKE
|
||||
#include "CMSWindowsScreen.h"
|
||||
#include "CMSWindowsSecondaryScreen.h"
|
||||
#include "CArchMiscWindows.h"
|
||||
#include "CMSWindowsClientTaskBarReceiver.h"
|
||||
#include "resource.h"
|
||||
#undef DAEMON_RUNNING
|
||||
#define DAEMON_RUNNING(running_) CArchMiscWindows::daemonRunning(running_)
|
||||
#elif UNIX_LIKE
|
||||
#include "CXWindowsSecondaryScreen.h"
|
||||
#include "CXWindowsScreen.h"
|
||||
#include "CXWindowsClientTaskBarReceiver.h"
|
||||
#endif
|
||||
|
||||
@ -88,28 +87,28 @@ CArgs* CArgs::s_instance = NULL;
|
||||
// platform dependent factories
|
||||
//
|
||||
|
||||
//! Factory for creating secondary screens
|
||||
//! Factory for creating screens
|
||||
/*!
|
||||
Objects of this type create secondary screens appropriate for the
|
||||
platform.
|
||||
Objects of this type create screens appropriate for the platform.
|
||||
*/
|
||||
class CSecondaryScreenFactory : public ISecondaryScreenFactory {
|
||||
class CScreenFactory : public IScreenFactory {
|
||||
public:
|
||||
CSecondaryScreenFactory() { }
|
||||
virtual ~CSecondaryScreenFactory() { }
|
||||
CScreenFactory() { }
|
||||
virtual ~CScreenFactory() { }
|
||||
|
||||
// ISecondaryScreenFactory overrides
|
||||
virtual CSecondaryScreen*
|
||||
create(IScreenReceiver*);
|
||||
// IScreenFactory overrides
|
||||
virtual IPlatformScreen*
|
||||
create(IScreenReceiver*, IPrimaryScreenReceiver*);
|
||||
};
|
||||
|
||||
CSecondaryScreen*
|
||||
CSecondaryScreenFactory::create(IScreenReceiver* receiver)
|
||||
IPlatformScreen*
|
||||
CScreenFactory::create(IScreenReceiver* receiver,
|
||||
IPrimaryScreenReceiver* primaryReceiver)
|
||||
{
|
||||
#if WINDOWS_LIKE
|
||||
return new CMSWindowsSecondaryScreen(receiver);
|
||||
return new CMSWindowsScreen(receiver, primaryReceiver);
|
||||
#elif UNIX_LIKE
|
||||
return new CXWindowsSecondaryScreen(receiver);
|
||||
return new CXWindowsScreen(receiver, primaryReceiver);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -167,7 +166,7 @@ realMain(void)
|
||||
// create client
|
||||
s_client = new CClient(ARG->m_name);
|
||||
s_client->setAddress(ARG->m_serverAddress);
|
||||
s_client->setScreenFactory(new CSecondaryScreenFactory);
|
||||
s_client->setScreenFactory(new CScreenFactory);
|
||||
s_client->setSocketFactory(new CTCPSocketFactory);
|
||||
s_client->setStreamFilterFactory(NULL);
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
#include "CServer.h"
|
||||
#include "CConfig.h"
|
||||
#include "IPrimaryScreenFactory.h"
|
||||
#include "IScreenFactory.h"
|
||||
#include "ProtocolTypes.h"
|
||||
#include "Version.h"
|
||||
#include "XScreen.h"
|
||||
@ -34,14 +34,13 @@
|
||||
#define DAEMON_RUNNING(running_)
|
||||
#if WINDOWS_LIKE
|
||||
#include "CMSWindowsScreen.h"
|
||||
#include "CMSWindowsPrimaryScreen.h"
|
||||
#include "CArchMiscWindows.h"
|
||||
#include "CMSWindowsServerTaskBarReceiver.h"
|
||||
#include "resource.h"
|
||||
#undef DAEMON_RUNNING
|
||||
#define DAEMON_RUNNING(running_) CArchMiscWindows::daemonRunning(running_)
|
||||
#elif UNIX_LIKE
|
||||
#include "CXWindowsPrimaryScreen.h"
|
||||
#include "CXWindowsScreen.h"
|
||||
#include "CXWindowsServerTaskBarReceiver.h"
|
||||
#endif
|
||||
|
||||
@ -100,29 +99,28 @@ CArgs* CArgs::s_instance = NULL;
|
||||
// platform dependent factories
|
||||
//
|
||||
|
||||
//! Factory for creating primary screens
|
||||
//! Factory for creating screens
|
||||
/*!
|
||||
Objects of this type create primary screens appropriate for the
|
||||
platform.
|
||||
Objects of this type create screens appropriate for the platform.
|
||||
*/
|
||||
class CPrimaryScreenFactory : public IPrimaryScreenFactory {
|
||||
class CScreenFactory : public IScreenFactory {
|
||||
public:
|
||||
CPrimaryScreenFactory() { }
|
||||
virtual ~CPrimaryScreenFactory() { }
|
||||
CScreenFactory() { }
|
||||
virtual ~CScreenFactory() { }
|
||||
|
||||
// IPrimaryScreenFactory overrides
|
||||
virtual CPrimaryScreen*
|
||||
// IScreenFactory overrides
|
||||
virtual IPlatformScreen*
|
||||
create(IScreenReceiver*, IPrimaryScreenReceiver*);
|
||||
};
|
||||
|
||||
CPrimaryScreen*
|
||||
CPrimaryScreenFactory::create(IScreenReceiver* receiver,
|
||||
IPlatformScreen*
|
||||
CScreenFactory::create(IScreenReceiver* receiver,
|
||||
IPrimaryScreenReceiver* primaryReceiver)
|
||||
{
|
||||
#if WINDOWS_LIKE
|
||||
return new CMSWindowsPrimaryScreen(receiver, primaryReceiver);
|
||||
return new CMSWindowsScreen(receiver, primaryReceiver);
|
||||
#elif UNIX_LIKE
|
||||
return new CXWindowsPrimaryScreen(receiver, primaryReceiver);
|
||||
return new CXWindowsScreen(receiver, primaryReceiver);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -201,7 +199,7 @@ realMain(void)
|
||||
// create server
|
||||
s_server = new CServer(ARG->m_name);
|
||||
s_server->setConfig(ARG->m_config);
|
||||
s_server->setScreenFactory(new CPrimaryScreenFactory);
|
||||
s_server->setScreenFactory(new CScreenFactory);
|
||||
s_server->setSocketFactory(new CTCPSocketFactory);
|
||||
s_server->setStreamFilterFactory(NULL);
|
||||
|
||||
|
@ -96,7 +96,7 @@ dnl checks for system services
|
||||
|
||||
|
||||
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"
|
||||
|
||||
AC_OUTPUT([
|
||||
|
@ -32,6 +32,7 @@
|
||||
# include "CArchDaemonWindows.h"
|
||||
# include "CArchFileWindows.h"
|
||||
# include "CArchLogWindows.h"
|
||||
# include "CArchMiscWindows.h"
|
||||
# include "CArchMultithreadWindows.h"
|
||||
# include "CArchNetworkWinsock.h"
|
||||
# include "CArchSleepWindows.h"
|
||||
@ -116,6 +117,10 @@ CArch::CArch(ARCH_ARGS* args)
|
||||
m_console = new ARCH_CONSOLE;
|
||||
m_daemon = new ARCH_DAEMON;
|
||||
m_taskbar = new ARCH_TASKBAR(args);
|
||||
|
||||
#if WINDOWS_LIKE
|
||||
CArchMiscWindows::init();
|
||||
#endif
|
||||
}
|
||||
|
||||
CArch::~CArch()
|
||||
|
@ -29,6 +29,13 @@ CArchConsoleWindows::CArchConsoleWindows() :
|
||||
s_thread = ARCH->newCurrentThread();
|
||||
|
||||
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()
|
||||
|
@ -19,16 +19,31 @@
|
||||
// CArchMiscWindows
|
||||
//
|
||||
|
||||
void
|
||||
CArchMiscWindows::init()
|
||||
{
|
||||
isWindows95Family();
|
||||
}
|
||||
|
||||
bool
|
||||
CArchMiscWindows::isWindows95Family()
|
||||
{
|
||||
OSVERSIONINFO version;
|
||||
version.dwOSVersionInfoSize = sizeof(version);
|
||||
if (GetVersionEx(&version) == 0) {
|
||||
// cannot determine OS; assume windows 95 family
|
||||
return true;
|
||||
static bool init = false;
|
||||
static bool result = false;
|
||||
|
||||
if (!init) {
|
||||
OSVERSIONINFO version;
|
||||
version.dwOSVersionInfoSize = sizeof(version);
|
||||
if (GetVersionEx(&version) == 0) {
|
||||
// cannot determine OS; assume windows 95 family
|
||||
result = true;
|
||||
}
|
||||
else {
|
||||
result = (version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
|
||||
}
|
||||
init = true;
|
||||
}
|
||||
return (version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -26,6 +26,9 @@ class CArchMiscWindows {
|
||||
public:
|
||||
typedef int (*RunFunc)(void);
|
||||
|
||||
//! Initialize
|
||||
static void init();
|
||||
|
||||
//! Test if windows 95, et al.
|
||||
/*!
|
||||
Returns true iff the platform is win95/98/me.
|
||||
|
@ -252,14 +252,12 @@ CArchMultithreadPosix::waitCondVar(CArchCond cond,
|
||||
CArchMutex
|
||||
CArchMultithreadPosix::newMutex()
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
int status = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
assert(status == 0);
|
||||
CArchMutexImpl* mutex = new CArchMutexImpl;
|
||||
int status = pthread_mutex_init(&mutex->m_mutex, NULL);
|
||||
status = pthread_mutex_init(&mutex->m_mutex, &attr);
|
||||
assert(status == 0);
|
||||
/*
|
||||
status = pthread_mutexattr_settype(&mutex->m_mutex,
|
||||
PTHREAD_MUTEX_RECURSIVE);
|
||||
assert(status == 0);
|
||||
*/
|
||||
return mutex;
|
||||
}
|
||||
|
||||
|
@ -124,11 +124,11 @@ public:
|
||||
// mutex methods
|
||||
//
|
||||
|
||||
//! Create a non-recursive mutex
|
||||
//! Create a recursive mutex
|
||||
/*!
|
||||
Creates a non-recursive mutex. A thread must not lock a
|
||||
non-recursive mutex when it already holds a lock on that mutex.
|
||||
If it does it will deadlock. The mutex is an opaque data type.
|
||||
Creates a recursive mutex. A thread may lock a recursive mutex
|
||||
when it already holds a lock on that mutex. The mutex is an
|
||||
opaque data type.
|
||||
*/
|
||||
virtual CArchMutex newMutex() = 0;
|
||||
|
||||
|
125
lib/base/CPriorityQueue.h
Normal file
125
lib/base/CPriorityQueue.h
Normal 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
|
@ -36,6 +36,7 @@ libbase_a_SOURCES = \
|
||||
CFunctionJob.h \
|
||||
CJobList.h \
|
||||
CLog.h \
|
||||
CPriorityQueue.h \
|
||||
CStopwatch.h \
|
||||
CString.h \
|
||||
CStringUtil.h \
|
||||
|
@ -14,12 +14,13 @@
|
||||
|
||||
#include "CClient.h"
|
||||
#include "CServerProxy.h"
|
||||
#include "ISecondaryScreenFactory.h"
|
||||
#include "CScreen.h"
|
||||
#include "IScreenFactory.h"
|
||||
#include "CClipboard.h"
|
||||
#include "CInputPacketStream.h"
|
||||
#include "COutputPacketStream.h"
|
||||
#include "CProtocolUtil.h"
|
||||
#include "CSecondaryScreen.h"
|
||||
#include "IPlatformScreen.h"
|
||||
#include "IServer.h"
|
||||
#include "ProtocolTypes.h"
|
||||
#include "XScreen.h"
|
||||
@ -72,7 +73,7 @@ CClient::setAddress(const CNetworkAddress& serverAddress)
|
||||
}
|
||||
|
||||
void
|
||||
CClient::setScreenFactory(ISecondaryScreenFactory* adopted)
|
||||
CClient::setScreenFactory(IScreenFactory* adopted)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
delete m_screenFactory;
|
||||
@ -305,8 +306,9 @@ CClient::enter(SInt32 xAbs, SInt32 yAbs, UInt32, KeyModifierMask mask, bool)
|
||||
CLock lock(&m_mutex);
|
||||
m_active = true;
|
||||
}
|
||||
|
||||
m_screen->enter(xAbs, yAbs, mask);
|
||||
m_screen->mouseMove(xAbs, yAbs);
|
||||
m_screen->enter();
|
||||
m_screen->setToggleState(mask);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -464,7 +466,10 @@ CClient::openSecondaryScreen()
|
||||
// create screen
|
||||
LOG((CLOG_DEBUG1 "creating secondary screen"));
|
||||
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) {
|
||||
throw XScreenOpenFailure();
|
||||
@ -634,9 +639,11 @@ CClient::runServer()
|
||||
m_server = proxy;
|
||||
}
|
||||
|
||||
bool enabled = false;
|
||||
try {
|
||||
// prepare for remote control
|
||||
m_screen->remoteControl();
|
||||
// enable the screen
|
||||
m_screen->enable();
|
||||
enabled = true;
|
||||
|
||||
// process messages
|
||||
bool rejected = true;
|
||||
@ -647,8 +654,8 @@ CClient::runServer()
|
||||
setStatus(kNotRunning);
|
||||
}
|
||||
|
||||
// prepare for local control
|
||||
m_screen->localControl();
|
||||
// disable the screen
|
||||
m_screen->disable();
|
||||
|
||||
// clean up
|
||||
CLock lock(&m_mutex);
|
||||
@ -661,7 +668,9 @@ CClient::runServer()
|
||||
}
|
||||
catch (...) {
|
||||
setStatus(kNotRunning);
|
||||
m_screen->localControl();
|
||||
if (enabled) {
|
||||
m_screen->disable();
|
||||
}
|
||||
CLock lock(&m_mutex);
|
||||
m_rejected = false;
|
||||
m_server = NULL;
|
||||
|
@ -22,12 +22,12 @@
|
||||
#include "CMutex.h"
|
||||
#include "CJobList.h"
|
||||
|
||||
class CSecondaryScreen;
|
||||
class CScreen;
|
||||
class CServerProxy;
|
||||
class CThread;
|
||||
class IDataSocket;
|
||||
class IScreenReceiver;
|
||||
class ISecondaryScreenFactory;
|
||||
class IScreenFactory;
|
||||
class ISocketFactory;
|
||||
class IStreamFilterFactory;
|
||||
|
||||
@ -60,13 +60,12 @@ public:
|
||||
*/
|
||||
void setAddress(const CNetworkAddress& serverAddress);
|
||||
|
||||
//! Set secondary screen factory
|
||||
//! Set screen factory
|
||||
/*!
|
||||
Sets the factory for creating secondary screens. This must be
|
||||
set before calling open(). This object takes ownership of the
|
||||
factory.
|
||||
Sets the factory for creating screens. This must be set before
|
||||
calling open(). This object takes ownership of the factory.
|
||||
*/
|
||||
void setScreenFactory(ISecondaryScreenFactory*);
|
||||
void setScreenFactory(IScreenFactory*);
|
||||
|
||||
//! Set socket factory
|
||||
/*!
|
||||
@ -184,12 +183,12 @@ private:
|
||||
private:
|
||||
CMutex m_mutex;
|
||||
CString m_name;
|
||||
CSecondaryScreen* m_screen;
|
||||
CScreen* m_screen;
|
||||
IScreenReceiver* m_server;
|
||||
CNetworkAddress m_serverAddress;
|
||||
ISecondaryScreenFactory* m_screenFactory;
|
||||
ISocketFactory* m_socketFactory;
|
||||
IStreamFilterFactory* m_streamFilterFactory;
|
||||
IScreenFactory* m_screenFactory;
|
||||
ISocketFactory* m_socketFactory;
|
||||
IStreamFilterFactory* m_streamFilterFactory;
|
||||
CThread* m_session;
|
||||
bool m_active;
|
||||
bool m_rejected;
|
||||
|
75
lib/platform/CMSWindowsDesktop.cpp
Normal file
75
lib/platform/CMSWindowsDesktop.cpp
Normal 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;
|
||||
}
|
||||
}
|
52
lib/platform/CMSWindowsDesktop.h
Normal file
52
lib/platform/CMSWindowsDesktop.h
Normal 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
|
1495
lib/platform/CMSWindowsKeyMapper.cpp
Normal file
1495
lib/platform/CMSWindowsKeyMapper.cpp
Normal file
File diff suppressed because it is too large
Load Diff
142
lib/platform/CMSWindowsKeyMapper.h
Normal file
142
lib/platform/CMSWindowsKeyMapper.h
Normal 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
@ -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
@ -15,7 +15,8 @@
|
||||
#ifndef CMSWINDOWSSCREEN_H
|
||||
#define CMSWINDOWSSCREEN_H
|
||||
|
||||
#include "IScreen.h"
|
||||
#include "IPlatformScreen.h"
|
||||
#include "CMSWindowsKeyMapper.h"
|
||||
#include "CSynergyHook.h"
|
||||
#include "CMutex.h"
|
||||
#include "CString.h"
|
||||
@ -23,22 +24,13 @@
|
||||
#include <windows.h>
|
||||
|
||||
class CMSWindowsScreenSaver;
|
||||
class CThread;
|
||||
|
||||
// Microsoft windows event
|
||||
class CEvent {
|
||||
public:
|
||||
MSG m_msg;
|
||||
LRESULT m_result;
|
||||
};
|
||||
|
||||
class IScreenReceiver;
|
||||
class IMSWindowsScreenEventHandler;
|
||||
class IPrimaryScreenReceiver;
|
||||
|
||||
//! Implementation of IScreen for Microsoft Windows
|
||||
class CMSWindowsScreen : public IScreen {
|
||||
//! Implementation of IPlatformScreen for Microsoft Windows
|
||||
class CMSWindowsScreen : public IPlatformScreen {
|
||||
public:
|
||||
CMSWindowsScreen(IScreenReceiver*, IMSWindowsScreenEventHandler*);
|
||||
CMSWindowsScreen(IScreenReceiver*, IPrimaryScreenReceiver*);
|
||||
virtual ~CMSWindowsScreen();
|
||||
|
||||
//! @name manipulators
|
||||
@ -51,37 +43,10 @@ public:
|
||||
*/
|
||||
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
|
||||
//@{
|
||||
|
||||
//! Test for multiple monitors
|
||||
/*!
|
||||
Returns true iff the system appears to have multiple monitors.
|
||||
*/
|
||||
bool isMultimon() const;
|
||||
|
||||
//! Get instance
|
||||
/*!
|
||||
Returns the application instance handle passed to init().
|
||||
@ -90,53 +55,116 @@ public:
|
||||
|
||||
//@}
|
||||
|
||||
// IScreen overrides
|
||||
// note -- this class expects the hook DLL to have been loaded
|
||||
// and initialized before open() is called.
|
||||
void open();
|
||||
void mainLoop();
|
||||
void exitMainLoop();
|
||||
void close();
|
||||
bool setClipboard(ClipboardID, const IClipboard*);
|
||||
void checkClipboards();
|
||||
void openScreensaver(bool notify);
|
||||
void closeScreensaver();
|
||||
void screensaver(bool activate);
|
||||
void syncDesktop();
|
||||
bool getClipboard(ClipboardID, IClipboard*) const;
|
||||
void getShape(SInt32&, SInt32&, SInt32&, SInt32&) const;
|
||||
void getCursorPos(SInt32&, SInt32&) const;
|
||||
void getCursorCenter(SInt32&, SInt32&) const;
|
||||
// IPlatformScreen overrides
|
||||
virtual void open(IKeyState*);
|
||||
virtual void close();
|
||||
virtual void enable();
|
||||
virtual void disable();
|
||||
virtual void mainLoop();
|
||||
virtual void exitMainLoop();
|
||||
virtual void enter();
|
||||
virtual bool leave();
|
||||
virtual bool setClipboard(ClipboardID, const IClipboard*);
|
||||
virtual void checkClipboards();
|
||||
virtual void openScreensaver(bool notify);
|
||||
virtual void closeScreensaver();
|
||||
virtual void screensaver(bool activate);
|
||||
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:
|
||||
// update screen size cache
|
||||
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
|
||||
// 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
|
||||
// any windows or hooks).
|
||||
bool switchDesktop(HDESK desk);
|
||||
|
||||
// get the input desktop. caller must CloseDesktop() the result.
|
||||
// do not call under windows 95/98/me.
|
||||
HDESK openInputDesktop() const;
|
||||
// make sure we're on the expected desktop
|
||||
void syncDesktop() const;
|
||||
|
||||
// get the desktop's name. do not call under windows 95/98/me.
|
||||
CString getDesktopName(HDESK) const;
|
||||
// handle message before it gets dispatched. returns true iff
|
||||
// the message should not be dispatched.
|
||||
bool onPreDispatch(HWND, UINT, WPARAM, LPARAM);
|
||||
|
||||
// returns true iff desk is the current desk. do not call under
|
||||
// windows 95/98/me.
|
||||
bool isCurrentDesktop(HDESK desk) const;
|
||||
// handle message before it gets dispatched. returns true iff
|
||||
// the message should not be dispatched.
|
||||
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
|
||||
static LRESULT CALLBACK wndProc(HWND, UINT, WPARAM, LPARAM);
|
||||
@ -144,53 +172,63 @@ private:
|
||||
private:
|
||||
static HINSTANCE s_instance;
|
||||
|
||||
IScreenReceiver* m_receiver;
|
||||
IMSWindowsScreenEventHandler* m_eventHandler;
|
||||
|
||||
ATOM m_class;
|
||||
HICON m_icon;
|
||||
HCURSOR m_cursor;
|
||||
// true if screen is being used as a primary screen, false otherwise
|
||||
bool m_isPrimary;
|
||||
|
||||
// true if windows 95/98/me
|
||||
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;
|
||||
|
||||
// screen shape
|
||||
// screen shape stuff
|
||||
SInt32 m_x, m_y;
|
||||
SInt32 m_w, m_h;
|
||||
SInt32 m_xCenter, m_yCenter;
|
||||
|
||||
// true if system appears to have multiple monitors
|
||||
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
|
||||
DWORD m_threadID;
|
||||
|
||||
// the thread id of the last attached thread
|
||||
DWORD m_lastThreadID;
|
||||
|
||||
// clipboard stuff
|
||||
HWND m_nextClipboardWindow;
|
||||
bool m_ownClipboard;
|
||||
|
||||
// the timer used to check for desktop switching
|
||||
UINT m_timer;
|
||||
|
||||
// the one shot timer
|
||||
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
|
||||
HDESK m_desk;
|
||||
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
|
||||
// the desktop is inaccessible we won't receive user input
|
||||
// and we'll lose track of the keyboard state. when the
|
||||
@ -198,6 +236,29 @@ private:
|
||||
// handler of that.
|
||||
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;
|
||||
};
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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
|
@ -82,7 +82,7 @@ static HANDLE g_hookEventLL = NULL;
|
||||
static HHOOK g_keyboardLL = NULL;
|
||||
static HHOOK g_mouseLL = NULL;
|
||||
static bool g_screenSaver = false;
|
||||
static bool g_relay = false;
|
||||
static EHookMode g_mode = kHOOK_WATCH_JUMP_ZONE;
|
||||
static UInt32 g_zoneSides = 0;
|
||||
static SInt32 g_zoneSize = 0;
|
||||
static SInt32 g_xScreen = 0;
|
||||
@ -151,7 +151,7 @@ keyboardHookHandler(WPARAM wParam, LPARAM lParam)
|
||||
// the scroll lock toggle state.
|
||||
PostThreadMessage(g_threadID, SYNERGY_MSG_KEY, wParam, lParam);
|
||||
|
||||
if (g_relay) {
|
||||
if (g_mode == kHOOK_RELAY_EVENTS) {
|
||||
// let certain keys pass through
|
||||
switch (wParam) {
|
||||
case VK_CAPITAL:
|
||||
@ -202,18 +202,18 @@ mouseHookHandler(WPARAM wParam, SInt32 x, SInt32 y, SInt32 data)
|
||||
case WM_NCXBUTTONUP:
|
||||
// always relay the event. eat it if relaying.
|
||||
PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_BUTTON, wParam, data);
|
||||
return g_relay;
|
||||
return (g_mode == kHOOK_RELAY_EVENTS);
|
||||
|
||||
case WM_MOUSEWHEEL:
|
||||
if (g_relay) {
|
||||
if (g_mode == kHOOK_RELAY_EVENTS) {
|
||||
// relay event
|
||||
PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_WHEEL, data, 0);
|
||||
}
|
||||
return g_relay;
|
||||
return (g_mode == kHOOK_RELAY_EVENTS);
|
||||
|
||||
case WM_NCMOUSEMOVE:
|
||||
case WM_MOUSEMOVE:
|
||||
if (g_relay) {
|
||||
if (g_mode == kHOOK_RELAY_EVENTS) {
|
||||
// we want the cursor to be hidden at all times so we
|
||||
// hide the cursor on whatever window has it. but then
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
if (g_relay) {
|
||||
if (g_mode == kHOOK_RELAY_EVENTS) {
|
||||
MSG* msg = reinterpret_cast<MSG*>(lParam);
|
||||
if (msg->message == g_wmMouseWheel) {
|
||||
// post message to our window
|
||||
@ -614,7 +614,7 @@ init(DWORD threadID)
|
||||
g_threadID = threadID;
|
||||
|
||||
// set defaults
|
||||
g_relay = false;
|
||||
g_mode = kHOOK_WATCH_JUMP_ZONE;
|
||||
g_zoneSides = 0;
|
||||
g_zoneSize = 0;
|
||||
g_xScreen = 0;
|
||||
@ -827,14 +827,14 @@ setZone(SInt32 x, SInt32 y, SInt32 w, SInt32 h, SInt32 jumpZoneSize)
|
||||
}
|
||||
|
||||
void
|
||||
setRelay(int enable)
|
||||
setMode(EHookMode mode)
|
||||
{
|
||||
if ((enable != 0) == g_relay) {
|
||||
if (mode == g_mode) {
|
||||
// no change
|
||||
return;
|
||||
}
|
||||
g_relay = (enable != 0);
|
||||
if (!g_relay) {
|
||||
g_mode = mode;
|
||||
if (g_mode != kHOOK_RELAY_EVENTS) {
|
||||
restoreCursor();
|
||||
}
|
||||
}
|
||||
|
@ -49,6 +49,11 @@ enum EHookResult {
|
||||
kHOOK_OKAY_LL
|
||||
};
|
||||
|
||||
enum EHookMode {
|
||||
kHOOK_WATCH_JUMP_ZONE,
|
||||
kHOOK_RELAY_EVENTS
|
||||
};
|
||||
|
||||
typedef int (*InitFunc)(DWORD targetQueueThreadID);
|
||||
typedef int (*CleanupFunc)(void);
|
||||
typedef EHookResult (*InstallFunc)(void);
|
||||
@ -57,7 +62,7 @@ typedef int (*InstallScreenSaverFunc)(void);
|
||||
typedef int (*UninstallScreenSaverFunc)(void);
|
||||
typedef void (*SetSidesFunc)(UInt32);
|
||||
typedef void (*SetZoneFunc)(SInt32, SInt32, SInt32, SInt32, SInt32);
|
||||
typedef void (*SetRelayFunc)(int);
|
||||
typedef void (*SetModeFunc)(int);
|
||||
|
||||
CSYNERGYHOOK_API int init(DWORD);
|
||||
CSYNERGYHOOK_API int cleanup(void);
|
||||
@ -68,7 +73,7 @@ CSYNERGYHOOK_API int uninstallScreenSaver(void);
|
||||
CSYNERGYHOOK_API void setSides(UInt32 sides);
|
||||
CSYNERGYHOOK_API void setZone(SInt32 x, SInt32 y, SInt32 w, SInt32 h,
|
||||
SInt32 jumpZoneSize);
|
||||
CSYNERGYHOOK_API void setRelay(int enable); // relay iff enable != 0
|
||||
CSYNERGYHOOK_API void setMode(EHookMode mode);
|
||||
|
||||
}
|
||||
|
||||
|
910
lib/platform/CXWindowsKeyMapper.cpp
Normal file
910
lib/platform/CXWindowsKeyMapper.cpp
Normal 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;
|
||||
}
|
153
lib/platform/CXWindowsKeyMapper.h
Normal file
153
lib/platform/CXWindowsKeyMapper.h
Normal 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
@ -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
@ -15,40 +15,28 @@
|
||||
#ifndef CXWINDOWSSCREEN_H
|
||||
#define CXWINDOWSSCREEN_H
|
||||
|
||||
#include "IScreen.h"
|
||||
#include "IPlatformScreen.h"
|
||||
#include "CXWindowsKeyMapper.h"
|
||||
#include "CMutex.h"
|
||||
#include "CStopwatch.h"
|
||||
#include "CPriorityQueue.h"
|
||||
#include "stdvector.h"
|
||||
#if defined(X_DISPLAY_MISSING)
|
||||
# error X11 is required to build synergy
|
||||
#else
|
||||
# include <X11/Xlib.h>
|
||||
#endif
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
class IJob;
|
||||
class IScreenEventHandler;
|
||||
class IScreenReceiver;
|
||||
class CXWindowsClipboard;
|
||||
class CXWindowsScreenSaver;
|
||||
class IJob;
|
||||
class IScreenReceiver;
|
||||
class IPrimaryScreenReceiver;
|
||||
|
||||
/*!
|
||||
\class CEvent
|
||||
\brief User event data
|
||||
An architecture dependent type holding user event data.
|
||||
*/
|
||||
// X11 event
|
||||
class CEvent {
|
||||
//! Implementation of IPlatformScreen for X11
|
||||
class CXWindowsScreen : public IPlatformScreen {
|
||||
public:
|
||||
XEvent m_event;
|
||||
SInt32 m_result;
|
||||
};
|
||||
|
||||
//! Implementation of IScreen for X11
|
||||
class CXWindowsScreen : public IScreen {
|
||||
public:
|
||||
CXWindowsScreen(IScreenReceiver*, IScreenEventHandler*);
|
||||
CXWindowsScreen(IScreenReceiver*, IPrimaryScreenReceiver*);
|
||||
virtual ~CXWindowsScreen();
|
||||
|
||||
//! @name manipulators
|
||||
@ -56,10 +44,10 @@ public:
|
||||
|
||||
//! Add timer
|
||||
/*!
|
||||
Add a job to invoke every timeout seconds. The job is
|
||||
called with the display locked. If a job timeout expires twice
|
||||
or more before the job can be called then the job is called
|
||||
just once. The caller retains ownership of the job.
|
||||
Add a job to invoke every timeout seconds. The job is called
|
||||
with the display locked. If a job timeout expires twice or
|
||||
more before the job can be called then the job is called just
|
||||
once. The caller retains ownership of the job.
|
||||
*/
|
||||
void addTimer(IJob*, double timeout);
|
||||
|
||||
@ -69,64 +57,55 @@ public:
|
||||
*/
|
||||
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
|
||||
void open();
|
||||
void mainLoop();
|
||||
void exitMainLoop();
|
||||
void close();
|
||||
bool setClipboard(ClipboardID, const IClipboard*);
|
||||
void checkClipboards();
|
||||
void openScreensaver(bool notify);
|
||||
void closeScreensaver();
|
||||
void screensaver(bool activate);
|
||||
void syncDesktop();
|
||||
bool getClipboard(ClipboardID, IClipboard*) const;
|
||||
void getShape(SInt32&, SInt32&, SInt32&, SInt32&) const;
|
||||
void getCursorPos(SInt32&, SInt32&) const;
|
||||
void getCursorCenter(SInt32&, SInt32&) const;
|
||||
// IPlatformScreen overrides
|
||||
virtual void open(IKeyState*);
|
||||
virtual void close();
|
||||
virtual void enable();
|
||||
virtual void disable();
|
||||
virtual void mainLoop();
|
||||
virtual void exitMainLoop();
|
||||
virtual void enter();
|
||||
virtual bool leave();
|
||||
virtual bool setClipboard(ClipboardID, const IClipboard*);
|
||||
virtual void checkClipboards();
|
||||
virtual void openScreensaver(bool notify);
|
||||
virtual void closeScreensaver();
|
||||
virtual void screensaver(bool activate);
|
||||
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:
|
||||
// update screen size cache
|
||||
void updateScreenShape();
|
||||
|
||||
// process events before dispatching to receiver
|
||||
bool onPreDispatch(CEvent* event);
|
||||
void onEvent(XEvent* event);
|
||||
|
||||
// create the transparent cursor
|
||||
void createBlankCursor();
|
||||
Cursor createBlankCursor() const;
|
||||
|
||||
// remove a timer without locking
|
||||
void removeTimerNoLock(IJob*);
|
||||
@ -149,78 +128,6 @@ private:
|
||||
static int ioErrorHandler(Display*);
|
||||
|
||||
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
|
||||
class CTimer {
|
||||
public:
|
||||
@ -252,32 +159,80 @@ private:
|
||||
double m_time;
|
||||
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:
|
||||
friend class CDisplayLock;
|
||||
|
||||
typedef CPriorityQueue<CTimer> CTimerPriorityQueue;
|
||||
|
||||
// true if screen is being used as a primary screen, false otherwise
|
||||
bool m_isPrimary;
|
||||
|
||||
// X is not thread safe
|
||||
CMutex m_mutex;
|
||||
|
||||
Display* m_display;
|
||||
Window m_root;
|
||||
bool m_stop;
|
||||
|
||||
IScreenReceiver* m_receiver;
|
||||
IScreenEventHandler* m_eventHandler;
|
||||
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_w, m_h;
|
||||
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
|
||||
CXWindowsClipboard* m_clipboard[kClipboardEnd];
|
||||
|
||||
// the transparent cursor
|
||||
Cursor m_cursor;
|
||||
// the quit message
|
||||
Atom m_atomQuit;
|
||||
|
||||
// screen saver stuff
|
||||
CXWindowsScreenSaver* m_screensaver;
|
||||
@ -290,22 +245,23 @@ private:
|
||||
CMutex m_timersMutex;
|
||||
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
|
||||
// ioErrorHandler().
|
||||
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
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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
|
@ -16,6 +16,14 @@
|
||||
#include "CThread.h"
|
||||
#include "CLog.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
|
||||
@ -805,6 +813,218 @@ struct codepair {
|
||||
{ 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
|
||||
@ -812,6 +1032,7 @@ struct codepair {
|
||||
|
||||
CXWindowsUtil::CKeySymMap CXWindowsUtil::s_keySymToUCS4;
|
||||
CXWindowsUtil::CUCS4Map CXWindowsUtil::s_UCS4ToKeySym;
|
||||
CXWindowsUtil::CKeySymsMap CXWindowsUtil::s_decomposedKeySyms;
|
||||
|
||||
bool
|
||||
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
|
||||
CXWindowsUtil::propertyNotifyPredicate(Display*, XEvent* xevent, XPointer arg)
|
||||
{
|
||||
@ -1031,6 +1267,19 @@ CXWindowsUtil::initKeyMaps()
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "CString.h"
|
||||
#include "BasicTypes.h"
|
||||
#include "stdmap.h"
|
||||
#include "stdvector.h"
|
||||
#if defined(X_DISPLAY_MISSING)
|
||||
# error X11 is required to build synergy
|
||||
#else
|
||||
@ -27,6 +28,8 @@
|
||||
//! X11 utility functions
|
||||
class CXWindowsUtil {
|
||||
public:
|
||||
typedef std::vector<KeySym> KeySyms;
|
||||
|
||||
//! Get property
|
||||
/*!
|
||||
Gets property \c property on \c window. \b Appends the data to
|
||||
@ -70,6 +73,14 @@ public:
|
||||
*/
|
||||
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
|
||||
/*!
|
||||
This class sets an X error handler in the c'tor and restores the
|
||||
@ -133,9 +144,11 @@ private:
|
||||
private:
|
||||
typedef std::map<KeySym, UInt32> CKeySymMap;
|
||||
typedef std::map<UInt32, KeySym> CUCS4Map;
|
||||
typedef std::map<KeySym, KeySyms> CKeySymsMap;
|
||||
|
||||
static CKeySymMap s_keySymToUCS4;
|
||||
static CUCS4Map s_UCS4ToKeySym;
|
||||
static CKeySymsMap s_decomposedKeySyms;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -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
|
@ -23,21 +23,20 @@ EXTRA_DIST = \
|
||||
CMSWindowsClipboardAnyTextConverter.cpp \
|
||||
CMSWindowsClipboardTextConverter.cpp \
|
||||
CMSWindowsClipboardUTF16Converter.cpp \
|
||||
CMSWindowsPrimaryScreen.cpp \
|
||||
CMSWindowsDesktop.cpp \
|
||||
CMSWindowsKeyMapper.cpp \
|
||||
CMSWindowsScreen.cpp \
|
||||
CMSWindowsScreenSaver.cpp \
|
||||
CMSWindowsSecondaryScreen.cpp \
|
||||
CSynergyHook.cpp \
|
||||
CMSWindowsClipboard.h \
|
||||
CMSWindowsClipboardAnyTextConverter.h \
|
||||
CMSWindowsClipboardTextConverter.h \
|
||||
CMSWindowsClipboardUTF16Converter.h \
|
||||
CMSWindowsPrimaryScreen.h \
|
||||
CMSWindowsDesktop.h \
|
||||
CMSWindowsKeyMapper.h \
|
||||
CMSWindowsScreen.h \
|
||||
CMSWindowsScreenSaver.h \
|
||||
CMSWindowsSecondaryScreen.h \
|
||||
CSynergyHook.h \
|
||||
IMSWindowsScreenEventHandler.h \
|
||||
$(NULL)
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
@ -50,19 +49,17 @@ libplatform_a_SOURCES = \
|
||||
CXWindowsClipboardTextConverter.cpp \
|
||||
CXWindowsClipboardUCS2Converter.cpp \
|
||||
CXWindowsClipboardUTF8Converter.cpp \
|
||||
CXWindowsPrimaryScreen.cpp \
|
||||
CXWindowsKeyMapper.cpp \
|
||||
CXWindowsScreen.cpp \
|
||||
CXWindowsScreenSaver.cpp \
|
||||
CXWindowsSecondaryScreen.cpp \
|
||||
CXWindowsUtil.cpp \
|
||||
CXWindowsClipboard.h \
|
||||
CXWindowsClipboardTextConverter.h \
|
||||
CXWindowsClipboardUCS2Converter.h \
|
||||
CXWindowsClipboardUTF8Converter.h \
|
||||
CXWindowsPrimaryScreen.h \
|
||||
CXWindowsKeyMapper.h \
|
||||
CXWindowsScreen.h \
|
||||
CXWindowsScreenSaver.h \
|
||||
CXWindowsSecondaryScreen.h \
|
||||
CXWindowsUtil.h \
|
||||
$(NULL)
|
||||
INCLUDES = \
|
||||
|
@ -103,7 +103,11 @@ SOURCE=.\CMSWindowsClipboardUTF16Converter.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CMSWindowsPrimaryScreen.cpp
|
||||
SOURCE=.\CMSWindowsDesktop.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CMSWindowsKeyMapper.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
@ -113,10 +117,6 @@ SOURCE=.\CMSWindowsScreen.cpp
|
||||
|
||||
SOURCE=.\CMSWindowsScreenSaver.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CMSWindowsSecondaryScreen.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
@ -139,7 +139,11 @@ SOURCE=.\CMSWindowsClipboardUTF16Converter.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CMSWindowsPrimaryScreen.h
|
||||
SOURCE=.\CMSWindowsDesktop.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CMSWindowsKeyMapper.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
@ -149,14 +153,6 @@ SOURCE=.\CMSWindowsScreen.h
|
||||
|
||||
SOURCE=.\CMSWindowsScreenSaver.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CMSWindowsSecondaryScreen.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\IMSWindowsScreenEventHandler.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
||||
|
@ -13,11 +13,11 @@
|
||||
*/
|
||||
|
||||
#include "CPrimaryClient.h"
|
||||
#include "IPrimaryScreenFactory.h"
|
||||
#include "CScreen.h"
|
||||
#include "IScreenFactory.h"
|
||||
#include "IServer.h"
|
||||
#include "XScreen.h"
|
||||
#include "XSynergy.h"
|
||||
#include "CPrimaryScreen.h"
|
||||
#include "CClipboard.h"
|
||||
#include "CLog.h"
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
// CPrimaryClient
|
||||
//
|
||||
|
||||
CPrimaryClient::CPrimaryClient(IPrimaryScreenFactory* screenFactory,
|
||||
CPrimaryClient::CPrimaryClient(IScreenFactory* screenFactory,
|
||||
IServer* server,
|
||||
IPrimaryScreenReceiver* receiver,
|
||||
const CString& name) :
|
||||
@ -38,7 +38,11 @@ CPrimaryClient::CPrimaryClient(IPrimaryScreenFactory* screenFactory,
|
||||
// create screen
|
||||
LOG((CLOG_DEBUG1 "creating primary screen"));
|
||||
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) {
|
||||
throw XScreenOpenFailure();
|
||||
@ -86,7 +90,7 @@ CPrimaryClient::isLockedToScreen() const
|
||||
KeyModifierMask
|
||||
CPrimaryClient::getToggleMask() const
|
||||
{
|
||||
return m_screen->getToggleMask();
|
||||
return m_screen->getActiveModifiers();
|
||||
}
|
||||
|
||||
void
|
||||
@ -149,13 +153,28 @@ CPrimaryClient::close()
|
||||
m_screen->close();
|
||||
}
|
||||
|
||||
void
|
||||
CPrimaryClient::enable()
|
||||
{
|
||||
m_screen->enable();
|
||||
}
|
||||
|
||||
void
|
||||
CPrimaryClient::disable()
|
||||
{
|
||||
m_screen->disable();
|
||||
}
|
||||
|
||||
void
|
||||
CPrimaryClient::enter(SInt32 xAbs, SInt32 yAbs,
|
||||
UInt32 seqNum, KeyModifierMask, bool screensaver)
|
||||
{
|
||||
// note -- we must not call any server methods except onError().
|
||||
m_seqNum = seqNum;
|
||||
m_screen->enter(xAbs, yAbs, screensaver);
|
||||
if (!screensaver) {
|
||||
m_screen->warpCursor(xAbs, yAbs);
|
||||
}
|
||||
m_screen->enter();
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -19,9 +19,9 @@
|
||||
#include "IScreenReceiver.h"
|
||||
#include "ProtocolTypes.h"
|
||||
|
||||
class CScreen;
|
||||
class IClipboard;
|
||||
class CPrimaryScreen;
|
||||
class IPrimaryScreenFactory;
|
||||
class IScreenFactory;
|
||||
class IPrimaryScreenReceiver;
|
||||
class IServer;
|
||||
|
||||
@ -38,7 +38,7 @@ public:
|
||||
\c factory. Throws XScreenOpenFailure or whatever the factory can
|
||||
throw if the screen cannot be created.
|
||||
*/
|
||||
CPrimaryClient(IPrimaryScreenFactory* factory, IServer*,
|
||||
CPrimaryClient(IScreenFactory* factory, IServer*,
|
||||
IPrimaryScreenReceiver*, const CString& name);
|
||||
~CPrimaryClient();
|
||||
|
||||
@ -96,6 +96,9 @@ public:
|
||||
virtual bool onGrabClipboard(ClipboardID);
|
||||
virtual void onClipboardChanged(ClipboardID, const CString&);
|
||||
|
||||
// XXX -- these go in IClient
|
||||
virtual void enable();
|
||||
virtual void disable();
|
||||
// IClient overrides
|
||||
virtual void open();
|
||||
virtual void mainLoop();
|
||||
@ -127,7 +130,7 @@ public:
|
||||
|
||||
private:
|
||||
IServer* m_server;
|
||||
CPrimaryScreen* m_screen;
|
||||
CScreen* m_screen;
|
||||
CString m_name;
|
||||
UInt32 m_seqNum;
|
||||
CClientInfo m_info;
|
||||
|
@ -15,7 +15,7 @@
|
||||
#include "CServer.h"
|
||||
#include "CHTTPServer.h"
|
||||
#include "CPrimaryClient.h"
|
||||
#include "IPrimaryScreenFactory.h"
|
||||
#include "IScreenFactory.h"
|
||||
#include "CInputPacketStream.h"
|
||||
#include "COutputPacketStream.h"
|
||||
#include "CProtocolUtil.h"
|
||||
@ -89,6 +89,7 @@ CServer::open()
|
||||
LOG((CLOG_INFO "opening screen"));
|
||||
openPrimaryScreen();
|
||||
setStatus(kNotRunning);
|
||||
m_primaryClient->enable();
|
||||
}
|
||||
catch (XScreen& e) {
|
||||
// can't open screen
|
||||
@ -212,6 +213,7 @@ void
|
||||
CServer::close()
|
||||
{
|
||||
if (m_primaryClient != NULL) {
|
||||
m_primaryClient->disable();
|
||||
closePrimaryScreen();
|
||||
}
|
||||
LOG((CLOG_INFO "closed screen"));
|
||||
@ -280,7 +282,7 @@ CServer::setConfig(const CConfig& config)
|
||||
}
|
||||
|
||||
void
|
||||
CServer::setScreenFactory(IPrimaryScreenFactory* adopted)
|
||||
CServer::setScreenFactory(IScreenFactory* adopted)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
delete m_screenFactory;
|
||||
@ -1601,7 +1603,7 @@ CServer::runClient(void* vsocket)
|
||||
try {
|
||||
CProtocolUtil::writef(proxy->getOutputStream(), kMsgEBusy);
|
||||
}
|
||||
catch (XSocket&) {
|
||||
catch (XIO&) {
|
||||
// ignore
|
||||
}
|
||||
delete proxy;
|
||||
@ -1614,7 +1616,7 @@ CServer::runClient(void* vsocket)
|
||||
try {
|
||||
CProtocolUtil::writef(proxy->getOutputStream(), kMsgEUnknown);
|
||||
}
|
||||
catch (XSocket&) {
|
||||
catch (XIO&) {
|
||||
// ignore
|
||||
}
|
||||
delete proxy;
|
||||
@ -1646,7 +1648,7 @@ CServer::runClient(void* vsocket)
|
||||
try {
|
||||
CProtocolUtil::writef(proxy->getOutputStream(), kMsgEBad);
|
||||
}
|
||||
catch (XSocket&) {
|
||||
catch (XIO&) {
|
||||
// ignore. client probably aborted the connection.
|
||||
}
|
||||
}
|
||||
@ -1766,7 +1768,7 @@ CServer::handshakeClient(IDataSocket* socket)
|
||||
CProtocolUtil::writef(output, kMsgEIncompatible,
|
||||
kProtocolMajorVersion, kProtocolMinorVersion);
|
||||
}
|
||||
catch (XSocket&) {
|
||||
catch (XIO&) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
@ -1776,7 +1778,7 @@ CServer::handshakeClient(IDataSocket* socket)
|
||||
try {
|
||||
CProtocolUtil::writef(output, kMsgEBad);
|
||||
}
|
||||
catch (XSocket&) {
|
||||
catch (XIO&) {
|
||||
// ignore. client probably aborted the connection.
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ class CHTTPServer;
|
||||
class CPrimaryClient;
|
||||
class IClient;
|
||||
class IDataSocket;
|
||||
class IPrimaryScreenFactory;
|
||||
class IScreenFactory;
|
||||
class IServerProtocol;
|
||||
class ISocketFactory;
|
||||
class IStreamFilterFactory;
|
||||
@ -102,13 +102,12 @@ public:
|
||||
*/
|
||||
bool setConfig(const CConfig&);
|
||||
|
||||
//! Set primary screen factory
|
||||
//! Set screen factory
|
||||
/*!
|
||||
Sets the factory for creating primary screens. This must be
|
||||
set before calling open(). This object takes ownership of the
|
||||
factory.
|
||||
Sets the factory for creating screens. This must be set before
|
||||
calling open(). This object takes ownership of the factory.
|
||||
*/
|
||||
void setScreenFactory(IPrimaryScreenFactory*);
|
||||
void setScreenFactory(IScreenFactory*);
|
||||
|
||||
//! Set socket factory
|
||||
/*!
|
||||
@ -341,8 +340,8 @@ private:
|
||||
double m_bindTimeout;
|
||||
|
||||
// factories
|
||||
IPrimaryScreenFactory* m_screenFactory;
|
||||
ISocketFactory* m_socketFactory;
|
||||
IScreenFactory* m_screenFactory;
|
||||
ISocketFactory* m_socketFactory;
|
||||
IStreamFilterFactory* m_streamFilterFactory;
|
||||
|
||||
// running threads
|
||||
|
@ -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
|
||||
}
|
@ -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
1001
lib/synergy/CScreen.cpp
Normal file
File diff suppressed because it is too large
Load Diff
357
lib/synergy/CScreen.h
Normal file
357
lib/synergy/CScreen.h
Normal 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
|
@ -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));
|
||||
}
|
@ -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
156
lib/synergy/IKeyState.h
Normal 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
|
@ -12,21 +12,24 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef ISCREEN_H
|
||||
#define ISCREEN_H
|
||||
#ifndef IPLATFORMSCREEN_H
|
||||
#define IPLATFORMSCREEN_H
|
||||
|
||||
#include "IInterface.h"
|
||||
#include "IPrimaryScreen.h"
|
||||
#include "ISecondaryScreen.h"
|
||||
#include "ClipboardTypes.h"
|
||||
#include "OptionTypes.h"
|
||||
|
||||
class IClipboard;
|
||||
class IKeyState;
|
||||
|
||||
//! Screen interface
|
||||
/*!
|
||||
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.
|
||||
*/
|
||||
class IScreen : public IInterface {
|
||||
class IPlatformScreen : public IPrimaryScreen, public ISecondaryScreen {
|
||||
public:
|
||||
//! @name manipulators
|
||||
//@{
|
||||
@ -37,7 +40,29 @@ public:
|
||||
if the screen cannot be opened but retrying later may succeed.
|
||||
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
|
||||
/*!
|
||||
@ -54,12 +79,20 @@ public:
|
||||
*/
|
||||
virtual void exitMainLoop() = 0;
|
||||
|
||||
//! Close screen
|
||||
//! Enter screen
|
||||
/*!
|
||||
Called to close the screen. close() should quietly ignore calls
|
||||
that don't have a matching successful call to open().
|
||||
Called when the user navigates to this screen.
|
||||
*/
|
||||
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
|
||||
/*!
|
||||
@ -84,6 +117,7 @@ public:
|
||||
it's closed. If \c notify is false then the screen saver is
|
||||
disabled on open and restored on close.
|
||||
*/
|
||||
// XXX -- pass an interface pointer, not a notify flag
|
||||
virtual void openScreensaver(bool notify) = 0;
|
||||
|
||||
//! Close screen saver
|
||||
@ -101,20 +135,35 @@ public:
|
||||
*/
|
||||
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.
|
||||
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.
|
||||
Reset all options to their default values.
|
||||
*/
|
||||
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
|
||||
//@{
|
||||
|
||||
//! Test if is primary screen
|
||||
/*!
|
||||
Return true iff this screen is a primary screen.
|
||||
*/
|
||||
virtual bool isPrimary() const = 0;
|
||||
|
||||
//! Get clipboard
|
||||
/*!
|
||||
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;
|
||||
|
||||
//! 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
|
84
lib/synergy/IPrimaryScreen.h
Normal file
84
lib/synergy/IPrimaryScreen.h
Normal 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
|
@ -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
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* 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
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@ -12,27 +12,29 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef IPRIMARYSCREENFACTORY_H
|
||||
#define IPRIMARYSCREENFACTORY_H
|
||||
#ifndef ISCREENFACTORY_H
|
||||
#define ISCREENFACTORY_H
|
||||
|
||||
#include "IInterface.h"
|
||||
|
||||
class CPrimaryScreen;
|
||||
class IPrimaryScreenReceiver;
|
||||
class IPlatformScreen;
|
||||
class IScreenReceiver;
|
||||
|
||||
//! 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:
|
||||
//! Create screen
|
||||
/*!
|
||||
Create and return a primary screen. The caller must delete the
|
||||
returned object.
|
||||
Create and return a screen. The caller must delete the returned
|
||||
object. The screen is a primary screen iff the IPrimaryScreenReceiver
|
||||
is not NULL.
|
||||
*/
|
||||
virtual CPrimaryScreen*
|
||||
virtual IPlatformScreen*
|
||||
create(IScreenReceiver*, IPrimaryScreenReceiver*) = 0;
|
||||
};
|
||||
|
82
lib/synergy/ISecondaryScreen.h
Normal file
82
lib/synergy/ISecondaryScreen.h
Normal 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
|
@ -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
|
@ -28,27 +28,26 @@ libsynergy_a_SOURCES = \
|
||||
CClipboard.cpp \
|
||||
CInputPacketStream.cpp \
|
||||
COutputPacketStream.cpp \
|
||||
CPrimaryScreen.cpp \
|
||||
CProtocolUtil.cpp \
|
||||
CSecondaryScreen.cpp \
|
||||
CScreen.cpp \
|
||||
XScreen.cpp \
|
||||
XSynergy.cpp \
|
||||
CClipboard.h \
|
||||
CInputPacketStream.h \
|
||||
COutputPacketStream.h \
|
||||
CPrimaryScreen.h \
|
||||
CProtocolUtil.h \
|
||||
CSecondaryScreen.h \
|
||||
CScreen.h \
|
||||
ClipboardTypes.h \
|
||||
IClient.h \
|
||||
IClipboard.h \
|
||||
IPrimaryScreenFactory.h \
|
||||
IKeyState.h \
|
||||
IPlatformScreen.h \
|
||||
IPrimaryScreen.h \
|
||||
IPrimaryScreenReceiver.h \
|
||||
IScreen.h \
|
||||
IScreenEventHandler.h \
|
||||
IScreenFactory.h \
|
||||
IScreenReceiver.h \
|
||||
IScreenSaver.h \
|
||||
ISecondaryScreenFactory.h \
|
||||
ISecondaryScreen.h \
|
||||
IServer.h \
|
||||
KeyTypes.h \
|
||||
MouseTypes.h \
|
||||
|
@ -99,15 +99,11 @@ SOURCE=.\COutputPacketStream.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CPrimaryScreen.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CProtocolUtil.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CSecondaryScreen.cpp
|
||||
SOURCE=.\CScreen.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
@ -139,15 +135,11 @@ SOURCE=.\COutputPacketStream.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CPrimaryScreen.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CProtocolUtil.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CSecondaryScreen.h
|
||||
SOURCE=.\CScreen.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
@ -159,7 +151,15 @@ SOURCE=.\IClipboard.h
|
||||
# End 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
|
||||
# Begin Source File
|
||||
|
||||
@ -167,11 +167,7 @@ SOURCE=.\IPrimaryScreenReceiver.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\IScreen.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\IScreenEventHandler.h
|
||||
SOURCE=.\IScreenFactory.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
@ -183,7 +179,7 @@ SOURCE=.\IScreenSaver.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ISecondaryScreenFactory.h
|
||||
SOURCE=.\ISecondaryScreen.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user