checkpoint. merging win32 code. server on X is currently broken

and client probably is.
This commit is contained in:
crs 2001-11-19 00:33:36 +00:00
parent 51505783aa
commit 3f6146b15f
66 changed files with 5222 additions and 424 deletions

View File

@ -13,7 +13,7 @@ RMR = /bin/rm -rf
# #
# compiler options # compiler options
# #
GCXXDEFS = -D_XOPEN_SOURCE=500 GCXXDEFS = -D_XOPEN_SOURCE=600
GCXXINCS = -I$(DEPTH)/include -I/usr/X11R6/include GCXXINCS = -I$(DEPTH)/include -I/usr/X11R6/include
GCXXOPTS = -Wall -W -fexceptions GCXXOPTS = -Wall -W -fexceptions
CXXOPTIMIZER = -g CXXOPTIMIZER = -g

63
all.dsp Normal file
View File

@ -0,0 +1,63 @@
# Microsoft Developer Studio Project File - Name="all" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Generic Project" 0x010a
CFG=all - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "all.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "all.mak" CFG="all - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "all - Win32 Release" (based on "Win32 (x86) Generic Project")
!MESSAGE "all - Win32 Debug" (based on "Win32 (x86) Generic Project")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "millpond"
# PROP Scc_LocalPath "."
MTL=midl.exe
!IF "$(CFG)" == "all - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
!ELSEIF "$(CFG)" == "all - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "all___Win32_Debug"
# PROP BASE Intermediate_Dir "all___Win32_Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
!ENDIF
# Begin Target
# Name "all - Win32 Release"
# Name "all - Win32 Debug"
# End Target
# End Project

View File

@ -37,7 +37,29 @@ typedef uint64_t UInt64;
#if defined(CONFIG_PLATFORM_WIN32) #if defined(CONFIG_PLATFORM_WIN32)
// FIXME // use VC++ extensions if available
#if defined(_MSC_VER)
typedef signed __int8 SInt8;
typedef signed __int16 SInt16;
typedef signed __int32 SInt32;
typedef signed __int64 SInt64;
typedef unsigned __int8 UInt8;
typedef unsigned __int16 UInt16;
typedef unsigned __int32 UInt32;
typedef unsigned __int64 UInt64;
#else
typedef signed char SInt8;
typedef short SInt16;
typedef int SInt32;
typedef long long SInt64;
typedef unsigned char UInt8;
typedef unsigned short UInt16;
typedef unsigned int UInt32;
typedef unsigned long long UInt64;
#endif
#endif // CONFIG_PLATFORM_WIN32 #endif // CONFIG_PLATFORM_WIN32

View File

@ -1,14 +1,37 @@
#include "CLog.h" #include "CLog.h"
#include "BasicTypes.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#if defined(CONFIG_PLATFORM_WIN32)
#include <windows.h>
#define vsnprintf _vsnprintf
#endif
static int g_maxPriority = -1;
static const char* g_priority[] = {
"FATAL",
"ERROR",
"WARNING",
"NOTE",
"INFO",
"DEBUG",
};
static const int g_numPriority = (int)(sizeof(g_priority) /
sizeof(g_priority[0]));
static const int g_maxPriorityLength = 7; // length of longest string
static const int g_prioritySuffixLength = 2;
static const int g_priorityPad = g_maxPriorityLength +
g_prioritySuffixLength;
static const int g_newlineLength = 2;
// //
// CLog // CLog
// //
static int g_maxPriority = -1; CLog::Outputter CLog::s_outputter = NULL;
void CLog::print(const char* fmt, ...) void CLog::print(const char* fmt, ...)
{ {
@ -19,11 +42,14 @@ void CLog::print(const char* fmt, ...)
fmt += 3; fmt += 3;
} }
// compute prefix padding length
int pad = g_priorityPad;
// print to buffer // print to buffer
char stack[1024]; char stack[1024];
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
char* buffer = vsprint(0, stack, char* buffer = vsprint(pad, stack,
sizeof(stack) / sizeof(stack[0]), fmt, args); sizeof(stack) / sizeof(stack[0]), fmt, args);
va_end(args); va_end(args);
@ -48,17 +74,19 @@ void CLog::printt(const char* file, int line,
// compute prefix padding length // compute prefix padding length
char stack[1024]; char stack[1024];
sprintf(stack, "%d", line); sprintf(stack, "%d", line);
int pad = strlen(file) + 1 + strlen(stack) + 1 + 1; int pad = strlen(file) + 1 /* comma */ +
strlen(stack) + 1 /* colon */ + 1 /* space */ +
g_priorityPad;
// print to buffer // print to buffer, leaving space for a newline at the end
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
char* buffer = vsprint(pad, stack, char* buffer = vsprint(pad, stack,
sizeof(stack) / sizeof(stack[0]), fmt, args); sizeof(stack) / sizeof(stack[0]), fmt, args);
va_end(args); va_end(args);
// print the prefix to the buffer // print the prefix to the buffer. leave space for priority label.
sprintf(buffer, "%s,%d:", file, line); sprintf(buffer + g_priorityPad, "%s,%d:", file, line);
buffer[pad - 1] = ' '; buffer[pad - 1] = ' ';
// output buffer // output buffer
@ -69,35 +97,51 @@ void CLog::printt(const char* file, int line,
delete[] buffer; delete[] buffer;
} }
void CLog::output(int priority, const char* msg) void CLog::setOutputter(Outputter outputter)
{ {
static const char* s_priority[] = { s_outputter = outputter;
"FATAL", }
"ERROR",
"WARNING", void CLog::output(int priority, char* msg)
"NOTE", {
"INFO", assert(priority >= 0 && priority < g_numPriority);
"DEBUG",
};
static const int s_numPriority = (int)(sizeof(s_priority) /
sizeof(s_priority[0]));
assert(priority >= 0 && priority < s_numPriority);
assert(msg != 0); assert(msg != 0);
if (g_maxPriority == -1) { if (g_maxPriority == -1) {
g_maxPriority = s_numPriority - 1; g_maxPriority = g_numPriority - 1;
const char* priEnv = getenv("SYN_LOG_PRI"); const char* priEnv = getenv("SYN_LOG_PRI");
if (priEnv != NULL) { if (priEnv != NULL) {
for (int i = 0; i < s_numPriority; ++i) for (int i = 0; i < g_numPriority; ++i)
if (strcmp(priEnv, s_priority[i]) == 0) { if (strcmp(priEnv, g_priority[i]) == 0) {
g_maxPriority = i; g_maxPriority = i;
break; break;
} }
} }
} }
if (priority <= g_maxPriority) if (priority <= g_maxPriority) {
fprintf(stderr, "%s: %s\n", s_priority[priority], msg); // insert priority label
int n = strlen(g_priority[priority]);
sprintf(msg + g_maxPriorityLength - n, "%s:", g_priority[priority]);
msg[g_maxPriorityLength + 1] = ' ';
// put a newline at the end
#if defined(CONFIG_PLATFORM_WIN32)
strcat(msg + g_priorityPad, "\r\n");
#else
strcat(msg + g_priorityPad, "\n");
#endif
// print it
if (s_outputter)
s_outputter(msg + g_maxPriorityLength - n);
else
#if defined(CONFIG_PLATFORM_WIN32)
OutputDebugString(msg + g_maxPriorityLength - n);
#else
fprintf(stderr, "%s", msg + g_maxPriorityLength - n);
#endif
}
} }
char* CLog::vsprint(int pad, char* buffer, int len, char* CLog::vsprint(int pad, char* buffer, int len,
@ -109,7 +153,7 @@ char* CLog::vsprint(int pad, char* buffer, int len,
int n; int n;
if (len >= pad) { if (len >= pad) {
n = vsnprintf(buffer + pad, len - pad, fmt, args); n = vsnprintf(buffer + pad, len - pad, fmt, args);
if (n != -1 && n <= len - pad) if (n != -1 && n <= len - pad + g_newlineLength)
return buffer; return buffer;
} }
@ -120,7 +164,7 @@ char* CLog::vsprint(int pad, char* buffer, int len,
len *= 2; len *= 2;
buffer = new char[len + pad]; buffer = new char[len + pad];
n = vsnprintf(buffer + pad, len - pad, fmt, args); n = vsnprintf(buffer + pad, len - pad, fmt, args);
} while (n == -1 || n > len - pad); } while (n == -1 || n > len - pad + g_newlineLength);
return buffer; return buffer;
} }

View File

@ -5,13 +5,19 @@
class CLog { class CLog {
public: public:
typedef void (*Outputter)(const char*);
static void print(const char*, ...); static void print(const char*, ...);
static void printt(const char* file, int line, const char*, ...); static void printt(const char* file, int line, const char*, ...);
static void setOutputter(Outputter);
private: private:
static void output(int priority, const char* msg); static void output(int priority, char* msg);
static char* vsprint(int pad, char*, int len, const char*, va_list); static char* vsprint(int pad, char*, int len, const char*, va_list);
static int nprint(const char*, va_list); static int nprint(const char*, va_list);
private:
static Outputter s_outputter;
}; };
#if defined(NOLOGGING) #if defined(NOLOGGING)

View File

@ -2,7 +2,7 @@
#include <errno.h> #include <errno.h>
// win32 wants a const char* argument to std::exception c'tor // win32 wants a const char* argument to std::exception c'tor
#if CONFIG_PLATFORM_WIN32 #if defined(CONFIG_PLATFORM_WIN32)
#define STDEXCEPTARG "" #define STDEXCEPTARG ""
#endif #endif

150
base/base.dsp Normal file
View File

@ -0,0 +1,150 @@
# Microsoft Developer Studio Project File - Name="base" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Static Library" 0x0104
CFG=base - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "base.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "base.mak" CFG="base - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "base - Win32 Release" (based on "Win32 (x86) Static Library")
!MESSAGE "base - Win32 Debug" (based on "Win32 (x86) Static Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "millpond"
# PROP Scc_LocalPath "."
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "base - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ELSEIF "$(CFG)" == "base - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ENDIF
# Begin Target
# Name "base - Win32 Release"
# Name "base - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\CFunctionJob.cpp
# End Source File
# Begin Source File
SOURCE=.\CLog.cpp
# End Source File
# Begin Source File
SOURCE=.\CStopwatch.cpp
# End Source File
# Begin Source File
SOURCE=.\XBase.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\BasicTypes.h
# End Source File
# Begin Source File
SOURCE=.\CFunctionJob.h
# End Source File
# Begin Source File
SOURCE=.\CLog.h
# End Source File
# Begin Source File
SOURCE=.\common.h
# End Source File
# Begin Source File
SOURCE=.\CStopwatch.h
# End Source File
# Begin Source File
SOURCE=.\CString.h
# End Source File
# Begin Source File
SOURCE=.\IInterface.h
# End Source File
# Begin Source File
SOURCE=.\IJob.h
# End Source File
# Begin Source File
SOURCE=.\TMethodJob.h
# End Source File
# Begin Source File
SOURCE=.\XBase.h
# End Source File
# End Group
# End Target
# End Project

View File

@ -15,10 +15,14 @@
#define CONFIG_TYPES_X11 #define CONFIG_TYPES_X11
#define CONFIG_PTHREADS #define CONFIG_PTHREADS
#elif defined(_WINDOWS) && defined(WIN32) #elif defined(_WIN32)
#define CONFIG_PLATFORM_WIN32 #define CONFIG_PLATFORM_WIN32
#if (_MSC_VER >= 1200)
#pragma warning(disable: 4786) // identifier truncated in debug info
#endif
#else #else
#error unsupported platform #error unsupported platform

View File

@ -9,8 +9,17 @@
#include "XSynergy.h" #include "XSynergy.h"
#include "TMethodJob.h" #include "TMethodJob.h"
#include "CLog.h" #include "CLog.h"
#include <assert.h>
#include <memory> #include <memory>
// hack to work around operator=() bug in STL in g++ prior to v3
#if defined(__GNUC__) && (__GNUC__ < 3)
#define assign(_dst, _src, _type) _dst.reset(_src)
#else
#define assign(_dst, _src, _type) _dst = std::auto_ptr<_type >(_src)
#endif
// //
// CClient // CClient
// //
@ -31,13 +40,50 @@ CClient::~CClient()
void CClient::run(const CNetworkAddress& serverAddress) void CClient::run(const CNetworkAddress& serverAddress)
{ {
CThread* thread;
try {
log((CLOG_NOTE "starting client"));
// connect to secondary screen
openSecondaryScreen();
// start server interactions
m_serverAddress = &serverAddress; m_serverAddress = &serverAddress;
CThread thread(new TMethodJob<CClient>(this, &CClient::runSession)); thread = new CThread(new TMethodJob<CClient>(this, &CClient::runSession));
thread.wait();
// handle events
log((CLOG_DEBUG "starting event handling"));
m_screen->run();
// clean up
log((CLOG_DEBUG "stopping client"));
thread->cancel();
thread->wait();
delete thread;
closeSecondaryScreen();
}
catch (XBase& e) {
log((CLOG_ERR "client error: %s\n", e.what()));
// clean up
thread->cancel();
thread->wait();
delete thread;
closeSecondaryScreen();
}
catch (...) {
log((CLOG_DEBUG "unknown client error"));
// clean up
thread->cancel();
thread->wait();
delete thread;
closeSecondaryScreen();
throw;
}
} }
#include "CTCPSocket.h" #include "CTCPSocket.h" // FIXME
#include "CXWindowsSecondaryScreen.h"
void CClient::runSession(void*) void CClient::runSession(void*)
{ {
log((CLOG_DEBUG "starting client \"%s\"", m_name.c_str())); log((CLOG_DEBUG "starting client \"%s\"", m_name.c_str()));
@ -51,7 +97,7 @@ void CClient::runSession(void*)
// create socket and attempt to connect to server // create socket and attempt to connect to server
log((CLOG_DEBUG "connecting to server")); log((CLOG_DEBUG "connecting to server"));
socket.reset(new CTCPSocket()); // FIXME -- use factory assign(socket, new CTCPSocket(), ISocket); // FIXME -- use factory
socket->connect(*m_serverAddress); socket->connect(*m_serverAddress);
log((CLOG_INFO "connected to server")); log((CLOG_INFO "connected to server"));
@ -72,8 +118,8 @@ void CClient::runSession(void*)
*/ */
// attach the packetizing filters // attach the packetizing filters
input.reset(new CInputPacketStream(srcInput, own)); assign(input, new CInputPacketStream(srcInput, own), IInputStream);
output.reset(new COutputPacketStream(srcOutput, own)); assign(output, new COutputPacketStream(srcOutput, own), IOutputStream);
// wait for hello from server // wait for hello from server
log((CLOG_DEBUG "wait for hello")); log((CLOG_DEBUG "wait for hello"));
@ -99,26 +145,17 @@ void CClient::runSession(void*)
} }
catch (XIncompatibleClient& e) { catch (XIncompatibleClient& e) {
log((CLOG_ERR "server has incompatible version %d.%d", e.getMajor(), e.getMinor())); log((CLOG_ERR "server has incompatible version %d.%d", e.getMajor(), e.getMinor()));
m_screen->stop();
return; return;
} }
catch (XThread&) { catch (XThread&) {
log((CLOG_ERR "connection timed out")); log((CLOG_ERR "connection timed out"));
m_screen->stop();
throw; throw;
} }
catch (XBase& e) { catch (XBase& e) {
log((CLOG_ERR "connection failed: %s", e.what())); log((CLOG_ERR "connection failed: %s", e.what()));
return; m_screen->stop();
}
// connect to screen
std::auto_ptr<CScreenCleaner> screenCleaner;
try {
log((CLOG_DEBUG "creating secondary screen"));
m_screen = new CXWindowsSecondaryScreen;
screenCleaner.reset(new CScreenCleaner(this, m_screen));
}
catch (XBase& e) {
log((CLOG_ERR "cannot open screen: %s", e.what()));
return; return;
} }
@ -199,16 +236,56 @@ void CClient::runSession(void*)
} }
catch (XBase& e) { catch (XBase& e) {
log((CLOG_ERR "error: %s", e.what())); log((CLOG_ERR "error: %s", e.what()));
m_screen->stop();
return; return;
} }
// done with screen
log((CLOG_DEBUG "destroying secondary screen"));
screenCleaner.reset();
// done with socket // done with socket
log((CLOG_DEBUG "disconnecting from server")); log((CLOG_DEBUG "disconnecting from server"));
socket->close(); socket->close();
// exit event loop
m_screen->stop();
}
// FIXME -- use factory to create screen
#if defined(CONFIG_PLATFORM_WIN32)
#include "CMSWindowsSecondaryScreen.h"
#elif defined(CONFIG_PLATFORM_UNIX)
#include "CXWindowsSecondaryScreen.h"
#endif
void CClient::openSecondaryScreen()
{
assert(m_screen == NULL);
// open screen
log((CLOG_DEBUG "creating secondary screen"));
#if defined(CONFIG_PLATFORM_WIN32)
m_screen = new CMSWindowsSecondaryScreen;
#elif defined(CONFIG_PLATFORM_UNIX)
m_screen = new CXWindowsSecondaryScreen;
#endif
log((CLOG_DEBUG "opening secondary screen"));
m_screen->open(this);
}
void CClient::closeSecondaryScreen()
{
assert(m_screen != NULL);
// close the secondary screen
try {
log((CLOG_DEBUG "closing secondary screen"));
m_screen->close();
}
catch (...) {
// ignore
}
// clean up
log((CLOG_DEBUG "destroying secondary screen"));
delete m_screen;
m_screen = NULL;
} }
void CClient::onEnter() void CClient::onEnter()
@ -306,28 +383,3 @@ void CClient::onMouseWheel()
CProtocolUtil::readf(m_input, kMsgDMouseWheel + 4, &delta); CProtocolUtil::readf(m_input, kMsgDMouseWheel + 4, &delta);
m_screen->mouseWheel(delta); m_screen->mouseWheel(delta);
} }
//
// CClient::CScreenCleaner
//
CClient::CScreenCleaner::CScreenCleaner(CClient* client,
ISecondaryScreen* screen) :
m_screen(screen)
{
assert(m_screen != NULL);
try {
m_screen->open(client);
}
catch (...) {
delete m_screen;
throw;
}
}
CClient::CScreenCleaner::~CScreenCleaner()
{
m_screen->close();
delete m_screen;
}

View File

@ -24,6 +24,10 @@ class CClient {
private: private:
void runSession(void*); void runSession(void*);
// open/close the primary screen
void openSecondaryScreen();
void closeSecondaryScreen();
// message handlers // message handlers
void onEnter(); void onEnter();
void onLeave(); void onLeave();
@ -40,16 +44,6 @@ class CClient {
void onMouseMove(); void onMouseMove();
void onMouseWheel(); void onMouseWheel();
private:
class CScreenCleaner {
public:
CScreenCleaner(CClient*, ISecondaryScreen*);
~CScreenCleaner();
private:
ISecondaryScreen* m_screen;
};
private: private:
CString m_name; CString m_name;
IInputStream* m_input; IInputStream* m_input;

View File

@ -0,0 +1,839 @@
#include "CMSWindowsSecondaryScreen.h"
#include "CClient.h"
#include "CThread.h"
#include "CLog.h"
#include <assert.h>
//
// CMSWindowsSecondaryScreen
//
CMSWindowsSecondaryScreen::CMSWindowsSecondaryScreen() :
m_client(NULL),
m_window(NULL)
{
// do nothing
}
CMSWindowsSecondaryScreen::~CMSWindowsSecondaryScreen()
{
assert(m_window == NULL);
}
static HWND s_debug = NULL;
static HWND s_debugLog = NULL;
static DWORD s_thread = 0;
static BOOL CALLBACK WINAPI debugProc(HWND, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_INITDIALOG:
return TRUE;
case WM_CLOSE:
PostQuitMessage(0);
return TRUE;
}
return FALSE;
}
static void debugOutput(const char* msg)
{
if (s_thread != 0) {
const DWORD threadID = ::GetCurrentThreadId();
if (threadID != s_thread) {
GetDesktopWindow();
AttachThreadInput(threadID, s_thread, TRUE);
}
}
DWORD len = SendMessage(s_debugLog, WM_GETTEXTLENGTH, 0, 0);
if (len > 20000) {
SendMessage(s_debugLog, EM_SETSEL, -1, 0);
SendMessage(s_debugLog, WM_SETTEXT, FALSE, (LPARAM)(LPCTSTR)msg);
}
else {
SendMessage(s_debugLog, EM_SETSEL, -1, len);
SendMessage(s_debugLog, EM_REPLACESEL, FALSE, (LPARAM)(LPCTSTR)msg);
}
SendMessage(s_debugLog, EM_SCROLLCARET, 0, 0);
}
void CMSWindowsSecondaryScreen::run()
{
CLog::setOutputter(&debugOutput);
doRun();
CLog::setOutputter(NULL);
}
void CMSWindowsSecondaryScreen::stop()
{
doStop();
}
void CMSWindowsSecondaryScreen::open(CClient* client)
{
assert(m_client == NULL);
assert(client != NULL);
// set the client
m_client = client;
// open the display
openDisplay();
}
void CMSWindowsSecondaryScreen::close()
{
assert(m_client != NULL);
// close the display
closeDisplay();
// done with client
m_client = NULL;
}
void CMSWindowsSecondaryScreen::enter(SInt32 x, SInt32 y)
{
assert(m_window != NULL);
// warp to requested location
SInt32 w, h;
getScreenSize(&w, &h);
mouse_event(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE,
(DWORD)((65535.99 * x) / (w - 1)),
(DWORD)((65535.99 * y) / (h - 1)),
0, 0);
// show cursor
ShowWindow(m_window, SW_HIDE);
}
void CMSWindowsSecondaryScreen::leave()
{
assert(m_window != NULL);
// move hider window under the mouse (rather than moving the mouse
// somewhere else on the screen)
POINT point;
GetCursorPos(&point);
MoveWindow(m_window, point.x, point.y, 1, 1, FALSE);
// raise and show the hider window. take activation.
ShowWindow(m_window, SW_SHOWNORMAL);
// hide cursor by moving it into the hider window
SetCursorPos(point.x, point.y);
}
void CMSWindowsSecondaryScreen::keyDown(
KeyID key, KeyModifierMask mask)
{
const UINT vkey = mapKey(key, mask);
if (vkey != 0) {
const UINT code = MapVirtualKey(vkey, 0);
keybd_event(vkey, code, 0, 0);
}
}
void CMSWindowsSecondaryScreen::keyRepeat(
KeyID key, KeyModifierMask mask, SInt32 count)
{
const UINT vkey = mapKey(key, mask);
if (vkey != 0) {
const UINT code = MapVirtualKey(vkey, 0);
for (SInt32 i = 0; i < count; ++i) {
keybd_event(vkey, code, KEYEVENTF_KEYUP, 0);
keybd_event(vkey, code, 0, 0);
}
}
}
void CMSWindowsSecondaryScreen::keyUp(
KeyID key, KeyModifierMask mask)
{
const UINT vkey = mapKey(key, mask);
if (vkey != 0) {
const UINT code = MapVirtualKey(vkey, 0);
keybd_event(vkey, code, KEYEVENTF_KEYUP, 0);
}
}
void CMSWindowsSecondaryScreen::mouseDown(ButtonID button)
{
// map button id to button flag
DWORD flags;
switch (button) {
case kButtonLeft:
flags = MOUSEEVENTF_LEFTDOWN;
break;
case kButtonMiddle:
flags = MOUSEEVENTF_MIDDLEDOWN;
break;
case kButtonRight:
flags = MOUSEEVENTF_RIGHTDOWN;
break;
default:
return;
}
// send event
mouse_event(flags, 0, 0, 0, 0);
}
void CMSWindowsSecondaryScreen::mouseUp(ButtonID button)
{
// map button id to button flag
DWORD flags;
switch (button) {
case kButtonLeft:
flags = MOUSEEVENTF_LEFTUP;
break;
case kButtonMiddle:
flags = MOUSEEVENTF_MIDDLEUP;
break;
case kButtonRight:
flags = MOUSEEVENTF_RIGHTUP;
break;
default:
return;
}
// send event
mouse_event(flags, 0, 0, 0, 0);
}
void CMSWindowsSecondaryScreen::mouseMove(SInt32 x, SInt32 y)
{
SInt32 w, h;
getScreenSize(&w, &h);
mouse_event(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE,
(SInt32)(65535.99 * x / (w - 1)),
(SInt32)(65535.99 * y / (h - 1)),
0, 0);
}
void CMSWindowsSecondaryScreen::mouseWheel(SInt32 delta)
{
mouse_event(MOUSEEVENTF_WHEEL, 0, 0, delta, 0);
}
void CMSWindowsSecondaryScreen::getSize(
SInt32* width, SInt32* height) const
{
getScreenSize(width, height);
}
SInt32 CMSWindowsSecondaryScreen::getJumpZoneSize() const
{
return 0;
}
#include "resource.h" // FIXME
void CMSWindowsSecondaryScreen::onOpenDisplay()
{
assert(m_window == NULL);
// create debug dialog
s_thread = GetCurrentThreadId();;
s_debug = CreateDialog(getInstance(), MAKEINTRESOURCE(IDD_SYNERGY), NULL, &debugProc);
s_debugLog = ::GetDlgItem(s_debug, IDC_LOG);
CLog::setOutputter(&debugOutput);
ShowWindow(s_debug, SW_SHOWNORMAL);
// create the cursor hiding window. this window is used to hide the
// cursor when it's not on the screen. the window is hidden as soon
// as the cursor enters the screen or the display's real cursor is
// moved.
m_window = CreateWindowEx(WS_EX_TOPMOST |
WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW,
(LPCTSTR)getClass(), "Synergy",
WS_POPUP | WS_DISABLED,
0, 0, 1, 1, NULL, NULL,
getInstance(),
NULL);
// hide the cursor
leave();
}
void CMSWindowsSecondaryScreen::onCloseDisplay()
{
assert(m_window != NULL);
// destroy window
DestroyWindow(m_window);
m_window = NULL;
CLog::setOutputter(NULL);
DestroyWindow(s_debug);
s_debug = NULL;
s_thread = 0;
}
bool CMSWindowsSecondaryScreen::onEvent(MSG* msg)
{
if (IsDialogMessage(s_debug, msg)) {
return true;
}
// handle event
switch (msg->message) {
// FIXME -- handle display changes
case WM_PAINT:
ValidateRect(m_window, NULL);
return true;
case WM_MOUSEMOVE:
// mouse was moved. hide the hider window.
ShowWindow(m_window, SW_HIDE);
break;
case WM_ACTIVATEAPP:
if (msg->wParam == FALSE) {
// some other app activated. hide the hider window.
ShowWindow(m_window, SW_HIDE);
}
break;
/*
// FIXME -- handle screen resolution changes
case SelectionClear:
target->XXX(xevent.xselectionclear.);
break;
case SelectionNotify:
target->XXX(xevent.xselection.);
break;
case SelectionRequest:
target->XXX(xevent.xselectionrequest.);
break;
*/
}
return false;
}
static const UINT g_latin1[] =
{
/* 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, 0, 0, 0, 0,
/* 0xa8 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xb0 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 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
};
static const UINT g_latin2[] =
{
/* 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, 0, 0, 0, 0,
/* 0xa8 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xb0 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 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
};
static const UINT g_latin3[] =
{
/* 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, 0, 0, 0, 0,
/* 0xa8 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xb0 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 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
};
static const UINT g_latin4[] =
{
/* 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, 0, 0, 0, 0,
/* 0xa8 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xb0 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 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
};
static const UINT g_latin5[] =
{
/* 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, 0, 0, 0, 0,
/* 0xa8 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xb0 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 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
};
static const UINT g_latin6[] =
{
/* 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, 0, 0, 0, 0,
/* 0xa8 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xb0 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 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
};
static const UINT g_latin7[] =
{
/* 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, 0, 0, 0, 0,
/* 0xa8 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xb0 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 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
};
static const UINT g_latin8[] =
{
/* 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, 0, 0, 0, 0,
/* 0xa8 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xb0 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 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
};
static const UINT g_latin9[] =
{
/* 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, 0, 0, 0, 0,
/* 0xa8 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xb0 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 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
};
static const UINT g_terminal[] =
{
/* 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, 0, 0, 0, 0,
/* 0xa8 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xb0 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 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
};
static const UINT g_function[] =
{
/* 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, 0, 0, 0, 0,
/* 0xa8 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xb0 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 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
};
// FIXME -- will this work?
// 0x100 + = shift
// 0x200 + = ctrl
// 0x400 + = alt
/* XK_KP_Space to XK_KP_Equal */
static const UINT g_miscellany[] =
{
/* 0x00 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x08 */ VK_BACK, VK_TAB, /*0x100 +*/ VK_RETURN, VK_CLEAR, 0, VK_RETURN, 0, 0,
/* 0x10 */ 0, 0, 0, VK_PAUSE, VK_SCROLL, 0/*sys-req*/, 0, 0,
/* 0x18 */ 0, 0, 0, VK_ESCAPE, 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 */ VK_HOME, VK_LEFT, VK_UP, VK_RIGHT,
/* 0x54 */ VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
/* 0x58 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x60 */ VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, VK_APPS,
/* 0x68 */ 0, 0, VK_HELP, VK_CANCEL, 0, 0, 0, 0,
/* 0x70 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x78 */ 0, 0, 0, 0, 0, 0, VK_MODECHANGE, VK_NUMLOCK,
/* 0x80 */ VK_SPACE, 0, 0, 0, 0, 0, 0, 0,
/* 0x88 */ 0, VK_TAB, 0, 0, 0, VK_RETURN, 0, 0,
/* 0x90 */ 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP,
/* 0x98 */ VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT,
/* 0x9c */ VK_END, 0, VK_INSERT, VK_DELETE,
/* 0xa0 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xa8 */ 0, 0, VK_MULTIPLY, VK_ADD,
/* 0xac */ VK_SEPARATOR, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
/* 0xb0 */ VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3,
/* 0xb4 */ VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
/* 0xb8 */ VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, 0, VK_F1, VK_F2,
/* 0xc0 */ VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10,
/* 0xc8 */ VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, VK_F17, VK_F18,
/* 0xd0 */ VK_F19, VK_F20, VK_F21, VK_F22, VK_F23, VK_F24, 0, 0,
/* 0xd8 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xe0 */ 0, VK_LSHIFT, VK_RSHIFT, VK_LCONTROL,
/* 0xe4 */ VK_RCONTROL, VK_CAPITAL, 0, VK_LWIN,
/* 0xe8 */ VK_RWIN, VK_LMENU, VK_RMENU, 0, 0, 0, 0, 0,
/* 0xf0 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xf8 */ 0, 0, 0, 0, 0, 0, 0, VK_DELETE
};
static const UINT* g_katakana = NULL;
static const UINT* g_arabic = NULL;
static const UINT* g_cyrillic = NULL;
static const UINT* g_greek = NULL;
static const UINT* g_technical = NULL;
static const UINT* g_special = NULL;
static const UINT* g_publishing = NULL;
static const UINT* g_apl = NULL;
static const UINT* g_hebrew = NULL;
static const UINT* g_thai = NULL;
static const UINT* g_korean = NULL;
static const UINT* g_armenian = NULL;
static const UINT* g_georgian = NULL;
static const UINT* g_azeri = NULL;
static const UINT* g_vietnamese = NULL;
static const UINT* g_currency = NULL;
static const UINT* g_mapTable[] =
{
/* 0x00 */ g_latin1, g_latin2, g_latin3, g_latin4,
/* 0x04 */ g_katakana, g_arabic, g_cyrillic, g_greek,
/* 0x08 */ g_technical, g_special, g_publishing, g_apl,
/* 0x0c */ g_hebrew, g_thai, g_korean, NULL,
/* 0x10 */ NULL, NULL, g_latin8, g_latin9,
/* 0x14 */ g_armenian, g_georgian, g_azeri, NULL,
/* 0x18 */ NULL, NULL, NULL, NULL, NULL, NULL, g_vietnamese, NULL,
/* 0x20 */ g_currency, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 0x28 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 0x30 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 0x38 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 0x40 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 0x48 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 0x50 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 0x58 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 0x60 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 0x68 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 0x70 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 0x78 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 0x80 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 0x88 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 0x90 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 0x98 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 0xa0 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 0xa8 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 0xb0 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 0xb8 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 0xc0 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 0xc8 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 0xd0 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 0xd8 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 0xe0 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 0xe8 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 0xf0 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 0xf8 */ NULL, NULL, NULL, NULL,
/* 0xfc */ NULL, g_terminal, g_function, g_miscellany
};
UINT CMSWindowsSecondaryScreen::mapKey(
KeyID id, KeyModifierMask /*mask*/) const
{
const UInt32 mapID = ((id >> 8) & 0xff);
const UInt32 code = (id & 0xff);
// lookup the key table
const UINT* map = g_mapTable[mapID];
if (map == NULL) {
return 0;
}
if (mapID == 0) {
SHORT scan = VkKeyScan(code);
if (scan != 0xffff) {
// FIXME -- must ensure shift state is correct. that means
// tracking the shift state from the moment we enter until
// the moment we leave (and probably disallowing leave if
// any shift keys are down). if current shift state is
// correct then do nothing extra, otherwise must surround
// injected key event with injected shift key events to
// get shift key in correct state then back to the previous
// state.
return (UINT)LOBYTE(scan);
}
}
// lookup the key in the table
return map[code];
}

View File

@ -0,0 +1,43 @@
#ifndef CMSWINDOWSSECONDARYSCREEN_H
#define CMSWINDOWSSECONDARYSCREEN_H
#include "CMSWindowsScreen.h"
#include "ISecondaryScreen.h"
class CMSWindowsSecondaryScreen : public CMSWindowsScreen, public ISecondaryScreen {
public:
CMSWindowsSecondaryScreen();
virtual ~CMSWindowsSecondaryScreen();
// ISecondaryScreen overrides
virtual void run();
virtual void stop();
virtual void open(CClient*);
virtual void close();
virtual void enter(SInt32 xAbsolute, SInt32 yAbsolute);
virtual void leave();
virtual void keyDown(KeyID, KeyModifierMask);
virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count);
virtual void keyUp(KeyID, KeyModifierMask);
virtual void mouseDown(ButtonID);
virtual void mouseUp(ButtonID);
virtual void mouseMove(SInt32 xAbsolute, SInt32 yAbsolute);
virtual void mouseWheel(SInt32 delta);
virtual void getSize(SInt32* width, SInt32* height) const;
virtual SInt32 getJumpZoneSize() const;
protected:
// CMSWindowsScreen overrides
virtual bool onEvent(MSG*);
virtual void onOpenDisplay();
virtual void onCloseDisplay();
private:
UINT mapKey(KeyID, KeyModifierMask) const;
private:
CClient* m_client;
HWND m_window;
};
#endif

View File

@ -22,6 +22,51 @@ CXWindowsSecondaryScreen::~CXWindowsSecondaryScreen()
assert(m_window == None); assert(m_window == None);
} }
void CXWindowsSecondaryScreen::run()
{
assert(m_window != None);
for (;;) {
// wait for and get the next event
XEvent xevent;
if (!getEvent(&xevent)) {
break;
}
// handle event
switch (xevent.type) {
case LeaveNotify: {
// mouse moved out of hider window somehow. hide the window.
assert(m_window != None);
CDisplayLock display(this);
XUnmapWindow(display, m_window);
break;
}
/*
// FIXME -- handle screen resolution changes
case SelectionClear:
target->XXX(xevent.xselectionclear.);
break;
case SelectionNotify:
target->XXX(xevent.xselection.);
break;
case SelectionRequest:
target->XXX(xevent.xselectionrequest.);
break;
*/
}
}
}
void CXWindowsSecondaryScreen::stop()
{
doStop();
}
void CXWindowsSecondaryScreen::open(CClient* client) void CXWindowsSecondaryScreen::open(CClient* client)
{ {
assert(m_client == NULL); assert(m_client == NULL);
@ -174,44 +219,6 @@ void CXWindowsSecondaryScreen::onCloseDisplay()
m_window = None; m_window = None;
} }
void CXWindowsSecondaryScreen::eventThread(void*)
{
assert(m_window != None);
for (;;) {
// wait for and get the next event
XEvent xevent;
getEvent(&xevent);
// handle event
switch (xevent.type) {
case LeaveNotify: {
// mouse moved out of hider window somehow. hide the window.
assert(m_window != None);
CDisplayLock display(this);
XUnmapWindow(display, m_window);
break;
}
/*
// FIXME -- handle screen resolution changes
case SelectionClear:
target->XXX(xevent.xselectionclear.);
break;
case SelectionNotify:
target->XXX(xevent.xselection.);
break;
case SelectionRequest:
target->XXX(xevent.xselectionrequest.);
break;
*/
}
}
}
void CXWindowsSecondaryScreen::leaveNoLock(Display* display) void CXWindowsSecondaryScreen::leaveNoLock(Display* display)
{ {
assert(display != NULL); assert(display != NULL);

View File

@ -10,6 +10,8 @@ class CXWindowsSecondaryScreen : public CXWindowsScreen, public ISecondaryScreen
virtual ~CXWindowsSecondaryScreen(); virtual ~CXWindowsSecondaryScreen();
// ISecondaryScreen overrides // ISecondaryScreen overrides
virtual void run();
virtual void stop();
virtual void open(CClient*); virtual void open(CClient*);
virtual void close(); virtual void close();
virtual void enter(SInt32 xAbsolute, SInt32 yAbsolute); virtual void enter(SInt32 xAbsolute, SInt32 yAbsolute);
@ -28,7 +30,6 @@ class CXWindowsSecondaryScreen : public CXWindowsScreen, public ISecondaryScreen
// CXWindowsScreen overrides // CXWindowsScreen overrides
virtual void onOpenDisplay(); virtual void onOpenDisplay();
virtual void onCloseDisplay(); virtual void onCloseDisplay();
virtual void eventThread(void*);
private: private:
void leaveNoLock(Display*); void leaveNoLock(Display*);

View File

@ -4,7 +4,7 @@ include $(DEPTH)/Makecommon
# #
# target file # target file
# #
TARGET = client TARGETS = client
# #
# source files # source files
@ -37,8 +37,8 @@ LLDLIBS = \
-lpthread \ -lpthread \
$(NULL) $(NULL)
targets: $(TARGET) targets: $(TARGETS)
$(TARGET): $(OBJECTS) $(DEPLIBS) $(TARGETS): $(OBJECTS) $(DEPLIBS)
$(CXX) $(CXXFLAGS) -o $@ $(OBJECTS) $(LDFLAGS) $(CXX) $(CXXFLAGS) -o $@ $(OBJECTS) $(LDFLAGS)

View File

@ -1,24 +1,76 @@
#include "CClient.h" #include "CClient.h"
#include "CString.h"
#include "CNetwork.h"
#include "CNetworkAddress.h" #include "CNetworkAddress.h"
#include "CThread.h" #include "CThread.h"
void realMain(const CString& name,
const CString& hostname,
SInt32 port)
{
CThread::init();
CNetwork::init();
CClient* client = NULL;
try {
CNetworkAddress addr(hostname, port);
client = new CClient(name);
client->run(addr);
delete client;
CNetwork::cleanup();
}
catch (...) {
delete client;
CNetwork::cleanup();
throw;
}
}
#if defined(CONFIG_PLATFORM_WIN32)
#include "CMSWindowsScreen.h"
int WINAPI WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
{
CMSWindowsScreen::init(instance);
if (__argc != 2) {
CString msg = "hostname required. exiting.";
MessageBox(NULL, msg.c_str(), "error", MB_OK | MB_ICONERROR);
return 1;
}
try {
realMain("ingrid", __argv[1], 50001);
return 0;
}
catch (XBase& e) {
CString msg = "failed: ";
msg += e.what();
MessageBox(NULL, msg.c_str(), "error", MB_OK | MB_ICONERROR);
return 1;
}
}
#else
#include <stdio.h> #include <stdio.h>
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
CThread::init();
if (argc != 2) { if (argc != 2) {
fprintf(stderr, "usage: %s <hostname>\n", argv[0]); fprintf(stderr, "usage: %s <hostname>\n", argv[0]);
return 1; return 1;
} }
try { try {
CClient* client = new CClient("ingrid"); realMain("ingrid", argv[1], 50001);
client->run(CNetworkAddress(argv[1], 50001)); return 0;
} }
catch (XBase& e) { catch (XBase& e) {
fprintf(stderr, "failed: %s\n", e.what()); fprintf(stderr, "failed: %s\n", e.what());
return 1; return 1;
} }
return 0;
} }
#endif

127
client/client.dsp Normal file
View File

@ -0,0 +1,127 @@
# Microsoft Developer Studio Project File - Name="client" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Application" 0x0101
CFG=client - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "client.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "client.mak" CFG="client - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "client - Win32 Release" (based on "Win32 (x86) Application")
!MESSAGE "client - Win32 Debug" (based on "Win32 (x86) Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "millpond"
# PROP Scc_LocalPath "."
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "client - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\base" /I "..\io" /I "..\mt" /I "..\net" /I "..\synergy" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c
# SUBTRACT CPP /YX
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
!ELSEIF "$(CFG)" == "client - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\base" /I "..\io" /I "..\mt" /I "..\net" /I "..\synergy" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c
# SUBTRACT CPP /YX
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "client - Win32 Release"
# Name "client - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\CClient.cpp
# End Source File
# Begin Source File
SOURCE=.\client.cpp
# End Source File
# Begin Source File
SOURCE=.\client.rc
# End Source File
# Begin Source File
SOURCE=.\CMSWindowsSecondaryScreen.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\CClient.h
# End Source File
# Begin Source File
SOURCE=.\CMSWindowsSecondaryScreen.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project

97
client/client.rc Normal file
View File

@ -0,0 +1,97 @@
//Microsoft Developer Studio generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_SYNERGY DIALOG DISCARDABLE 0, 0, 329, 158
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Synergy"
FONT 8, "MS Sans Serif"
BEGIN
EDITTEXT IDC_LOG,7,7,315,144,ES_MULTILINE | ES_AUTOHSCROLL |
ES_READONLY | WS_VSCROLL | WS_HSCROLL
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO DISCARDABLE
BEGIN
IDD_SYNERGY, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 322
TOPMARGIN, 7
BOTTOMMARGIN, 151
END
END
#endif // APSTUDIO_INVOKED
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

17
client/resource.h Normal file
View File

@ -0,0 +1,17 @@
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by client.rc
//
#define IDD_SYNERGY 101
#define IDC_LOG 1000
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

150
io/io.dsp Normal file
View File

@ -0,0 +1,150 @@
# Microsoft Developer Studio Project File - Name="io" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Static Library" 0x0104
CFG=io - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "io.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "io.mak" CFG="io - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "io - Win32 Release" (based on "Win32 (x86) Static Library")
!MESSAGE "io - Win32 Debug" (based on "Win32 (x86) Static Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "millpond"
# PROP Scc_LocalPath "."
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "io - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\base" /I "..\mt" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ELSEIF "$(CFG)" == "io - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\base" /I "..\mt" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ENDIF
# Begin Target
# Name "io - Win32 Release"
# Name "io - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\CBufferedInputStream.cpp
# End Source File
# Begin Source File
SOURCE=.\CBufferedOutputStream.cpp
# End Source File
# Begin Source File
SOURCE=.\CInputStreamFilter.cpp
# End Source File
# Begin Source File
SOURCE=.\COutputStreamFilter.cpp
# End Source File
# Begin Source File
SOURCE=.\CStreamBuffer.cpp
# End Source File
# Begin Source File
SOURCE=.\XIO.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\CBufferedInputStream.h
# End Source File
# Begin Source File
SOURCE=.\CBufferedOutputStream.h
# End Source File
# Begin Source File
SOURCE=.\CInputStreamFilter.h
# End Source File
# Begin Source File
SOURCE=.\COutputStreamFilter.h
# End Source File
# Begin Source File
SOURCE=.\CStreamBuffer.h
# End Source File
# Begin Source File
SOURCE=.\IInputStream.h
# End Source File
# Begin Source File
SOURCE=.\IOutputStream.h
# End Source File
# Begin Source File
SOURCE=.\XIO.h
# End Source File
# End Group
# End Target
# End Project

View File

@ -238,7 +238,7 @@ bool CCondVarBase::wait(
} }
// prepare to wait // prepare to wait
CRefCountedPtr<CThreadRep> currentRep(CThreadRep::getCurrentThreadRep()); CThreadPtr currentRep = CThreadRep::getCurrentThreadRep();
const DWORD winTimeout = (timeout < 0.0) ? INFINITE : const DWORD winTimeout = (timeout < 0.0) ? INFINITE :
static_cast<DWORD>(1000.0 * timeout); static_cast<DWORD>(1000.0 * timeout);
HANDLE* events = reinterpret_cast<HANDLE*>(m_cond); HANDLE* events = reinterpret_cast<HANDLE*>(m_cond);

View File

@ -5,26 +5,6 @@
#include "CStopwatch.h" #include "CStopwatch.h"
#include "CLog.h" #include "CLog.h"
//
// CThreadPtr
//
class CThreadPtr {
public:
CThreadPtr(CThreadRep* rep) : m_rep(rep) { }
~CThreadPtr() { m_rep->unref(); }
CThreadRep* operator->() const { return m_rep; }
private:
// not implemented
CThreadPtr(const CThreadPtr&);
CThreadPtr& operator=(const CThreadPtr&);
private:
CThreadRep* m_rep;
};
// //
// CThread // CThread
// //

View File

@ -12,10 +12,17 @@
#define SIGWAKEUP SIGUSR1 #define SIGWAKEUP SIGUSR1
#endif #endif
#if defined(CONFIG_PLATFORM_WIN32)
# if !defined(_MT)
# error multithreading compile option is required
# endif
#include <process.h>
#endif
// FIXME -- temporary exception type // FIXME -- temporary exception type
class XThreadUnavailable { }; class XThreadUnavailable { };
#ifndef NDEBUG #if defined(CONFIG_PLATFORM_UNIX) && !defined(NDEBUG)
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <sys/types.h> #include <sys/types.h>
@ -145,7 +152,6 @@ void CThreadRep::initThreads()
# ifndef NDEBUG # ifndef NDEBUG
act.sa_handler = &threadDebug; act.sa_handler = &threadDebug;
sigaction(SIGSEGV, &act, NULL); sigaction(SIGSEGV, &act, NULL);
# endif
# endif # endif
// set signal mask // set signal mask
@ -159,6 +165,7 @@ void CThreadRep::initThreads()
sigemptyset(&sigset); sigemptyset(&sigset);
sigaddset(&sigset, SIGPIPE); sigaddset(&sigset, SIGPIPE);
pthread_sigmask(SIG_BLOCK, &sigset, NULL); pthread_sigmask(SIG_BLOCK, &sigset, NULL);
#endif
} }
} }
@ -255,7 +262,7 @@ void CThreadRep::doThreadFunc()
m_job->run(); m_job->run();
} }
catch (XThreadCancel& e) { catch (XThreadCancel&) {
// client called cancel() // client called cancel()
log((CLOG_DEBUG "caught cancel on thread %p", this)); log((CLOG_DEBUG "caught cancel on thread %p", this));
} }
@ -421,8 +428,6 @@ void CThreadRep::threadCancel(int)
#elif defined(CONFIG_PLATFORM_WIN32) #elif defined(CONFIG_PLATFORM_WIN32)
#include <process.h>
void CThreadRep::init() void CThreadRep::init()
{ {
m_result = NULL; m_result = NULL;
@ -485,7 +490,7 @@ bool CThreadRep::wait(CThreadRep* target, double timeout)
{ {
// get the current thread. if it's the same as the target thread // get the current thread. if it's the same as the target thread
// then the thread is waiting on itself. // then the thread is waiting on itself.
CRefCountedPtr<CThreadRep> currentRep(CThreadRep::getCurrentThreadRep()); CThreadPtr currentRep(CThreadRep::getCurrentThreadRep());
if (target == this) if (target == this)
return false; return false;

View File

@ -122,4 +122,24 @@ class CThreadRep {
#endif #endif
}; };
//
// CThreadPtr -- auto unref'ing pointer to thread rep
//
class CThreadPtr {
public:
CThreadPtr(CThreadRep* rep) : m_rep(rep) { }
~CThreadPtr() { m_rep->unref(); }
CThreadRep* operator->() const { return m_rep; }
private:
// not implemented
CThreadPtr(const CThreadPtr&);
CThreadPtr& operator=(const CThreadPtr&);
private:
CThreadRep* m_rep;
};
#endif #endif

146
mt/mt.dsp Normal file
View File

@ -0,0 +1,146 @@
# Microsoft Developer Studio Project File - Name="mt" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Static Library" 0x0104
CFG=mt - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "mt.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "mt.mak" CFG="mt - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "mt - Win32 Release" (based on "Win32 (x86) Static Library")
!MESSAGE "mt - Win32 Debug" (based on "Win32 (x86) Static Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "millpond"
# PROP Scc_LocalPath "."
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "mt - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\base" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ELSEIF "$(CFG)" == "mt - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\base" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ENDIF
# Begin Target
# Name "mt - Win32 Release"
# Name "mt - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\CCondVar.cpp
# End Source File
# Begin Source File
SOURCE=.\CLock.cpp
# End Source File
# Begin Source File
SOURCE=.\CMutex.cpp
# End Source File
# Begin Source File
SOURCE=.\CThread.cpp
# End Source File
# Begin Source File
SOURCE=.\CThreadRep.cpp
# End Source File
# Begin Source File
SOURCE=.\CTimerThread.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\CCondVar.h
# End Source File
# Begin Source File
SOURCE=.\CLock.h
# End Source File
# Begin Source File
SOURCE=.\CMutex.h
# End Source File
# Begin Source File
SOURCE=.\CThread.h
# End Source File
# Begin Source File
SOURCE=.\CThreadRep.h
# End Source File
# Begin Source File
SOURCE=.\CTimerThread.h
# End Source File
# Begin Source File
SOURCE=.\XThread.h
# End Source File
# End Group
# End Target
# End Project

339
net/CNetwork.cpp Normal file
View File

@ -0,0 +1,339 @@
#include "CNetwork.h"
#include "XNetwork.h"
#include "CLog.h"
#include <assert.h>
//
// CNetwork
//
CNetwork::Socket (PASCAL FAR *CNetwork::accept)(CNetwork::Socket s, CNetwork::Address FAR *addr, CNetwork::AddressLength FAR *addrlen);
int (PASCAL FAR *CNetwork::bind)(CNetwork::Socket s, const CNetwork::Address FAR *addr, CNetwork::AddressLength namelen);
int (PASCAL FAR *CNetwork::close)(CNetwork::Socket s);
int (PASCAL FAR *CNetwork::connect)(CNetwork::Socket s, const CNetwork::Address FAR *name, CNetwork::AddressLength namelen);
int (PASCAL FAR *CNetwork::ioctl)(CNetwork::Socket s, int cmd, ...);
int (PASCAL FAR *CNetwork::getpeername)(CNetwork::Socket s, CNetwork::Address FAR *name, CNetwork::AddressLength FAR * namelen);
int (PASCAL FAR *CNetwork::getsockname)(CNetwork::Socket s, CNetwork::Address FAR *name, CNetwork::AddressLength FAR * namelen);
int (PASCAL FAR *CNetwork::getsockopt)(CNetwork::Socket s, int level, int optname, void FAR * optval, CNetwork::AddressLength FAR *optlen);
UInt32 (PASCAL FAR *CNetwork::swaphtonl)(UInt32 hostlong);
UInt16 (PASCAL FAR *CNetwork::swaphtons)(UInt16 hostshort);
unsigned long (PASCAL FAR *CNetwork::inet_addr)(const char FAR * cp);
char FAR * (PASCAL FAR *CNetwork::inet_ntoa)(struct in_addr in);
int (PASCAL FAR *CNetwork::listen)(CNetwork::Socket s, int backlog);
UInt32 (PASCAL FAR *CNetwork::swapntohl)(UInt32 netlong);
UInt16 (PASCAL FAR *CNetwork::swapntohs)(UInt16 netshort);
ssize_t (PASCAL FAR *CNetwork::read)(CNetwork::Socket s, void FAR * buf, size_t len);
ssize_t (PASCAL FAR *CNetwork::recv)(CNetwork::Socket s, void FAR * buf, size_t len, int flags);
ssize_t (PASCAL FAR *CNetwork::recvfrom)(CNetwork::Socket s, void FAR * buf, size_t len, int flags, CNetwork::Address FAR *from, CNetwork::AddressLength FAR * fromlen);
int (PASCAL FAR *CNetwork::poll)(CNetwork::PollEntry fds[], int nfds, int timeout);
ssize_t (PASCAL FAR *CNetwork::send)(CNetwork::Socket s, const void FAR * buf, size_t len, int flags);
ssize_t (PASCAL FAR *CNetwork::sendto)(CNetwork::Socket s, const void FAR * buf, size_t len, int flags, const CNetwork::Address FAR *to, CNetwork::AddressLength tolen);
int (PASCAL FAR *CNetwork::setsockopt)(CNetwork::Socket s, int level, int optname, const void FAR * optval, CNetwork::AddressLength optlen);
int (PASCAL FAR *CNetwork::shutdown)(CNetwork::Socket s, int how);
CNetwork::Socket (PASCAL FAR *CNetwork::socket)(int af, int type, int protocol);
ssize_t (PASCAL FAR *CNetwork::write)(CNetwork::Socket s, const void FAR * buf, size_t len);
struct hostent FAR * (PASCAL FAR *CNetwork::gethostbyaddr)(const char FAR * addr, int len, int type);
struct hostent FAR * (PASCAL FAR *CNetwork::gethostbyname)(const char FAR * name);
int (PASCAL FAR *CNetwork::gethostname)(char FAR * name, int namelen);
struct servent FAR * (PASCAL FAR *CNetwork::getservbyport)(int port, const char FAR * proto);
struct servent FAR * (PASCAL FAR *CNetwork::getservbyname)(const char FAR * name, const char FAR * proto);
struct protoent FAR * (PASCAL FAR *CNetwork::getprotobynumber)(int proto);
struct protoent FAR * (PASCAL FAR *CNetwork::getprotobyname)(const char FAR * name);
int (PASCAL FAR *CNetwork::getsockerror)(void);
int (PASCAL FAR *CNetwork::gethosterror)(void);
#if defined(CONFIG_PLATFORM_WIN32)
int (PASCAL FAR *CNetwork::WSACleanup)(void);
int (PASCAL FAR *CNetwork::__WSAFDIsSet)(CNetwork::Socket, fd_set FAR *);
const int CNetwork::Error = SOCKET_ERROR;
const CNetwork::Socket CNetwork::Null = INVALID_SOCKET;
#undef FD_ISSET
#define FD_ISSET(fd, set) CNetwork::__WSAFDIsSet((SOCKET)(fd), (fd_set FAR *)(set))
static HMODULE s_networkModule = NULL;
static FARPROC netGetProcAddress(HMODULE module, LPCSTR name)
{
FARPROC func = ::GetProcAddress(module, name);
if (!func)
throw XNetworkFunctionUnavailable(name);
return func;
}
void CNetwork::init()
{
assert(WSACleanup == NULL);
assert(s_networkModule == NULL);
// try winsock 2
HMODULE module = (HMODULE)::LoadLibrary("ws2_32.dll");
if (module == NULL) {
log((CLOG_DEBUG "ws2_32.dll not found"));
}
else {
try {
init2(module);
return;
}
catch (XNetwork& e) {
log((CLOG_DEBUG "ws2_32.dll error: %s", e.what()));
}
}
// try winsock 1
module = (HMODULE)::LoadLibrary("wsock32.dll");
if (module == NULL) {
log((CLOG_DEBUG "wsock32.dll not found"));
}
else {
try {
init2(module);
return;
}
catch (XNetwork& e) {
log((CLOG_DEBUG "wsock32.dll error: %s", e.what()));
}
}
// no networking
throw XNetworkUnavailable();
}
void CNetwork::cleanup()
{
if (s_networkModule != NULL) {
WSACleanup();
::FreeLibrary(s_networkModule);
WSACleanup = NULL;
s_networkModule = NULL;
}
}
#define setfunc(var, name, type) var = (type)netGetProcAddress(module, #name)
void CNetwork::init2(HMODULE module)
{
assert(module != NULL);
// get startup function address
int (PASCAL FAR *startup)(WORD, LPWSADATA);
setfunc(startup, WSAStartup, int(PASCAL FAR*)(WORD, LPWSADATA));
// startup network library
WORD version = MAKEWORD(1 /*major*/, 1 /*minor*/);
WSADATA data;
int err = startup(version, &data);
if (data.wVersion != version)
throw XNetworkVersion(LOBYTE(data.wVersion), HIBYTE(data.wVersion));
if (err != 0)
throw XNetworkFailed();
// get function addresses
setfunc(accept, accept, Socket (PASCAL FAR *)(Socket s, Address FAR *addr, AddressLength FAR *addrlen));
setfunc(bind, bind, int (PASCAL FAR *)(Socket s, const Address FAR *addr, AddressLength namelen));
setfunc(close, closesocket, int (PASCAL FAR *)(Socket s));
setfunc(connect, connect, int (PASCAL FAR *)(Socket s, const Address FAR *name, AddressLength namelen));
setfunc(ioctl, ioctlsocket, int (PASCAL FAR *)(Socket s, int cmd, ...));
setfunc(getpeername, getpeername, int (PASCAL FAR *)(Socket s, Address FAR *name, AddressLength FAR * namelen));
setfunc(getsockname, getsockname, int (PASCAL FAR *)(Socket s, Address FAR *name, AddressLength FAR * namelen));
setfunc(getsockopt, getsockopt, int (PASCAL FAR *)(Socket s, int level, int optname, void FAR * optval, AddressLength FAR *optlen));
setfunc(swaphtonl, htonl, UInt32 (PASCAL FAR *)(UInt32 hostlong));
setfunc(swaphtons, htons, UInt16 (PASCAL FAR *)(UInt16 hostshort));
setfunc(inet_addr, inet_addr, unsigned long (PASCAL FAR *)(const char FAR * cp));
setfunc(inet_ntoa, inet_ntoa, char FAR * (PASCAL FAR *)(struct in_addr in));
setfunc(listen, listen, int (PASCAL FAR *)(Socket s, int backlog));
setfunc(swapntohl, ntohl, UInt32 (PASCAL FAR *)(UInt32 netlong));
setfunc(swapntohs, ntohs, UInt16 (PASCAL FAR *)(UInt16 netshort));
setfunc(recv, recv, ssize_t (PASCAL FAR *)(Socket s, void FAR * buf, size_t len, int flags));
setfunc(recvfrom, recvfrom, ssize_t (PASCAL FAR *)(Socket s, void FAR * buf, size_t len, int flags, Address FAR *from, AddressLength FAR * fromlen));
setfunc(send, send, ssize_t (PASCAL FAR *)(Socket s, const void FAR * buf, size_t len, int flags));
setfunc(sendto, sendto, ssize_t (PASCAL FAR *)(Socket s, const void FAR * buf, size_t len, int flags, const Address FAR *to, AddressLength tolen));
setfunc(setsockopt, setsockopt, int (PASCAL FAR *)(Socket s, int level, int optname, const void FAR * optval, AddressLength optlen));
setfunc(shutdown, shutdown, int (PASCAL FAR *)(Socket s, int how));
setfunc(socket, socket, Socket (PASCAL FAR *)(int af, int type, int protocol));
setfunc(gethostbyaddr, gethostbyaddr, struct hostent FAR * (PASCAL FAR *)(const char FAR * addr, int len, int type));
setfunc(gethostbyname, gethostbyname, struct hostent FAR * (PASCAL FAR *)(const char FAR * name));
setfunc(gethostname, gethostname, int (PASCAL FAR *)(char FAR * name, int namelen));
setfunc(getservbyport, getservbyport, struct servent FAR * (PASCAL FAR *)(int port, const char FAR * proto));
setfunc(getservbyname, getservbyname, struct servent FAR * (PASCAL FAR *)(const char FAR * name, const char FAR * proto));
setfunc(getprotobynumber, getprotobynumber, struct protoent FAR * (PASCAL FAR *)(int proto));
setfunc(getprotobyname, getprotobyname, struct protoent FAR * (PASCAL FAR *)(const char FAR * name));
setfunc(getsockerror, WSAGetLastError, int (PASCAL FAR *)(void));
setfunc(gethosterror, WSAGetLastError, int (PASCAL FAR *)(void));
setfunc(WSACleanup, WSACleanup, int (PASCAL FAR *)(void));
setfunc(__WSAFDIsSet, __WSAFDIsSet, int (PASCAL FAR *)(CNetwork::Socket, fd_set FAR *));
setfunc(select, select, int (PASCAL FAR *)(int nfds, fd_set FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout));
poll = poll2;
read = read2;
write = write2;
s_networkModule = module;
}
int PASCAL FAR CNetwork::poll2(PollEntry fd[], int nfds, int timeout)
{
int i;
// prepare sets for select
fd_set readSet, writeSet, errSet;
fd_set* readSetP = NULL;
fd_set* writeSetP = NULL;
fd_set* errSetP = NULL;
FD_ZERO(&readSet);
FD_ZERO(&writeSet);
FD_ZERO(&errSet);
for (i = 0; i < nfds; ++i) {
if (fd[i].events & kPOLLIN) {
FD_SET(fd[i].fd, &readSet);
readSetP = &readSet;
}
if (fd[i].events & kPOLLOUT) {
FD_SET(fd[i].fd, &writeSet);
writeSetP = &writeSet;
}
if (true) {
FD_SET(fd[i].fd, &errSet);
errSetP = &errSet;
}
}
// prepare timeout for select
struct timeval timeout2;
struct timeval* timeout2P;
if (timeout < 0) {
timeout2P = NULL;
}
else {
timeout2P = &timeout2;
timeout2.tv_sec = timeout / 1000;
timeout2.tv_usec = 1000 * (timeout % 1000);
}
// do the select. note that winsock ignores the first argument.
int n = select(0, readSetP, writeSetP, errSetP, timeout2P);
// handle results
if (n == Error)
return Error;
if (n == 0)
return 0;
for (i = 0; i < nfds; ++i) {
fd[i].revents = 0;
if (FD_ISSET(fd[i].fd, &readSet))
fd[i].revents |= kPOLLIN;
if (FD_ISSET(fd[i].fd, &writeSet))
fd[i].revents |= kPOLLOUT;
if (FD_ISSET(fd[i].fd, &errSet))
fd[i].revents |= kPOLLERR;
}
return n;
}
ssize_t PASCAL FAR CNetwork::read2(Socket s, void FAR * buf, size_t len)
{
return recv(s, buf, len, 0);
}
ssize_t PASCAL FAR CNetwork::write2(Socket s,
const void FAR * buf, size_t len)
{
return send(s, buf, len, 0);
}
#endif
#if defined(CONFIG_PLATFORM_UNIX)
#include <unistd.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
// FIXME -- use reentrant versions of non-reentrant functions
#define setfunc(var, name, type) var = (type)::name
static UInt32 myhtonl(UInt32 v)
{
return htonl(v);
}
static UInt16 myhtons(UInt16 v)
{
return htons(v);
}
static UInt32 myntohl(UInt32 v)
{
return ntohl(v);
}
static UInt16 myntohs(UInt16 v)
{
return ntohs(v);
}
static int myerrno()
{
return errno;
}
static int myherrno()
{
return h_errno;
}
static int mygethostname(char* name, int namelen)
{
return gethostname(name, namelen);
}
const int CNetwork::Error = -1;
const CNetwork::Socket CNetwork::Null = -1;
void CNetwork::init()
{
setfunc(accept, accept, Socket (PASCAL FAR *)(Socket s, Address FAR *addr, AddressLength FAR *addrlen));
setfunc(bind, bind, int (PASCAL FAR *)(Socket s, const Address FAR *addr, AddressLength namelen));
setfunc(close, close, int (PASCAL FAR *)(Socket s));
setfunc(connect, connect, int (PASCAL FAR *)(Socket s, const Address FAR *name, AddressLength namelen));
setfunc(ioctl, ioctl, int (PASCAL FAR *)(Socket s, int cmd, ...));
setfunc(getpeername, getpeername, int (PASCAL FAR *)(Socket s, Address FAR *name, AddressLength FAR * namelen));
setfunc(getsockname, getsockname, int (PASCAL FAR *)(Socket s, Address FAR *name, AddressLength FAR * namelen));
setfunc(getsockopt, getsockopt, int (PASCAL FAR *)(Socket s, int level, int optname, void FAR * optval, AddressLength FAR *optlen));
setfunc(swaphtonl, myhtonl, UInt32 (PASCAL FAR *)(UInt32 hostlong));
setfunc(swaphtons, myhtons, UInt16 (PASCAL FAR *)(UInt16 hostshort));
setfunc(inet_addr, inet_addr, unsigned long (PASCAL FAR *)(const char FAR * cp));
setfunc(inet_ntoa, inet_ntoa, char FAR * (PASCAL FAR *)(struct in_addr in));
setfunc(listen, listen, int (PASCAL FAR *)(Socket s, int backlog));
setfunc(swapntohl, myntohl, UInt32 (PASCAL FAR *)(UInt32 netlong));
setfunc(swapntohs, myntohs, UInt16 (PASCAL FAR *)(UInt16 netshort));
setfunc(poll, poll, int (PASCAL FAR *)(CNetwork::PollEntry fds[], int nfds, int timeout));
setfunc(read, read, ssize_t (PASCAL FAR *)(CNetwork::Socket s, void FAR * buf, size_t len));
setfunc(recv, recv, ssize_t (PASCAL FAR *)(Socket s, void FAR * buf, size_t len, int flags));
setfunc(recvfrom, recvfrom, ssize_t (PASCAL FAR *)(Socket s, void FAR * buf, size_t len, int flags, Address FAR *from, AddressLength FAR * fromlen));
setfunc(send, send, ssize_t (PASCAL FAR *)(Socket s, const void FAR * buf, size_t len, int flags));
setfunc(sendto, sendto, ssize_t (PASCAL FAR *)(Socket s, const void FAR * buf, size_t len, int flags, const Address FAR *to, AddressLength tolen));
setfunc(setsockopt, setsockopt, int (PASCAL FAR *)(Socket s, int level, int optname, const void FAR * optval, AddressLength optlen));
setfunc(shutdown, shutdown, int (PASCAL FAR *)(Socket s, int how));
setfunc(socket, socket, Socket (PASCAL FAR *)(int af, int type, int protocol));
setfunc(write, write, ssize_t (PASCAL FAR *)(CNetwork::Socket s, const void FAR * buf, size_t len));
setfunc(gethostbyaddr, gethostbyaddr, struct hostent FAR * (PASCAL FAR *)(const char FAR * addr, int len, int type));
setfunc(gethostbyname, gethostbyname, struct hostent FAR * (PASCAL FAR *)(const char FAR * name));
setfunc(gethostname, mygethostname, int (PASCAL FAR *)(char FAR * name, int namelen));
setfunc(getservbyport, getservbyport, struct servent FAR * (PASCAL FAR *)(int port, const char FAR * proto));
setfunc(getservbyname, getservbyname, struct servent FAR * (PASCAL FAR *)(const char FAR * name, const char FAR * proto));
setfunc(getprotobynumber, getprotobynumber, struct protoent FAR * (PASCAL FAR *)(int proto));
setfunc(getprotobyname, getprotobyname, struct protoent FAR * (PASCAL FAR *)(const char FAR * name));
setfunc(getsockerror, myerrno, int (PASCAL FAR *)(void));
setfunc(gethosterror, myherrno, int (PASCAL FAR *)(void));
}
void CNetwork::cleanup()
{
// do nothing
}
#endif

143
net/CNetwork.h Normal file
View File

@ -0,0 +1,143 @@
#ifndef CNETWORK_H
#define CNETWORK_H
#include "BasicTypes.h"
#if defined(CONFIG_PLATFORM_WIN32)
// declare no functions in winsock2
# define INCL_WINSOCK_API_PROTOTYPES 0
# define INCL_WINSOCK_API_TYPEDEFS 0
# include <winsock2.h>
typedef int ssize_t;
#else
# define FAR
# define PASCAL
#endif
#if defined(CONFIG_PLATFORM_UNIX)
# include <sys/types.h>
# include <sys/poll.h>
# include <sys/socket.h>
# include <netdb.h>
# include <netinet/in.h>
# include <errno.h>
#endif
// FIXME -- must handle htonl and ilk when defined as macros
class CNetwork {
public:
#if defined(CONFIG_PLATFORM_WIN32)
typedef SOCKET Socket;
typedef struct sockaddr Address;
typedef int AddressLength;
struct PollEntry {
Socket fd;
short events;
short revents;
};
enum {
kPOLLIN = 1,
kPOLLOUT = 2,
kPOLLERR = 4,
kPOLLNVAL = 8
};
#elif defined(CONFIG_PLATFORM_UNIX)
typedef int Socket;
typedef struct sockaddr Address;
typedef socklen_t AddressLength;
typedef struct pollfd PollEntry;
enum {
kPOLLIN = POLLIN,
kPOLLOUT = POLLOUT,
kPOLLERR = POLLERR,
kPOLLNVAL = POLLNVAL
};
#endif
// manipulators
static void init();
static void cleanup();
// constants
static const int Error;
static const Socket Null;
// getsockerror() constants
enum {
#if defined(CONFIG_PLATFORM_WIN32)
kEADDRINUSE = WSAEADDRINUSE,
#elif defined(CONFIG_PLATFORM_UNIX)
kEADDRINUSE = EADDRINUSE,
#endif
kNone = 0
};
// gethosterror() constants
enum {
#if defined(CONFIG_PLATFORM_WIN32)
kHOST_NOT_FOUND = WSAHOST_NOT_FOUND,
kNO_DATA = WSANO_DATA,
kNO_RECOVERY = WSANO_RECOVERY,
kTRY_AGAIN = WSATRY_AGAIN,
#elif defined(CONFIG_PLATFORM_UNIX)
kHOST_NOT_FOUND = HOST_NOT_FOUND,
kNO_DATA = NO_DATA,
kNO_RECOVERY = NO_RECOVERY,
kTRY_AGAIN = TRY_AGAIN,
#endif
kHNone = 0
};
// socket interface
static Socket (PASCAL FAR *accept)(Socket s, Address FAR *addr, AddressLength FAR *addrlen);
static int (PASCAL FAR *bind)(Socket s, const Address FAR *addr, AddressLength namelen);
static int (PASCAL FAR *close)(Socket s);
static int (PASCAL FAR *connect)(Socket s, const Address FAR *name, AddressLength namelen);
static int (PASCAL FAR *ioctl)(Socket s, int cmd, ...);
static int (PASCAL FAR *getpeername)(Socket s, Address FAR *name, AddressLength FAR * namelen);
static int (PASCAL FAR *getsockname)(Socket s, Address FAR *name, AddressLength FAR * namelen);
static int (PASCAL FAR *getsockopt)(Socket s, int level, int optname, void FAR * optval, AddressLength FAR *optlen);
static UInt32 (PASCAL FAR *swaphtonl)(UInt32 hostlong);
static UInt16 (PASCAL FAR *swaphtons)(UInt16 hostshort);
static unsigned long (PASCAL FAR *inet_addr)(const char FAR * cp);
static char FAR * (PASCAL FAR *inet_ntoa)(struct in_addr in);
static int (PASCAL FAR *listen)(Socket s, int backlog);
static UInt32 (PASCAL FAR *swapntohl)(UInt32 netlong);
static UInt16 (PASCAL FAR *swapntohs)(UInt16 netshort);
static ssize_t (PASCAL FAR *read)(Socket s, void FAR * buf, size_t len);
static ssize_t (PASCAL FAR *recv)(Socket s, void FAR * buf, size_t len, int flags);
static ssize_t (PASCAL FAR *recvfrom)(Socket s, void FAR * buf, size_t len, int flags, Address FAR *from, AddressLength FAR * fromlen);
static int (PASCAL FAR *poll)(PollEntry[], int nfds, int timeout);
static ssize_t (PASCAL FAR *send)(Socket s, const void FAR * buf, size_t len, int flags);
static ssize_t (PASCAL FAR *sendto)(Socket s, const void FAR * buf, size_t len, int flags, const Address FAR *to, AddressLength tolen);
static int (PASCAL FAR *setsockopt)(Socket s, int level, int optname, const void FAR * optval, AddressLength optlen);
static int (PASCAL FAR *shutdown)(Socket s, int how);
static Socket (PASCAL FAR *socket)(int af, int type, int protocol);
static ssize_t (PASCAL FAR *write)(Socket s, const void FAR * buf, size_t len);
static struct hostent FAR * (PASCAL FAR *gethostbyaddr)(const char FAR * addr, int len, int type);
static struct hostent FAR * (PASCAL FAR *gethostbyname)(const char FAR * name);
static int (PASCAL FAR *gethostname)(char FAR * name, int namelen);
static struct servent FAR * (PASCAL FAR *getservbyport)(int port, const char FAR * proto);
static struct servent FAR * (PASCAL FAR *getservbyname)(const char FAR * name, const char FAR * proto);
static struct protoent FAR * (PASCAL FAR *getprotobynumber)(int proto);
static struct protoent FAR * (PASCAL FAR *getprotobyname)(const char FAR * name);
static int (PASCAL FAR *getsockerror)(void);
static int (PASCAL FAR *gethosterror)(void);
#if defined(CONFIG_PLATFORM_WIN32)
private:
static void init2(HMODULE);
static int PASCAL FAR poll2(PollEntry[], int nfds, int timeout);
static ssize_t PASCAL FAR read2(Socket s, void FAR * buf, size_t len);
static ssize_t PASCAL FAR write2(Socket s, const void FAR * buf, size_t len);
static int (PASCAL FAR *WSACleanup)(void);
static int (PASCAL FAR *__WSAFDIsSet)(CNetwork::Socket, fd_set FAR *);
static int (PASCAL FAR *select)(int nfds, fd_set FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout);
#endif
};
#endif

View File

@ -1,8 +1,4 @@
#include "CNetworkAddress.h" #include "CNetworkAddress.h"
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
// //
// CNetworkAddress // CNetworkAddress
@ -15,7 +11,7 @@ CNetworkAddress::CNetworkAddress(UInt16 port)
struct sockaddr_in* inetAddress = reinterpret_cast<struct sockaddr_in*>(&m_address); struct sockaddr_in* inetAddress = reinterpret_cast<struct sockaddr_in*>(&m_address);
inetAddress->sin_family = AF_INET; inetAddress->sin_family = AF_INET;
inetAddress->sin_port = htons(port); inetAddress->sin_port = CNetwork::swaphtons(port);
inetAddress->sin_addr.s_addr = INADDR_ANY; inetAddress->sin_addr.s_addr = INADDR_ANY;
memset(inetAddress->sin_zero, 0, sizeof(inetAddress->sin_zero)); memset(inetAddress->sin_zero, 0, sizeof(inetAddress->sin_zero));
} }
@ -25,17 +21,17 @@ CNetworkAddress::CNetworkAddress(const CString& hostname, UInt16 port)
if (port == 0) if (port == 0)
throw XSocketAddress(XSocketAddress::kBadPort, hostname, port); throw XSocketAddress(XSocketAddress::kBadPort, hostname, port);
struct hostent* hent = gethostbyname(hostname.c_str()); struct hostent* hent = CNetwork::gethostbyname(hostname.c_str());
if (hent == NULL) { if (hent == NULL) {
switch (h_errno) { switch (CNetwork::gethosterror()) {
case HOST_NOT_FOUND: case CNetwork::kHOST_NOT_FOUND:
throw XSocketAddress(XSocketAddress::kNotFound, hostname, port); throw XSocketAddress(XSocketAddress::kNotFound, hostname, port);
case NO_DATA: case CNetwork::kNO_DATA:
throw XSocketAddress(XSocketAddress::kNoAddress, hostname, port); throw XSocketAddress(XSocketAddress::kNoAddress, hostname, port);
case NO_RECOVERY: case CNetwork::kNO_RECOVERY:
case TRY_AGAIN: case CNetwork::kTRY_AGAIN:
default: default:
throw XSocketAddress(XSocketAddress::kUnknown, hostname, port); throw XSocketAddress(XSocketAddress::kUnknown, hostname, port);
} }
@ -43,7 +39,7 @@ CNetworkAddress::CNetworkAddress(const CString& hostname, UInt16 port)
struct sockaddr_in* inetAddress = reinterpret_cast<struct sockaddr_in*>(&m_address); struct sockaddr_in* inetAddress = reinterpret_cast<struct sockaddr_in*>(&m_address);
inetAddress->sin_family = hent->h_addrtype; inetAddress->sin_family = hent->h_addrtype;
inetAddress->sin_port = htons(port); inetAddress->sin_port = CNetwork::swaphtons(port);
memcpy(&inetAddress->sin_addr, hent->h_addr_list[0], hent->h_length); memcpy(&inetAddress->sin_addr, hent->h_addr_list[0], hent->h_length);
memset(inetAddress->sin_zero, 0, sizeof(inetAddress->sin_zero)); memset(inetAddress->sin_zero, 0, sizeof(inetAddress->sin_zero));
} }
@ -53,12 +49,12 @@ CNetworkAddress::~CNetworkAddress()
// do nothing // do nothing
} }
const struct sockaddr* CNetworkAddress::getAddress() const const CNetwork::Address* CNetworkAddress::getAddress() const
{ {
return &m_address; return &m_address;
} }
int CNetworkAddress::getAddressLength() const CNetwork::AddressLength CNetworkAddress::getAddressLength() const
{ {
return sizeof(m_address); return sizeof(m_address);
} }

View File

@ -2,8 +2,8 @@
#define CNETWORKADDRESS_H #define CNETWORKADDRESS_H
#include "BasicTypes.h" #include "BasicTypes.h"
#include "CNetwork.h"
#include "XSocket.h" #include "XSocket.h"
#include <sys/socket.h>
class CString; class CString;
@ -17,11 +17,11 @@ class CNetworkAddress {
// accessors // accessors
const struct sockaddr* getAddress() const; const CNetwork::Address* getAddress() const;
int getAddressLength() const; CNetwork::AddressLength getAddressLength() const;
private: private:
struct sockaddr m_address; CNetwork::Address m_address;
}; };
#endif #endif

View File

@ -2,11 +2,6 @@
#include "CTCPSocket.h" #include "CTCPSocket.h"
#include "CNetworkAddress.h" #include "CNetworkAddress.h"
#include "CThread.h" #include "CThread.h"
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
// //
// CTCPListenSocket // CTCPListenSocket
@ -14,8 +9,8 @@
CTCPListenSocket::CTCPListenSocket() CTCPListenSocket::CTCPListenSocket()
{ {
m_fd = socket(PF_INET, SOCK_STREAM, 0); m_fd = CNetwork::socket(PF_INET, SOCK_STREAM, 0);
if (m_fd == -1) { if (m_fd == CNetwork::Null) {
throw XSocketCreate(); throw XSocketCreate();
} }
} }
@ -33,40 +28,44 @@ CTCPListenSocket::~CTCPListenSocket()
void CTCPListenSocket::bind( void CTCPListenSocket::bind(
const CNetworkAddress& addr) const CNetworkAddress& addr)
{ {
if (::bind(m_fd, addr.getAddress(), addr.getAddressLength()) == -1) { if (CNetwork::bind(m_fd, addr.getAddress(),
if (errno == EADDRINUSE) { addr.getAddressLength()) == CNetwork::Error) {
if (CNetwork::getsockerror() == CNetwork::kEADDRINUSE) {
throw XSocketAddressInUse(); throw XSocketAddressInUse();
} }
throw XSocketBind(); throw XSocketBind();
} }
if (listen(m_fd, 3) == -1) { if (CNetwork::listen(m_fd, 3) == CNetwork::Error) {
throw XSocketBind(); throw XSocketBind();
} }
} }
ISocket* CTCPListenSocket::accept() ISocket* CTCPListenSocket::accept()
{ {
CNetwork::PollEntry pfds[1];
pfds[0].fd = m_fd;
pfds[0].events = CNetwork::kPOLLIN;
for (;;) { for (;;) {
struct sockaddr addr;
socklen_t addrlen = sizeof(addr);
CThread::testCancel(); CThread::testCancel();
int fd = ::accept(m_fd, &addr, &addrlen); const int status = CNetwork::poll(pfds, 1, 50);
if (fd == -1) { if (status > 0 && (pfds[0].revents & CNetwork::kPOLLIN) != 0) {
CThread::testCancel(); CNetwork::Address addr;
} CNetwork::AddressLength addrlen = sizeof(addr);
else { int fd = CNetwork::accept(m_fd, &addr, &addrlen);
if (fd != CNetwork::Null) {
return new CTCPSocket(fd); return new CTCPSocket(fd);
} }
} }
} }
}
void CTCPListenSocket::close() void CTCPListenSocket::close()
{ {
if (m_fd == -1) { if (m_fd == CNetwork::Null) {
throw XIOClosed(); throw XIOClosed();
} }
if (::close(m_fd) == -1) { if (CNetwork::close(m_fd) == CNetwork::Error) {
throw XIOClose(); throw XIOClose();
} }
m_fd = -1; m_fd = CNetwork::Null;
} }

View File

@ -2,6 +2,7 @@
#define CTCPLISTENSOCKET_H #define CTCPLISTENSOCKET_H
#include "IListenSocket.h" #include "IListenSocket.h"
#include "CNetwork.h"
class CTCPListenSocket : public IListenSocket { class CTCPListenSocket : public IListenSocket {
public: public:
@ -18,7 +19,7 @@ class CTCPListenSocket : public IListenSocket {
virtual void close(); virtual void close();
private: private:
int m_fd; CNetwork::Socket m_fd;
}; };
#endif #endif

View File

@ -8,12 +8,6 @@
#include "CThread.h" #include "CThread.h"
#include "TMethodJob.h" #include "TMethodJob.h"
#include "CStopwatch.h" #include "CStopwatch.h"
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/poll.h>
#include <netinet/in.h>
#include <assert.h> #include <assert.h>
// //
@ -22,16 +16,16 @@
CTCPSocket::CTCPSocket() CTCPSocket::CTCPSocket()
{ {
m_fd = socket(PF_INET, SOCK_STREAM, 0); m_fd = CNetwork::socket(PF_INET, SOCK_STREAM, 0);
if (m_fd == -1) { if (m_fd == CNetwork::Null) {
throw XSocketCreate(); throw XSocketCreate();
} }
init(); init();
} }
CTCPSocket::CTCPSocket(int fd) : m_fd(fd) CTCPSocket::CTCPSocket(CNetwork::Socket fd) : m_fd(fd)
{ {
assert(m_fd != -1); assert(m_fd != CNetwork::Null);
init(); init();
@ -60,8 +54,9 @@ CTCPSocket::~CTCPSocket()
void CTCPSocket::bind(const CNetworkAddress& addr) void CTCPSocket::bind(const CNetworkAddress& addr)
{ {
if (::bind(m_fd, addr.getAddress(), addr.getAddressLength()) == -1) { if (CNetwork::bind(m_fd, addr.getAddress(),
if (errno == EADDRINUSE) { addr.getAddressLength()) == CNetwork::Error) {
if (errno == CNetwork::kEADDRINUSE) {
throw XSocketAddressInUse(); throw XSocketAddressInUse();
} }
throw XSocketBind(); throw XSocketBind();
@ -71,7 +66,8 @@ void CTCPSocket::bind(const CNetworkAddress& addr)
void CTCPSocket::connect(const CNetworkAddress& addr) void CTCPSocket::connect(const CNetworkAddress& addr)
{ {
CThread::testCancel(); CThread::testCancel();
if (::connect(m_fd, addr.getAddress(), addr.getAddressLength()) == -1) { if (CNetwork::connect(m_fd, addr.getAddress(),
addr.getAddressLength()) == CNetwork::Error) {
CThread::testCancel(); CThread::testCancel();
throw XSocketConnect(); throw XSocketConnect();
} }
@ -103,11 +99,11 @@ void CTCPSocket::close()
} }
CLock lock(m_mutex); CLock lock(m_mutex);
if (m_fd != -1) { if (m_fd != CNetwork::Null) {
if (::close(m_fd) == -1) { if (CNetwork::close(m_fd) == CNetwork::Error) {
throw XIOClose(); throw XIOClose();
} }
m_fd = -1; m_fd = CNetwork::Null;
} }
} }
@ -150,10 +146,10 @@ void CTCPSocket::ioThread(void*)
void CTCPSocket::ioService() void CTCPSocket::ioService()
{ {
assert(m_fd != -1); assert(m_fd != CNetwork::Null);
// now service the connection // now service the connection
struct pollfd pfds[1]; CNetwork::PollEntry pfds[1];
pfds[0].fd = m_fd; pfds[0].fd = m_fd;
for (;;) { for (;;) {
{ {
@ -162,31 +158,32 @@ void CTCPSocket::ioService()
pfds[0].events = 0; pfds[0].events = 0;
if ((m_connected & kRead) != 0) { if ((m_connected & kRead) != 0) {
// still open for reading // still open for reading
pfds[0].events |= POLLIN; pfds[0].events |= CNetwork::kPOLLIN;
} }
if ((m_connected & kWrite) != 0 && m_output->getSize() > 0) { if ((m_connected & kWrite) != 0 && m_output->getSize() > 0) {
// data queued for writing // data queued for writing
pfds[0].events |= POLLOUT; pfds[0].events |= CNetwork::kPOLLOUT;
} }
} }
// check for status // check for status
CThread::testCancel(); CThread::testCancel();
const int status = poll(pfds, 1, 50); const int status = CNetwork::poll(pfds, 1, 50);
CThread::testCancel(); CThread::testCancel();
// transfer data and handle errors // transfer data and handle errors
if (status == 1) { if (status == 1) {
if ((pfds[0].revents & (POLLERR | POLLNVAL)) != 0) { if ((pfds[0].revents & (CNetwork::kPOLLERR |
CNetwork::kPOLLNVAL)) != 0) {
// stream is no good anymore so bail // stream is no good anymore so bail
m_input->hangup(); m_input->hangup();
return; return;
} }
// read some data // read some data
if (pfds[0].revents & POLLIN) { if (pfds[0].revents & CNetwork::kPOLLIN) {
UInt8 buffer[4096]; UInt8 buffer[4096];
ssize_t n = read(m_fd, buffer, sizeof(buffer)); ssize_t n = CNetwork::read(m_fd, buffer, sizeof(buffer));
if (n > 0) { if (n > 0) {
CLock lock(m_mutex); CLock lock(m_mutex);
m_input->write(buffer, n); m_input->write(buffer, n);
@ -199,7 +196,7 @@ void CTCPSocket::ioService()
} }
// write some data // write some data
if (pfds[0].revents & POLLOUT) { if (pfds[0].revents & CNetwork::kPOLLOUT) {
CLock lock(m_mutex); CLock lock(m_mutex);
// get amount of data to write // get amount of data to write
@ -211,13 +208,13 @@ void CTCPSocket::ioService()
// write data // write data
const void* buffer = m_output->peek(n); const void* buffer = m_output->peek(n);
n = (UInt32)write(m_fd, buffer, n); n = (UInt32)CNetwork::write(m_fd, buffer, n);
// discard written data // discard written data
if (n > 0) { if (n > 0) {
m_output->pop(n); m_output->pop(n);
} }
else if (n == (UInt32)-1 && errno == EPIPE) { else if (n == (UInt32)-1 && CNetwork::getsockerror() == EPIPE) {
return; return;
} }
} }
@ -228,13 +225,13 @@ void CTCPSocket::ioService()
void CTCPSocket::closeInput(void*) void CTCPSocket::closeInput(void*)
{ {
// note -- m_mutex should already be locked // note -- m_mutex should already be locked
shutdown(m_fd, 0); CNetwork::shutdown(m_fd, 0);
m_connected &= ~kRead; m_connected &= ~kRead;
} }
void CTCPSocket::closeOutput(void*) void CTCPSocket::closeOutput(void*)
{ {
// note -- m_mutex should already be locked // note -- m_mutex should already be locked
shutdown(m_fd, 1); CNetwork::shutdown(m_fd, 1);
m_connected &= ~kWrite; m_connected &= ~kWrite;
} }

View File

@ -2,6 +2,7 @@
#define CTCPSOCKET_H #define CTCPSOCKET_H
#include "ISocket.h" #include "ISocket.h"
#include "CNetwork.h"
#include "XThread.h" #include "XThread.h"
class CMutex; class CMutex;
@ -14,7 +15,7 @@ class CBufferedOutputStream;
class CTCPSocket : public ISocket { class CTCPSocket : public ISocket {
public: public:
CTCPSocket(); CTCPSocket();
CTCPSocket(int fd); CTCPSocket(CNetwork::Socket);
~CTCPSocket(); ~CTCPSocket();
// manipulators // manipulators
@ -38,7 +39,7 @@ class CTCPSocket : public ISocket {
private: private:
enum { kClosed = 0, kRead = 1, kWrite = 2, kReadWrite = 3 }; enum { kClosed = 0, kRead = 1, kWrite = 2, kReadWrite = 3 };
int m_fd; CNetwork::Socket m_fd;
CBufferedInputStream* m_input; CBufferedInputStream* m_input;
CBufferedOutputStream* m_output; CBufferedOutputStream* m_output;

View File

@ -15,10 +15,11 @@ LCXXINCS = \
-I$(DEPTH)/io \ -I$(DEPTH)/io \
$(NULL) $(NULL)
CXXFILES = \ CXXFILES = \
XSocket.cpp \ CNetwork.cpp \
CNetworkAddress.cpp \ CNetworkAddress.cpp \
CTCPSocket.cpp \ CTCPSocket.cpp \
CTCPListenSocket.cpp \ CTCPListenSocket.cpp \
XSocket.cpp \
$(NULL) $(NULL)
targets: $(LIBTARGET) targets: $(LIBTARGET)

72
net/XNetwork.cpp Normal file
View File

@ -0,0 +1,72 @@
#include "XNetwork.h"
//
// XNetworkUnavailable
//
CString XNetworkUnavailable::getWhat() const throw()
{
return format("XNetworkUnavailable", "network library is not available");
}
//
// XNetworkFailed
//
CString XNetworkFailed::getWhat() const throw()
{
return format("XNetworkFailed", "cannot initialize network library");
}
//
// XNetworkVersion
//
XNetworkVersion::XNetworkVersion(int major, int minor) throw() :
m_major(major),
m_minor(minor)
{
// do nothing
}
int XNetworkVersion::getMajor() const throw()
{
return m_major;
}
int XNetworkVersion::getMinor() const throw()
{
return m_minor;
}
CString XNetworkVersion::getWhat() const throw()
{
return format("XNetworkVersion",
"unsupported network version %d.%d",
m_major, m_minor);
}
//
// XNetworkFunctionUnavailable
//
XNetworkFunctionUnavailable::XNetworkFunctionUnavailable(
const char* name) throw()
{
try {
m_name = name;
}
catch (...) {
// ignore
}
}
CString XNetworkFunctionUnavailable::getWhat() const throw()
{
return format("XNetworkFunctionUnavailable",
"missing network function %s",
m_name.c_str());
}

52
net/XNetwork.h Normal file
View File

@ -0,0 +1,52 @@
#ifndef XNETWORK_H
#define XNETWORK_H
#include "CString.h"
#include "XBase.h"
#include "BasicTypes.h"
class XNetwork : public XBase { };
class XNetworkUnavailable : public XNetwork {
protected:
// XBase overrides
virtual CString getWhat() const throw();
};
class XNetworkFailed : public XNetwork {
protected:
// XBase overrides
virtual CString getWhat() const throw();
};
class XNetworkVersion : public XNetwork {
public:
XNetworkVersion(int major, int minor) throw();
// accessors
int getMajor() const throw();
int getMinor() const throw();
protected:
// XBase overrides
virtual CString getWhat() const throw();
private:
int m_major;
int m_minor;
};
class XNetworkFunctionUnavailable : public XNetwork {
public:
XNetworkFunctionUnavailable(const char* name) throw();
protected:
// XBase overrides
virtual CString getWhat() const throw();
private:
CString m_name;
};
#endif

174
net/net.dsp Normal file
View File

@ -0,0 +1,174 @@
# Microsoft Developer Studio Project File - Name="net" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Static Library" 0x0104
CFG=net - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "net.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "net.mak" CFG="net - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "net - Win32 Release" (based on "Win32 (x86) Static Library")
!MESSAGE "net - Win32 Debug" (based on "Win32 (x86) Static Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "millpond"
# PROP Scc_LocalPath "."
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "net - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\base" /I "..\io" /I "..\mt" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ELSEIF "$(CFG)" == "net - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\base" /I "..\io" /I "..\mt" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ENDIF
# Begin Target
# Name "net - Win32 Release"
# Name "net - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\CNetwork.cpp
# End Source File
# Begin Source File
SOURCE=.\CNetworkAddress.cpp
# End Source File
# Begin Source File
SOURCE=.\CSocketInputStream.cpp
# End Source File
# Begin Source File
SOURCE=.\CSocketOutputStream.cpp
# End Source File
# Begin Source File
SOURCE=.\CSocketStreamBuffer.cpp
# End Source File
# Begin Source File
SOURCE=.\CTCPListenSocket.cpp
# End Source File
# Begin Source File
SOURCE=.\CTCPSocket.cpp
# End Source File
# Begin Source File
SOURCE=.\XNetwork.cpp
# End Source File
# Begin Source File
SOURCE=.\XSocket.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\CNetwork.h
# End Source File
# Begin Source File
SOURCE=.\CNetworkAddress.h
# End Source File
# Begin Source File
SOURCE=.\CSocketInputStream.h
# End Source File
# Begin Source File
SOURCE=.\CSocketOutputStream.h
# End Source File
# Begin Source File
SOURCE=.\CSocketStreamBuffer.h
# End Source File
# Begin Source File
SOURCE=.\CTCPListenSocket.h
# End Source File
# Begin Source File
SOURCE=.\CTCPSocket.h
# End Source File
# Begin Source File
SOURCE=.\IListenSocket.h
# End Source File
# Begin Source File
SOURCE=.\ISocket.h
# End Source File
# Begin Source File
SOURCE=.\XNetwork.h
# End Source File
# Begin Source File
SOURCE=.\XSocket.h
# End Source File
# End Group
# End Target
# End Project

20
notes
View File

@ -78,3 +78,23 @@ server:
asynchronously handle primary screen events asynchronously handle primary screen events
comm comm
send/recv messages to/from clients send/recv messages to/from clients
---
win32:
double click support
need to support window stations
login screen on NT is a separate window station
handle display changes
---
win32 key translation (client)
get character for key (with appropriate shift)
keypad enter -> VK_???
sys req -> VK_???
compose -> VK_???
X11 key translation (server)
handle compose key?
* don't send compose, don't send dead keys, send composed key?
* send all keys, let client do compose

View File

@ -0,0 +1,509 @@
#include "CMSWindowsPrimaryScreen.h"
#include "CServer.h"
#include "CSynergyHook.h"
#include "CThread.h"
#include "CLog.h"
#include <assert.h>
//
// CMSWindowsPrimaryScreen
//
CMSWindowsPrimaryScreen::CMSWindowsPrimaryScreen() :
m_server(NULL),
m_active(false),
m_window(NULL),
m_hookLibrary(NULL),
m_mark(0),
m_markReceived(0)
{
// do nothing
}
CMSWindowsPrimaryScreen::~CMSWindowsPrimaryScreen()
{
assert(m_window == NULL);
assert(m_hookLibrary == NULL);
}
static HWND s_debug = NULL;
static HWND s_debugLog = NULL;
static DWORD s_thread = 0;
static BOOL CALLBACK WINAPI debugProc(HWND, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_INITDIALOG:
return TRUE;
case WM_CLOSE:
PostQuitMessage(0);
return TRUE;
}
return FALSE;
}
static void debugOutput(const char* msg)
{
if (s_thread != 0) {
const DWORD threadID = ::GetCurrentThreadId();
if (threadID != s_thread) {
GetDesktopWindow();
AttachThreadInput(threadID, s_thread, TRUE);
}
}
DWORD len = SendMessage(s_debugLog, WM_GETTEXTLENGTH, 0, 0);
if (len > 20000) {
SendMessage(s_debugLog, EM_SETSEL, -1, 0);
SendMessage(s_debugLog, WM_SETTEXT, FALSE, (LPARAM)(LPCTSTR)msg);
}
else {
SendMessage(s_debugLog, EM_SETSEL, -1, len);
SendMessage(s_debugLog, EM_REPLACESEL, FALSE, (LPARAM)(LPCTSTR)msg);
}
SendMessage(s_debugLog, EM_SCROLLCARET, 0, 0);
}
void CMSWindowsPrimaryScreen::run()
{
CLog::setOutputter(&debugOutput);
doRun();
CLog::setOutputter(NULL);
}
void CMSWindowsPrimaryScreen::stop()
{
doStop();
}
void CMSWindowsPrimaryScreen::open(CServer* server)
{
assert(m_server == NULL);
assert(server != NULL);
// set the server
m_server = server;
// open the display
openDisplay();
// enter the screen
doEnter();
}
void CMSWindowsPrimaryScreen::close()
{
assert(m_server != NULL);
// close the display
closeDisplay();
// done with server
m_server = NULL;
}
void CMSWindowsPrimaryScreen::enter(SInt32 x, SInt32 y)
{
log((CLOG_INFO "entering primary at %d,%d", x, y));
assert(m_active == true);
// do non-warp enter stuff
doEnter();
// warp to requested location
warpCursor(x, y);
}
void CMSWindowsPrimaryScreen::doEnter()
{
// set the zones that should cause a jump
SInt32 w, h;
getScreenSize(&w, &h);
SetZoneFunc setZone = (SetZoneFunc)GetProcAddress(
m_hookLibrary, "setZone");
setZone(m_server->getActivePrimarySides(), w, h, getJumpZoneSize());
// all messages prior to now are invalid
nextMark();
// not active anymore
m_active = false;
}
void CMSWindowsPrimaryScreen::leave()
{
log((CLOG_INFO "leaving primary"));
assert(m_active == false);
// all messages prior to now are invalid
nextMark();
// relay all mouse and keyboard events
SetRelayFunc setRelay = (SetRelayFunc)GetProcAddress(
m_hookLibrary, "setRelay");
setRelay();
// warp the mouse to the center of the screen
SInt32 w, h;
getScreenSize(&w, &h);
warpCursor(w >> 1, h >> 1);
// warp is also invalid
nextMark();
// local client now active
m_active = true;
}
void CMSWindowsPrimaryScreen::warpCursor(SInt32 x, SInt32 y)
{
SInt32 w, h;
getScreenSize(&w, &h);
mouse_event(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE,
(DWORD)((65535.99 * x) / (w - 1)),
(DWORD)((65535.99 * y) / (h - 1)),
0, 0);
}
void CMSWindowsPrimaryScreen::setClipboard(
const IClipboard* /*clipboard*/)
{
assert(m_window != NULL);
// FIXME -- should we retry until we get it?
if (!OpenClipboard(m_window))
return;
if (EmptyClipboard()) {
log((CLOG_DEBUG "grabbed clipboard"));
// FIXME -- set the clipboard data
}
CloseClipboard();
}
void CMSWindowsPrimaryScreen::getSize(
SInt32* width, SInt32* height) const
{
getScreenSize(width, height);
}
SInt32 CMSWindowsPrimaryScreen::getJumpZoneSize() const
{
return 1;
}
void CMSWindowsPrimaryScreen::getClipboard(
IClipboard* clipboard) const
{
// FIXME -- put this in superclass?
// FIXME -- don't use CurrentTime
// getDisplayClipboard(clipboard, m_window, CurrentTime);
}
#include "resource.h" // FIXME
void CMSWindowsPrimaryScreen::onOpenDisplay()
{
assert(m_window == NULL);
assert(m_server != NULL);
// create debug dialog
s_thread = GetCurrentThreadId();;
s_debug = CreateDialog(getInstance(), MAKEINTRESOURCE(IDD_SYNERGY), NULL, &debugProc);
s_debugLog = ::GetDlgItem(s_debug, IDC_LOG);
CLog::setOutputter(&debugOutput);
ShowWindow(s_debug, SW_SHOWNORMAL);
// create the window
m_window = CreateWindowEx(WS_EX_TOPMOST |
WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW,
(LPCTSTR)getClass(), "Synergy",
WS_POPUP,
0, 0, 1, 1, NULL, NULL,
getInstance(),
NULL);
// load the hook library
bool hooked = false;
m_hookLibrary = LoadLibrary("synrgyhk");
if (m_hookLibrary != NULL) {
// install input hooks
InstallFunc install = (InstallFunc)GetProcAddress(
m_hookLibrary, "install");
if (install != NULL) {
hooked = (install(m_window) != 0);
}
}
if (!hooked) {
DestroyWindow(m_window);
m_window = NULL;
// FIXME -- throw
}
// initialize marks
m_mark = 0;
m_markReceived = 0;
nextMark();
}
void CMSWindowsPrimaryScreen::onCloseDisplay()
{
assert(m_window != NULL);
// uninstall input hooks
UninstallFunc uninstall = (UninstallFunc)GetProcAddress(
m_hookLibrary, "uninstall");
if (uninstall != NULL) {
uninstall();
}
// done with hook library
FreeLibrary(m_hookLibrary);
m_hookLibrary = NULL;
// destroy window
DestroyWindow(m_window);
m_window = NULL;
CLog::setOutputter(NULL);
DestroyWindow(s_debug);
s_debug = NULL;
s_thread = 0;
}
bool CMSWindowsPrimaryScreen::onEvent(MSG* msg)
{
if (IsDialogMessage(s_debug, msg)) {
return true;
}
// handle event
switch (msg->message) {
// FIXME -- handle display changes
case WM_PAINT:
ValidateRect(m_window, NULL);
return true;
case SYNERGY_MSG_MARK:
m_markReceived = msg->wParam;
return true;
case SYNERGY_MSG_KEY:
// ignore if not at current mark
if (m_mark == m_markReceived) {
// FIXME -- vk code; key data
}
return true;
case SYNERGY_MSG_MOUSE_BUTTON:
// ignore if not at current mark
if (m_mark == m_markReceived) {
const ButtonID button = mapButton(msg->wParam);
switch (msg->wParam) {
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
log((CLOG_DEBUG "event: button press button=%d", button));
if (button != kButtonNone) {
m_server->onMouseDown(button);
}
break;
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_RBUTTONUP:
log((CLOG_DEBUG "event: button release button=%d", button));
if (button != kButtonNone) {
m_server->onMouseUp(button);
}
break;
}
}
return true;
case SYNERGY_MSG_MOUSE_MOVE:
// ignore if not at current mark
if (m_mark == m_markReceived) {
SInt32 x = (SInt32)msg->wParam;
SInt32 y = (SInt32)msg->lParam;
if (!m_active) {
log((CLOG_DEBUG "event: inactive move %d,%d", x, y));
m_server->onMouseMovePrimary(x, y);
}
else {
log((CLOG_DEBUG "event: active move %d,%d", x, y));
// get screen size
SInt32 w, h;
getScreenSize(&w, &h);
// get center pixel
w >>= 1;
h >>= 1;
// ignore and discard message if motion is to center of
// screen. those are caused by us warping the mouse.
if (x != w || y != h) {
// get mouse deltas
x -= w;
y -= h;
// warp mouse back to center
warpCursor(w, h);
// send motion
m_server->onMouseMoveSecondary(x, y);
}
}
}
return true;
}
return false;
/*
case WM_MOUSEMOVE: {
if (!m_active) {
// mouse entered a jump zone window
POINT p;
p.x = (short)LOWORD(msg.lParam);
p.y = (short)HIWORD(msg.lParam);
ClientToScreen(msg.hwnd, &p);
log((CLOG_DEBUG "event: WM_MOUSEMOVE %d,%d", p.x, p.y));
m_server->onMouseMovePrimary((SInt32)p.x, (SInt32)p.y);
}
break;
}
case KeyPress: {
log((CLOG_DEBUG "event: KeyPress code=%d, state=0x%04x", xevent.xkey.keycode, xevent.xkey.state));
const KeyModifierMask mask = mapModifier(xevent.xkey.state);
const KeyID key = mapKey(xevent.xkey.keycode, mask);
if (key != kKeyNULL) {
m_server->onKeyDown(key, mask);
}
break;
}
// FIXME -- simulate key repeat. X sends press/release for
// repeat. must detect auto repeat and use kKeyRepeat.
case KeyRelease: {
log((CLOG_DEBUG "event: KeyRelease code=%d, state=0x%04x", xevent.xkey.keycode, xevent.xkey.state));
const KeyModifierMask mask = mapModifier(xevent.xkey.state);
const KeyID key = mapKey(xevent.xkey.keycode, mask);
if (key != kKeyNULL) {
m_server->onKeyUp(key, mask);
}
break;
}
case ButtonPress: {
log((CLOG_DEBUG "event: ButtonPress button=%d", xevent.xbutton.button));
const ButtonID button = mapButton(xevent.xbutton.button);
if (button != kButtonNULL) {
m_server->onMouseDown(button);
}
break;
}
case ButtonRelease: {
log((CLOG_DEBUG "event: ButtonRelease button=%d", xevent.xbutton.button));
const ButtonID button = mapButton(xevent.xbutton.button);
if (button != kButtonNULL) {
m_server->onMouseUp(button);
}
break;
}
case SelectionClear:
target->XXX(xevent.xselectionclear.);
break;
case SelectionNotify:
target->XXX(xevent.xselection.);
break;
case SelectionRequest:
target->XXX(xevent.xselectionrequest.);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
*/
}
void CMSWindowsPrimaryScreen::nextMark()
{
assert(m_window != NULL);
PostMessage(m_window, SYNERGY_MSG_MARK, ++m_mark, 0);
}
#if 0
bool CMSWindowsPrimaryScreen::keyboardHook(
int /*code*/, WPARAM wParam, LPARAM lParam)
{
if (m_active) {
// handle keyboard events
const KeyID key = mapKey(wParam, lParam);
if (key != kKeyNone) {
const KeyModifierMask modifiers = mapModifier(wParam, lParam);
if ((lParam & KF_UP) == 0) {
log((CLOG_DEBUG "event: key press key=%d", key));
m_server->onKeyDown(key, modifiers);
}
else {
log((CLOG_DEBUG "event: key release key=%d", key));
m_server->onKeyUp(key, modifiers);
}
return true;
}
}
return false;
}
#endif
KeyModifierMask CMSWindowsPrimaryScreen::mapModifier(
WPARAM keycode, LPARAM info) const
{
// FIXME -- should be configurable
KeyModifierMask mask = 0;
if (GetKeyState(VK_SHIFT) < 0)
mask |= KeyModifierShift;
if ((GetKeyState(VK_CAPITAL) & 1) != 0)
mask |= KeyModifierCapsLock;
if (GetKeyState(VK_CONTROL) < 0)
mask |= KeyModifierControl;
if (GetKeyState(VK_MENU) < 0)
mask |= KeyModifierAlt;
if ((GetKeyState(VK_NUMLOCK) & 1) != 0)
mask |= KeyModifierNumLock;
if (GetKeyState(VK_LWIN) < 0 || GetKeyState(VK_RWIN) < 0)
mask |= KeyModifierMeta;
if ((GetKeyState(VK_SCROLL) & 1) != 0)
mask |= KeyModifierScrollLock;
return mask;
}
KeyID CMSWindowsPrimaryScreen::mapKey(
WPARAM keycode, LPARAM info) const
{
// FIXME -- must convert to X keysyms
return keycode;
}
ButtonID CMSWindowsPrimaryScreen::mapButton(
WPARAM button) const
{
switch (button) {
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
return kButtonLeft;
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
return kButtonMiddle;
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
return kButtonRight;
default:
return kButtonNone;
}
}

View File

@ -0,0 +1,56 @@
#ifndef CMSWINDOWSPRIMARYSCREEN_H
#define CMSWINDOWSPRIMARYSCREEN_H
#include "KeyTypes.h"
#include "MouseTypes.h"
#include "CMSWindowsScreen.h"
#include "IPrimaryScreen.h"
class CMSWindowsPrimaryScreen : public CMSWindowsScreen, public IPrimaryScreen {
public:
typedef bool (CMSWindowsPrimaryScreen::*HookMethod)(int, WPARAM, LPARAM);
CMSWindowsPrimaryScreen();
virtual ~CMSWindowsPrimaryScreen();
// IPrimaryScreen overrides
virtual void run();
virtual void stop();
virtual void open(CServer*);
virtual void close();
virtual void enter(SInt32 xAbsolute, SInt32 yAbsolute);
virtual void leave();
virtual void warpCursor(SInt32 xAbsolute, SInt32 yAbsolute);
virtual void setClipboard(const IClipboard*);
virtual void getSize(SInt32* width, SInt32* height) const;
virtual SInt32 getJumpZoneSize() const;
virtual void getClipboard(IClipboard*) const;
protected:
// CMSWindowsScreen overrides
virtual bool onEvent(MSG*);
virtual void onOpenDisplay();
virtual void onCloseDisplay();
private:
void doEnter();
void nextMark();
// bool keyboardHook(int, WPARAM, LPARAM);
// bool mouseHook(int, WPARAM, LPARAM);
KeyModifierMask mapModifier(WPARAM keycode, LPARAM info) const;
KeyID mapKey(WPARAM keycode, LPARAM info) const;
ButtonID mapButton(WPARAM button) const;
private:
CServer* m_server;
bool m_active;
HWND m_window;
HINSTANCE m_hookLibrary;
UInt32 m_mark;
UInt32 m_markReceived;
};
#endif

View File

@ -9,6 +9,8 @@ class CScreenMap {
public: public:
enum EDirection { kLeft, kRight, kTop, kBottom, enum EDirection { kLeft, kRight, kTop, kBottom,
kFirstDirection = kLeft, kLastDirection = kBottom }; kFirstDirection = kLeft, kLastDirection = kBottom };
enum EDirectionMask { kLeftMask = 1, kRightMask = 2,
kTopMask = 4, kBottomMask = 8 };
CScreenMap(); CScreenMap();
virtual ~CScreenMap(); virtual ~CScreenMap();

View File

@ -20,6 +20,14 @@
#include <assert.h> #include <assert.h>
#include <memory> #include <memory>
// hack to work around operator=() bug in STL in g++ prior to v3
#if defined(__GNUC__) && (__GNUC__ < 3)
#define assign(_dst, _src, _type) _dst.reset(_src)
#else
#define assign(_dst, _src, _type) _dst = std::auto_ptr<_type >(_src)
#endif
/* XXX /* XXX
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
@ -33,8 +41,7 @@ else { wait(0); exit(1); }
// CServer // CServer
// //
CServer::CServer() : m_done(&m_mutex, false), CServer::CServer() : m_primary(NULL),
m_primary(NULL),
m_active(NULL), m_active(NULL),
m_primaryInfo(NULL) m_primaryInfo(NULL)
{ {
@ -61,31 +68,28 @@ void CServer::run()
// start listening for configuration connections // start listening for configuration connections
// FIXME // FIXME
// wait until done // handle events
log((CLOG_DEBUG "waiting for quit")); log((CLOG_DEBUG "starting event handling"));
CLock lock(&m_mutex); m_primary->run();
while (m_done == false) {
m_done.wait();
}
// clean up // clean up
log((CLOG_DEBUG "stopping server")); log((CLOG_DEBUG "stopping server"));
closePrimaryScreen();
cleanupThreads(); cleanupThreads();
closePrimaryScreen();
} }
catch (XBase& e) { catch (XBase& e) {
log((CLOG_ERR "server error: %s\n", e.what())); log((CLOG_ERR "server error: %s\n", e.what()));
// clean up // clean up
closePrimaryScreen();
cleanupThreads(); cleanupThreads();
closePrimaryScreen();
} }
catch (...) { catch (...) {
log((CLOG_DEBUG "server shutdown")); log((CLOG_DEBUG "unknown server error"));
// clean up // clean up
closePrimaryScreen();
cleanupThreads(); cleanupThreads();
closePrimaryScreen();
throw; throw;
} }
} }
@ -107,6 +111,21 @@ void CServer::getScreenMap(CScreenMap* screenMap) const
*screenMap = m_screenMap; *screenMap = m_screenMap;
} }
UInt32 CServer::getActivePrimarySides() const
{
UInt32 sides = 0;
CLock lock(&m_mutex);
if (!m_screenMap.getNeighbor("primary", CScreenMap::kLeft).empty())
sides |= CScreenMap::kLeftMask;
if (!m_screenMap.getNeighbor("primary", CScreenMap::kRight).empty())
sides |= CScreenMap::kRightMask;
if (!m_screenMap.getNeighbor("primary", CScreenMap::kTop).empty())
sides |= CScreenMap::kTopMask;
if (!m_screenMap.getNeighbor("primary", CScreenMap::kBottom).empty())
sides |= CScreenMap::kBottomMask;
return sides;
}
void CServer::setInfo(const CString& client, void CServer::setInfo(const CString& client,
SInt32 w, SInt32 h, SInt32 zoneSize) SInt32 w, SInt32 h, SInt32 zoneSize)
{ {
@ -206,7 +225,7 @@ void CServer::onMouseUp(ButtonID id)
} }
} }
void CServer::onMouseMovePrimary(SInt32 x, SInt32 y) bool CServer::onMouseMovePrimary(SInt32 x, SInt32 y)
{ {
log((CLOG_DEBUG "onMouseMovePrimary %d,%d", x, y)); log((CLOG_DEBUG "onMouseMovePrimary %d,%d", x, y));
@ -216,7 +235,7 @@ void CServer::onMouseMovePrimary(SInt32 x, SInt32 y)
// ignore if mouse is locked to screen // ignore if mouse is locked to screen
if (isLockedToScreen()) { if (isLockedToScreen()) {
return; return false;
} }
// see if we should change screens // see if we should change screens
@ -243,7 +262,7 @@ void CServer::onMouseMovePrimary(SInt32 x, SInt32 y)
} }
else { else {
// still on local screen // still on local screen
return; return false;
} }
// get jump destination // get jump destination
@ -251,7 +270,7 @@ void CServer::onMouseMovePrimary(SInt32 x, SInt32 y)
// if no screen in jump direction then ignore the move // if no screen in jump direction then ignore the move
if (newScreen == NULL) { if (newScreen == NULL) {
return; return false;
} }
// remap position to account for resolution differences // remap position to account for resolution differences
@ -259,6 +278,7 @@ void CServer::onMouseMovePrimary(SInt32 x, SInt32 y)
// switch screen // switch screen
switchScreen(newScreen, x, y); switchScreen(newScreen, x, y);
return true;
} }
void CServer::onMouseMoveSecondary(SInt32 dx, SInt32 dy) void CServer::onMouseMoveSecondary(SInt32 dx, SInt32 dy)
@ -365,7 +385,11 @@ bool CServer::isLockedToScreen() const
return false; return false;
} }
#if defined(CONFIG_PLATFORM_WIN32)
#include "CMSWindowsClipboard.h" // FIXME
#elif defined(CONFIG_PLATFORM_UNIX)
#include "CXWindowsClipboard.h" // FIXME #include "CXWindowsClipboard.h" // FIXME
#endif
void CServer::switchScreen(CScreenInfo* dst, void CServer::switchScreen(CScreenInfo* dst,
SInt32 x, SInt32 y) SInt32 x, SInt32 y)
{ {
@ -384,7 +408,11 @@ void CServer::switchScreen(CScreenInfo* dst,
m_primary->leave(); m_primary->leave();
// FIXME -- testing // FIXME -- testing
#if defined(CONFIG_PLATFORM_WIN32)
CMSWindowsClipboard clipboard;
#elif defined(CONFIG_PLATFORM_UNIX)
CXWindowsClipboard clipboard; CXWindowsClipboard clipboard;
#endif
m_primary->getClipboard(&clipboard); m_primary->getClipboard(&clipboard);
} }
else { else {
@ -610,8 +638,8 @@ void CServer::acceptClients(void*)
std::auto_ptr<IListenSocket> listen; std::auto_ptr<IListenSocket> listen;
try { try {
// create socket listener // create socket listener
// listen.reset(m_socketFactory->createListen()); // listen = std::auto_ptr<IListenSocket>(m_socketFactory->createListen());
listen.reset(new CTCPListenSocket); // FIXME assign(listen, new CTCPListenSocket, IListenSocket); // FIXME
// bind to the desired port. keep retrying if we can't bind // bind to the desired port. keep retrying if we can't bind
// the address immediately. // the address immediately.
@ -689,8 +717,8 @@ void CServer::handshakeClient(void* vsocket)
} }
// attach the packetizing filters // attach the packetizing filters
input.reset(new CInputPacketStream(srcInput, own)); assign(input, new CInputPacketStream(srcInput, own), IInputStream);
output.reset(new COutputPacketStream(srcOutput, own)); assign(output, new COutputPacketStream(srcOutput, own), IOutputStream);
std::auto_ptr<IServerProtocol> protocol; std::auto_ptr<IServerProtocol> protocol;
std::auto_ptr<CConnectionNote> connectedNote; std::auto_ptr<CConnectionNote> connectedNote;
@ -730,12 +758,13 @@ void CServer::handshakeClient(void* vsocket)
// create a protocol interpreter for the version // create a protocol interpreter for the version
log((CLOG_DEBUG "creating interpreter for client %s version %d.%d", name.c_str(), major, minor)); log((CLOG_DEBUG "creating interpreter for client %s version %d.%d", name.c_str(), major, minor));
protocol.reset(CServerProtocol::create(major, minor, assign(protocol, CServerProtocol::create(major, minor,
this, name, input.get(), output.get())); this, name, input.get(), output.get()),
IServerProtocol);
// client is now pending // client is now pending
connectedNote.reset(new CConnectionNote(this, assign(connectedNote, new CConnectionNote(this,
name, protocol.get())); name, protocol.get()), CConnectionNote);
// ask and wait for the client's info // ask and wait for the client's info
log((CLOG_DEBUG "waiting for info for client %s", name.c_str())); log((CLOG_DEBUG "waiting for info for client %s", name.c_str()));
@ -766,20 +795,26 @@ void CServer::handshakeClient(void* vsocket)
void CServer::quit() void CServer::quit()
{ {
CLock lock(&m_mutex); m_primary->stop();
m_done = true;
m_done.broadcast();
} }
// FIXME -- use factory to create screen // FIXME -- use factory to create screen
#if defined(CONFIG_PLATFORM_WIN32)
#include "CMSWindowsPrimaryScreen.h"
#elif defined(CONFIG_PLATFORM_UNIX)
#include "CXWindowsPrimaryScreen.h" #include "CXWindowsPrimaryScreen.h"
#endif
void CServer::openPrimaryScreen() void CServer::openPrimaryScreen()
{ {
assert(m_primary == NULL); assert(m_primary == NULL);
// open screen // open screen
log((CLOG_DEBUG "creating primary screen")); log((CLOG_DEBUG "creating primary screen"));
#if defined(CONFIG_PLATFORM_WIN32)
m_primary = new CMSWindowsPrimaryScreen;
#elif defined(CONFIG_PLATFORM_UNIX)
m_primary = new CXWindowsPrimaryScreen; m_primary = new CXWindowsPrimaryScreen;
#endif
log((CLOG_DEBUG "opening primary screen")); log((CLOG_DEBUG "opening primary screen"));
m_primary->open(this); m_primary->open(this);
@ -828,8 +863,9 @@ void CServer::removeCleanupThread(const CThread& thread)
for (CThreadList::iterator index = m_cleanupList.begin(); for (CThreadList::iterator index = m_cleanupList.begin();
index != m_cleanupList.end(); ++index) { index != m_cleanupList.end(); ++index) {
if (**index == thread) { if (**index == thread) {
CThread* thread = *index;
m_cleanupList.erase(index); m_cleanupList.erase(index);
delete *index; delete thread;
return; return;
} }
} }
@ -877,7 +913,7 @@ void CServer::removeConnection(const CString& name)
assert(index != m_screens.end()); assert(index != m_screens.end());
// if this is active screen then we have to jump off of it // if this is active screen then we have to jump off of it
if (m_active == index->second) { if (m_active == index->second && m_active != m_primaryInfo) {
// record new position (center of primary screen) // record new position (center of primary screen)
m_x = m_primaryInfo->m_width >> 1; m_x = m_primaryInfo->m_width >> 1;
m_y = m_primaryInfo->m_height >> 1; m_y = m_primaryInfo->m_height >> 1;

View File

@ -4,7 +4,6 @@
#include "KeyTypes.h" #include "KeyTypes.h"
#include "MouseTypes.h" #include "MouseTypes.h"
#include "CScreenMap.h" #include "CScreenMap.h"
#include "CCondVar.h"
#include "CMutex.h" #include "CMutex.h"
#include "CString.h" #include "CString.h"
#include "XBase.h" #include "XBase.h"
@ -24,18 +23,23 @@ class CServer {
// manipulators // manipulators
// start the server. does not return until quit() is called.
void run(); void run();
// tell server to exit gracefully
void quit();
// update screen map // update screen map
void setScreenMap(const CScreenMap&); void setScreenMap(const CScreenMap&);
// handle events on server's screen // handle events on server's screen. onMouseMovePrimary() returns
// true iff the mouse enters a jump zone and jumps.
void onKeyDown(KeyID, KeyModifierMask); void onKeyDown(KeyID, KeyModifierMask);
void onKeyUp(KeyID, KeyModifierMask); void onKeyUp(KeyID, KeyModifierMask);
void onKeyRepeat(KeyID, KeyModifierMask); void onKeyRepeat(KeyID, KeyModifierMask);
void onMouseDown(ButtonID); void onMouseDown(ButtonID);
void onMouseUp(ButtonID); void onMouseUp(ButtonID);
void onMouseMovePrimary(SInt32 x, SInt32 y); bool onMouseMovePrimary(SInt32 x, SInt32 y);
void onMouseMoveSecondary(SInt32 dx, SInt32 dy); void onMouseMoveSecondary(SInt32 dx, SInt32 dy);
void onMouseWheel(SInt32 delta); void onMouseWheel(SInt32 delta);
@ -50,9 +54,11 @@ class CServer {
// get the current screen map // get the current screen map
void getScreenMap(CScreenMap*) const; void getScreenMap(CScreenMap*) const;
// get the sides of the primary screen that have neighbors
UInt32 getActivePrimarySides() const;
protected: protected:
bool onCommandKey(KeyID, KeyModifierMask, bool down); bool onCommandKey(KeyID, KeyModifierMask, bool down);
void quit();
private: private:
class CCleanupNote { class CCleanupNote {
@ -137,7 +143,6 @@ class CServer {
typedef std::map<CString, CScreenInfo*> CScreenList; typedef std::map<CString, CScreenInfo*> CScreenList;
CMutex m_mutex; CMutex m_mutex;
CCondVar<bool> m_done;
double m_bindTimeout; double m_bindTimeout;

242
server/CSynergyHook.cpp Normal file
View File

@ -0,0 +1,242 @@
#include "CSynergyHook.h"
#include "CScreenMap.h"
#include <assert.h>
//
// globals
//
#pragma comment(linker, "-section:shared,rws")
#pragma data_seg("shared")
// all data in this shared section *must* be initialized
static HINSTANCE g_hinstance = NULL;
static DWORD g_process = NULL;
static HWND g_hwnd = NULL;
static HHOOK g_keyboard = NULL;
static HHOOK g_mouse = NULL;
static bool g_relay = false;
static SInt32 g_zoneSize = 0;
static UInt32 g_zoneSides = 0;
static SInt32 g_wScreen = 0;
static SInt32 g_hScreen = 0;
static HCURSOR g_cursor = NULL;
static DWORD g_cursorThread = 0;
#pragma data_seg()
//
// internal functions
//
static void hideCursor(DWORD thread)
{
// we should be running the context of the window who's cursor
// we want to hide so we shouldn't have to attach thread input.
g_cursor = GetCursor();
g_cursorThread = thread;
SetCursor(NULL);
}
static void restoreCursor()
{
// restore the show cursor in the window we hid it last
if (g_cursor != NULL && g_cursorThread != 0) {
DWORD myThread = GetCurrentThreadId();
if (myThread != g_cursorThread)
AttachThreadInput(myThread, g_cursorThread, TRUE);
SetCursor(g_cursor);
if (myThread != g_cursorThread)
AttachThreadInput(myThread, g_cursorThread, FALSE);
}
g_cursor = NULL;
g_cursorThread = 0;
}
static LRESULT CALLBACK keyboardHook(int code, WPARAM wParam, LPARAM lParam)
{
if (code >= 0) {
// FIXME
}
return CallNextHookEx(g_keyboard, code, wParam, lParam);
}
static LRESULT CALLBACK mouseHook(int code, WPARAM wParam, LPARAM lParam)
{
if (code >= 0) {
if (g_relay) {
switch (wParam) {
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_RBUTTONUP:
PostMessage(g_hwnd, SYNERGY_MSG_MOUSE_BUTTON, wParam, 0);
return 1;
case WM_MOUSEMOVE: {
const MOUSEHOOKSTRUCT* info = (const MOUSEHOOKSTRUCT*)lParam;
SInt32 x = (SInt32)info->pt.x;
SInt32 y = (SInt32)info->pt.y;
// 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
// window (or at some later time before we stop relaying).
// so check the window with the cursor. if it's not the
// same window that had it before then show the cursor
// in the last window and hide it in this window.
DWORD thread = GetWindowThreadProcessId(info->hwnd, NULL);
if (thread != g_cursorThread) {
restoreCursor();
hideCursor(thread);
}
// relay the motion
PostMessage(g_hwnd, SYNERGY_MSG_MOUSE_MOVE, x, y);
return 1;
}
}
}
else {
// check for mouse inside jump zone
bool inside = false;
const MOUSEHOOKSTRUCT* info = (const MOUSEHOOKSTRUCT*)lParam;
SInt32 x = (SInt32)info->pt.x;
SInt32 y = (SInt32)info->pt.y;
if (!inside && (g_zoneSides & CScreenMap::kLeftMask) != 0) {
inside = (x < g_zoneSize);
}
if (!inside && (g_zoneSides & CScreenMap::kRightMask) != 0) {
inside = (x >= g_wScreen - g_zoneSize);
}
if (!inside && (g_zoneSides & CScreenMap::kTopMask) != 0) {
inside = (y < g_zoneSize);
}
if (!inside && (g_zoneSides & CScreenMap::kBottomMask) != 0) {
inside = (y >= g_hScreen - g_zoneSize);
}
// if inside then eat event and notify our window
if (inside) {
restoreCursor();
PostMessage(g_hwnd, SYNERGY_MSG_MOUSE_MOVE, x, y);
return 1;
}
}
}
return CallNextHookEx(g_mouse, code, wParam, lParam);
}
//
// external functions
//
BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID)
{
if (reason == DLL_PROCESS_ATTACH) {
if (g_hinstance == NULL) {
g_hinstance = instance;
g_process = GetCurrentProcessId();
}
}
else if (reason == DLL_PROCESS_DETACH) {
if (g_process == GetCurrentProcessId()) {
if (g_keyboard != NULL || g_mouse != NULL) {
uninstall();
}
g_process = NULL;
}
}
return TRUE;
}
extern "C" {
int install(HWND hwnd)
{
assert(g_hinstance != NULL);
assert(g_keyboard == NULL);
assert(g_mouse == NULL);
// save window
g_hwnd = hwnd;
// set defaults
g_relay = false;
g_zoneSize = 0;
g_zoneSides = 0;
g_wScreen = 0;
g_hScreen = 0;
g_cursor = NULL;
g_cursorThread = 0;
// install keyboard hook
g_keyboard = SetWindowsHookEx(WH_KEYBOARD,
&keyboardHook,
g_hinstance,
0);
if (g_keyboard == NULL) {
g_hwnd = NULL;
return 0;
}
// install mouse hook
g_mouse = SetWindowsHookEx(WH_MOUSE,
&mouseHook,
g_hinstance,
0);
if (g_mouse == NULL) {
// uninstall keyboard hook before failing
UnhookWindowsHookEx(g_keyboard);
g_keyboard = NULL;
g_hwnd = NULL;
return 0;
}
return 1;
}
int uninstall(void)
{
assert(g_keyboard != NULL);
assert(g_mouse != NULL);
// uninstall hooks
UnhookWindowsHookEx(g_keyboard);
UnhookWindowsHookEx(g_mouse);
g_keyboard = NULL;
g_mouse = NULL;
g_hwnd = NULL;
// show the cursor
restoreCursor();
return 1;
}
void setZone(UInt32 sides,
SInt32 w, SInt32 h, SInt32 jumpZoneSize)
{
g_zoneSize = jumpZoneSize;
g_zoneSides = sides;
g_wScreen = w;
g_hScreen = h;
g_relay = false;
restoreCursor();
}
void setRelay(void)
{
g_relay = true;
g_zoneSize = 0;
g_zoneSides = 0;
g_wScreen = 0;
g_hScreen = 0;
}
}

37
server/CSynergyHook.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef CSYNERGYHOOK_H
#define CSYNERGYHOOK_H
#include "BasicTypes.h"
#include <windows.h>
#if defined(CONFIG_PLATFORM_WIN32)
#if defined(SYNRGYHK_EXPORTS)
#define CSYNERGYHOOK_API __declspec(dllexport)
#else
#define CSYNERGYHOOK_API __declspec(dllimport)
#endif
#else
#define CSYNERGYHOOK_API
#endif
#define SYNERGY_MSG_MARK WM_APP + 0x0001 // mark id; <unused>
#define SYNERGY_MSG_KEY WM_APP + 0x0002 // vk code; key data
#define SYNERGY_MSG_MOUSE_BUTTON WM_APP + 0x0003 // button msg; <unused>
#define SYNERGY_MSG_MOUSE_MOVE WM_APP + 0x0004 // x; y
typedef int (*InstallFunc)(HWND);
typedef int (*UninstallFunc)(void);
typedef void (*SetZoneFunc)(UInt32, SInt32, SInt32, SInt32);
typedef void (*SetRelayFunc)(void);
extern "C" {
CSYNERGYHOOK_API int install(HWND);
CSYNERGYHOOK_API int uninstall(void);
CSYNERGYHOOK_API void setZone(UInt32 sides,
SInt32 w, SInt32 h, SInt32 jumpZoneSize);
CSYNERGYHOOK_API void setRelay(void);
}
#endif

View File

@ -22,6 +22,123 @@ CXWindowsPrimaryScreen::~CXWindowsPrimaryScreen()
assert(m_window == None); assert(m_window == None);
} }
void CXWindowsPrimaryScreen::run()
{
for (;;) {
// wait for and get the next event
XEvent xevent;
if (!getEvent(&xevent)) {
break;
}
// handle event
switch (xevent.type) {
case CreateNotify: {
// select events on new window
CDisplayLock display(this);
selectEvents(display, xevent.xcreatewindow.window);
break;
}
case KeyPress: {
log((CLOG_DEBUG "event: KeyPress code=%d, state=0x%04x", xevent.xkey.keycode, xevent.xkey.state));
const KeyModifierMask mask = mapModifier(xevent.xkey.state);
const KeyID key = mapKey(xevent.xkey.keycode, mask);
if (key != kKeyNone) {
m_server->onKeyDown(key, mask);
}
break;
}
// FIXME -- simulate key repeat. X sends press/release for
// repeat. must detect auto repeat and use kKeyRepeat.
case KeyRelease: {
log((CLOG_DEBUG "event: KeyRelease code=%d, state=0x%04x", xevent.xkey.keycode, xevent.xkey.state));
const KeyModifierMask mask = mapModifier(xevent.xkey.state);
const KeyID key = mapKey(xevent.xkey.keycode, mask);
if (key != kKeyNone) {
m_server->onKeyUp(key, mask);
}
break;
}
case ButtonPress: {
log((CLOG_DEBUG "event: ButtonPress button=%d", xevent.xbutton.button));
const ButtonID button = mapButton(xevent.xbutton.button);
if (button != kButtonNone) {
m_server->onMouseDown(button);
}
break;
}
case ButtonRelease: {
log((CLOG_DEBUG "event: ButtonRelease button=%d", xevent.xbutton.button));
const ButtonID button = mapButton(xevent.xbutton.button);
if (button != kButtonNone) {
m_server->onMouseUp(button);
}
break;
}
case MotionNotify: {
log((CLOG_DEBUG "event: MotionNotify %d,%d", xevent.xmotion.x_root, xevent.xmotion.y_root));
SInt32 x, y;
if (!m_active) {
x = xevent.xmotion.x_root;
y = xevent.xmotion.y_root;
m_server->onMouseMovePrimary(x, y);
}
else {
// FIXME -- slurp up all remaining motion events?
// probably not since key strokes may go to wrong place.
// get mouse deltas
{
CDisplayLock display(this);
Window root, window;
int xRoot, yRoot, xWindow, yWindow;
unsigned int mask;
if (!XQueryPointer(display, m_window, &root, &window,
&xRoot, &yRoot, &xWindow, &yWindow, &mask))
break;
// compute position of center of window
SInt32 w, h;
getScreenSize(&w, &h);
x = xRoot - (w >> 1);
y = yRoot - (h >> 1);
// warp mouse back to center
warpCursorNoLock(display, w >> 1, h >> 1);
}
m_server->onMouseMoveSecondary(x, y);
}
break;
}
/*
case SelectionClear:
target->XXX(xevent.xselectionclear.);
break;
case SelectionNotify:
target->XXX(xevent.xselection.);
break;
case SelectionRequest:
target->XXX(xevent.xselectionrequest.);
break;
*/
}
}
}
void CXWindowsPrimaryScreen::stop()
{
doStop();
}
void CXWindowsPrimaryScreen::open(CServer* server) void CXWindowsPrimaryScreen::open(CServer* server)
{ {
assert(m_server == NULL); assert(m_server == NULL);
@ -251,116 +368,6 @@ void CXWindowsPrimaryScreen::selectEvents(
} }
} }
void CXWindowsPrimaryScreen::eventThread(void*)
{
for (;;) {
// wait for and get the next event
XEvent xevent;
getEvent(&xevent);
// handle event
switch (xevent.type) {
case CreateNotify: {
// select events on new window
CDisplayLock display(this);
selectEvents(display, xevent.xcreatewindow.window);
break;
}
case KeyPress: {
log((CLOG_DEBUG "event: KeyPress code=%d, state=0x%04x", xevent.xkey.keycode, xevent.xkey.state));
const KeyModifierMask mask = mapModifier(xevent.xkey.state);
const KeyID key = mapKey(xevent.xkey.keycode, mask);
if (key != kKeyNone) {
m_server->onKeyDown(key, mask);
}
break;
}
// FIXME -- simulate key repeat. X sends press/release for
// repeat. must detect auto repeat and use kKeyRepeat.
case KeyRelease: {
log((CLOG_DEBUG "event: KeyRelease code=%d, state=0x%04x", xevent.xkey.keycode, xevent.xkey.state));
const KeyModifierMask mask = mapModifier(xevent.xkey.state);
const KeyID key = mapKey(xevent.xkey.keycode, mask);
if (key != kKeyNone) {
m_server->onKeyUp(key, mask);
}
break;
}
case ButtonPress: {
log((CLOG_DEBUG "event: ButtonPress button=%d", xevent.xbutton.button));
const ButtonID button = mapButton(xevent.xbutton.button);
if (button != kButtonNone) {
m_server->onMouseDown(button);
}
break;
}
case ButtonRelease: {
log((CLOG_DEBUG "event: ButtonRelease button=%d", xevent.xbutton.button));
const ButtonID button = mapButton(xevent.xbutton.button);
if (button != kButtonNone) {
m_server->onMouseUp(button);
}
break;
}
case MotionNotify: {
log((CLOG_DEBUG "event: MotionNotify %d,%d", xevent.xmotion.x_root, xevent.xmotion.y_root));
SInt32 x, y;
if (!m_active) {
x = xevent.xmotion.x_root;
y = xevent.xmotion.y_root;
m_server->onMouseMovePrimary(x, y);
}
else {
// FIXME -- slurp up all remaining motion events?
// probably not since key strokes may go to wrong place.
// get mouse deltas
{
CDisplayLock display(this);
Window root, window;
int xRoot, yRoot, xWindow, yWindow;
unsigned int mask;
if (!XQueryPointer(display, m_window, &root, &window,
&xRoot, &yRoot, &xWindow, &yWindow, &mask))
break;
// compute position of center of window
SInt32 w, h;
getScreenSize(&w, &h);
x = xRoot - (w >> 1);
y = yRoot - (h >> 1);
// warp mouse back to center
warpCursorNoLock(display, w >> 1, h >> 1);
}
m_server->onMouseMoveSecondary(x, y);
}
break;
}
/*
case SelectionClear:
target->XXX(xevent.xselectionclear.);
break;
case SelectionNotify:
target->XXX(xevent.xselection.);
break;
case SelectionRequest:
target->XXX(xevent.xselectionrequest.);
break;
*/
}
}
}
KeyModifierMask CXWindowsPrimaryScreen::mapModifier( KeyModifierMask CXWindowsPrimaryScreen::mapModifier(
unsigned int state) const unsigned int state) const
{ {

View File

@ -12,6 +12,8 @@ class CXWindowsPrimaryScreen : public CXWindowsScreen, public IPrimaryScreen {
virtual ~CXWindowsPrimaryScreen(); virtual ~CXWindowsPrimaryScreen();
// IPrimaryScreen overrides // IPrimaryScreen overrides
virtual void run();
virtual void stop();
virtual void open(CServer*); virtual void open(CServer*);
virtual void close(); virtual void close();
virtual void enter(SInt32 xAbsolute, SInt32 yAbsolute); virtual void enter(SInt32 xAbsolute, SInt32 yAbsolute);
@ -26,7 +28,6 @@ class CXWindowsPrimaryScreen : public CXWindowsScreen, public IPrimaryScreen {
// CXWindowsScreen overrides // CXWindowsScreen overrides
virtual void onOpenDisplay(); virtual void onOpenDisplay();
virtual void onCloseDisplay(); virtual void onCloseDisplay();
virtual void eventThread(void*);
private: private:
void selectEvents(Display*, Window) const; void selectEvents(Display*, Window) const;

View File

@ -4,7 +4,7 @@ include $(DEPTH)/Makecommon
# #
# target file # target file
# #
TARGET = server TARGETS = server
# #
# source files # source files
@ -40,8 +40,8 @@ LLDLIBS = \
-lpthread \ -lpthread \
$(NULL) $(NULL)
targets: $(TARGET) targets: $(TARGETS)
$(TARGET): $(OBJECTS) $(DEPLIBS) $(TARGETS): $(OBJECTS) $(DEPLIBS)
$(CXX) $(CXXFLAGS) -o $@ $(OBJECTS) $(LDFLAGS) $(CXX) $(CXXFLAGS) -o $@ $(OBJECTS) $(LDFLAGS)

63
server/makehook.dsp Normal file
View File

@ -0,0 +1,63 @@
# Microsoft Developer Studio Project File - Name="makehook" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Generic Project" 0x010a
CFG=makehook - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "makehook.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "makehook.mak" CFG="makehook - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "makehook - Win32 Release" (based on "Win32 (x86) Generic Project")
!MESSAGE "makehook - Win32 Debug" (based on "Win32 (x86) Generic Project")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
MTL=midl.exe
!IF "$(CFG)" == "makehook - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "makehook___Win32_Release"
# PROP BASE Intermediate_Dir "makehook___Win32_Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
!ELSEIF "$(CFG)" == "makehook - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "makehook___Win32_Debug"
# PROP BASE Intermediate_Dir "makehook___Win32_Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
!ENDIF
# Begin Target
# Name "makehook - Win32 Release"
# Name "makehook - Win32 Debug"
# End Target
# End Project

17
server/resource.h Normal file
View File

@ -0,0 +1,17 @@
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by server.rc
//
#define IDD_SYNERGY 101
#define IDC_LOG 1000
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@ -1,16 +1,12 @@
#include "CServer.h" #include "CServer.h"
#include "CScreenMap.h" #include "CScreenMap.h"
#include "CThread.h" #include "CThread.h"
#include <stdio.h> #include "CNetwork.h"
int main(int argc, char** argv) void realMain()
{ {
CThread::init(); CThread::init();
CNetwork::init();
if (argc != 1) {
fprintf(stderr, "usage: %s\n", argv[0]);
return 1;
}
CScreenMap screenMap; CScreenMap screenMap;
screenMap.addScreen("primary"); screenMap.addScreen("primary");
@ -18,15 +14,66 @@ int main(int argc, char** argv)
screenMap.connect("primary", CScreenMap::kRight, "ingrid"); screenMap.connect("primary", CScreenMap::kRight, "ingrid");
screenMap.connect("ingrid", CScreenMap::kLeft, "primary"); screenMap.connect("ingrid", CScreenMap::kLeft, "primary");
CServer* server = NULL;
try { try {
CServer* server = new CServer(); server = new CServer();
server->setScreenMap(screenMap); server->setScreenMap(screenMap);
server->run(); server->run();
delete server;
CNetwork::cleanup();
}
catch (...) {
delete server;
CNetwork::cleanup();
throw;
}
}
#if defined(CONFIG_PLATFORM_WIN32)
#include "CMSWindowsScreen.h"
int WINAPI WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
{
CMSWindowsScreen::init(instance);
if (__argc != 1) {
CString msg = "no arguments allowed. exiting.";
MessageBox(NULL, msg.c_str(), "error", MB_OK | MB_ICONERROR);
return 1;
}
try {
realMain();
return 0;
}
catch (XBase& e) {
CString msg = "failed: ";
msg += e.what();
MessageBox(NULL, msg.c_str(), "error", MB_OK | MB_ICONERROR);
return 1;
}
}
#else
#include <stdio.h>
int main(int argc, char** argv)
{
if (argc != 1) {
fprintf(stderr, "usage: %s\n", argv[0]);
return 1;
}
try {
realMain();
return 0;
} }
catch (XBase& e) { catch (XBase& e) {
fprintf(stderr, "failed: %s\n", e.what()); fprintf(stderr, "failed: %s\n", e.what());
return 1; return 1;
} }
return 0;
} }
#endif

155
server/server.dsp Normal file
View File

@ -0,0 +1,155 @@
# Microsoft Developer Studio Project File - Name="server" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Application" 0x0101
CFG=server - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "server.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "server.mak" CFG="server - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "server - Win32 Release" (based on "Win32 (x86) Application")
!MESSAGE "server - Win32 Debug" (based on "Win32 (x86) Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "millpond"
# PROP Scc_LocalPath "."
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "server - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\base" /I "..\io" /I "..\mt" /I "..\net" /I "..\synergy" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c
# SUBTRACT CPP /YX
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
!ELSEIF "$(CFG)" == "server - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\base" /I "..\io" /I "..\mt" /I "..\net" /I "..\synergy" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c
# SUBTRACT CPP /YX
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "server - Win32 Release"
# Name "server - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\CMSWindowsPrimaryScreen.cpp
# End Source File
# Begin Source File
SOURCE=.\CScreenMap.cpp
# End Source File
# Begin Source File
SOURCE=.\CServer.cpp
# End Source File
# Begin Source File
SOURCE=.\CServerProtocol.cpp
# End Source File
# Begin Source File
SOURCE=.\CServerProtocol1_0.cpp
# End Source File
# Begin Source File
SOURCE=.\server.cpp
# End Source File
# Begin Source File
SOURCE=.\server.rc
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\CMSWindowsPrimaryScreen.h
# End Source File
# Begin Source File
SOURCE=.\CScreenMap.h
# End Source File
# Begin Source File
SOURCE=.\CServer.h
# End Source File
# Begin Source File
SOURCE=.\CServerProtocol.h
# End Source File
# Begin Source File
SOURCE=.\CServerProtocol1_0.h
# End Source File
# Begin Source File
SOURCE=.\resource.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project

97
server/server.rc Normal file
View File

@ -0,0 +1,97 @@
//Microsoft Developer Studio generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_SYNERGY DIALOG DISCARDABLE 0, 0, 329, 158
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Synergy"
FONT 8, "MS Sans Serif"
BEGIN
EDITTEXT IDC_LOG,7,7,315,144,ES_MULTILINE | ES_AUTOHSCROLL |
ES_READONLY | WS_VSCROLL | WS_HSCROLL
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO DISCARDABLE
BEGIN
IDD_SYNERGY, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 322
TOPMARGIN, 7
BOTTOMMARGIN, 151
END
END
#endif // APSTUDIO_INVOKED
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

111
server/synrgyhk.dsp Normal file
View File

@ -0,0 +1,111 @@
# Microsoft Developer Studio Project File - Name="synrgyhk" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=synrgyhk - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "synrgyhk.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "synrgyhk.mak" CFG="synrgyhk - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "synrgyhk - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "synrgyhk - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "millpond"
# PROP Scc_LocalPath "."
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "synrgyhk - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "synrgyhk___Win32_Release"
# PROP BASE Intermediate_Dir "synrgyhk___Win32_Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SYNRGYHK_EXPORTS" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\base" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SYNRGYHK_EXPORTS" /FD /c
# SUBTRACT CPP /YX
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
!ELSEIF "$(CFG)" == "synrgyhk - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "synrgyhk___Win32_Debug"
# PROP BASE Intermediate_Dir "synrgyhk___Win32_Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SYNRGYHK_EXPORTS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\base" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SYNRGYHK_EXPORTS" /FD /GZ /c
# SUBTRACT CPP /YX
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "synrgyhk - Win32 Release"
# Name "synrgyhk - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\CSynergyHook.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\CSynergyHook.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project

215
synergy.dsw Normal file
View File

@ -0,0 +1,215 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "all"=.\all.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
millpond
.
end source code control
}}}
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name client
End Project Dependency
Begin Project Dependency
Project_Dep_Name server
End Project Dependency
}}}
###############################################################################
Project: "base"=.\base\base.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
millpond
.\base
end source code control
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "client"=.\client\client.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
millpond
.\client
end source code control
}}}
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name base
End Project Dependency
Begin Project Dependency
Project_Dep_Name io
End Project Dependency
Begin Project Dependency
Project_Dep_Name mt
End Project Dependency
Begin Project Dependency
Project_Dep_Name net
End Project Dependency
Begin Project Dependency
Project_Dep_Name synergy
End Project Dependency
}}}
###############################################################################
Project: "io"=.\io\io.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
millpond
.\io
end source code control
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "makehook"=.\server\makehook.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name synrgyhk
End Project Dependency
}}}
###############################################################################
Project: "mt"=.\mt\mt.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
millpond
.\mt
end source code control
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "net"=.\net\net.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
millpond
.\net
end source code control
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "server"=.\server\server.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
millpond
.\server
end source code control
}}}
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name base
End Project Dependency
Begin Project Dependency
Project_Dep_Name io
End Project Dependency
Begin Project Dependency
Project_Dep_Name mt
End Project Dependency
Begin Project Dependency
Project_Dep_Name net
End Project Dependency
Begin Project Dependency
Project_Dep_Name synergy
End Project Dependency
Begin Project Dependency
Project_Dep_Name makehook
End Project Dependency
}}}
###############################################################################
Project: "synergy"=.\synergy\synergy.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
millpond
.\synergy
end source code control
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "synrgyhk"=.\server\synrgyhk.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
millpond
.\server
end source code control
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################

View File

@ -0,0 +1,41 @@
#include "CMSWindowsClipboard.h"
#include "CString.h"
#include "CLog.h"
//
// CMSWindowsClipboard
//
CMSWindowsClipboard::CMSWindowsClipboard()
{
}
CMSWindowsClipboard::~CMSWindowsClipboard()
{
}
void CMSWindowsClipboard::open()
{
log((CLOG_INFO "open clipboard"));
}
void CMSWindowsClipboard::close()
{
log((CLOG_INFO "close clipboard"));
}
void CMSWindowsClipboard::add(
EFormat format, const CString& data)
{
log((CLOG_INFO "add clipboard format: %d\n%s", format, data.c_str()));
}
bool CMSWindowsClipboard::has(EFormat /*format*/) const
{
return false;
}
CString CMSWindowsClipboard::get(EFormat /*format*/) const
{
return CString();
}

View File

@ -0,0 +1,19 @@
#ifndef CMSWINDOWSCLIPBOARD_H
#define CMSWINDOWSCLIPBOARD_H
#include "IClipboard.h"
class CMSWindowsClipboard : public IClipboard {
public:
CMSWindowsClipboard();
virtual ~CMSWindowsClipboard();
// IClipboard overrides
virtual void open();
virtual void close();
virtual void add(EFormat, const CString& data);
virtual bool has(EFormat) const;
virtual CString get(EFormat) const;
};
#endif

View File

@ -0,0 +1,248 @@
#include "CMSWindowsScreen.h"
#include "CThread.h"
#include "CLock.h"
#include "TMethodJob.h"
#include "CLog.h"
#include "CString.h"
#include <string.h>
#include <assert.h>
//
// CMSWindowsScreen
//
HINSTANCE CMSWindowsScreen::s_instance = NULL;
CMSWindowsScreen::CMSWindowsScreen() :
m_class(0),
m_cursor(NULL),
m_w(0), m_h(0),
m_thread(0)
{
// do nothing
}
CMSWindowsScreen::~CMSWindowsScreen()
{
assert(m_class == 0);
}
void CMSWindowsScreen::init(HINSTANCE instance)
{
s_instance = instance;
}
void CMSWindowsScreen::doRun()
{
m_thread = GetCurrentThreadId();
for (;;) {
// wait for and get the next event
MSG msg;
getEvent(&msg);
// handle quit message
if (msg.message == WM_QUIT) {
break;
}
// dispatch message
if (!onEvent(&msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
void CMSWindowsScreen::doStop()
{
PostThreadMessage(m_thread, WM_QUIT, 0, 0);
}
void CMSWindowsScreen::openDisplay()
{
assert(s_instance != NULL);
assert(m_class == 0);
// create a transparent cursor
int cw = GetSystemMetrics(SM_CXCURSOR);
int ch = GetSystemMetrics(SM_CYCURSOR);
UInt8* cursorBits = new UInt8[ch * ((cw + 31) >> 5)];
memset(cursorBits, 0, ch * ((cw + 31) >> 5));
m_cursor = CreateCursor(s_instance, 0, 0, cw, ch, cursorBits, cursorBits);
delete[] cursorBits;
// register a window class
WNDCLASSEX classInfo;
classInfo.cbSize = sizeof(classInfo);
classInfo.style = CS_DBLCLKS | CS_NOCLOSE;
classInfo.lpfnWndProc = &CMSWindowsScreen::wndProc;
classInfo.cbClsExtra = 0;
classInfo.cbWndExtra = 0;
classInfo.hInstance = s_instance;
classInfo.hIcon = NULL;
classInfo.hCursor = m_cursor;
classInfo.hbrBackground = NULL;
classInfo.lpszMenuName = NULL;
classInfo.lpszClassName = "Synergy";
classInfo.hIconSm = NULL;
m_class = RegisterClassEx(&classInfo);
// get screen size
// FIXME -- should handle multiple screens
m_w = GetSystemMetrics(SM_CXSCREEN);
m_h = GetSystemMetrics(SM_CYSCREEN);
log((CLOG_INFO "display size: %dx%d", m_w, m_h));
// let subclass prep display
onOpenDisplay();
}
void CMSWindowsScreen::closeDisplay()
{
assert(s_instance != NULL);
assert(m_class != 0);
// let subclass close down display
onCloseDisplay();
// unregister the window class
UnregisterClass((LPCTSTR)m_class, s_instance);
m_class = 0;
// delete resources
DestroyCursor(m_cursor);
m_cursor = NULL;
log((CLOG_DEBUG "closed display"));
}
HINSTANCE CMSWindowsScreen::getInstance()
{
return s_instance;
}
ATOM CMSWindowsScreen::getClass() const
{
return m_class;
}
void CMSWindowsScreen::getScreenSize(
SInt32* w, SInt32* h) const
{
assert(m_class != 0);
assert(w != NULL && h != NULL);
*w = m_w;
*h = m_h;
}
void CMSWindowsScreen::getEvent(MSG* msg) const
{
// wait for an event in a cancellable way
while (HIWORD(GetQueueStatus(QS_ALLINPUT)) == 0) {
CThread::sleep(0.05);
}
GetMessage(msg, NULL, 0, 0);
}
void CMSWindowsScreen::getDisplayClipboard(
IClipboard* clipboard,
HWND requestor) const
{
/* FIXME
assert(clipboard != NULL);
assert(requestor != None);
// clear the clipboard object
clipboard->open();
// block others from using the display while we get the clipboard.
// in particular, this prevents the event thread from stealing the
// selection notify event we're expecting.
CLock lock(&m_mutex);
// use PRIMARY selection as the "clipboard"
Atom selection = XA_PRIMARY;
// ask the selection for all the formats it has. some owners return
// the TARGETS atom and some the ATOM atom when TARGETS is requested.
Atom format;
CString targets;
if (getDisplayClipboard(selection, m_atomTargets,
requestor, timestamp, &format, &targets) &&
(format == m_atomTargets || format == XA_ATOM)) {
// get each target (that we can interpret). some owners return
// some targets multiple times in the list so don't try to get
// those multiple times.
const Atom* targetAtoms = reinterpret_cast<const Atom*>(targets.data());
const SInt32 numTargets = targets.size() / sizeof(Atom);
std::set<IClipboard::EFormat> clipboardFormats;
std::set<Atom> targets;
log((CLOG_DEBUG "selection has %d targets", numTargets));
for (SInt32 i = 0; i < numTargets; ++i) {
Atom format = targetAtoms[i];
log((CLOG_DEBUG " source target %d", format));
// skip already handled targets
if (targets.count(format) > 0) {
log((CLOG_DEBUG " skipping handled target %d", format));
continue;
}
// mark this target as done
targets.insert(format);
// determine the expected clipboard format
IClipboard::EFormat expectedFormat = getFormat(format);
// if we can use the format and we haven't already retrieved
// it then get it
if (expectedFormat == IClipboard::kNum) {
log((CLOG_DEBUG " no format for target", format));
continue;
}
if (clipboardFormats.count(expectedFormat) > 0) {
log((CLOG_DEBUG " skipping handled format %d", expectedFormat));
continue;
}
CString data;
if (!getDisplayClipboard(selection, format,
requestor, timestamp, &format, &data)) {
log((CLOG_DEBUG " no data for target", format));
continue;
}
// use the actual format, not the expected
IClipboard::EFormat actualFormat = getFormat(format);
if (actualFormat == IClipboard::kNum) {
log((CLOG_DEBUG " no format for target", format));
continue;
}
if (clipboardFormats.count(actualFormat) > 0) {
log((CLOG_DEBUG " skipping handled format %d", actualFormat));
continue;
}
// add to clipboard and note we've done it
clipboard->add(actualFormat, data);
clipboardFormats.insert(actualFormat);
}
}
else {
// non-ICCCM conforming selection owner. try TEXT format.
// FIXME
log((CLOG_DEBUG "selection doesn't support TARGETS, format is %d", format));
}
// done with clipboard
clipboard->close();
*/
}
LRESULT CALLBACK CMSWindowsScreen::wndProc(
HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hwnd, msg, wParam, lParam);
}

View File

@ -0,0 +1,73 @@
#ifndef CMSWINDOWSSCREEN_H
#define CMSWINDOWSSCREEN_H
#include "CMutex.h"
#include "IClipboard.h"
#include "BasicTypes.h"
#include <windows.h>
class CString;
class CThread;
class CMSWindowsScreen {
public:
CMSWindowsScreen();
virtual ~CMSWindowsScreen();
// manipulators
static void init(HINSTANCE);
protected:
// runs an event loop and returns when WM_QUIT is received
void doRun();
// sends WM_QUIT to force doRun() to return
void doStop();
// open the X display. calls onOpenDisplay() after opening the display,
// getting the screen, its size, and root window. then it starts the
// event thread.
void openDisplay();
// destroy the window and close the display. calls onCloseDisplay()
// after the event thread has been shut down but before the display
// is closed.
void closeDisplay();
// get the application instance handle and the registered window
// class atom
static HINSTANCE getInstance();
ATOM getClass() const;
// get the size of the screen
void getScreenSize(SInt32* w, SInt32* h) const;
// wait for and get the next message. cancellable.
void getEvent(MSG*) const;
// copy the clipboard contents to clipboard
void getDisplayClipboard(IClipboard* clipboard, HWND) const;
// called by doRun() to handle an event
virtual bool onEvent(MSG*) = 0;
// called by openDisplay() to allow subclasses to prepare the display
virtual void onOpenDisplay() = 0;
// called by closeDisplay() to
virtual void onCloseDisplay() = 0;
private:
static LRESULT CALLBACK wndProc(HWND, UINT, WPARAM, LPARAM);
private:
static HINSTANCE s_instance;
ATOM m_class;
HICON m_icon;
HCURSOR m_cursor;
SInt32 m_w, m_h;
DWORD m_thread;
};
#endif

View File

@ -17,4 +17,3 @@ class CXWindowsClipboard : public IClipboard {
}; };
#endif #endif

View File

@ -17,7 +17,8 @@
CXWindowsScreen::CXWindowsScreen() : CXWindowsScreen::CXWindowsScreen() :
m_display(NULL), m_display(NULL),
m_root(None), m_root(None),
m_w(0), m_h(0) m_w(0), m_h(0),
m_stop(false)
{ {
// do nothing // do nothing
} }
@ -58,24 +59,11 @@ void CXWindowsScreen::openDisplay()
// let subclass prep display // let subclass prep display
onOpenDisplay(); onOpenDisplay();
// start processing events
m_eventThread = new CThread(new TMethodJob<CXWindowsScreen>(
this, &CXWindowsScreen::eventThread));
} }
void CXWindowsScreen::closeDisplay() void CXWindowsScreen::closeDisplay()
{ {
assert(m_display != NULL); assert(m_display != NULL);
assert(m_eventThread != NULL);
// stop event thread
log((CLOG_DEBUG "stopping event thread"));
m_eventThread->cancel();
m_eventThread->wait();
delete m_eventThread;
m_eventThread = NULL;
log((CLOG_DEBUG "stopped event thread"));
// let subclass close down display // let subclass close down display
onCloseDisplay(); onCloseDisplay();
@ -143,18 +131,31 @@ Cursor CXWindowsScreen::createBlankCursor() const
return cursor; return cursor;
} }
void CXWindowsScreen::getEvent(XEvent* xevent) const bool CXWindowsScreen::getEvent(XEvent* xevent) const
{ {
// wait for an event in a cancellable way and don't lock the // wait for an event in a cancellable way and don't lock the
// display while we're waiting. // display while we're waiting.
m_mutex.lock(); m_mutex.lock();
while (XPending(m_display) == 0) { while (!m_stop && XPending(m_display) == 0) {
m_mutex.unlock(); m_mutex.unlock();
CThread::sleep(0.05); CThread::sleep(0.05);
m_mutex.lock(); m_mutex.lock();
} }
if (m_stop) {
m_mutex.unlock();
return true;
}
else {
XNextEvent(m_display, xevent); XNextEvent(m_display, xevent);
m_mutex.unlock(); m_mutex.unlock();
return false;
}
}
void CXWindowsScreen::doStop()
{
CLock lock(&m_mutex);
m_stop = true;
} }
void CXWindowsScreen::getDisplayClipboard( void CXWindowsScreen::getDisplayClipboard(

View File

@ -7,7 +7,6 @@
#include <X11/Xlib.h> #include <X11/Xlib.h>
class CString; class CString;
class CThread;
class CXWindowsScreen { class CXWindowsScreen {
public: public:
@ -50,7 +49,10 @@ class CXWindowsScreen {
Cursor createBlankCursor() const; Cursor createBlankCursor() const;
// wait for and get the next X event. cancellable. // wait for and get the next X event. cancellable.
void getEvent(XEvent*) const; bool getEvent(XEvent*) const;
// cause getEvent() to return false immediately and forever after
void doStop();
// copy the clipboard contents to clipboard. requestor must be a // copy the clipboard contents to clipboard. requestor must be a
// valid window; it will be used to receive the transfer. timestamp // valid window; it will be used to receive the transfer. timestamp
@ -64,9 +66,6 @@ class CXWindowsScreen {
// called by closeDisplay() to // called by closeDisplay() to
virtual void onCloseDisplay() = 0; virtual void onCloseDisplay() = 0;
// override to process X events
virtual void eventThread(void*) = 0;
private: private:
struct PropertyNotifyInfo { struct PropertyNotifyInfo {
public: public:
@ -87,11 +86,11 @@ class CXWindowsScreen {
XEvent* xevent, XPointer arg); XEvent* xevent, XPointer arg);
private: private:
CThread* m_eventThread;
Display* m_display; Display* m_display;
int m_screen; int m_screen;
Window m_root; Window m_root;
SInt32 m_w, m_h; SInt32 m_w, m_h;
bool m_stop;
// atoms we'll need // atoms we'll need
Atom m_atomTargets; Atom m_atomTargets;

View File

@ -41,4 +41,3 @@ class IClipboard : public IInterface {
}; };
#endif #endif

View File

@ -11,6 +11,15 @@ class IPrimaryScreen : public IInterface {
public: public:
// manipulators // manipulators
// enter the screen's message loop. this returns when it detects
// the application should terminate or when stop() is called.
// the screen must be open()'d before run() and must not be
// close()'d until run() returns.
virtual void run() = 0;
// cause run() to return
virtual void stop() = 0;
// initialize the screen and start reporting events to the server. // initialize the screen and start reporting events to the server.
// events should be reported no matter where on the screen they // events should be reported no matter where on the screen they
// occur but do not interfere with normal event dispatch. the // occur but do not interfere with normal event dispatch. the
@ -26,8 +35,9 @@ class IPrimaryScreen : public IInterface {
// called when the user navigates back to the primary screen. // called when the user navigates back to the primary screen.
// warp the cursor to the given coordinates, unhide it, and // warp the cursor to the given coordinates, unhide it, and
// ungrab the input devices. every call to method has a matching // ungrab the input devices. every call to enter has a matching
// call to leave() which preceeds it. // call to leave() which preceeds it, however the screen can
// assume an implicit call to enter() in the call to open().
virtual void enter(SInt32 xAbsolute, SInt32 yAbsolute) = 0; virtual void enter(SInt32 xAbsolute, SInt32 yAbsolute) = 0;
// called when the user navigates off the primary screen. hide // called when the user navigates off the primary screen. hide

View File

@ -13,6 +13,15 @@ class ISecondaryScreen : public IInterface {
public: public:
// manipulators // manipulators
// enter the screen's message loop. this returns when it detects
// the application should terminate or when stop() is called.
// the screen must be open()'d before run() and must not be
// close()'d until run() returns.
virtual void run() = 0;
// cause run() to return
virtual void stop() = 0;
// initialize the screen, hide the cursor, and disable the screen // initialize the screen, hide the cursor, and disable the screen
// saver. start reporting certain events to the client (clipboard // saver. start reporting certain events to the client (clipboard
// stolen and screen size changed). // stolen and screen size changed).

186
synergy/synergy.dsp Normal file
View File

@ -0,0 +1,186 @@
# Microsoft Developer Studio Project File - Name="synergy" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Static Library" 0x0104
CFG=synergy - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "synergy.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "synergy.mak" CFG="synergy - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "synergy - Win32 Release" (based on "Win32 (x86) Static Library")
!MESSAGE "synergy - Win32 Debug" (based on "Win32 (x86) Static Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "millpond"
# PROP Scc_LocalPath "."
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "synergy - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\base" /I "..\io" /I "..\mt" /I "..\net" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ELSEIF "$(CFG)" == "synergy - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\base" /I "..\io" /I "..\mt" /I "..\net" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ENDIF
# Begin Target
# Name "synergy - Win32 Release"
# Name "synergy - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\CInputPacketStream.cpp
# End Source File
# Begin Source File
SOURCE=.\CMSWindowsClipboard.cpp
# End Source File
# Begin Source File
SOURCE=.\CMSWindowsScreen.cpp
# End Source File
# Begin Source File
SOURCE=.\COutputPacketStream.cpp
# End Source File
# Begin Source File
SOURCE=.\CProtocolUtil.cpp
# End Source File
# Begin Source File
SOURCE=.\CTCPSocketFactory.cpp
# End Source File
# Begin Source File
SOURCE=.\XSynergy.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\CInputPacketStream.h
# End Source File
# Begin Source File
SOURCE=.\CMSWindowsClipboard.h
# End Source File
# Begin Source File
SOURCE=.\CMSWindowsScreen.h
# End Source File
# Begin Source File
SOURCE=.\COutputPacketStream.h
# End Source File
# Begin Source File
SOURCE=.\CProtocolUtil.h
# End Source File
# Begin Source File
SOURCE=.\CTCPSocketFactory.h
# End Source File
# Begin Source File
SOURCE=.\IClipboard.h
# End Source File
# Begin Source File
SOURCE=.\IPrimaryScreen.h
# End Source File
# Begin Source File
SOURCE=.\ISecondaryScreen.h
# End Source File
# Begin Source File
SOURCE=.\IServerProtocol.h
# End Source File
# Begin Source File
SOURCE=.\ISocketFactory.h
# End Source File
# Begin Source File
SOURCE=.\KeyTypes.h
# End Source File
# Begin Source File
SOURCE=.\MouseTypes.h
# End Source File
# Begin Source File
SOURCE=.\ProtocolTypes.h
# End Source File
# Begin Source File
SOURCE=.\XSynergy.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project