Patch by Jerry:

- Fixed line endings
- Integ test for file transfer
- Fixed crashed problem when log info is larger than 2048 bytes
- Fixed compile error caused by std exception (by Feng ye)
- Fixed include path on Mac and linux (by Feng ye)
This commit is contained in:
Nick Bolton 2013-07-24 16:41:12 +00:00
parent c368013f13
commit 394ece004a
72 changed files with 3884 additions and 3127 deletions

View File

@ -174,35 +174,35 @@ if (UNIX)
else() else()
# add include dir for bsd (posix uses /usr/include/) # add include dir for bsd (posix uses /usr/include/)
set(CMAKE_INCLUDE_PATH "${CMAKE_INCLUDE_PATH}:/usr/local/include") set(CMAKE_INCLUDE_PATH "${CMAKE_INCLUDE_PATH}:/usr/local/include")
set(XKBlib "X11/Xlib.h;X11/XKBlib.h") set(XKBlib "X11/Xlib.h;X11/XKBlib.h")
check_symbol_exists("XRRNotifyEvent" "${XKBlib};X11/extensions/Xrandr.h" HAVE_X11_EXTENSIONS_XRANDR_H) check_symbol_exists("XRRNotifyEvent" "${XKBlib};X11/extensions/Xrandr.h" HAVE_X11_EXTENSIONS_XRANDR_H)
check_include_files("${XKBlib};X11/extensions/dpms.h" HAVE_X11_EXTENSIONS_DPMS_H) check_include_files("${XKBlib};X11/extensions/dpms.h" HAVE_X11_EXTENSIONS_DPMS_H)
check_include_files("X11/extensions/Xinerama.h" HAVE_X11_EXTENSIONS_XINERAMA_H) check_include_files("X11/extensions/Xinerama.h" HAVE_X11_EXTENSIONS_XINERAMA_H)
check_include_files("${XKBlib};X11/extensions/XKBstr.h" HAVE_X11_EXTENSIONS_XKBSTR_H) check_include_files("${XKBlib};X11/extensions/XKBstr.h" HAVE_X11_EXTENSIONS_XKBSTR_H)
check_include_files("X11/extensions/XKB.h" HAVE_XKB_EXTENSION) check_include_files("X11/extensions/XKB.h" HAVE_XKB_EXTENSION)
check_include_files("X11/extensions/XTest.h" HAVE_X11_EXTENSIONS_XTEST_H) check_include_files("X11/extensions/XTest.h" HAVE_X11_EXTENSIONS_XTEST_H)
check_include_files("${XKBlib}" HAVE_X11_XKBLIB_H) check_include_files("${XKBlib}" HAVE_X11_XKBLIB_H)
check_include_files("X11/extensions/XInput2.h" HAVE_XI2) check_include_files("X11/extensions/XInput2.h" HAVE_XI2)
if (HAVE_X11_EXTENSIONS_DPMS_H) if (HAVE_X11_EXTENSIONS_DPMS_H)
# Assume that function prototypes declared, when include exists. # Assume that function prototypes declared, when include exists.
set(HAVE_DPMS_PROTOTYPES 1) set(HAVE_DPMS_PROTOTYPES 1)
endif() endif()
if (NOT HAVE_X11_XKBLIB_H) if (NOT HAVE_X11_XKBLIB_H)
message(FATAL_ERROR "Missing header: " ${XKBlib}) message(FATAL_ERROR "Missing header: " ${XKBlib})
endif() endif()
check_library_exists("SM;ICE" IceConnectionNumber "" HAVE_ICE) check_library_exists("SM;ICE" IceConnectionNumber "" HAVE_ICE)
check_library_exists("Xext;X11" DPMSQueryExtension "" HAVE_Xext) check_library_exists("Xext;X11" DPMSQueryExtension "" HAVE_Xext)
check_library_exists("Xtst;Xext;X11" XTestQueryExtension "" HAVE_Xtst) check_library_exists("Xtst;Xext;X11" XTestQueryExtension "" HAVE_Xtst)
check_library_exists("Xinerama" XineramaQueryExtension "" HAVE_Xinerama) check_library_exists("Xinerama" XineramaQueryExtension "" HAVE_Xinerama)
check_library_exists("Xi" XISelectEvents "" HAVE_Xi) check_library_exists("Xi" XISelectEvents "" HAVE_Xi)
check_library_exists("Xrandr" XRRQueryExtension "" HAVE_Xrandr) check_library_exists("Xrandr" XRRQueryExtension "" HAVE_Xrandr)
if (HAVE_ICE) if (HAVE_ICE)
@ -213,13 +213,13 @@ if (UNIX)
endif() endif()
if (HAVE_Xtst) if (HAVE_Xtst)
# Xtxt depends on X11. # Xtxt depends on X11.
set(HAVE_X11) set(HAVE_X11)
list(APPEND libs Xtst X11) list(APPEND libs Xtst X11)
else() else()
message(FATAL_ERROR "Missing library: Xtst") message(FATAL_ERROR "Missing library: Xtst")
endif() endif()
@ -229,14 +229,14 @@ if (UNIX)
endif() endif()
if (HAVE_Xinerama) if (HAVE_Xinerama)
list(APPEND libs Xinerama) list(APPEND libs Xinerama)
else (HAVE_Xinerama) else (HAVE_Xinerama)
if (HAVE_X11_EXTENSIONS_XINERAMA_H) if (HAVE_X11_EXTENSIONS_XINERAMA_H)
set(HAVE_X11_EXTENSIONS_XINERAMA_H 0) set(HAVE_X11_EXTENSIONS_XINERAMA_H 0)
message(WARNING "Old Xinerama implementation detected, disabled") message(WARNING "Old Xinerama implementation detected, disabled")
endif() endif()
endif() endif()
if (HAVE_Xrandr) if (HAVE_Xrandr)
list(APPEND libs Xrandr) list(APPEND libs Xrandr)
endif() endif()
@ -382,13 +382,13 @@ if (CONF_DOXYGEN)
set(VERSION, "${VERSION}") set(VERSION, "${VERSION}")
# For doxygen.cfg, save the results based on a template (doxygen.cfg.in). # For doxygen.cfg, save the results based on a template (doxygen.cfg.in).
configure_file(${cmake_dir}/doxygen.cfg.in ${doc_dir}/doxygen.cfg) configure_file(${cmake_dir}/doxygen.cfg.in ${doc_dir}/doxygen.cfg)
endif() endif()
if (${CMAKE_SYSTEM_NAME} MATCHES "IRIX") if (${CMAKE_SYSTEM_NAME} MATCHES "IRIX")
set_target_properties(synergys PROPERTIES LINK_FLAGS "-all -woff 33 -woff 84 -woff 15") set_target_properties(synergys PROPERTIES LINK_FLAGS "-all -woff 33 -woff 84 -woff 15")
set_target_properties(synergyc PROPERTIES LINK_FLAGS "-all -woff 33 -woff 84 -woff 15") set_target_properties(synergyc PROPERTIES LINK_FLAGS "-all -woff 33 -woff 84 -woff 15")
set_target_properties(synergyd PROPERTIES LINK_FLAGS "-all -woff 33 -woff 84 -woff 15") set_target_properties(synergyd PROPERTIES LINK_FLAGS "-all -woff 33 -woff 84 -woff 15")
endif() endif()

View File

@ -13,11 +13,11 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
add_subdirectory(lib) add_subdirectory(lib)
add_subdirectory(cmd) add_subdirectory(cmd)
if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "IRIX") if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "IRIX")
add_subdirectory(test) add_subdirectory(test)
endif() endif()
add_subdirectory(plugin) add_subdirectory(plugin)
add_subdirectory(micro) add_subdirectory(micro)

View File

@ -64,17 +64,17 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, INT nCmdSh
} }
if (!server && !client) { if (!server && !client) {
MessageBox(NULL, MessageBox(NULL,
"Either the --server argument or the --client argument must be provided.", "Either the --server argument or the --client argument must be provided.",
"Server or client?", MB_OK); "Server or client?", MB_OK);
return 1; return 1;
} }
if (argc <= 2) { if (argc <= 2) {
MessageBox(NULL, MessageBox(NULL,
"No additional arguments were provided. Append the --help argument for help.\n\n" "No additional arguments were provided. Append the --help argument for help.\n\n"
"Hint: Create a shortcut and append the \"Target\" field with the arguments.", "Hint: Create a shortcut and append the \"Target\" field with the arguments.",
"No additional arguments", MB_OK); "No additional arguments", MB_OK);
return 1; return 1;
} }

View File

@ -1,26 +1,26 @@
/* /*
* synergy -- mouse and keyboard sharing utility * synergy -- mouse and keyboard sharing utility
* Copyright (C) 2013 Bolton Software Ltd. * Copyright (C) 2013 Bolton Software Ltd.
* *
* This package is free software; you can redistribute it and/or * This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file. * found in the file COPYING that should have accompanied this file.
* *
* This package is distributed in the hope that it will be useful, * This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
enum CryptoMode { enum CryptoMode {
Disabled, Disabled,
OFB, OFB,
CFB, CFB,
CTR, CTR,
GCM GCM
}; };

View File

@ -1,26 +1,26 @@
/* /*
* synergy -- mouse and keyboard sharing utility * synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012 Bolton Software Ltd. * Copyright (C) 2012 Bolton Software Ltd.
* Copyright (C) 2012 Nick Bolton * Copyright (C) 2012 Nick Bolton
* *
* This package is free software; you can redistribute it and/or * This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file. * found in the file COPYING that should have accompanied this file.
* *
* This package is distributed in the hope that it will be useful, * This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
// this class is a duplicate of /src/lib/ipc/Ipc.cpp // this class is a duplicate of /src/lib/ipc/Ipc.cpp
#include "Ipc.h" #include "Ipc.h"
const char* kIpcMsgHello = "IHEL%1i"; const char* kIpcMsgHello = "IHEL%1i";
const char* kIpcMsgLogLine = "ILOG%s"; const char* kIpcMsgLogLine = "ILOG%s";
const char* kIpcMsgCommand = "ICMD%s%1i"; const char* kIpcMsgCommand = "ICMD%s%1i";
const char* kIpcMsgShutdown = "ISDN"; const char* kIpcMsgShutdown = "ISDN";

View File

@ -1,42 +1,42 @@
/* /*
* synergy -- mouse and keyboard sharing utility * synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012 Bolton Software Ltd. * Copyright (C) 2012 Bolton Software Ltd.
* Copyright (C) 2012 Nick Bolton * Copyright (C) 2012 Nick Bolton
* *
* This package is free software; you can redistribute it and/or * This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file. * found in the file COPYING that should have accompanied this file.
* *
* This package is distributed in the hope that it will be useful, * This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
// this class is a duplicate of /src/lib/ipc/Ipc.h // this class is a duplicate of /src/lib/ipc/Ipc.h
#pragma once #pragma once
#define IPC_HOST "127.0.0.1" #define IPC_HOST "127.0.0.1"
#define IPC_PORT 24801 #define IPC_PORT 24801
enum qIpcMessageType { enum qIpcMessageType {
kIpcHello, kIpcHello,
kIpcLogLine, kIpcLogLine,
kIpcCommand, kIpcCommand,
kIpcShutdown, kIpcShutdown,
}; };
enum qIpcClientType { enum qIpcClientType {
kIpcClientUnknown, kIpcClientUnknown,
kIpcClientGui, kIpcClientGui,
kIpcClientNode, kIpcClientNode,
}; };
extern const char* kIpcMsgHello; extern const char* kIpcMsgHello;
extern const char* kIpcMsgLogLine; extern const char* kIpcMsgLogLine;
extern const char* kIpcMsgCommand; extern const char* kIpcMsgCommand;
extern const char* kIpcMsgShutdown; extern const char* kIpcMsgShutdown;

View File

@ -1,147 +1,147 @@
/* /*
* synergy -- mouse and keyboard sharing utility * synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012 Bolton Software Ltd. * Copyright (C) 2012 Bolton Software Ltd.
* Copyright (C) 2012 Nick Bolton * Copyright (C) 2012 Nick Bolton
* *
* This package is free software; you can redistribute it and/or * This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file. * found in the file COPYING that should have accompanied this file.
* *
* This package is distributed in the hope that it will be useful, * This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "IpcClient.h" #include "IpcClient.h"
#include <QTcpSocket> #include <QTcpSocket>
#include <QHostAddress> #include <QHostAddress>
#include <iostream> #include <iostream>
#include <QTimer> #include <QTimer>
#include "IpcReader.h" #include "IpcReader.h"
#include "Ipc.h" #include "Ipc.h"
IpcClient::IpcClient() : IpcClient::IpcClient() :
m_ReaderStarted(false), m_ReaderStarted(false),
m_Enabled(false) m_Enabled(false)
{ {
m_Socket = new QTcpSocket(this); m_Socket = new QTcpSocket(this);
connect(m_Socket, SIGNAL(connected()), this, SLOT(connected())); connect(m_Socket, SIGNAL(connected()), this, SLOT(connected()));
connect(m_Socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error(QAbstractSocket::SocketError))); connect(m_Socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error(QAbstractSocket::SocketError)));
m_Reader = new IpcReader(m_Socket); m_Reader = new IpcReader(m_Socket);
connect(m_Reader, SIGNAL(readLogLine(const QString&)), this, SLOT(handleReadLogLine(const QString&))); connect(m_Reader, SIGNAL(readLogLine(const QString&)), this, SLOT(handleReadLogLine(const QString&)));
} }
IpcClient::~IpcClient() IpcClient::~IpcClient()
{ {
} }
void IpcClient::connected() void IpcClient::connected()
{ {
char typeBuf[1]; char typeBuf[1];
typeBuf[0] = kIpcClientGui; typeBuf[0] = kIpcClientGui;
sendHello(); sendHello();
infoMessage("connection established"); infoMessage("connection established");
} }
void IpcClient::connectToHost() void IpcClient::connectToHost()
{ {
m_Enabled = true; m_Enabled = true;
infoMessage("connecting to service..."); infoMessage("connecting to service...");
m_Socket->connectToHost(QHostAddress(QHostAddress::LocalHost), IPC_PORT); m_Socket->connectToHost(QHostAddress(QHostAddress::LocalHost), IPC_PORT);
if (!m_ReaderStarted) { if (!m_ReaderStarted) {
m_Reader->start(); m_Reader->start();
m_ReaderStarted = true; m_ReaderStarted = true;
} }
} }
void IpcClient::disconnectFromHost() void IpcClient::disconnectFromHost()
{ {
infoMessage("service disconnect"); infoMessage("service disconnect");
m_Reader->stop(); m_Reader->stop();
m_Socket->close(); m_Socket->close();
} }
void IpcClient::error(QAbstractSocket::SocketError error) void IpcClient::error(QAbstractSocket::SocketError error)
{ {
QString text; QString text;
switch (error) { switch (error) {
case 0: text = "connection refused"; break; case 0: text = "connection refused"; break;
case 1: text = "remote host closed"; break; case 1: text = "remote host closed"; break;
default: text = QString("code=%1").arg(error); break; default: text = QString("code=%1").arg(error); break;
} }
errorMessage(QString("ipc connection error, %1").arg(text)); errorMessage(QString("ipc connection error, %1").arg(text));
QTimer::singleShot(1000, this, SLOT(retryConnect())); QTimer::singleShot(1000, this, SLOT(retryConnect()));
} }
void IpcClient::retryConnect() void IpcClient::retryConnect()
{ {
if (m_Enabled) { if (m_Enabled) {
connectToHost(); connectToHost();
} }
} }
void IpcClient::sendHello() void IpcClient::sendHello()
{ {
QDataStream stream(m_Socket); QDataStream stream(m_Socket);
stream.writeRawData(kIpcMsgHello, 4); stream.writeRawData(kIpcMsgHello, 4);
char typeBuf[1]; char typeBuf[1];
typeBuf[0] = kIpcClientGui; typeBuf[0] = kIpcClientGui;
stream.writeRawData(typeBuf, 1); stream.writeRawData(typeBuf, 1);
} }
void IpcClient::sendCommand(const QString& command, bool elevate) void IpcClient::sendCommand(const QString& command, bool elevate)
{ {
QDataStream stream(m_Socket); QDataStream stream(m_Socket);
stream.writeRawData(kIpcMsgCommand, 4); stream.writeRawData(kIpcMsgCommand, 4);
std::string stdStringCommand = command.toStdString(); std::string stdStringCommand = command.toStdString();
const char* charCommand = stdStringCommand.c_str(); const char* charCommand = stdStringCommand.c_str();
int length = strlen(charCommand); int length = strlen(charCommand);
char lenBuf[4]; char lenBuf[4];
intToBytes(length, lenBuf, 4); intToBytes(length, lenBuf, 4);
stream.writeRawData(lenBuf, 4); stream.writeRawData(lenBuf, 4);
stream.writeRawData(charCommand, length); stream.writeRawData(charCommand, length);
char elevateBuf[1]; char elevateBuf[1];
elevateBuf[0] = elevate ? 1 : 0; elevateBuf[0] = elevate ? 1 : 0;
stream.writeRawData(elevateBuf, 1); stream.writeRawData(elevateBuf, 1);
} }
void IpcClient::handleReadLogLine(const QString& text) void IpcClient::handleReadLogLine(const QString& text)
{ {
readLogLine(text); readLogLine(text);
} }
// TODO: qt must have a built in way of converting int to bytes. // TODO: qt must have a built in way of converting int to bytes.
void IpcClient::intToBytes(int value, char *buffer, int size) void IpcClient::intToBytes(int value, char *buffer, int size)
{ {
if (size == 1) { if (size == 1) {
buffer[0] = value & 0xff; buffer[0] = value & 0xff;
} }
else if (size == 2) { else if (size == 2) {
buffer[0] = (value >> 8) & 0xff; buffer[0] = (value >> 8) & 0xff;
buffer[1] = value & 0xff; buffer[1] = value & 0xff;
} }
else if (size == 4) { else if (size == 4) {
buffer[0] = (value >> 24) & 0xff; buffer[0] = (value >> 24) & 0xff;
buffer[1] = (value >> 16) & 0xff; buffer[1] = (value >> 16) & 0xff;
buffer[2] = (value >> 8) & 0xff; buffer[2] = (value >> 8) & 0xff;
buffer[3] = value & 0xff; buffer[3] = value & 0xff;
} }
else { else {
// TODO: other sizes, if needed. // TODO: other sizes, if needed.
} }
} }

View File

@ -1,61 +1,61 @@
/* /*
* synergy -- mouse and keyboard sharing utility * synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012 Bolton Software Ltd. * Copyright (C) 2012 Bolton Software Ltd.
* Copyright (C) 2012 Nick Bolton * Copyright (C) 2012 Nick Bolton
* *
* This package is free software; you can redistribute it and/or * This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file. * found in the file COPYING that should have accompanied this file.
* *
* This package is distributed in the hope that it will be useful, * This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include <QObject> #include <QObject>
#include <QAbstractSocket> #include <QAbstractSocket>
class QTcpSocket; class QTcpSocket;
class IpcReader; class IpcReader;
class IpcClient : public QObject class IpcClient : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
IpcClient(); IpcClient();
virtual ~IpcClient(); virtual ~IpcClient();
void sendHello(); void sendHello();
void sendCommand(const QString& command, bool elevate); void sendCommand(const QString& command, bool elevate);
void connectToHost(); void connectToHost();
void disconnectFromHost(); void disconnectFromHost();
public slots: public slots:
void retryConnect(); void retryConnect();
private: private:
void intToBytes(int value, char* buffer, int size); void intToBytes(int value, char* buffer, int size);
private slots: private slots:
void connected(); void connected();
void error(QAbstractSocket::SocketError error); void error(QAbstractSocket::SocketError error);
void handleReadLogLine(const QString& text); void handleReadLogLine(const QString& text);
signals: signals:
void readLogLine(const QString& text); void readLogLine(const QString& text);
void infoMessage(const QString& text); void infoMessage(const QString& text);
void errorMessage(const QString& text); void errorMessage(const QString& text);
private: private:
QTcpSocket* m_Socket; QTcpSocket* m_Socket;
IpcReader* m_Reader; IpcReader* m_Reader;
bool m_ReaderStarted; bool m_ReaderStarted;
bool m_Enabled; bool m_Enabled;
}; };

View File

@ -1,131 +1,131 @@
/* /*
* synergy -- mouse and keyboard sharing utility * synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012 Bolton Software Ltd. * Copyright (C) 2012 Bolton Software Ltd.
* Copyright (C) 2012 Nick Bolton * Copyright (C) 2012 Nick Bolton
* *
* This package is free software; you can redistribute it and/or * This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file. * found in the file COPYING that should have accompanied this file.
* *
* This package is distributed in the hope that it will be useful, * This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "IpcReader.h" #include "IpcReader.h"
#include <QTcpSocket> #include <QTcpSocket>
#include "Ipc.h" #include "Ipc.h"
#include <iostream> #include <iostream>
#include <QMutex> #include <QMutex>
#include <QByteArray> #include <QByteArray>
IpcReader::IpcReader(QTcpSocket* socket) : IpcReader::IpcReader(QTcpSocket* socket) :
m_Socket(socket) m_Socket(socket)
{ {
} }
IpcReader::~IpcReader() IpcReader::~IpcReader()
{ {
} }
void IpcReader::start() void IpcReader::start()
{ {
connect(m_Socket, SIGNAL(readyRead()), this, SLOT(read())); connect(m_Socket, SIGNAL(readyRead()), this, SLOT(read()));
} }
void IpcReader::stop() void IpcReader::stop()
{ {
disconnect(m_Socket, SIGNAL(readyRead()), this, SLOT(read())); disconnect(m_Socket, SIGNAL(readyRead()), this, SLOT(read()));
} }
void IpcReader::read() void IpcReader::read()
{ {
QMutexLocker locker(&m_Mutex); QMutexLocker locker(&m_Mutex);
std::cout << "ready read" << std::endl; std::cout << "ready read" << std::endl;
while (m_Socket->bytesAvailable()) { while (m_Socket->bytesAvailable()) {
std::cout << "bytes available" << std::endl; std::cout << "bytes available" << std::endl;
char codeBuf[5]; char codeBuf[5];
readStream(codeBuf, 4); readStream(codeBuf, 4);
codeBuf[4] = 0; codeBuf[4] = 0;
std::cout << "ipc read: " << codeBuf << std::endl; std::cout << "ipc read: " << codeBuf << std::endl;
if (memcmp(codeBuf, kIpcMsgLogLine, 4) == 0) { if (memcmp(codeBuf, kIpcMsgLogLine, 4) == 0) {
std::cout << "reading log line" << std::endl; std::cout << "reading log line" << std::endl;
char lenBuf[4]; char lenBuf[4];
readStream(lenBuf, 4); readStream(lenBuf, 4);
int len = bytesToInt(lenBuf, 4); int len = bytesToInt(lenBuf, 4);
char* data = new char[len]; char* data = new char[len];
readStream(data, len); readStream(data, len);
QString line = QString::fromUtf8(data, len); QString line = QString::fromUtf8(data, len);
delete data; delete data;
readLogLine(line); readLogLine(line);
} }
else { else {
std::cerr << "aborting, message invalid" << std::endl; std::cerr << "aborting, message invalid" << std::endl;
return; return;
} }
} }
std::cout << "read done" << std::endl; std::cout << "read done" << std::endl;
} }
bool IpcReader::readStream(char* buffer, int length) bool IpcReader::readStream(char* buffer, int length)
{ {
std::cout << "reading stream" << std::endl; std::cout << "reading stream" << std::endl;
int read = 0; int read = 0;
while (read < length) { while (read < length) {
int ask = length - read; int ask = length - read;
if (m_Socket->bytesAvailable() < ask) { if (m_Socket->bytesAvailable() < ask) {
std::cout << "buffer too short, waiting" << std::endl; std::cout << "buffer too short, waiting" << std::endl;
m_Socket->waitForReadyRead(-1); m_Socket->waitForReadyRead(-1);
} }
int got = m_Socket->read(buffer, ask); int got = m_Socket->read(buffer, ask);
read += got; read += got;
std::cout << "> ask=" << ask << " got=" << got std::cout << "> ask=" << ask << " got=" << got
<< " read=" << read << std::endl; << " read=" << read << std::endl;
if (got == -1) { if (got == -1) {
std::cout << "socket ended, aborting" << std::endl; std::cout << "socket ended, aborting" << std::endl;
return false; return false;
} }
else if (length - read > 0) { else if (length - read > 0) {
std::cout << "more remains, seek to " << got << std::endl; std::cout << "more remains, seek to " << got << std::endl;
buffer += got; buffer += got;
} }
} }
return true; return true;
} }
int IpcReader::bytesToInt(const char *buffer, int size) int IpcReader::bytesToInt(const char *buffer, int size)
{ {
if (size == 1) { if (size == 1) {
return (unsigned char)buffer[0]; return (unsigned char)buffer[0];
} }
else if (size == 2) { else if (size == 2) {
return return
(((unsigned char)buffer[0]) << 8) + (((unsigned char)buffer[0]) << 8) +
(unsigned char)buffer[1]; (unsigned char)buffer[1];
} }
else if (size == 4) { else if (size == 4) {
return return
(((unsigned char)buffer[0]) << 24) + (((unsigned char)buffer[0]) << 24) +
(((unsigned char)buffer[1]) << 16) + (((unsigned char)buffer[1]) << 16) +
(((unsigned char)buffer[2]) << 8) + (((unsigned char)buffer[2]) << 8) +
(unsigned char)buffer[3]; (unsigned char)buffer[3];
} }
else { else {
return 0; return 0;
} }
} }

View File

@ -1,49 +1,49 @@
/* /*
* synergy -- mouse and keyboard sharing utility * synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012 Bolton Software Ltd. * Copyright (C) 2012 Bolton Software Ltd.
* Copyright (C) 2012 Nick Bolton * Copyright (C) 2012 Nick Bolton
* *
* This package is free software; you can redistribute it and/or * This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file. * found in the file COPYING that should have accompanied this file.
* *
* This package is distributed in the hope that it will be useful, * This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include <QObject> #include <QObject>
#include <QMutex> #include <QMutex>
class QTcpSocket; class QTcpSocket;
class IpcReader : public QObject class IpcReader : public QObject
{ {
Q_OBJECT; Q_OBJECT;
public: public:
IpcReader(QTcpSocket* socket); IpcReader(QTcpSocket* socket);
virtual ~IpcReader(); virtual ~IpcReader();
void start(); void start();
void stop(); void stop();
signals: signals:
void readLogLine(const QString& text); void readLogLine(const QString& text);
private: private:
bool readStream(char* buffer, int length); bool readStream(char* buffer, int length);
int bytesToInt(const char* buffer, int size); int bytesToInt(const char* buffer, int size);
private slots: private slots:
void read(); void read();
private: private:
QTcpSocket* m_Socket; QTcpSocket* m_Socket;
QMutex m_Mutex; QMutex m_Mutex;
}; };

View File

@ -1,51 +1,51 @@
/* /*
* synergy -- mouse and keyboard sharing utility * synergy -- mouse and keyboard sharing utility
* Copyright (C) 2013 Bolton Software Ltd. * Copyright (C) 2013 Bolton Software Ltd.
* *
* This package is free software; you can redistribute it and/or * This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file. * found in the file COPYING that should have accompanied this file.
* *
* This package is distributed in the hope that it will be useful, * This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "QUtility.h" #include "QUtility.h"
void setIndexFromItemData(QComboBox* comboBox, const QVariant& itemData) void setIndexFromItemData(QComboBox* comboBox, const QVariant& itemData)
{ {
for (int i = 0; i < comboBox->count(); ++i) for (int i = 0; i < comboBox->count(); ++i)
{ {
if (comboBox->itemData(i) == itemData) if (comboBox->itemData(i) == itemData)
{ {
comboBox->setCurrentIndex(i); comboBox->setCurrentIndex(i);
return; return;
} }
} }
} }
QString hash(const QString& string) QString hash(const QString& string)
{ {
QByteArray data = string.toUtf8(); QByteArray data = string.toUtf8();
QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Md5); QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Md5);
return hash.toHex(); return hash.toHex();
} }
QString getFirstMacAddress() QString getFirstMacAddress()
{ {
QString mac; QString mac;
foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces())
{ {
mac = interface.hardwareAddress(); mac = interface.hardwareAddress();
if (mac.size() != 0) if (mac.size() != 0)
{ {
break; break;
} }
} }
return mac; return mac;
} }

View File

@ -1,27 +1,27 @@
/* /*
* synergy -- mouse and keyboard sharing utility * synergy -- mouse and keyboard sharing utility
* Copyright (C) 2013 Bolton Software Ltd. * Copyright (C) 2013 Bolton Software Ltd.
* *
* This package is free software; you can redistribute it and/or * This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file. * found in the file COPYING that should have accompanied this file.
* *
* This package is distributed in the hope that it will be useful, * This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include <QComboBox> #include <QComboBox>
#include <QVariant> #include <QVariant>
#include <QCryptographicHash> #include <QCryptographicHash>
#include <QNetworkInterface> #include <QNetworkInterface>
void setIndexFromItemData(QComboBox* comboBox, const QVariant& itemData); void setIndexFromItemData(QComboBox* comboBox, const QVariant& itemData);
QString hash(const QString& string); QString hash(const QString& string);
QString getFirstMacAddress(); QString getFirstMacAddress();

View File

@ -1,334 +1,334 @@
/* /*
* synergy -- mouse and keyboard sharing utility * synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012 Bolton Software Ltd. * Copyright (C) 2012 Bolton Software Ltd.
* *
* This package is free software; you can redistribute it and/or * This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file. * found in the file COPYING that should have accompanied this file.
* *
* This package is distributed in the hope that it will be useful, * This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "SetupWizard.h" #include "SetupWizard.h"
#include "MainWindow.h" #include "MainWindow.h"
#include "QSynergyApplication.h" #include "QSynergyApplication.h"
#include "QUtility.h" #include "QUtility.h"
#include <QMessageBox> #include <QMessageBox>
#include <QDesktopServices> #include <QDesktopServices>
#include <QUrl> #include <QUrl>
#include <QNetworkRequest> #include <QNetworkRequest>
#include <QNetworkReply> #include <QNetworkReply>
//#define PREMIUM_AUTH_URL "http://localhost/synergy/premium/json/auth/" //#define PREMIUM_AUTH_URL "http://localhost/synergy/premium/json/auth/"
#define PREMIUM_AUTH_URL "https://synergy-foss.org/premium/json/auth/" #define PREMIUM_AUTH_URL "https://synergy-foss.org/premium/json/auth/"
#define PREMIUM_REGISTER_URL "https://synergy-foss.org/premium/register/?source=gui-wizard" #define PREMIUM_REGISTER_URL "https://synergy-foss.org/premium/register/?source=gui-wizard"
SetupWizard::SetupWizard(MainWindow& mainWindow, bool startMain) : SetupWizard::SetupWizard(MainWindow& mainWindow, bool startMain) :
m_MainWindow(mainWindow), m_MainWindow(mainWindow),
m_StartMain(startMain) m_StartMain(startMain)
{ {
setupUi(this); setupUi(this);
#if defined(Q_OS_MAC) #if defined(Q_OS_MAC)
// the mac style needs a little more room because of the // the mac style needs a little more room because of the
// graphic on the left. // graphic on the left.
resize(600, 500); resize(600, 500);
setMinimumSize(size()); setMinimumSize(size());
#elif defined(Q_OS_WIN) #elif defined(Q_OS_WIN)
// when areo is disabled on windows, the next/back buttons // when areo is disabled on windows, the next/back buttons
// are hidden (must be a qt bug) -- resizing the window // are hidden (must be a qt bug) -- resizing the window
// to +1 of the original height seems to fix this. // to +1 of the original height seems to fix this.
// NOTE: calling setMinimumSize after this will break // NOTE: calling setMinimumSize after this will break
// it again, so don't do that. // it again, so don't do that.
resize(size().width(), size().height() + 1); resize(size().width(), size().height() + 1);
#endif #endif
connect(m_pServerRadioButton, SIGNAL(toggled(bool)), m_MainWindow.m_pGroupServer, SLOT(setChecked(bool))); connect(m_pServerRadioButton, SIGNAL(toggled(bool)), m_MainWindow.m_pGroupServer, SLOT(setChecked(bool)));
connect(m_pClientRadioButton, SIGNAL(toggled(bool)), m_MainWindow.m_pGroupClient, SLOT(setChecked(bool))); connect(m_pClientRadioButton, SIGNAL(toggled(bool)), m_MainWindow.m_pGroupClient, SLOT(setChecked(bool)));
m_Locale.fillLanguageComboBox(m_pComboLanguage); m_Locale.fillLanguageComboBox(m_pComboLanguage);
setIndexFromItemData(m_pComboLanguage, m_MainWindow.appConfig().language()); setIndexFromItemData(m_pComboLanguage, m_MainWindow.appConfig().language());
AppConfig& appConfig = m_MainWindow.appConfig(); AppConfig& appConfig = m_MainWindow.appConfig();
QString premiumEmail = appConfig.premiumEmail(); QString premiumEmail = appConfig.premiumEmail();
if (!premiumEmail.isEmpty()) if (!premiumEmail.isEmpty())
{ {
m_pRadioButtonPremiumLogin->setChecked(true); m_pRadioButtonPremiumLogin->setChecked(true);
m_pLineEditPremiumEmail->setText(premiumEmail); m_pLineEditPremiumEmail->setText(premiumEmail);
} }
} }
SetupWizard::~SetupWizard() SetupWizard::~SetupWizard()
{ {
} }
bool SetupWizard::validateCurrentPage() bool SetupWizard::validateCurrentPage()
{ {
QMessageBox message; QMessageBox message;
message.setWindowTitle(tr("Setup Synergy")); message.setWindowTitle(tr("Setup Synergy"));
message.setIcon(QMessageBox::Information); message.setIcon(QMessageBox::Information);
if (currentPage() == m_pNodePage) if (currentPage() == m_pNodePage)
{ {
bool result = m_pClientRadioButton->isChecked() || bool result = m_pClientRadioButton->isChecked() ||
m_pServerRadioButton->isChecked(); m_pServerRadioButton->isChecked();
if (!result) if (!result)
{ {
message.setText(tr("Please select an option.")); message.setText(tr("Please select an option."));
message.exec(); message.exec();
return false; return false;
} }
} }
else if (currentPage() == m_pPremiumUserPage) else if (currentPage() == m_pPremiumUserPage)
{ {
if (m_pRadioButtonPremiumLogin->isChecked()) if (m_pRadioButtonPremiumLogin->isChecked())
{ {
if (m_pLineEditPremiumEmail->text().isEmpty() || if (m_pLineEditPremiumEmail->text().isEmpty() ||
m_pLineEditPremiumPassword->text().isEmpty()) m_pLineEditPremiumPassword->text().isEmpty())
{ {
message.setText(tr("Please enter your email address and password.")); message.setText(tr("Please enter your email address and password."));
message.exec(); message.exec();
return false; return false;
} }
else if (!isPremiumLoginValid(message)) else if (!isPremiumLoginValid(message))
{ {
return false; return false;
} }
else else
{ {
m_pComboCryptoMode->setCurrentIndex(0); m_pComboCryptoMode->setCurrentIndex(0);
m_pComboCryptoMode->setEnabled(true); m_pComboCryptoMode->setEnabled(true);
} }
} }
else if (m_pRadioButtonPremiumRegister->isChecked()) else if (m_pRadioButtonPremiumRegister->isChecked())
{ {
const QUrl url(QString(PREMIUM_REGISTER_URL)); const QUrl url(QString(PREMIUM_REGISTER_URL));
QDesktopServices::openUrl(url); QDesktopServices::openUrl(url);
m_pRadioButtonPremiumLogin->setChecked(true); m_pRadioButtonPremiumLogin->setChecked(true);
return false; return false;
} }
else if (m_pRadioButtonPremiumLater->isChecked()) else if (m_pRadioButtonPremiumLater->isChecked())
{ {
int size = m_pComboCryptoMode->count(); int size = m_pComboCryptoMode->count();
m_pComboCryptoMode->setCurrentIndex(size - 1); m_pComboCryptoMode->setCurrentIndex(size - 1);
m_pComboCryptoMode->setEnabled(false); m_pComboCryptoMode->setEnabled(false);
} }
else { else {
message.setText(tr("Please select an option.")); message.setText(tr("Please select an option."));
message.exec(); message.exec();
return false; return false;
} }
} }
else if (currentPage() == m_pCryptoPage) else if (currentPage() == m_pCryptoPage)
{ {
QString modeText = m_pComboCryptoMode->currentText(); QString modeText = m_pComboCryptoMode->currentText();
if (modeText.isEmpty()) if (modeText.isEmpty())
{ {
message.setText(tr("Encryption mode required.")); message.setText(tr("Encryption mode required."));
message.exec(); message.exec();
return false; return false;
} }
if (parseCryptoMode(modeText) != Disabled) if (parseCryptoMode(modeText) != Disabled)
{ {
if (m_pLineEditCryptoPassword1->text().isEmpty()) if (m_pLineEditCryptoPassword1->text().isEmpty())
{ {
message.setText(tr("Encryption password required.")); message.setText(tr("Encryption password required."));
message.exec(); message.exec();
return false; return false;
} }
if (m_pLineEditCryptoPassword1->text() != m_pLineEditCryptoPassword2->text()) if (m_pLineEditCryptoPassword1->text() != m_pLineEditCryptoPassword2->text())
{ {
message.setText(tr("Encryption password and confirmation do not match.")); message.setText(tr("Encryption password and confirmation do not match."));
message.exec(); message.exec();
return false; return false;
} }
} }
} }
return true; return true;
} }
void SetupWizard::changeEvent(QEvent* event) void SetupWizard::changeEvent(QEvent* event)
{ {
if (event != 0) if (event != 0)
{ {
switch (event->type()) switch (event->type())
{ {
case QEvent::LanguageChange: case QEvent::LanguageChange:
{ {
m_pComboLanguage->blockSignals(true); m_pComboLanguage->blockSignals(true);
retranslateUi(this); retranslateUi(this);
m_pComboLanguage->blockSignals(false); m_pComboLanguage->blockSignals(false);
break; break;
} }
default: default:
QWizard::changeEvent(event); QWizard::changeEvent(event);
} }
} }
} }
void SetupWizard::accept() void SetupWizard::accept()
{ {
AppConfig& appConfig = m_MainWindow.appConfig(); AppConfig& appConfig = m_MainWindow.appConfig();
appConfig.setCryptoMode(parseCryptoMode(m_pComboCryptoMode->currentText())); appConfig.setCryptoMode(parseCryptoMode(m_pComboCryptoMode->currentText()));
appConfig.setCryptoPass(m_pLineEditCryptoPassword1->text()); appConfig.setCryptoPass(m_pLineEditCryptoPassword1->text());
appConfig.setLanguage(m_pComboLanguage->itemData(m_pComboLanguage->currentIndex()).toString()); appConfig.setLanguage(m_pComboLanguage->itemData(m_pComboLanguage->currentIndex()).toString());
appConfig.setPremiumEmail(m_pLineEditPremiumEmail->text()); appConfig.setPremiumEmail(m_pLineEditPremiumEmail->text());
if (!m_pRadioButtonPremiumLogin->isChecked()) if (!m_pRadioButtonPremiumLogin->isChecked())
{ {
appConfig.setPremiumToken(""); appConfig.setPremiumToken("");
} }
else else
{ {
QString mac = getFirstMacAddress(); QString mac = getFirstMacAddress();
QString hashSrc = m_pLineEditPremiumEmail->text() + mac; QString hashSrc = m_pLineEditPremiumEmail->text() + mac;
QString hashResult = hash(hashSrc); QString hashResult = hash(hashSrc);
appConfig.setPremiumToken(hashResult); appConfig.setPremiumToken(hashResult);
} }
appConfig.setWizardHasRun(); appConfig.setWizardHasRun();
appConfig.saveSettings(); appConfig.saveSettings();
QSettings& settings = m_MainWindow.settings(); QSettings& settings = m_MainWindow.settings();
if (m_pServerRadioButton->isChecked()) if (m_pServerRadioButton->isChecked())
{ {
settings.setValue("groupServerChecked", true); settings.setValue("groupServerChecked", true);
settings.setValue("groupClientChecked", false); settings.setValue("groupClientChecked", false);
} }
if (m_pClientRadioButton->isChecked()) if (m_pClientRadioButton->isChecked())
{ {
settings.setValue("groupClientChecked", true); settings.setValue("groupClientChecked", true);
settings.setValue("groupServerChecked", false); settings.setValue("groupServerChecked", false);
} }
settings.sync(); settings.sync();
if (m_StartMain) if (m_StartMain)
{ {
m_MainWindow.start(true); m_MainWindow.start(true);
} }
QWizard::accept(); QWizard::accept();
} }
void SetupWizard::reject() void SetupWizard::reject()
{ {
QSynergyApplication::getInstance()->switchTranslator(m_MainWindow.appConfig().language()); QSynergyApplication::getInstance()->switchTranslator(m_MainWindow.appConfig().language());
if (m_StartMain) if (m_StartMain)
{ {
m_MainWindow.start(true); m_MainWindow.start(true);
} }
QWizard::reject(); QWizard::reject();
} }
void SetupWizard::on_m_pComboCryptoMode_currentIndexChanged(int index) void SetupWizard::on_m_pComboCryptoMode_currentIndexChanged(int index)
{ {
bool enabled = parseCryptoMode(m_pComboCryptoMode->currentText()) != Disabled; bool enabled = parseCryptoMode(m_pComboCryptoMode->currentText()) != Disabled;
m_pLineEditCryptoPassword1->setEnabled(enabled); m_pLineEditCryptoPassword1->setEnabled(enabled);
m_pLineEditCryptoPassword2->setEnabled(enabled); m_pLineEditCryptoPassword2->setEnabled(enabled);
} }
CryptoMode SetupWizard::parseCryptoMode(const QString& s) CryptoMode SetupWizard::parseCryptoMode(const QString& s)
{ {
if (s.startsWith("OFB")) if (s.startsWith("OFB"))
{ {
return OFB; return OFB;
} }
else if (s.startsWith("CFB")) else if (s.startsWith("CFB"))
{ {
return CFB; return CFB;
} }
else if (s.startsWith("CTR")) else if (s.startsWith("CTR"))
{ {
return CTR; return CTR;
} }
else if (s.startsWith("GCM")) else if (s.startsWith("GCM"))
{ {
return GCM; return GCM;
} }
return Disabled; return Disabled;
} }
void SetupWizard::on_m_pComboLanguage_currentIndexChanged(int index) void SetupWizard::on_m_pComboLanguage_currentIndexChanged(int index)
{ {
QString ietfCode = m_pComboLanguage->itemData(index).toString(); QString ietfCode = m_pComboLanguage->itemData(index).toString();
QSynergyApplication::getInstance()->switchTranslator(ietfCode); QSynergyApplication::getInstance()->switchTranslator(ietfCode);
} }
void SetupWizard::on_m_pRadioButtonPremiumLogin_toggled(bool checked) void SetupWizard::on_m_pRadioButtonPremiumLogin_toggled(bool checked)
{ {
m_pLineEditPremiumEmail->setEnabled(checked); m_pLineEditPremiumEmail->setEnabled(checked);
m_pLineEditPremiumPassword->setEnabled(checked); m_pLineEditPremiumPassword->setEnabled(checked);
} }
bool SetupWizard::isPremiumLoginValid(QMessageBox& message) bool SetupWizard::isPremiumLoginValid(QMessageBox& message)
{ {
QString email = m_pLineEditPremiumEmail->text(); QString email = m_pLineEditPremiumEmail->text();
QString password = m_pLineEditPremiumPassword->text(); QString password = m_pLineEditPremiumPassword->text();
QString requestJson = "{\"email\":\"" + email + "\",\"password\":\"" + password + "\"}"; QString requestJson = "{\"email\":\"" + email + "\",\"password\":\"" + password + "\"}";
QByteArray requestData(requestJson.toStdString().c_str()); QByteArray requestData(requestJson.toStdString().c_str());
QString version = m_MainWindow.versionChecker().getVersion(); QString version = m_MainWindow.versionChecker().getVersion();
QString userAgent = "Synergy GUI " + version; QString userAgent = "Synergy GUI " + version;
QByteArray userAgentData(userAgent.toStdString().c_str()); QByteArray userAgentData(userAgent.toStdString().c_str());
QNetworkRequest request(QUrl(PREMIUM_AUTH_URL)); QNetworkRequest request(QUrl(PREMIUM_AUTH_URL));
request.setRawHeader("User-Agent", userAgentData); request.setRawHeader("User-Agent", userAgentData);
QUrl params; QUrl params;
params.addEncodedQueryItem("json", requestData); params.addEncodedQueryItem("json", requestData);
QNetworkReply* reply = m_Network.post(request, params.encodedQuery()); QNetworkReply* reply = m_Network.post(request, params.encodedQuery());
// use loop instead of waitForReadyRead (which doesnt seem to work). // use loop instead of waitForReadyRead (which doesnt seem to work).
QEventLoop loop; QEventLoop loop;
connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec(); loop.exec();
if (reply->error() != QNetworkReply::NoError) { if (reply->error() != QNetworkReply::NoError) {
message.setText(tr("Login failed, an error occurred.\n\nError: %1").arg(reply->errorString())); message.setText(tr("Login failed, an error occurred.\n\nError: %1").arg(reply->errorString()));
message.exec(); message.exec();
return false; return false;
} }
QByteArray responseData = reply->readAll(); QByteArray responseData = reply->readAll();
QString responseJson(responseData); QString responseJson(responseData);
// this feels like a lot of work, but its cheaper than getting a json // this feels like a lot of work, but its cheaper than getting a json
// parsing library involved. // parsing library involved.
QRegExp regex(".*\"result\":\\s*([^,}\\s]+).*"); QRegExp regex(".*\"result\":\\s*([^,}\\s]+).*");
if (regex.exactMatch(responseJson)) { if (regex.exactMatch(responseJson)) {
QString boolString = regex.cap(1); QString boolString = regex.cap(1);
if (boolString == "true") { if (boolString == "true") {
return true; return true;
} }
else if (boolString == "false") { else if (boolString == "false") {
message.setText(tr("Login failed, invalid email or password.")); message.setText(tr("Login failed, invalid email or password."));
message.exec(); message.exec();
return false; return false;
} }
} }
message.setText(tr("Login failed, an error occurred.\n\nServer response:\n\n%1").arg(responseJson.trimmed())); message.setText(tr("Login failed, an error occurred.\n\nServer response:\n\n%1").arg(responseJson.trimmed()));
message.exec(); message.exec();
return false; return false;
} }

View File

@ -1,57 +1,57 @@
/* /*
* synergy -- mouse and keyboard sharing utility * synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012 Bolton Software Ltd. * Copyright (C) 2012 Bolton Software Ltd.
* *
* This package is free software; you can redistribute it and/or * This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file. * found in the file COPYING that should have accompanied this file.
* *
* This package is distributed in the hope that it will be useful, * This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "ui_SetupWizardBase.h" #include "ui_SetupWizardBase.h"
#include "CryptoMode.h" #include "CryptoMode.h"
#include "SynergyLocale.h" #include "SynergyLocale.h"
#include <QWizard> #include <QWizard>
#include <QNetworkAccessManager> #include <QNetworkAccessManager>
class MainWindow; class MainWindow;
class QMessageBox; class QMessageBox;
class SetupWizard : public QWizard, public Ui::SetupWizardBase class SetupWizard : public QWizard, public Ui::SetupWizardBase
{ {
Q_OBJECT Q_OBJECT
public: public:
SetupWizard(MainWindow& mainWindow, bool startMain); SetupWizard(MainWindow& mainWindow, bool startMain);
virtual ~SetupWizard(); virtual ~SetupWizard();
bool validateCurrentPage(); bool validateCurrentPage();
protected: protected:
void changeEvent(QEvent* event); void changeEvent(QEvent* event);
void accept(); void accept();
void reject(); void reject();
private: private:
CryptoMode parseCryptoMode(const QString& s); CryptoMode parseCryptoMode(const QString& s);
bool isPremiumLoginValid(QMessageBox& message); bool isPremiumLoginValid(QMessageBox& message);
private: private:
MainWindow& m_MainWindow; MainWindow& m_MainWindow;
bool m_StartMain; bool m_StartMain;
SynergyLocale m_Locale; SynergyLocale m_Locale;
QNetworkAccessManager m_Network; QNetworkAccessManager m_Network;
private slots: private slots:
void on_m_pComboCryptoMode_currentIndexChanged(int index); void on_m_pComboCryptoMode_currentIndexChanged(int index);
void on_m_pComboLanguage_currentIndexChanged(int index); void on_m_pComboLanguage_currentIndexChanged(int index);
void on_m_pRadioButtonPremiumLogin_toggled(bool checked); void on_m_pRadioButtonPremiumLogin_toggled(bool checked);
}; };

View File

@ -1,68 +1,68 @@
/* /*
* synergy -- mouse and keyboard sharing utility * synergy -- mouse and keyboard sharing utility
* Copyright (C) 2013 Bolton Software Ltd. * Copyright (C) 2013 Bolton Software Ltd.
* *
* This package is free software; you can redistribute it and/or * This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file. * found in the file COPYING that should have accompanied this file.
* *
* This package is distributed in the hope that it will be useful, * This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
*/ */
#include "SynergyLocale.h" #include "SynergyLocale.h"
#include <QResource> #include <QResource>
#include <QtXml/QXmlStreamReader> #include <QtXml/QXmlStreamReader>
#include <QDebug> #include <QDebug>
SynergyLocale::SynergyLocale() SynergyLocale::SynergyLocale()
{ {
loadLanguages(); loadLanguages();
} }
void SynergyLocale::loadLanguages() void SynergyLocale::loadLanguages()
{ {
QResource resource(":/res/lang/Languages.xml"); QResource resource(":/res/lang/Languages.xml");
QByteArray bytes(reinterpret_cast<const char*>(resource.data()), resource.size()); QByteArray bytes(reinterpret_cast<const char*>(resource.data()), resource.size());
QXmlStreamReader xml(bytes); QXmlStreamReader xml(bytes);
while (!xml.atEnd()) while (!xml.atEnd())
{ {
QXmlStreamReader::TokenType token = xml.readNext(); QXmlStreamReader::TokenType token = xml.readNext();
if (xml.hasError()) if (xml.hasError())
{ {
qCritical() << xml.errorString(); qCritical() << xml.errorString();
throw std::exception(); throw std::exception();
} }
if (xml.name() == "language" && token == QXmlStreamReader::StartElement) if (xml.name() == "language" && token == QXmlStreamReader::StartElement)
{ {
QXmlStreamAttributes attributes = xml.attributes(); QXmlStreamAttributes attributes = xml.attributes();
addLanguage( addLanguage(
attributes.value("ietfCode").toString(), attributes.value("ietfCode").toString(),
attributes.value("name").toString()); attributes.value("name").toString());
} }
} }
} }
void SynergyLocale::addLanguage(const QString& ietfCode, const QString& name) void SynergyLocale::addLanguage(const QString& ietfCode, const QString& name)
{ {
m_Languages.push_back(SynergyLocale::Language(ietfCode, name)); m_Languages.push_back(SynergyLocale::Language(ietfCode, name));
} }
void SynergyLocale::fillLanguageComboBox(QComboBox* comboBox) void SynergyLocale::fillLanguageComboBox(QComboBox* comboBox)
{ {
comboBox->blockSignals(true); comboBox->blockSignals(true);
QVector<SynergyLocale::Language>::iterator it; QVector<SynergyLocale::Language>::iterator it;
for (it = m_Languages.begin(); it != m_Languages.end(); ++it) for (it = m_Languages.begin(); it != m_Languages.end(); ++it)
{ {
comboBox->addItem((*it).m_Name, (*it).m_IetfCode); comboBox->addItem((*it).m_Name, (*it).m_IetfCode);
} }
comboBox->blockSignals(false); comboBox->blockSignals(false);
} }

View File

@ -1,48 +1,48 @@
/* /*
* synergy -- mouse and keyboard sharing utility * synergy -- mouse and keyboard sharing utility
* Copyright (C) 2013 Bolton Software Ltd. * Copyright (C) 2013 Bolton Software Ltd.
* *
* This package is free software; you can redistribute it and/or * This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file. * found in the file COPYING that should have accompanied this file.
* *
* This package is distributed in the hope that it will be useful, * This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include <QString> #include <QString>
#include <QVector> #include <QVector>
#include <QComboBox> #include <QComboBox>
class SynergyLocale class SynergyLocale
{ {
class Language class Language
{ {
public: public:
Language() { } Language() { }
Language(const QString& IetfCode, const QString& name) Language(const QString& IetfCode, const QString& name)
: m_IetfCode(IetfCode), m_Name(name) { } : m_IetfCode(IetfCode), m_Name(name) { }
public: public:
QString m_IetfCode; QString m_IetfCode;
QString m_Name; QString m_Name;
}; };
public: public:
SynergyLocale(); SynergyLocale();
void fillLanguageComboBox(QComboBox* comboBox); void fillLanguageComboBox(QComboBox* comboBox);
private: private:
void loadLanguages(); void loadLanguages();
void addLanguage(const QString& IetfCode, const QString& name); void addLanguage(const QString& IetfCode, const QString& name);
private: private:
QVector<Language> m_Languages; QVector<Language> m_Languages;
}; };

View File

@ -1,30 +1,30 @@
/* /*
* synergy -- mouse and keyboard sharing utility * synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012 Bolton Software Ltd. * Copyright (C) 2012 Bolton Software Ltd.
* Copyright (C) 2012 Nick Bolton * Copyright (C) 2012 Nick Bolton
* *
* This package is free software; you can redistribute it and/or * This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file. * found in the file COPYING that should have accompanied this file.
* *
* This package is distributed in the hope that it will be useful, * This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "TcpSocketReader.h" #include "TcpSocketReader.h"
#include <QTcpSocket> #include <QTcpSocket>
IpcReader::IpcReader(QTcpSocket& socket) : IpcReader::IpcReader(QTcpSocket& socket) :
m_Socket(socket) m_Socket(socket)
{ {
connect(m_Socket, SIGNAL(readyRead()), this, SLOT(read())); connect(m_Socket, SIGNAL(readyRead()), this, SLOT(read()));
} }
IpcReader::~IpcReader() IpcReader::~IpcReader()
{ {
} }

View File

@ -1,103 +1,103 @@
/* /*
* synergy -- mouse and keyboard sharing utility * synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012 Bolton Software Ltd. * Copyright (C) 2012 Bolton Software Ltd.
* Copyright (C) 2012 Nick Bolton * Copyright (C) 2012 Nick Bolton
* *
* This package is free software; you can redistribute it and/or * This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file. * found in the file COPYING that should have accompanied this file.
* *
* This package is distributed in the hope that it will be useful, * This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "VersionChecker.h" #include "VersionChecker.h"
#include <QNetworkAccessManager> #include <QNetworkAccessManager>
#include <QNetworkRequest> #include <QNetworkRequest>
#include <QNetworkReply> #include <QNetworkReply>
#include <QProcess> #include <QProcess>
#include <QLocale> #include <QLocale>
#define VERSION_REGEX "(\\d+\\.\\d+\\.\\d+)" #define VERSION_REGEX "(\\d+\\.\\d+\\.\\d+)"
#define VERSION_URL "http://synergy-foss.org/version/" #define VERSION_URL "http://synergy-foss.org/version/"
VersionChecker::VersionChecker() VersionChecker::VersionChecker()
{ {
m_manager = new QNetworkAccessManager(this); m_manager = new QNetworkAccessManager(this);
connect(m_manager, SIGNAL(finished(QNetworkReply*)), connect(m_manager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(replyFinished(QNetworkReply*))); this, SLOT(replyFinished(QNetworkReply*)));
} }
VersionChecker::~VersionChecker() VersionChecker::~VersionChecker()
{ {
delete m_manager; delete m_manager;
} }
void VersionChecker::checkLatest() void VersionChecker::checkLatest()
{ {
m_manager->get(QNetworkRequest(QUrl(VERSION_URL))); m_manager->get(QNetworkRequest(QUrl(VERSION_URL)));
} }
void VersionChecker::replyFinished(QNetworkReply* reply) void VersionChecker::replyFinished(QNetworkReply* reply)
{ {
QString newestVersion = QString(reply->readAll()); QString newestVersion = QString(reply->readAll());
if (!newestVersion.isEmpty()) if (!newestVersion.isEmpty())
{ {
QString currentVersion = getVersion(); QString currentVersion = getVersion();
if (compareVersions(currentVersion, newestVersion) > 0) if (compareVersions(currentVersion, newestVersion) > 0)
emit updateFound(newestVersion); emit updateFound(newestVersion);
} }
} }
int VersionChecker::compareVersions(const QString& left, const QString& right) int VersionChecker::compareVersions(const QString& left, const QString& right)
{ {
if (left.compare(right) == 0) if (left.compare(right) == 0)
return 0; // versions are same. return 0; // versions are same.
QStringList leftSplit = left.split(QRegExp("\\.")); QStringList leftSplit = left.split(QRegExp("\\."));
if (leftSplit.size() != 3) if (leftSplit.size() != 3)
return 1; // assume right wins. return 1; // assume right wins.
QStringList rightSplit = right.split(QRegExp("\\.")); QStringList rightSplit = right.split(QRegExp("\\."));
if (rightSplit.size() != 3) if (rightSplit.size() != 3)
return -1; // assume left wins. return -1; // assume left wins.
int leftMajor = leftSplit.at(0).toInt(); int leftMajor = leftSplit.at(0).toInt();
int leftMinor = leftSplit.at(1).toInt(); int leftMinor = leftSplit.at(1).toInt();
int leftRev = leftSplit.at(2).toInt(); int leftRev = leftSplit.at(2).toInt();
int rightMajor = rightSplit.at(0).toInt(); int rightMajor = rightSplit.at(0).toInt();
int rightMinor = rightSplit.at(1).toInt(); int rightMinor = rightSplit.at(1).toInt();
int rightRev = rightSplit.at(2).toInt(); int rightRev = rightSplit.at(2).toInt();
bool rightWins = bool rightWins =
(rightMajor > leftMajor) || (rightMajor > leftMajor) ||
((rightMajor >= leftMajor) && (rightMinor > leftMinor)) || ((rightMajor >= leftMajor) && (rightMinor > leftMinor)) ||
((rightMajor >= leftMajor) && (rightMinor >= leftMinor) && (rightRev > leftRev)); ((rightMajor >= leftMajor) && (rightMinor >= leftMinor) && (rightRev > leftRev));
return rightWins ? 1 : -1; return rightWins ? 1 : -1;
} }
QString VersionChecker::getVersion() QString VersionChecker::getVersion()
{ {
QProcess process; QProcess process;
process.start(m_app, QStringList() << "--version"); process.start(m_app, QStringList() << "--version");
process.setReadChannel(QProcess::StandardOutput); process.setReadChannel(QProcess::StandardOutput);
if (process.waitForStarted() && process.waitForFinished()) if (process.waitForStarted() && process.waitForFinished())
{ {
QRegExp rx(VERSION_REGEX); QRegExp rx(VERSION_REGEX);
QString text = process.readLine(); QString text = process.readLine();
if (rx.indexIn(text) != -1) if (rx.indexIn(text) != -1)
return rx.cap(1); return rx.cap(1);
} }
return tr("Unknown"); return tr("Unknown");
} }

View File

@ -1,44 +1,44 @@
/* /*
* synergy -- mouse and keyboard sharing utility * synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012 Bolton Software Ltd. * Copyright (C) 2012 Bolton Software Ltd.
* Copyright (C) 2012 Nick Bolton * Copyright (C) 2012 Nick Bolton
* *
* This package is free software; you can redistribute it and/or * This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file. * found in the file COPYING that should have accompanied this file.
* *
* This package is distributed in the hope that it will be useful, * This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include <QObject> #include <QObject>
#include <QString> #include <QString>
class QNetworkAccessManager; class QNetworkAccessManager;
class QNetworkReply; class QNetworkReply;
class VersionChecker : public QObject class VersionChecker : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
VersionChecker(); VersionChecker();
virtual ~VersionChecker(); virtual ~VersionChecker();
void checkLatest(); void checkLatest();
QString getVersion(); QString getVersion();
void setApp(const QString& app) { m_app = app; } void setApp(const QString& app) { m_app = app; }
int compareVersions(const QString& left, const QString& right); int compareVersions(const QString& left, const QString& right);
public slots: public slots:
void replyFinished(QNetworkReply* reply); void replyFinished(QNetworkReply* reply);
signals: signals:
void updateFound(const QString& version); void updateFound(const QString& version);
private: private:
QNetworkAccessManager* m_manager; QNetworkAccessManager* m_manager;
QString m_app; QString m_app;
}; };

View File

@ -83,26 +83,26 @@ inet_aton(const char* cp, struct in_addr* inp)
// //
// CArchNetworkBSD // CArchNetworkBSD
// //
CArchNetworkBSD::CArchNetworkBSD() CArchNetworkBSD::CArchNetworkBSD()
{ {
} }
CArchNetworkBSD::~CArchNetworkBSD() CArchNetworkBSD::~CArchNetworkBSD()
{
ARCH->closeMutex(m_mutex);
}
void
CArchNetworkBSD::init()
{
// create mutex to make some calls thread safe
m_mutex = ARCH->newMutex();
}
CArchSocket
CArchNetworkBSD::newSocket(EAddressFamily family, ESocketType type)
{ {
ARCH->closeMutex(m_mutex);
}
void
CArchNetworkBSD::init()
{
// create mutex to make some calls thread safe
m_mutex = ARCH->newMutex();
}
CArchSocket
CArchNetworkBSD::newSocket(EAddressFamily family, ESocketType type)
{
// create socket // create socket
int fd = socket(s_family[family], s_type[type], 0); int fd = socket(s_family[family], s_type[type], 0);
if (fd == -1) { if (fd == -1) {

View File

@ -57,13 +57,13 @@ public:
//! Berkeley (BSD) sockets implementation of IArchNetwork //! Berkeley (BSD) sockets implementation of IArchNetwork
class CArchNetworkBSD : public IArchNetwork { class CArchNetworkBSD : public IArchNetwork {
public: public:
CArchNetworkBSD(); CArchNetworkBSD();
virtual ~CArchNetworkBSD(); virtual ~CArchNetworkBSD();
virtual void init(); virtual void init();
// IArchNetwork overrides // IArchNetwork overrides
virtual CArchSocket newSocket(EAddressFamily, ESocketType); virtual CArchSocket newSocket(EAddressFamily, ESocketType);
virtual CArchSocket copySocket(CArchSocket s); virtual void closeSocket(CArchSocket s); virtual CArchSocket copySocket(CArchSocket s); virtual void closeSocket(CArchSocket s);
virtual void closeSocketForRead(CArchSocket s); virtual void closeSocketForRead(CArchSocket s);
virtual void closeSocketForWrite(CArchSocket s); virtual void closeSocketForWrite(CArchSocket s);

View File

@ -60,7 +60,7 @@ interrupt(CArch::ESignal, void* data)
CEventQueue::CEventQueue() : CEventQueue::CEventQueue() :
m_systemTarget(0), m_systemTarget(0),
m_nextType(CEvent::kLast), m_nextType(CEvent::kLast),
m_typesForCClient(NULL), m_typesForCClient(NULL),
m_typesForIStream(NULL), m_typesForIStream(NULL),
m_typesForCIpcClient(NULL), m_typesForCIpcClient(NULL),

View File

@ -178,7 +178,7 @@ CLog::print(const char* file, int line, const char* fmt, ...)
// do not prefix time and file for kPRINT (CLOG_PRINT) // do not prefix time and file for kPRINT (CLOG_PRINT)
if (priority != kPRINT) { if (priority != kPRINT) {
char message[2048]; char message[kLogMessageLength];
#ifndef NDEBUG #ifndef NDEBUG
struct tm *tm; struct tm *tm;

View File

@ -137,6 +137,8 @@ private:
int m_maxPriority; int m_maxPriority;
}; };
const UInt16 kLogMessageLength = 2048;
/*! /*!
\def LOG(arg) \def LOG(arg)
Write to the log. Because macros cannot accept variable arguments, this Write to the log. Because macros cannot accept variable arguments, this

View File

@ -33,14 +33,20 @@
#include "CArch.h" #include "CArch.h"
#include "IPlatformScreen.h" #include "IPlatformScreen.h"
#include "CCryptoStream.h" #include "CCryptoStream.h"
#include "CThread.h"
#include "TMethodJob.h"
#include "CFileChunker.h"
#include <cstring> #include <cstring>
#include <cstdlib> #include <cstdlib>
#include <sstream> #include <sstream>
#include <fstream>
// //
// CClient // CClient
// //
const size_t CClient::m_chunkSize = 1024 * 512; // 512kb
CClient::CClient(IEventQueue* events, CClient::CClient(IEventQueue* events,
const CString& name, const CNetworkAddress& address, const CString& name, const CNetworkAddress& address,
ISocketFactory* socketFactory, ISocketFactory* socketFactory,
@ -438,6 +444,17 @@ CClient::sendConnectionFailedEvent(const char* msg)
m_events->addEvent(event); m_events->addEvent(event);
} }
void
CClient::sendFileChunk(const void* data)
{
CFileChunker::CFileChunk* fileChunk = reinterpret_cast<CFileChunker::CFileChunk*>(const_cast<void*>(data));
LOG((CLOG_DEBUG1 "sendFileChunk"));
assert(m_server != NULL);
// relay
m_server->fileChunkSending(fileChunk->m_chunk[0], &(fileChunk->m_chunk[1]), fileChunk->m_dataSize);
}
void void
CClient::setupConnecting() CClient::setupConnecting()
{ {
@ -737,6 +754,7 @@ CClient::handleGameDeviceFeedback(const CEvent& event, void*)
void void
CClient::handleFileChunkSending(const CEvent& event, void*) CClient::handleFileChunkSending(const CEvent& event, void*)
{ {
sendFileChunk(event.getData());
} }
void void
@ -763,3 +781,24 @@ CClient::isReceivedFileSizeValid()
{ {
return m_expectedFileSize == m_receivedFileData.size(); return m_expectedFileSize == m_receivedFileData.size();
} }
void
CClient::sendFileToServer(const char* filename)
{
CThread* thread = new CThread(
new TMethodJob<CClient>(
this, &CClient::sendFileThread,
reinterpret_cast<void*>(const_cast<char*>(filename))));
}
void
CClient::sendFileThread(void* filename)
{
try {
char* name = reinterpret_cast<char*>(filename);
CFileChunker::sendFileChunks(name, m_events, this);
}
catch (std::runtime_error error) {
LOG((CLOG_ERR "failed sending file chunks: %s", error.what()));
}
}

View File

@ -100,9 +100,9 @@ public:
//! Received a chunk of file data //! Received a chunk of file data
void fileChunkReceived(CString data); void fileChunkReceived(CString data);
//! Return true if recieved file size is valid //! Create a new thread and use it to send file to Server
bool isReceivedFileSizeValid(); void sendFileToServer(const char* filename);
//@} //@}
//! @name accessors //! @name accessors
@ -128,6 +128,9 @@ public:
*/ */
CNetworkAddress getServerAddress() const; CNetworkAddress getServerAddress() const;
//! Return true if recieved file size is valid
bool isReceivedFileSizeValid();
//@} //@}
// IScreen overrides // IScreen overrides
@ -167,6 +170,8 @@ private:
void sendClipboard(ClipboardID); void sendClipboard(ClipboardID);
void sendEvent(CEvent::Type, void*); void sendEvent(CEvent::Type, void*);
void sendConnectionFailedEvent(const char* msg); void sendConnectionFailedEvent(const char* msg);
void sendFileChunk(const void* data);
void sendFileThread(void*);
void setupConnecting(); void setupConnecting();
void setupConnection(); void setupConnection();
void setupScreen(); void setupScreen();
@ -188,7 +193,7 @@ private:
void handleGameDeviceTimingResp(const CEvent& event, void*); void handleGameDeviceTimingResp(const CEvent& event, void*);
void handleGameDeviceFeedback(const CEvent& event, void*); void handleGameDeviceFeedback(const CEvent& event, void*);
void handleFileChunkSending(const CEvent&, void*); void handleFileChunkSending(const CEvent&, void*);
public: public:
bool m_mock; bool m_mock;
@ -214,6 +219,7 @@ private:
CCryptoOptions m_crypto; CCryptoOptions m_crypto;
std::size_t m_expectedFileSize; std::size_t m_expectedFileSize;
CString m_receivedFileData; CString m_receivedFileData;
static const size_t m_chunkSize;
}; };
#endif #endif

View File

@ -935,7 +935,8 @@ CServerProxy::infoAcknowledgment()
m_ignoreMouse = false; m_ignoreMouse = false;
} }
void CServerProxy::fileChunkReceived() void
CServerProxy::fileChunkReceived()
{ {
// parse // parse
UInt8 mark; UInt8 mark;
@ -943,20 +944,42 @@ void CServerProxy::fileChunkReceived()
CProtocolUtil::readf(m_stream, kMsgDFileTransfer + 4, &mark, &content); CProtocolUtil::readf(m_stream, kMsgDFileTransfer + 4, &mark, &content);
switch (mark) { switch (mark) {
case '0': case kFileStart:
LOG((CLOG_DEBUG2 "recv file data: file size = %s", content)); LOG((CLOG_DEBUG2 "recv file data from server: size=%s", content.c_str()));
m_client->clearReceivedFileData(); m_client->clearReceivedFileData();
m_client->setExpectedFileSize(content); m_client->setExpectedFileSize(content);
break; break;
case '1': case kFileChunk:
LOG((CLOG_DEBUG2 "recv file data: chunck size = %i", content.size())); LOG((CLOG_DEBUG2 "recv file data from server: size=%i", content.size()));
m_client->fileChunkReceived(content); m_client->fileChunkReceived(content);
break; break;
case '2': case kFileEnd:
LOG((CLOG_DEBUG2 "file data transfer finished")); LOG((CLOG_DEBUG2 "file data transfer finished"));
m_events->addEvent(CEvent(m_events->forIScreen().fileRecieveComplete(), m_client)); m_events->addEvent(CEvent(m_events->forIScreen().fileRecieveComplete(), m_client));
break; break;
} }
} }
void
CServerProxy::fileChunkSending(UInt8 mark, char* data, size_t dataSize)
{
CString chunk(data, dataSize);
switch (mark) {
case kFileStart:
LOG((CLOG_DEBUG2 "file sending start: size=%s", data));
break;
case kFileChunk:
LOG((CLOG_DEBUG2 "file chunk sending: size=%i", chunk.size()));
break;
case kFileEnd:
LOG((CLOG_DEBUG2 "file sending finished"));
break;
}
CProtocolUtil::writef(m_stream, kMsgDFileTransfer, mark, &chunk);
}

View File

@ -56,6 +56,14 @@ public:
//@} //@}
//! @file transfer
//@{
//! sending file chunk to server
void fileChunkSending(UInt8 mark, char* data, size_t dataSize);
//@}
#ifdef TEST_ENV #ifdef TEST_ENV
void handleDataForTest() { handleData(CEvent(), NULL); } void handleDataForTest() { handleData(CEvent(), NULL); }
#endif #endif

View File

@ -1,39 +1,39 @@
/* /*
* synergy -- mouse and keyboard sharing utility * synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012 Bolton Software Ltd. * Copyright (C) 2012 Bolton Software Ltd.
* Copyright (C) 2012 Nick Bolton * Copyright (C) 2012 Nick Bolton
* *
* This package is free software; you can redistribute it and/or * This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file. * found in the file COPYING that should have accompanied this file.
* *
* This package is distributed in the hope that it will be useful, * This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "ILogOutputter.h" #include "ILogOutputter.h"
//! Write log to debugger //! Write log to debugger
/*! /*!
This outputter writes output to the debugger. In Visual Studio, this This outputter writes output to the debugger. In Visual Studio, this
can be seen in the Output window. can be seen in the Output window.
*/ */
class CMSWindowsDebugOutputter : public ILogOutputter { class CMSWindowsDebugOutputter : public ILogOutputter {
public: public:
CMSWindowsDebugOutputter(); CMSWindowsDebugOutputter();
virtual ~CMSWindowsDebugOutputter(); virtual ~CMSWindowsDebugOutputter();
// ILogOutputter overrides // ILogOutputter overrides
virtual void open(const char* title); virtual void open(const char* title);
virtual void close(); virtual void close();
virtual void show(bool showIfEmpty); virtual void show(bool showIfEmpty);
virtual bool write(ELevel level, const char* message); virtual bool write(ELevel level, const char* message);
virtual void flush(); virtual void flush();
}; };

View File

@ -203,7 +203,7 @@ CMSWindowsRelauncher::duplicateProcessToken(HANDLE process, LPSECURITY_ATTRIBUTE
LOG((CLOG_ERR "could not open token, process handle: %d (error: %i)", process, GetLastError())); LOG((CLOG_ERR "could not open token, process handle: %d (error: %i)", process, GetLastError()));
return NULL; return NULL;
} }
LOG((CLOG_DEBUG "got token %i, duplicating", sourceToken)); LOG((CLOG_DEBUG "got token %i, duplicating", sourceToken));
HANDLE newToken; HANDLE newToken;
@ -216,7 +216,7 @@ CMSWindowsRelauncher::duplicateProcessToken(HANDLE process, LPSECURITY_ATTRIBUTE
sourceToken, GetLastError())); sourceToken, GetLastError()));
return NULL; return NULL;
} }
LOG((CLOG_DEBUG "duplicated, new token: %i", newToken)); LOG((CLOG_DEBUG "duplicated, new token: %i", newToken));
return newToken; return newToken;
} }
@ -265,7 +265,7 @@ CMSWindowsRelauncher::getSessionToken(DWORD sessionId, LPSECURITY_ATTRIBUTES sec
LOG((CLOG_ERR "could not duplicate token (error: %i)", GetLastError())); LOG((CLOG_ERR "could not duplicate token (error: %i)", GetLastError()));
return 0; return 0;
} }
LOG((CLOG_DEBUG "duplicated, new token: %i", newToken)); LOG((CLOG_DEBUG "duplicated, new token: %i", newToken));
return newToken; return newToken;
} }
@ -284,10 +284,10 @@ CMSWindowsRelauncher::mainLoop(void*)
DWORD sessionId = -1; DWORD sessionId = -1;
bool launched = false; bool launched = false;
SECURITY_ATTRIBUTES saAttr; SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE; saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL; saAttr.lpSecurityDescriptor = NULL;
if (!CreatePipe(&m_stdOutRead, &m_stdOutWrite, &saAttr, 0)) { if (!CreatePipe(&m_stdOutRead, &m_stdOutWrite, &saAttr, 0)) {
@ -308,27 +308,27 @@ CMSWindowsRelauncher::mainLoop(void*)
sendSasEvent = CreateEvent(NULL, FALSE, FALSE, "Global\\SendSAS"); sendSasEvent = CreateEvent(NULL, FALSE, FALSE, "Global\\SendSAS");
} }
DWORD newSessionId = getSessionId(); DWORD newSessionId = getSessionId();
bool running = false; bool running = false;
if (launched) { if (launched) {
DWORD exitCode; DWORD exitCode;
GetExitCodeProcess(pi.hProcess, &exitCode); GetExitCodeProcess(pi.hProcess, &exitCode);
running = (exitCode == STILL_ACTIVE); running = (exitCode == STILL_ACTIVE);
if (!running) { if (!running) {
failures++; failures++;
LOG((CLOG_INFO "detected application not running, pid=%d, failures=%d", pi.dwProcessId, failures)); LOG((CLOG_INFO "detected application not running, pid=%d, failures=%d", pi.dwProcessId, failures));
// increasing backoff period, maximum of 10 seconds. // increasing backoff period, maximum of 10 seconds.
int timeout = (failures * 2) < 10 ? (failures * 2) : 10; int timeout = (failures * 2) < 10 ? (failures * 2) : 10;
LOG((CLOG_DEBUG "waiting, backoff period is %d seconds", timeout)); LOG((CLOG_DEBUG "waiting, backoff period is %d seconds", timeout));
ARCH->sleep(timeout); ARCH->sleep(timeout);
// double check, in case process started after we waited. // double check, in case process started after we waited.
GetExitCodeProcess(pi.hProcess, &exitCode); GetExitCodeProcess(pi.hProcess, &exitCode);
running = (exitCode == STILL_ACTIVE); running = (exitCode == STILL_ACTIVE);
} }
else { else {
// reset failures when running. // reset failures when running.
@ -383,7 +383,7 @@ CMSWindowsRelauncher::mainLoop(void*)
si.cb = sizeof(STARTUPINFO); si.cb = sizeof(STARTUPINFO);
si.lpDesktop = "winsta0\\Default"; // TODO: maybe this should be \winlogon if we have logonui.exe? si.lpDesktop = "winsta0\\Default"; // TODO: maybe this should be \winlogon if we have logonui.exe?
si.hStdError = m_stdOutWrite; si.hStdError = m_stdOutWrite;
si.hStdOutput = m_stdOutWrite; si.hStdOutput = m_stdOutWrite;
si.dwFlags |= STARTF_USESTDHANDLES; si.dwFlags |= STARTF_USESTDHANDLES;
LPVOID environment; LPVOID environment;
@ -502,45 +502,45 @@ CMSWindowsRelauncher::outputLoop(void*)
} }
} }
} }
void void
CMSWindowsRelauncher::shutdownProcess(HANDLE handle, DWORD pid, int timeout) CMSWindowsRelauncher::shutdownProcess(HANDLE handle, DWORD pid, int timeout)
{ {
DWORD exitCode; DWORD exitCode;
GetExitCodeProcess(handle, &exitCode); GetExitCodeProcess(handle, &exitCode);
if (exitCode != STILL_ACTIVE) if (exitCode != STILL_ACTIVE)
return; return;
CIpcShutdownMessage shutdown; CIpcShutdownMessage shutdown;
m_ipcServer.send(shutdown, kIpcClientNode); m_ipcServer.send(shutdown, kIpcClientNode);
// wait for process to exit gracefully. // wait for process to exit gracefully.
double start = ARCH->time(); double start = ARCH->time();
while (true) while (true)
{ {
GetExitCodeProcess(handle, &exitCode); GetExitCodeProcess(handle, &exitCode);
if (exitCode != STILL_ACTIVE) { if (exitCode != STILL_ACTIVE) {
// yay, we got a graceful shutdown. there should be no hook in use errors! // yay, we got a graceful shutdown. there should be no hook in use errors!
LOG((CLOG_INFO "process %d was shutdown gracefully", pid)); LOG((CLOG_INFO "process %d was shutdown gracefully", pid));
break; break;
} }
else { else {
double elapsed = (ARCH->time() - start); double elapsed = (ARCH->time() - start);
if (elapsed > timeout) { if (elapsed > timeout) {
// if timeout reached, kill forcefully. // if timeout reached, kill forcefully.
// calling TerminateProcess on synergy is very bad! // calling TerminateProcess on synergy is very bad!
// it causes the hook DLL to stay loaded in some apps, // it causes the hook DLL to stay loaded in some apps,
// making it impossible to start synergy again. // making it impossible to start synergy again.
LOG((CLOG_WARN "shutdown timed out after %d secs, forcefully terminating", (int)elapsed)); LOG((CLOG_WARN "shutdown timed out after %d secs, forcefully terminating", (int)elapsed));
TerminateProcess(handle, kExitSuccess); TerminateProcess(handle, kExitSuccess);
break; break;
} }
ARCH->sleep(1); ARCH->sleep(1);
} }
} }
} }
void void
@ -597,4 +597,4 @@ CMSWindowsRelauncher::shutdownExistingProcesses()
} }
CloseHandle(snapshot); CloseHandle(snapshot);
} }

View File

@ -1477,16 +1477,16 @@ CXWindowsUtil::mapKeySymToKeyID(KeySym k)
case XK_ISO_Left_Tab: case XK_ISO_Left_Tab:
return kKeyLeftTab; return kKeyLeftTab;
case XK_ISO_Level3_Shift: case XK_ISO_Level3_Shift:
return kKeyAltGr; return kKeyAltGr;
#ifdef XK_ISO_Level5_Shift #ifdef XK_ISO_Level5_Shift
case XK_ISO_Level5_Shift: case XK_ISO_Level5_Shift:
return XK_ISO_Level5_Shift; //FIXME: there is no "usual" key for this... return XK_ISO_Level5_Shift; //FIXME: there is no "usual" key for this...
#endif #endif
case XK_ISO_Next_Group: case XK_ISO_Next_Group:
return kKeyNextGroup; return kKeyNextGroup;
case XK_ISO_Prev_Group: case XK_ISO_Prev_Group:
return kKeyPrevGroup; return kKeyPrevGroup;
@ -1582,16 +1582,16 @@ CXWindowsUtil::getModifierBitForKeySym(KeySym keysym)
return kKeyModifierBitSuper; return kKeyModifierBitSuper;
case XK_Mode_switch: case XK_Mode_switch:
case XK_ISO_Level3_Shift: case XK_ISO_Level3_Shift:
return kKeyModifierBitAltGr; return kKeyModifierBitAltGr;
#ifdef XK_ISO_Level5_Shift #ifdef XK_ISO_Level5_Shift
case XK_ISO_Level5_Shift: case XK_ISO_Level5_Shift:
return kKeyModifierBitLevel5Lock; return kKeyModifierBitLevel5Lock;
#endif #endif
case XK_Caps_Lock: case XK_Caps_Lock:
return kKeyModifierBitCapsLock; return kKeyModifierBitCapsLock;
case XK_Num_Lock: case XK_Num_Lock:
return kKeyModifierBitNumLock; return kKeyModifierBitNumLock;

View File

@ -14,329 +14,329 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/*-------------------------------------------------------------------------------------------------------- /*--------------------------------------------------------------------------------------------------------
Original comment: Original comment:
APIHIJACK.CPP - Based on DelayLoadProfileDLL.CPP, by Matt Pietrek for MSJ February 2000. APIHIJACK.CPP - Based on DelayLoadProfileDLL.CPP, by Matt Pietrek for MSJ February 2000.
http://msdn.microsoft.com/library/periodic/period00/hood0200.htm http://msdn.microsoft.com/library/periodic/period00/hood0200.htm
Adapted by Wade Brainerd, wadeb@wadeb.com Adapted by Wade Brainerd, wadeb@wadeb.com
--------------------------------------------------------------------------------------------------------*/ --------------------------------------------------------------------------------------------------------*/
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#include <stdio.h> #include <stdio.h>
#include "HookDLL.h" #include "HookDLL.h"
#include <sstream> #include <sstream>
std::stringstream _hookDllLogStream; std::stringstream _hookDllLogStream;
#define LOG(s) \ #define LOG(s) \
_hookDllLogStream.str(""); \ _hookDllLogStream.str(""); \
_hookDllLogStream << "Synergy HookDLL: " << s << std::endl; \ _hookDllLogStream << "Synergy HookDLL: " << s << std::endl; \
OutputDebugString( _hookDllLogStream.str().c_str() ); OutputDebugString( _hookDllLogStream.str().c_str() );
//=========================================================================== //===========================================================================
// Called from the DLPD_IAT_STUB stubs. Increments "count" field of the stub // Called from the DLPD_IAT_STUB stubs. Increments "count" field of the stub
void __cdecl DefaultHook( PVOID dummy ) void __cdecl DefaultHook( PVOID dummy )
{ {
// asm only supported on 32-bit // asm only supported on 32-bit
#ifdef _M_IX86 #ifdef _M_IX86
__asm pushad // Save all general purpose registers __asm pushad // Save all general purpose registers
// Get return address, then subtract 5 (size of a CALL X instruction) // Get return address, then subtract 5 (size of a CALL X instruction)
// The result points at a DLPD_IAT_STUB // The result points at a DLPD_IAT_STUB
// pointer math! &dummy-1 really subtracts sizeof(PVOID) // pointer math! &dummy-1 really subtracts sizeof(PVOID)
PDWORD pRetAddr = (PDWORD)(&dummy - 1); PDWORD pRetAddr = (PDWORD)(&dummy - 1);
DLPD_IAT_STUB * pDLPDStub = (DLPD_IAT_STUB *)(*pRetAddr - 5); DLPD_IAT_STUB * pDLPDStub = (DLPD_IAT_STUB *)(*pRetAddr - 5);
pDLPDStub->count++; pDLPDStub->count++;
#if 0 #if 0
// Remove the above conditional to get a cheezy API trace from // Remove the above conditional to get a cheezy API trace from
// the loader process. It's slow! // the loader process. It's slow!
if ( !IMAGE_SNAP_BY_ORDINAL( pDLPDStub->pszNameOrOrdinal) ) if ( !IMAGE_SNAP_BY_ORDINAL( pDLPDStub->pszNameOrOrdinal) )
{ {
LOG( "Called hooked function: " ); LOG( "Called hooked function: " );
LOG( (PSTR)pDLPDStub->pszNameOrOrdinal ); LOG( (PSTR)pDLPDStub->pszNameOrOrdinal );
} }
#endif #endif
__asm popad // Restore all general purpose registers __asm popad // Restore all general purpose registers
#endif #endif
} }
// This function must be __cdecl!!! // This function must be __cdecl!!!
void __cdecl DelayLoadProfileDLL_UpdateCount( PVOID dummy ); void __cdecl DelayLoadProfileDLL_UpdateCount( PVOID dummy );
PIMAGE_IMPORT_DESCRIPTOR g_pFirstImportDesc; PIMAGE_IMPORT_DESCRIPTOR g_pFirstImportDesc;
//=========================================================================== //===========================================================================
// Given an HMODULE, returns a pointer to the PE header // Given an HMODULE, returns a pointer to the PE header
PIMAGE_NT_HEADERS PEHeaderFromHModule(HMODULE hModule) PIMAGE_NT_HEADERS PEHeaderFromHModule(HMODULE hModule)
{ {
PIMAGE_NT_HEADERS pNTHeader = 0; PIMAGE_NT_HEADERS pNTHeader = 0;
__try __try
{ {
if ( PIMAGE_DOS_HEADER(hModule)->e_magic != IMAGE_DOS_SIGNATURE ) if ( PIMAGE_DOS_HEADER(hModule)->e_magic != IMAGE_DOS_SIGNATURE )
__leave; __leave;
pNTHeader = PIMAGE_NT_HEADERS(PBYTE(hModule) pNTHeader = PIMAGE_NT_HEADERS(PBYTE(hModule)
+ PIMAGE_DOS_HEADER(hModule)->e_lfanew); + PIMAGE_DOS_HEADER(hModule)->e_lfanew);
if ( pNTHeader->Signature != IMAGE_NT_SIGNATURE ) if ( pNTHeader->Signature != IMAGE_NT_SIGNATURE )
pNTHeader = 0; pNTHeader = 0;
} }
__except( EXCEPTION_EXECUTE_HANDLER ) __except( EXCEPTION_EXECUTE_HANDLER )
{ {
} }
return pNTHeader; return pNTHeader;
} }
//=========================================================================== //===========================================================================
// Builds stubs for and redirects the IAT for one DLL (pImportDesc) // Builds stubs for and redirects the IAT for one DLL (pImportDesc)
bool RedirectIAT( SDLLHook* DLLHook, PIMAGE_IMPORT_DESCRIPTOR pImportDesc, PVOID pBaseLoadAddr ) bool RedirectIAT( SDLLHook* DLLHook, PIMAGE_IMPORT_DESCRIPTOR pImportDesc, PVOID pBaseLoadAddr )
{ {
PIMAGE_THUNK_DATA pIAT; // Ptr to import address table PIMAGE_THUNK_DATA pIAT; // Ptr to import address table
PIMAGE_THUNK_DATA pINT; // Ptr to import names table PIMAGE_THUNK_DATA pINT; // Ptr to import names table
PIMAGE_THUNK_DATA pIteratingIAT; PIMAGE_THUNK_DATA pIteratingIAT;
// Figure out which OS platform we're on // Figure out which OS platform we're on
OSVERSIONINFO osvi; OSVERSIONINFO osvi;
osvi.dwOSVersionInfoSize = sizeof(osvi); osvi.dwOSVersionInfoSize = sizeof(osvi);
GetVersionEx( &osvi ); GetVersionEx( &osvi );
// If no import names table, we can't redirect this, so bail // If no import names table, we can't redirect this, so bail
if ( pImportDesc->OriginalFirstThunk == 0 ) if ( pImportDesc->OriginalFirstThunk == 0 )
{ {
LOG( "no IAT available." ); LOG( "no IAT available." );
return false; return false;
} }
pIAT = MakePtr( PIMAGE_THUNK_DATA, pBaseLoadAddr, pImportDesc->FirstThunk ); pIAT = MakePtr( PIMAGE_THUNK_DATA, pBaseLoadAddr, pImportDesc->FirstThunk );
pINT = MakePtr( PIMAGE_THUNK_DATA, pBaseLoadAddr, pImportDesc->OriginalFirstThunk ); pINT = MakePtr( PIMAGE_THUNK_DATA, pBaseLoadAddr, pImportDesc->OriginalFirstThunk );
// Count how many entries there are in this IAT. Array is 0 terminated // Count how many entries there are in this IAT. Array is 0 terminated
pIteratingIAT = pIAT; pIteratingIAT = pIAT;
unsigned cFuncs = 0; unsigned cFuncs = 0;
while ( pIteratingIAT->u1.Function ) while ( pIteratingIAT->u1.Function )
{ {
cFuncs++; cFuncs++;
pIteratingIAT++; pIteratingIAT++;
} }
if ( cFuncs == 0 ) // If no imported functions, we're done! if ( cFuncs == 0 ) // If no imported functions, we're done!
{ {
LOG( "no imported functions" ); LOG( "no imported functions" );
return false; return false;
} }
// These next few lines ensure that we'll be able to modify the IAT, // These next few lines ensure that we'll be able to modify the IAT,
// which is often in a read-only section in the EXE. // which is often in a read-only section in the EXE.
DWORD flOldProtect, flNewProtect, flDontCare; DWORD flOldProtect, flNewProtect, flDontCare;
MEMORY_BASIC_INFORMATION mbi; MEMORY_BASIC_INFORMATION mbi;
// Get the current protection attributes // Get the current protection attributes
VirtualQuery( pIAT, &mbi, sizeof(mbi) ); VirtualQuery( pIAT, &mbi, sizeof(mbi) );
// remove ReadOnly and ExecuteRead attributes, add on ReadWrite flag // remove ReadOnly and ExecuteRead attributes, add on ReadWrite flag
flNewProtect = mbi.Protect; flNewProtect = mbi.Protect;
flNewProtect &= ~(PAGE_READONLY | PAGE_EXECUTE_READ); flNewProtect &= ~(PAGE_READONLY | PAGE_EXECUTE_READ);
flNewProtect |= (PAGE_READWRITE); flNewProtect |= (PAGE_READWRITE);
if ( !VirtualProtect( pIAT, sizeof(PVOID) * cFuncs, if ( !VirtualProtect( pIAT, sizeof(PVOID) * cFuncs,
flNewProtect, &flOldProtect) ) flNewProtect, &flOldProtect) )
{ {
LOG( "could not remove ReadOnly and ExecuteRead attributes, or add ReadWrite flag" ); LOG( "could not remove ReadOnly and ExecuteRead attributes, or add ReadWrite flag" );
return false; return false;
} }
// If the Default hook is enabled, build an array of redirection stubs in the processes memory. // If the Default hook is enabled, build an array of redirection stubs in the processes memory.
DLPD_IAT_STUB * pStubs = 0; DLPD_IAT_STUB * pStubs = 0;
if ( DLLHook->UseDefault ) if ( DLLHook->UseDefault )
{ {
// Allocate memory for the redirection stubs. Make one extra stub at the // Allocate memory for the redirection stubs. Make one extra stub at the
// end to be a sentinel // end to be a sentinel
pStubs = new DLPD_IAT_STUB[ cFuncs + 1]; pStubs = new DLPD_IAT_STUB[ cFuncs + 1];
if ( !pStubs ) if ( !pStubs )
{ {
LOG( "could not allocate memory for redirection stubs" ); LOG( "could not allocate memory for redirection stubs" );
return false; return false;
} }
} }
// Scan through the IAT, completing the stubs and redirecting the IAT // Scan through the IAT, completing the stubs and redirecting the IAT
// entries to point to the stubs // entries to point to the stubs
pIteratingIAT = pIAT; pIteratingIAT = pIAT;
while ( pIteratingIAT->u1.Function ) while ( pIteratingIAT->u1.Function )
{ {
void* HookFn = 0; // Set to either the SFunctionHook or pStubs. void* HookFn = 0; // Set to either the SFunctionHook or pStubs.
if ( !IMAGE_SNAP_BY_ORDINAL( pINT->u1.Ordinal ) ) // import by name if ( !IMAGE_SNAP_BY_ORDINAL( pINT->u1.Ordinal ) ) // import by name
{ {
PIMAGE_IMPORT_BY_NAME pImportName = MakePtr( PIMAGE_IMPORT_BY_NAME, pBaseLoadAddr, pINT->u1.AddressOfData ); PIMAGE_IMPORT_BY_NAME pImportName = MakePtr( PIMAGE_IMPORT_BY_NAME, pBaseLoadAddr, pINT->u1.AddressOfData );
LOG( "checking function with name: " << pImportName->Name ); LOG( "checking function with name: " << pImportName->Name );
// Iterate through the hook functions, searching for this import. // Iterate through the hook functions, searching for this import.
SFunctionHook* FHook = DLLHook->Functions; SFunctionHook* FHook = DLLHook->Functions;
while ( FHook->Name ) while ( FHook->Name )
{ {
if ( lstrcmpi( FHook->Name, (char*)pImportName->Name ) == 0 ) if ( lstrcmpi( FHook->Name, (char*)pImportName->Name ) == 0 )
{ {
// Save the old function in the SFunctionHook structure and get the new one. // Save the old function in the SFunctionHook structure and get the new one.
FHook->OrigFn = (void*)pIteratingIAT->u1.Function; FHook->OrigFn = (void*)pIteratingIAT->u1.Function;
HookFn = FHook->HookFn; HookFn = FHook->HookFn;
LOG( "hooked function: " << pImportName->Name ); LOG( "hooked function: " << pImportName->Name );
break; break;
} }
FHook++; FHook++;
} }
// If the default function is enabled, store the name for the user. // If the default function is enabled, store the name for the user.
if ( DLLHook->UseDefault ) if ( DLLHook->UseDefault )
pStubs->pszNameOrOrdinal = (DWORD)&pImportName->Name; pStubs->pszNameOrOrdinal = (DWORD)&pImportName->Name;
} }
else // added comparison for ordinal else // added comparison for ordinal
{ {
LOG( "checking function at ordinal: " << pINT->u1.Ordinal ); LOG( "checking function at ordinal: " << pINT->u1.Ordinal );
SFunctionHook* FHook = DLLHook->Functions; SFunctionHook* FHook = DLLHook->Functions;
while ( FHook->Name ) while ( FHook->Name )
{ {
if ( (DWORD)FHook->Name == pINT->u1.Ordinal ) if ( (DWORD)FHook->Name == pINT->u1.Ordinal )
{ {
// Save the old function in the SFunctionHook structure and get the new one. // Save the old function in the SFunctionHook structure and get the new one.
FHook->OrigFn = (void*)pIteratingIAT->u1.Function; FHook->OrigFn = (void*)pIteratingIAT->u1.Function;
HookFn = FHook->HookFn; HookFn = FHook->HookFn;
LOG( "hooked ordinal: " << pINT->u1.Ordinal ); LOG( "hooked ordinal: " << pINT->u1.Ordinal );
break; break;
} }
FHook++; FHook++;
} }
// If the default function is enabled, store the ordinal for the user. // If the default function is enabled, store the ordinal for the user.
if ( DLLHook->UseDefault ) if ( DLLHook->UseDefault )
pStubs->pszNameOrOrdinal = (DWORD)pINT->u1.Ordinal; pStubs->pszNameOrOrdinal = (DWORD)pINT->u1.Ordinal;
} }
// If the default function is enabled, fill in the fields to the stub code. // If the default function is enabled, fill in the fields to the stub code.
if ( DLLHook->UseDefault ) if ( DLLHook->UseDefault )
{ {
pStubs->data_call = (DWORD)(PDWORD)DLLHook->DefaultFn pStubs->data_call = (DWORD)(PDWORD)DLLHook->DefaultFn
- (DWORD)(PDWORD)&pStubs->instr_JMP; - (DWORD)(PDWORD)&pStubs->instr_JMP;
pStubs->data_JMP = *(PDWORD)pIteratingIAT - (DWORD)(PDWORD)&pStubs->count; pStubs->data_JMP = *(PDWORD)pIteratingIAT - (DWORD)(PDWORD)&pStubs->count;
// If it wasn't manually hooked, use the Stub function. // If it wasn't manually hooked, use the Stub function.
if ( !HookFn ) if ( !HookFn )
HookFn = (void*)pStubs; HookFn = (void*)pStubs;
} }
// Replace the IAT function pointer if we have a hook. // Replace the IAT function pointer if we have a hook.
if ( HookFn ) if ( HookFn )
{ {
// Cheez-o hack to see if what we're importing is code or data. // Cheez-o hack to see if what we're importing is code or data.
// If it's code, we shouldn't be able to write to it // If it's code, we shouldn't be able to write to it
if ( IsBadWritePtr( (PVOID)pIteratingIAT->u1.Function, 1 ) ) if ( IsBadWritePtr( (PVOID)pIteratingIAT->u1.Function, 1 ) )
{ {
pIteratingIAT->u1.Function = (DWORD)(PDWORD)HookFn; pIteratingIAT->u1.Function = (DWORD)(PDWORD)HookFn;
} }
else if ( osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ) else if ( osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
{ {
// Special hack for Win9X, which builds stubs for imported // Special hack for Win9X, which builds stubs for imported
// functions in system DLLs (Loaded above 2GB). These stubs are // functions in system DLLs (Loaded above 2GB). These stubs are
// writeable, so we have to explicitly check for this case // writeable, so we have to explicitly check for this case
if ( pIteratingIAT->u1.Function > (DWORD)(PDWORD)0x80000000 ) if ( pIteratingIAT->u1.Function > (DWORD)(PDWORD)0x80000000 )
pIteratingIAT->u1.Function = (DWORD)(PDWORD)HookFn; pIteratingIAT->u1.Function = (DWORD)(PDWORD)HookFn;
} }
} }
if ( DLLHook->UseDefault ) if ( DLLHook->UseDefault )
pStubs++; // Advance to next stub pStubs++; // Advance to next stub
pIteratingIAT++; // Advance to next IAT entry pIteratingIAT++; // Advance to next IAT entry
pINT++; // Advance to next INT entry pINT++; // Advance to next INT entry
} }
if ( DLLHook->UseDefault ) if ( DLLHook->UseDefault )
pStubs->pszNameOrOrdinal = 0; // Final stub is a sentinel pStubs->pszNameOrOrdinal = 0; // Final stub is a sentinel
// Put the page attributes back the way they were. // Put the page attributes back the way they were.
VirtualProtect( pIAT, sizeof(PVOID) * cFuncs, flOldProtect, &flDontCare); VirtualProtect( pIAT, sizeof(PVOID) * cFuncs, flOldProtect, &flDontCare);
return true; return true;
} }
//=========================================================================== //===========================================================================
// Top level routine to find the EXE's imports, and redirect them // Top level routine to find the EXE's imports, and redirect them
bool HookAPICalls( SDLLHook* hook ) bool HookAPICalls( SDLLHook* hook )
{ {
if ( !hook ) if ( !hook )
{ {
LOG("no hook"); LOG("no hook");
return false; return false;
} }
HMODULE hModEXE = GetModuleHandle( 0 ); HMODULE hModEXE = GetModuleHandle( 0 );
PIMAGE_NT_HEADERS pExeNTHdr = PEHeaderFromHModule( hModEXE ); PIMAGE_NT_HEADERS pExeNTHdr = PEHeaderFromHModule( hModEXE );
if ( !pExeNTHdr ) if ( !pExeNTHdr )
{ {
LOG("no PE header"); LOG("no PE header");
return false; return false;
} }
DWORD importRVA = pExeNTHdr->OptionalHeader.DataDirectory DWORD importRVA = pExeNTHdr->OptionalHeader.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; [IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
if ( !importRVA ) if ( !importRVA )
{ {
LOG("no virtual address for image directory entry import"); LOG("no virtual address for image directory entry import");
return false; return false;
} }
// Convert imports RVA to a usable pointer // Convert imports RVA to a usable pointer
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = MakePtr( PIMAGE_IMPORT_DESCRIPTOR, PIMAGE_IMPORT_DESCRIPTOR pImportDesc = MakePtr( PIMAGE_IMPORT_DESCRIPTOR,
hModEXE, importRVA ); hModEXE, importRVA );
// Save off imports address in a global for later use // Save off imports address in a global for later use
g_pFirstImportDesc = pImportDesc; g_pFirstImportDesc = pImportDesc;
// Iterate through each import descriptor, and redirect if appropriate // Iterate through each import descriptor, and redirect if appropriate
while ( pImportDesc->FirstThunk ) while ( pImportDesc->FirstThunk )
{ {
PSTR pszImportModuleName = MakePtr( PSTR, hModEXE, pImportDesc->Name); PSTR pszImportModuleName = MakePtr( PSTR, hModEXE, pImportDesc->Name);
if ( lstrcmpi( pszImportModuleName, hook->Name ) == 0 ) if ( lstrcmpi( pszImportModuleName, hook->Name ) == 0 )
{ {
LOG( "found " << hook->Name << " in process" ); LOG( "found " << hook->Name << " in process" );
if ( RedirectIAT( hook, pImportDesc, (PVOID)hModEXE ) ) if ( RedirectIAT( hook, pImportDesc, (PVOID)hModEXE ) )
{ {
LOG( "redirected IAT ok" ); LOG( "redirected IAT ok" );
return true; return true;
} }
else else
{ {
LOG( "failed to redirect IAT" ); LOG( "failed to redirect IAT" );
} }
} }
pImportDesc++; // Advance to next import descriptor pImportDesc++; // Advance to next import descriptor
} }
return false; return false;
} }

View File

@ -14,68 +14,68 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/*-------------------------------------------------------------------------------------------------------- /*--------------------------------------------------------------------------------------------------------
Original comment: Original comment:
APIHIJACK.H - Based on DelayLoadProfileDLL.CPP, by Matt Pietrek for MSJ February 2000. APIHIJACK.H - Based on DelayLoadProfileDLL.CPP, by Matt Pietrek for MSJ February 2000.
http://msdn.microsoft.com/library/periodic/period00/hood0200.htm http://msdn.microsoft.com/library/periodic/period00/hood0200.htm
Adapted by Wade Brainerd, wadeb@wadeb.com Adapted by Wade Brainerd, wadeb@wadeb.com
--------------------------------------------------------------------------------------------------------*/ --------------------------------------------------------------------------------------------------------*/
#pragma once #pragma once
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#pragma warning(disable:4200) #pragma warning(disable:4200)
// Macro for convenient pointer addition. // Macro for convenient pointer addition.
// Essentially treats the last two parameters as DWORDs. The first // Essentially treats the last two parameters as DWORDs. The first
// parameter is used to typecast the result to the appropriate pointer type. // parameter is used to typecast the result to the appropriate pointer type.
#define MakePtr(cast, ptr, addValue ) (cast)( (DWORD)(ptr)+(DWORD)(addValue)) #define MakePtr(cast, ptr, addValue ) (cast)( (DWORD)(ptr)+(DWORD)(addValue))
// Default Hook Stub Structure: Contains data about the original function, Name/Ordinal, Address // Default Hook Stub Structure: Contains data about the original function, Name/Ordinal, Address
// and a Count field. This is actually a block of assembly code. // and a Count field. This is actually a block of assembly code.
#pragma pack( push, 1 ) #pragma pack( push, 1 )
struct DLPD_IAT_STUB struct DLPD_IAT_STUB
{ {
BYTE instr_CALL; BYTE instr_CALL;
DWORD data_call; DWORD data_call;
BYTE instr_JMP; BYTE instr_JMP;
DWORD data_JMP; DWORD data_JMP;
DWORD count; DWORD count;
DWORD pszNameOrOrdinal; DWORD pszNameOrOrdinal;
DLPD_IAT_STUB() : instr_CALL( 0xE8 ), instr_JMP( 0xE9 ), count( 0 ) {} DLPD_IAT_STUB() : instr_CALL( 0xE8 ), instr_JMP( 0xE9 ), count( 0 ) {}
}; };
#pragma pack( pop ) #pragma pack( pop )
// Example DefaultHook procedure, called from the DLPD_IAT_STUB stubs. // Example DefaultHook procedure, called from the DLPD_IAT_STUB stubs.
// Increments "count" field of the stub. // Increments "count" field of the stub.
// See the implementation for more information. // See the implementation for more information.
void __cdecl DefaultHook( PVOID dummy ); void __cdecl DefaultHook( PVOID dummy );
struct SFunctionHook struct SFunctionHook
{ {
char* Name; // Function name, e.g. "DirectDrawCreateEx". char* Name; // Function name, e.g. "DirectDrawCreateEx".
void* HookFn; // Address of your function. void* HookFn; // Address of your function.
void* OrigFn; // Stored by HookAPICalls, the address of the original function. void* OrigFn; // Stored by HookAPICalls, the address of the original function.
}; };
struct SDLLHook struct SDLLHook
{ {
// Name of the DLL, e.g. "DDRAW.DLL" // Name of the DLL, e.g. "DDRAW.DLL"
char* Name; char* Name;
// Set true to call the default for all non-hooked functions before they are executed. // Set true to call the default for all non-hooked functions before they are executed.
bool UseDefault; bool UseDefault;
void* DefaultFn; void* DefaultFn;
// Function hook array. Terminated with a NULL Name field. // Function hook array. Terminated with a NULL Name field.
SFunctionHook Functions[]; SFunctionHook Functions[];
}; };
// Hook functions one or more DLLs. // Hook functions one or more DLLs.
bool HookAPICalls( SDLLHook* hook ); bool HookAPICalls( SDLLHook* hook );

View File

@ -1,229 +1,229 @@
/*************************************************************************** /***************************************************************************
* * * *
* XInput.h -- This module defines XBOX controller APIs * * XInput.h -- This module defines XBOX controller APIs *
* and constansts for the Windows platform. * * and constansts for the Windows platform. *
* * * *
* Copyright (C) 2012 Bolton Software Ltd. * Copyright (C) 2012 Bolton Software Ltd.
* Copyright (c) Microsoft Corp. All rights reserved. * * Copyright (c) Microsoft Corp. All rights reserved. *
* * * *
***************************************************************************/ ***************************************************************************/
#ifndef _XINPUT_H_ #ifndef _XINPUT_H_
#define _XINPUT_H_ #define _XINPUT_H_
#include <windef.h> #include <windef.h>
// Current name of the DLL shipped in the same SDK as this header. // Current name of the DLL shipped in the same SDK as this header.
// The name reflects the current version // The name reflects the current version
#ifndef XINPUT_USE_9_1_0 #ifndef XINPUT_USE_9_1_0
#define XINPUT_DLL_A "xinput1_3.dll" #define XINPUT_DLL_A "xinput1_3.dll"
#define XINPUT_DLL_W L"xinput1_3.dll" #define XINPUT_DLL_W L"xinput1_3.dll"
#else #else
#define XINPUT_DLL_A "xinput9_1_0.dll" #define XINPUT_DLL_A "xinput9_1_0.dll"
#define XINPUT_DLL_W L"xinput9_1_0.dll" #define XINPUT_DLL_W L"xinput9_1_0.dll"
#endif #endif
#ifdef UNICODE #ifdef UNICODE
#define XINPUT_DLL XINPUT_DLL_W #define XINPUT_DLL XINPUT_DLL_W
#else #else
#define XINPUT_DLL XINPUT_DLL_A #define XINPUT_DLL XINPUT_DLL_A
#endif #endif
// //
// Device types available in XINPUT_CAPABILITIES // Device types available in XINPUT_CAPABILITIES
// //
#define XINPUT_DEVTYPE_GAMEPAD 0x01 #define XINPUT_DEVTYPE_GAMEPAD 0x01
// //
// Device subtypes available in XINPUT_CAPABILITIES // Device subtypes available in XINPUT_CAPABILITIES
// //
#define XINPUT_DEVSUBTYPE_GAMEPAD 0x01 #define XINPUT_DEVSUBTYPE_GAMEPAD 0x01
#ifndef XINPUT_USE_9_1_0 #ifndef XINPUT_USE_9_1_0
#define XINPUT_DEVSUBTYPE_WHEEL 0x02 #define XINPUT_DEVSUBTYPE_WHEEL 0x02
#define XINPUT_DEVSUBTYPE_ARCADE_STICK 0x03 #define XINPUT_DEVSUBTYPE_ARCADE_STICK 0x03
#define XINPUT_DEVSUBTYPE_FLIGHT_SICK 0x04 #define XINPUT_DEVSUBTYPE_FLIGHT_SICK 0x04
#define XINPUT_DEVSUBTYPE_DANCE_PAD 0x05 #define XINPUT_DEVSUBTYPE_DANCE_PAD 0x05
#define XINPUT_DEVSUBTYPE_GUITAR 0x06 #define XINPUT_DEVSUBTYPE_GUITAR 0x06
#define XINPUT_DEVSUBTYPE_DRUM_KIT 0x08 #define XINPUT_DEVSUBTYPE_DRUM_KIT 0x08
#endif // !XINPUT_USE_9_1_0 #endif // !XINPUT_USE_9_1_0
// //
// Flags for XINPUT_CAPABILITIES // Flags for XINPUT_CAPABILITIES
// //
#define XINPUT_CAPS_VOICE_SUPPORTED 0x0004 #define XINPUT_CAPS_VOICE_SUPPORTED 0x0004
// //
// Constants for gamepad buttons // Constants for gamepad buttons
// //
#define XINPUT_GAMEPAD_DPAD_UP 0x0001 #define XINPUT_GAMEPAD_DPAD_UP 0x0001
#define XINPUT_GAMEPAD_DPAD_DOWN 0x0002 #define XINPUT_GAMEPAD_DPAD_DOWN 0x0002
#define XINPUT_GAMEPAD_DPAD_LEFT 0x0004 #define XINPUT_GAMEPAD_DPAD_LEFT 0x0004
#define XINPUT_GAMEPAD_DPAD_RIGHT 0x0008 #define XINPUT_GAMEPAD_DPAD_RIGHT 0x0008
#define XINPUT_GAMEPAD_START 0x0010 #define XINPUT_GAMEPAD_START 0x0010
#define XINPUT_GAMEPAD_BACK 0x0020 #define XINPUT_GAMEPAD_BACK 0x0020
#define XINPUT_GAMEPAD_LEFT_THUMB 0x0040 #define XINPUT_GAMEPAD_LEFT_THUMB 0x0040
#define XINPUT_GAMEPAD_RIGHT_THUMB 0x0080 #define XINPUT_GAMEPAD_RIGHT_THUMB 0x0080
#define XINPUT_GAMEPAD_LEFT_SHOULDER 0x0100 #define XINPUT_GAMEPAD_LEFT_SHOULDER 0x0100
#define XINPUT_GAMEPAD_RIGHT_SHOULDER 0x0200 #define XINPUT_GAMEPAD_RIGHT_SHOULDER 0x0200
#define XINPUT_GAMEPAD_A 0x1000 #define XINPUT_GAMEPAD_A 0x1000
#define XINPUT_GAMEPAD_B 0x2000 #define XINPUT_GAMEPAD_B 0x2000
#define XINPUT_GAMEPAD_X 0x4000 #define XINPUT_GAMEPAD_X 0x4000
#define XINPUT_GAMEPAD_Y 0x8000 #define XINPUT_GAMEPAD_Y 0x8000
// //
// Gamepad thresholds // Gamepad thresholds
// //
#define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE 7849 #define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE 7849
#define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689 #define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689
#define XINPUT_GAMEPAD_TRIGGER_THRESHOLD 30 #define XINPUT_GAMEPAD_TRIGGER_THRESHOLD 30
// //
// Flags to pass to XInputGetCapabilities // Flags to pass to XInputGetCapabilities
// //
#define XINPUT_FLAG_GAMEPAD 0x00000001 #define XINPUT_FLAG_GAMEPAD 0x00000001
#ifndef XINPUT_USE_9_1_0 #ifndef XINPUT_USE_9_1_0
// //
// Devices that support batteries // Devices that support batteries
// //
#define BATTERY_DEVTYPE_GAMEPAD 0x00 #define BATTERY_DEVTYPE_GAMEPAD 0x00
#define BATTERY_DEVTYPE_HEADSET 0x01 #define BATTERY_DEVTYPE_HEADSET 0x01
// //
// Flags for battery status level // Flags for battery status level
// //
#define BATTERY_TYPE_DISCONNECTED 0x00 // This device is not connected #define BATTERY_TYPE_DISCONNECTED 0x00 // This device is not connected
#define BATTERY_TYPE_WIRED 0x01 // Wired device, no battery #define BATTERY_TYPE_WIRED 0x01 // Wired device, no battery
#define BATTERY_TYPE_ALKALINE 0x02 // Alkaline battery source #define BATTERY_TYPE_ALKALINE 0x02 // Alkaline battery source
#define BATTERY_TYPE_NIMH 0x03 // Nickel Metal Hydride battery source #define BATTERY_TYPE_NIMH 0x03 // Nickel Metal Hydride battery source
#define BATTERY_TYPE_UNKNOWN 0xFF // Cannot determine the battery type #define BATTERY_TYPE_UNKNOWN 0xFF // Cannot determine the battery type
// These are only valid for wireless, connected devices, with known battery types // These are only valid for wireless, connected devices, with known battery types
// The amount of use time remaining depends on the type of device. // The amount of use time remaining depends on the type of device.
#define BATTERY_LEVEL_EMPTY 0x00 #define BATTERY_LEVEL_EMPTY 0x00
#define BATTERY_LEVEL_LOW 0x01 #define BATTERY_LEVEL_LOW 0x01
#define BATTERY_LEVEL_MEDIUM 0x02 #define BATTERY_LEVEL_MEDIUM 0x02
#define BATTERY_LEVEL_FULL 0x03 #define BATTERY_LEVEL_FULL 0x03
// User index definitions // User index definitions
#define XUSER_MAX_COUNT 4 #define XUSER_MAX_COUNT 4
#define XUSER_INDEX_ANY 0x000000FF #define XUSER_INDEX_ANY 0x000000FF
// //
// Codes returned for the gamepad keystroke // Codes returned for the gamepad keystroke
// //
#define VK_PAD_A 0x5800 #define VK_PAD_A 0x5800
#define VK_PAD_B 0x5801 #define VK_PAD_B 0x5801
#define VK_PAD_X 0x5802 #define VK_PAD_X 0x5802
#define VK_PAD_Y 0x5803 #define VK_PAD_Y 0x5803
#define VK_PAD_RSHOULDER 0x5804 #define VK_PAD_RSHOULDER 0x5804
#define VK_PAD_LSHOULDER 0x5805 #define VK_PAD_LSHOULDER 0x5805
#define VK_PAD_LTRIGGER 0x5806 #define VK_PAD_LTRIGGER 0x5806
#define VK_PAD_RTRIGGER 0x5807 #define VK_PAD_RTRIGGER 0x5807
#define VK_PAD_DPAD_UP 0x5810 #define VK_PAD_DPAD_UP 0x5810
#define VK_PAD_DPAD_DOWN 0x5811 #define VK_PAD_DPAD_DOWN 0x5811
#define VK_PAD_DPAD_LEFT 0x5812 #define VK_PAD_DPAD_LEFT 0x5812
#define VK_PAD_DPAD_RIGHT 0x5813 #define VK_PAD_DPAD_RIGHT 0x5813
#define VK_PAD_START 0x5814 #define VK_PAD_START 0x5814
#define VK_PAD_BACK 0x5815 #define VK_PAD_BACK 0x5815
#define VK_PAD_LTHUMB_PRESS 0x5816 #define VK_PAD_LTHUMB_PRESS 0x5816
#define VK_PAD_RTHUMB_PRESS 0x5817 #define VK_PAD_RTHUMB_PRESS 0x5817
#define VK_PAD_LTHUMB_UP 0x5820 #define VK_PAD_LTHUMB_UP 0x5820
#define VK_PAD_LTHUMB_DOWN 0x5821 #define VK_PAD_LTHUMB_DOWN 0x5821
#define VK_PAD_LTHUMB_RIGHT 0x5822 #define VK_PAD_LTHUMB_RIGHT 0x5822
#define VK_PAD_LTHUMB_LEFT 0x5823 #define VK_PAD_LTHUMB_LEFT 0x5823
#define VK_PAD_LTHUMB_UPLEFT 0x5824 #define VK_PAD_LTHUMB_UPLEFT 0x5824
#define VK_PAD_LTHUMB_UPRIGHT 0x5825 #define VK_PAD_LTHUMB_UPRIGHT 0x5825
#define VK_PAD_LTHUMB_DOWNRIGHT 0x5826 #define VK_PAD_LTHUMB_DOWNRIGHT 0x5826
#define VK_PAD_LTHUMB_DOWNLEFT 0x5827 #define VK_PAD_LTHUMB_DOWNLEFT 0x5827
#define VK_PAD_RTHUMB_UP 0x5830 #define VK_PAD_RTHUMB_UP 0x5830
#define VK_PAD_RTHUMB_DOWN 0x5831 #define VK_PAD_RTHUMB_DOWN 0x5831
#define VK_PAD_RTHUMB_RIGHT 0x5832 #define VK_PAD_RTHUMB_RIGHT 0x5832
#define VK_PAD_RTHUMB_LEFT 0x5833 #define VK_PAD_RTHUMB_LEFT 0x5833
#define VK_PAD_RTHUMB_UPLEFT 0x5834 #define VK_PAD_RTHUMB_UPLEFT 0x5834
#define VK_PAD_RTHUMB_UPRIGHT 0x5835 #define VK_PAD_RTHUMB_UPRIGHT 0x5835
#define VK_PAD_RTHUMB_DOWNRIGHT 0x5836 #define VK_PAD_RTHUMB_DOWNRIGHT 0x5836
#define VK_PAD_RTHUMB_DOWNLEFT 0x5837 #define VK_PAD_RTHUMB_DOWNLEFT 0x5837
// //
// Flags used in XINPUT_KEYSTROKE // Flags used in XINPUT_KEYSTROKE
// //
#define XINPUT_KEYSTROKE_KEYDOWN 0x0001 #define XINPUT_KEYSTROKE_KEYDOWN 0x0001
#define XINPUT_KEYSTROKE_KEYUP 0x0002 #define XINPUT_KEYSTROKE_KEYUP 0x0002
#define XINPUT_KEYSTROKE_REPEAT 0x0004 #define XINPUT_KEYSTROKE_REPEAT 0x0004
#endif //!XINPUT_USE_9_1_0 #endif //!XINPUT_USE_9_1_0
// //
// Structures used by XInput APIs // Structures used by XInput APIs
// //
typedef struct _XINPUT_GAMEPAD typedef struct _XINPUT_GAMEPAD
{ {
WORD wButtons; WORD wButtons;
BYTE bLeftTrigger; BYTE bLeftTrigger;
BYTE bRightTrigger; BYTE bRightTrigger;
SHORT sThumbLX; SHORT sThumbLX;
SHORT sThumbLY; SHORT sThumbLY;
SHORT sThumbRX; SHORT sThumbRX;
SHORT sThumbRY; SHORT sThumbRY;
} XINPUT_GAMEPAD, *PXINPUT_GAMEPAD; } XINPUT_GAMEPAD, *PXINPUT_GAMEPAD;
typedef struct _XINPUT_STATE typedef struct _XINPUT_STATE
{ {
DWORD dwPacketNumber; DWORD dwPacketNumber;
XINPUT_GAMEPAD Gamepad; XINPUT_GAMEPAD Gamepad;
} XINPUT_STATE, *PXINPUT_STATE; } XINPUT_STATE, *PXINPUT_STATE;
typedef struct _XINPUT_VIBRATION typedef struct _XINPUT_VIBRATION
{ {
WORD wLeftMotorSpeed; WORD wLeftMotorSpeed;
WORD wRightMotorSpeed; WORD wRightMotorSpeed;
} XINPUT_VIBRATION, *PXINPUT_VIBRATION; } XINPUT_VIBRATION, *PXINPUT_VIBRATION;
typedef struct _XINPUT_CAPABILITIES typedef struct _XINPUT_CAPABILITIES
{ {
BYTE Type; BYTE Type;
BYTE SubType; BYTE SubType;
WORD Flags; WORD Flags;
XINPUT_GAMEPAD Gamepad; XINPUT_GAMEPAD Gamepad;
XINPUT_VIBRATION Vibration; XINPUT_VIBRATION Vibration;
} XINPUT_CAPABILITIES, *PXINPUT_CAPABILITIES; } XINPUT_CAPABILITIES, *PXINPUT_CAPABILITIES;
#ifndef XINPUT_USE_9_1_0 #ifndef XINPUT_USE_9_1_0
typedef struct _XINPUT_BATTERY_INFORMATION typedef struct _XINPUT_BATTERY_INFORMATION
{ {
BYTE BatteryType; BYTE BatteryType;
BYTE BatteryLevel; BYTE BatteryLevel;
} XINPUT_BATTERY_INFORMATION, *PXINPUT_BATTERY_INFORMATION; } XINPUT_BATTERY_INFORMATION, *PXINPUT_BATTERY_INFORMATION;
typedef struct _XINPUT_KEYSTROKE typedef struct _XINPUT_KEYSTROKE
{ {
WORD VirtualKey; WORD VirtualKey;
WCHAR Unicode; WCHAR Unicode;
WORD Flags; WORD Flags;
BYTE UserIndex; BYTE UserIndex;
BYTE HidCode; BYTE HidCode;
} XINPUT_KEYSTROKE, *PXINPUT_KEYSTROKE; } XINPUT_KEYSTROKE, *PXINPUT_KEYSTROKE;
#endif // !XINPUT_USE_9_1_0 #endif // !XINPUT_USE_9_1_0
// //
// XInput APIs // XInput APIs
// //
// now defined in proxy class. // now defined in proxy class.
#endif //_XINPUT_H_ #endif //_XINPUT_H_

View File

@ -1,296 +1,296 @@
/* /*
* synergy -- mouse and keyboard sharing utility * synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012 Bolton Software Ltd. * Copyright (C) 2012 Bolton Software Ltd.
* Copyright (C) 2011 Chris Schoeneman * Copyright (C) 2011 Chris Schoeneman
* *
* This package is free software; you can redistribute it and/or * This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file. * found in the file COPYING that should have accompanied this file.
* *
* This package is distributed in the hope that it will be useful, * This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#define SYNERGY_EXPORT_XINPUT_HOOKS #define SYNERGY_EXPORT_XINPUT_HOOKS
#define REQUIRED_XINPUT_DLL "xinput1_3.dll" #define REQUIRED_XINPUT_DLL "xinput1_3.dll"
#define HOOK_TIMEOUT 10000 // 10 sec #define HOOK_TIMEOUT 10000 // 10 sec
#include <Windows.h> #include <Windows.h>
#include <XInput.h> #include <XInput.h>
#include "XInputHook.h" #include "XInputHook.h"
#include "HookDLL.h" #include "HookDLL.h"
#include <iostream> #include <iostream>
HINSTANCE dll; HINSTANCE dll;
char name[256]; char name[256];
#pragma data_seg(".SHARED") #pragma data_seg(".SHARED")
HHOOK s_hook = NULL; HHOOK s_hook = NULL;
// @todo use a struct for multiple gamepad support // @todo use a struct for multiple gamepad support
WORD s_buttons = 0; WORD s_buttons = 0;
SHORT s_leftStickX = 0; SHORT s_leftStickX = 0;
SHORT s_leftStickY = 0; SHORT s_leftStickY = 0;
SHORT s_rightStickX = 0; SHORT s_rightStickX = 0;
SHORT s_rightStickY = 0; SHORT s_rightStickY = 0;
BYTE s_leftTrigger = 0; BYTE s_leftTrigger = 0;
BYTE s_rightTrigger = 0; BYTE s_rightTrigger = 0;
BOOL s_timingReqQueued = FALSE; BOOL s_timingReqQueued = FALSE;
BOOL s_timingRespQueued = FALSE; BOOL s_timingRespQueued = FALSE;
DWORD s_lastFakeMillis = 0; DWORD s_lastFakeMillis = 0;
WORD s_fakeFreqMillis = 0; WORD s_fakeFreqMillis = 0;
DWORD s_packetNumber = 0; DWORD s_packetNumber = 0;
WORD s_leftMotor = 0; WORD s_leftMotor = 0;
WORD s_rightMotor = 0; WORD s_rightMotor = 0;
BOOL s_feedbackQueued = FALSE; BOOL s_feedbackQueued = FALSE;
#pragma data_seg() #pragma data_seg()
#pragma comment(linker, "/SECTION:.SHARED,RWS") #pragma comment(linker, "/SECTION:.SHARED,RWS")
#include <sstream> #include <sstream>
std::stringstream _xInputHookLogStream; std::stringstream _xInputHookLogStream;
#define LOG(s) \ #define LOG(s) \
_xInputHookLogStream.str(""); \ _xInputHookLogStream.str(""); \
_xInputHookLogStream << "Synergy XInputHook: " << s << endl; \ _xInputHookLogStream << "Synergy XInputHook: " << s << endl; \
OutputDebugString( _xInputHookLogStream.str().c_str()) OutputDebugString( _xInputHookLogStream.str().c_str())
using namespace std; using namespace std;
SDLLHook s_xInputHook = SDLLHook s_xInputHook =
{ {
XINPUT_DLL, XINPUT_DLL,
false, NULL, false, NULL,
{ {
{ (char*)(0x80000002), HookXInputGetState }, { (char*)(0x80000002), HookXInputGetState },
{ (char*)(0x80000003), HookXInputSetState }, { (char*)(0x80000003), HookXInputSetState },
{ (char*)(0x80000004), HookXInputGetCapabilities }, { (char*)(0x80000004), HookXInputGetCapabilities },
} }
}; };
BOOL APIENTRY BOOL APIENTRY
DllMain(HINSTANCE module, DWORD reason, LPVOID reserved) DllMain(HINSTANCE module, DWORD reason, LPVOID reserved)
{ {
if (reason == DLL_PROCESS_ATTACH) if (reason == DLL_PROCESS_ATTACH)
{ {
dll = module; dll = module;
// disable unwanted thread notifications to reduce overhead // disable unwanted thread notifications to reduce overhead
DisableThreadLibraryCalls(dll); DisableThreadLibraryCalls(dll);
GetModuleFileName(GetModuleHandle(NULL), name, sizeof(name)); GetModuleFileName(GetModuleHandle(NULL), name, sizeof(name));
// don't hook synergys (this needs to detect real input) // don't hook synergys (this needs to detect real input)
if (string(name).find("synergy") == string::npos) if (string(name).find("synergy") == string::npos)
{ {
LOG("checking '" << name << "' for " << XINPUT_DLL); LOG("checking '" << name << "' for " << XINPUT_DLL);
HookAPICalls(&s_xInputHook); HookAPICalls(&s_xInputHook);
} }
} }
return TRUE; return TRUE;
} }
void void
SetXInputButtons(DWORD userIndex, WORD buttons) SetXInputButtons(DWORD userIndex, WORD buttons)
{ {
s_buttons = buttons; s_buttons = buttons;
s_packetNumber++; s_packetNumber++;
LOG("SetXInputButtons: idx=" << userIndex << ", btns=" << buttons); LOG("SetXInputButtons: idx=" << userIndex << ", btns=" << buttons);
} }
void void
SetXInputSticks(DWORD userIndex, SHORT lx, SHORT ly, SHORT rx, SHORT ry) SetXInputSticks(DWORD userIndex, SHORT lx, SHORT ly, SHORT rx, SHORT ry)
{ {
s_leftStickX = lx; s_leftStickX = lx;
s_leftStickY = ly; s_leftStickY = ly;
s_rightStickX = rx; s_rightStickX = rx;
s_rightStickY = ry; s_rightStickY = ry;
s_packetNumber++; s_packetNumber++;
LOG("SetXInputSticks:" << LOG("SetXInputSticks:" <<
" l=" << s_leftStickX << "," << s_leftStickY << " l=" << s_leftStickX << "," << s_leftStickY <<
" r=" << s_rightStickX << "," << s_rightStickY); " r=" << s_rightStickX << "," << s_rightStickY);
} }
void void
SetXInputTriggers(DWORD userIndex, BYTE left, BYTE right) SetXInputTriggers(DWORD userIndex, BYTE left, BYTE right)
{ {
s_leftTrigger = left; s_leftTrigger = left;
s_rightTrigger = right; s_rightTrigger = right;
s_packetNumber++; s_packetNumber++;
LOG("SetXInputTriggers: " << LOG("SetXInputTriggers: " <<
"l=" << (int)left << " r=" << (int)right); "l=" << (int)left << " r=" << (int)right);
} }
void void
QueueXInputTimingReq() QueueXInputTimingReq()
{ {
s_timingReqQueued = TRUE; s_timingReqQueued = TRUE;
} }
BOOL BOOL
DequeueXInputTimingResp() DequeueXInputTimingResp()
{ {
BOOL result = s_timingRespQueued; BOOL result = s_timingRespQueued;
s_timingRespQueued = FALSE; s_timingRespQueued = FALSE;
return result; return result;
} }
BOOL BOOL
DequeueXInputFeedback(WORD* leftMotor, WORD* rightMotor) DequeueXInputFeedback(WORD* leftMotor, WORD* rightMotor)
{ {
if (s_feedbackQueued) if (s_feedbackQueued)
{ {
*leftMotor = s_leftMotor; *leftMotor = s_leftMotor;
*rightMotor = s_rightMotor; *rightMotor = s_rightMotor;
s_feedbackQueued = FALSE; s_feedbackQueued = FALSE;
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
} }
WORD WORD
GetXInputFakeFreqMillis() GetXInputFakeFreqMillis()
{ {
return s_fakeFreqMillis; return s_fakeFreqMillis;
} }
DWORD WINAPI DWORD WINAPI
HookXInputGetState(DWORD userIndex, XINPUT_STATE* state) HookXInputGetState(DWORD userIndex, XINPUT_STATE* state)
{ {
// @todo multiple device support // @todo multiple device support
if (userIndex != 0) if (userIndex != 0)
{ {
return ERROR_DEVICE_NOT_CONNECTED; return ERROR_DEVICE_NOT_CONNECTED;
} }
DWORD now = GetTickCount(); DWORD now = GetTickCount();
s_fakeFreqMillis = (WORD)(now - s_lastFakeMillis); s_fakeFreqMillis = (WORD)(now - s_lastFakeMillis);
s_lastFakeMillis = now; s_lastFakeMillis = now;
state->dwPacketNumber = s_packetNumber; state->dwPacketNumber = s_packetNumber;
state->Gamepad.wButtons = s_buttons; state->Gamepad.wButtons = s_buttons;
state->Gamepad.bLeftTrigger = s_leftTrigger; state->Gamepad.bLeftTrigger = s_leftTrigger;
state->Gamepad.bRightTrigger = s_rightTrigger; state->Gamepad.bRightTrigger = s_rightTrigger;
state->Gamepad.sThumbLX = s_leftStickX; state->Gamepad.sThumbLX = s_leftStickX;
state->Gamepad.sThumbLY = s_leftStickY; state->Gamepad.sThumbLY = s_leftStickY;
state->Gamepad.sThumbRX = s_rightStickX; state->Gamepad.sThumbRX = s_rightStickX;
state->Gamepad.sThumbRY = s_rightStickY; state->Gamepad.sThumbRY = s_rightStickY;
LOG("HookXInputGetState" LOG("HookXInputGetState"
<< ", idx=" << userIndex << ", idx=" << userIndex
<< ", pkt=" << state->dwPacketNumber << ", pkt=" << state->dwPacketNumber
<< ", btn=" << state->Gamepad.wButtons << ", btn=" << state->Gamepad.wButtons
<< ", t1=" << (int)state->Gamepad.bLeftTrigger << ", t1=" << (int)state->Gamepad.bLeftTrigger
<< ", t2=" << (int)state->Gamepad.bRightTrigger << ", t2=" << (int)state->Gamepad.bRightTrigger
<< ", s1=" << state->Gamepad.sThumbLX << "," << state->Gamepad.sThumbLY << ", s1=" << state->Gamepad.sThumbLX << "," << state->Gamepad.sThumbLY
<< ", s2=" << state->Gamepad.sThumbRX << "," << state->Gamepad.sThumbRY); << ", s2=" << state->Gamepad.sThumbRX << "," << state->Gamepad.sThumbRY);
if (s_timingReqQueued) if (s_timingReqQueued)
{ {
s_timingRespQueued = TRUE; s_timingRespQueued = TRUE;
s_timingReqQueued = FALSE; s_timingReqQueued = FALSE;
LOG("timing response queued"); LOG("timing response queued");
} }
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
DWORD WINAPI DWORD WINAPI
HookXInputSetState(DWORD userIndex, XINPUT_VIBRATION* vibration) HookXInputSetState(DWORD userIndex, XINPUT_VIBRATION* vibration)
{ {
// @todo multiple device support // @todo multiple device support
if (userIndex != 0) if (userIndex != 0)
{ {
return ERROR_DEVICE_NOT_CONNECTED; return ERROR_DEVICE_NOT_CONNECTED;
} }
// only change values and queue feedback change if // only change values and queue feedback change if
// feedback has actually changed. // feedback has actually changed.
if ((s_leftMotor != vibration->wLeftMotorSpeed) || if ((s_leftMotor != vibration->wLeftMotorSpeed) ||
(s_rightMotor != vibration->wRightMotorSpeed)) (s_rightMotor != vibration->wRightMotorSpeed))
{ {
s_leftMotor = vibration->wLeftMotorSpeed; s_leftMotor = vibration->wLeftMotorSpeed;
s_rightMotor = vibration->wRightMotorSpeed; s_rightMotor = vibration->wRightMotorSpeed;
s_feedbackQueued = TRUE; s_feedbackQueued = TRUE;
LOG("HookXInputSetState" LOG("HookXInputSetState"
", idx=" << userIndex << ", idx=" << userIndex <<
", lm=" << s_leftMotor << ", lm=" << s_leftMotor <<
", rm=" << s_rightMotor); ", rm=" << s_rightMotor);
} }
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
DWORD WINAPI DWORD WINAPI
HookXInputGetCapabilities(DWORD userIndex, DWORD flags, XINPUT_CAPABILITIES* capabilities) HookXInputGetCapabilities(DWORD userIndex, DWORD flags, XINPUT_CAPABILITIES* capabilities)
{ {
// @todo multiple device support // @todo multiple device support
if (userIndex != 0) if (userIndex != 0)
{ {
return ERROR_DEVICE_NOT_CONNECTED; return ERROR_DEVICE_NOT_CONNECTED;
} }
LOG("HookXInputGetCapabilities" LOG("HookXInputGetCapabilities"
", idx=" << userIndex << ", idx=" << userIndex <<
", flags=" << flags); ", flags=" << flags);
capabilities->Type = 1; capabilities->Type = 1;
capabilities->SubType = 1; capabilities->SubType = 1;
capabilities->Flags = 4; capabilities->Flags = 4;
capabilities->Gamepad.bLeftTrigger = 1; capabilities->Gamepad.bLeftTrigger = 1;
capabilities->Gamepad.bRightTrigger = 1; capabilities->Gamepad.bRightTrigger = 1;
capabilities->Gamepad.sThumbLX = 1; capabilities->Gamepad.sThumbLX = 1;
capabilities->Gamepad.sThumbLY = 1; capabilities->Gamepad.sThumbLY = 1;
capabilities->Gamepad.sThumbRX = 1; capabilities->Gamepad.sThumbRX = 1;
capabilities->Gamepad.sThumbRY = 1; capabilities->Gamepad.sThumbRY = 1;
capabilities->Gamepad.wButtons = 62463; capabilities->Gamepad.wButtons = 62463;
capabilities->Vibration.wLeftMotorSpeed = 1; capabilities->Vibration.wLeftMotorSpeed = 1;
capabilities->Vibration.wRightMotorSpeed = 1; capabilities->Vibration.wRightMotorSpeed = 1;
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
synxinhk_API LRESULT CALLBACK synxinhk_API LRESULT CALLBACK
HookProc(int code, WPARAM wParam, LPARAM lParam) HookProc(int code, WPARAM wParam, LPARAM lParam)
{ {
return CallNextHookEx(s_hook, code, wParam, lParam); return CallNextHookEx(s_hook, code, wParam, lParam);
} }
synxinhk_API BOOL synxinhk_API BOOL
InstallXInputHook() InstallXInputHook()
{ {
if (_stricmp(XINPUT_DLL, REQUIRED_XINPUT_DLL) != 0) if (_stricmp(XINPUT_DLL, REQUIRED_XINPUT_DLL) != 0)
{ {
LOG("DLL not supported: " << XINPUT_DLL); LOG("DLL not supported: " << XINPUT_DLL);
return FALSE; return FALSE;
} }
LOG("installing hook"); LOG("installing hook");
s_hook = SetWindowsHookEx(WH_CBT, HookProc, dll, 0); s_hook = SetWindowsHookEx(WH_CBT, HookProc, dll, 0);
LOG("hook installed"); LOG("hook installed");
return TRUE; return TRUE;
} }
synxinhk_API void synxinhk_API void
RemoveXInputHook() RemoveXInputHook()
{ {
LOG("removing hook"); LOG("removing hook");
UnhookWindowsHookEx(s_hook); UnhookWindowsHookEx(s_hook);
LOG("hook removed"); LOG("hook removed");
} }

View File

@ -1,44 +1,44 @@
/* /*
* synergy -- mouse and keyboard sharing utility * synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012 Bolton Software Ltd. * Copyright (C) 2012 Bolton Software Ltd.
* Copyright (C) 2011 Chris Schoeneman * Copyright (C) 2011 Chris Schoeneman
* *
* This package is free software; you can redistribute it and/or * This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file. * found in the file COPYING that should have accompanied this file.
* *
* This package is distributed in the hope that it will be useful, * This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#ifdef synxinhk_EXPORTS #ifdef synxinhk_EXPORTS
#define synxinhk_API __declspec(dllexport) #define synxinhk_API __declspec(dllexport)
#else #else
#define synxinhk_API __declspec(dllimport) #define synxinhk_API __declspec(dllimport)
#endif #endif
synxinhk_API LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam); synxinhk_API LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam);
synxinhk_API BOOL InstallXInputHook(); synxinhk_API BOOL InstallXInputHook();
synxinhk_API void RemoveXInputHook(); synxinhk_API void RemoveXInputHook();
synxinhk_API void SetXInputButtons(DWORD userIndex, WORD buttons); synxinhk_API void SetXInputButtons(DWORD userIndex, WORD buttons);
synxinhk_API void SetXInputSticks(DWORD userIndex, SHORT lx, SHORT ly, SHORT rx, SHORT ry); synxinhk_API void SetXInputSticks(DWORD userIndex, SHORT lx, SHORT ly, SHORT rx, SHORT ry);
synxinhk_API void SetXInputTriggers(DWORD userIndex, BYTE left, BYTE right); synxinhk_API void SetXInputTriggers(DWORD userIndex, BYTE left, BYTE right);
synxinhk_API void QueueXInputTimingReq(); synxinhk_API void QueueXInputTimingReq();
synxinhk_API BOOL DequeueXInputTimingResp(); synxinhk_API BOOL DequeueXInputTimingResp();
synxinhk_API WORD GetXInputFakeFreqMillis(); synxinhk_API WORD GetXInputFakeFreqMillis();
synxinhk_API BOOL DequeueXInputFeedback(WORD* leftMotor, WORD* rightMotor); synxinhk_API BOOL DequeueXInputFeedback(WORD* leftMotor, WORD* rightMotor);
#ifdef SYNERGY_EXPORT_XINPUT_HOOKS #ifdef SYNERGY_EXPORT_XINPUT_HOOKS
synxinhk_API DWORD WINAPI HookXInputGetState(DWORD dwUserIndex, XINPUT_STATE* pState); synxinhk_API DWORD WINAPI HookXInputGetState(DWORD dwUserIndex, XINPUT_STATE* pState);
synxinhk_API DWORD WINAPI HookXInputSetState(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration); synxinhk_API DWORD WINAPI HookXInputSetState(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration);
synxinhk_API DWORD WINAPI HookXInputGetCapabilities(DWORD userIndex, DWORD flags, XINPUT_CAPABILITIES* capabilities); synxinhk_API DWORD WINAPI HookXInputGetCapabilities(DWORD userIndex, DWORD flags, XINPUT_CAPABILITIES* capabilities);
#endif #endif

View File

@ -18,7 +18,7 @@
#define SYNERGY_EXPORT_XINPUT_HOOKS #define SYNERGY_EXPORT_XINPUT_HOOKS
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <Windows.h> #include <Windows.h>
#include "XInputProxy13.h" #include "XInputProxy13.h"
#include "XInputHook.h" #include "XInputHook.h"
@ -31,43 +31,43 @@
#pragma comment(linker, "/EXPORT:XInputGetBatteryInformation=_XInputGetBatteryInformation@12,@7") #pragma comment(linker, "/EXPORT:XInputGetBatteryInformation=_XInputGetBatteryInformation@12,@7")
#pragma comment(linker, "/EXPORT:XInputGetKeystroke=_XInputGetKeystroke@12,@8") #pragma comment(linker, "/EXPORT:XInputGetKeystroke=_XInputGetKeystroke@12,@8")
sxinpx13_API DWORD WINAPI
XInputGetState(DWORD dwUserIndex, XINPUT_STATE* pState)
{
return HookXInputGetState(dwUserIndex, pState);
}
sxinpx13_API DWORD WINAPI
XInputSetState(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration)
{
return HookXInputSetState(dwUserIndex, pVibration);
}
sxinpx13_API DWORD WINAPI
XInputGetCapabilities(DWORD dwUserIndex, DWORD dwFlags, XINPUT_CAPABILITIES* pCapabilities)
{
return HookXInputGetCapabilities(dwUserIndex, dwFlags, pCapabilities);
}
sxinpx13_API void WINAPI
XInputEnable(BOOL enable)
{
}
sxinpx13_API DWORD WINAPI
XInputGetDSoundAudioDeviceGuids(DWORD dwUserIndex, GUID* pDSoundRenderGuid, GUID* pDSoundCaptureGuid)
{
return ERROR_DEVICE_NOT_CONNECTED;
}
sxinpx13_API DWORD WINAPI
XInputGetBatteryInformation(DWORD dwUserIndex, BYTE devType, XINPUT_BATTERY_INFORMATION* pBatteryInformation)
{
return ERROR_DEVICE_NOT_CONNECTED;
}
sxinpx13_API DWORD WINAPI sxinpx13_API DWORD WINAPI
XInputGetKeystroke(DWORD dwUserIndex, DWORD dwReserved, PXINPUT_KEYSTROKE pKeystroke) XInputGetState(DWORD dwUserIndex, XINPUT_STATE* pState)
{ {
return HookXInputGetState(dwUserIndex, pState);
}
sxinpx13_API DWORD WINAPI
XInputSetState(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration)
{
return HookXInputSetState(dwUserIndex, pVibration);
}
sxinpx13_API DWORD WINAPI
XInputGetCapabilities(DWORD dwUserIndex, DWORD dwFlags, XINPUT_CAPABILITIES* pCapabilities)
{
return HookXInputGetCapabilities(dwUserIndex, dwFlags, pCapabilities);
}
sxinpx13_API void WINAPI
XInputEnable(BOOL enable)
{
}
sxinpx13_API DWORD WINAPI
XInputGetDSoundAudioDeviceGuids(DWORD dwUserIndex, GUID* pDSoundRenderGuid, GUID* pDSoundCaptureGuid)
{
return ERROR_DEVICE_NOT_CONNECTED;
}
sxinpx13_API DWORD WINAPI
XInputGetBatteryInformation(DWORD dwUserIndex, BYTE devType, XINPUT_BATTERY_INFORMATION* pBatteryInformation)
{
return ERROR_DEVICE_NOT_CONNECTED;
}
sxinpx13_API DWORD WINAPI
XInputGetKeystroke(DWORD dwUserIndex, DWORD dwReserved, PXINPUT_KEYSTROKE pKeystroke)
{
return ERROR_DEVICE_NOT_CONNECTED; return ERROR_DEVICE_NOT_CONNECTED;
} }

View File

@ -14,67 +14,67 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#ifdef sxinpx13_EXPORTS #ifdef sxinpx13_EXPORTS
#define sxinpx13_API __declspec(dllexport) #define sxinpx13_API __declspec(dllexport)
#else #else
#define sxinpx13_API __declspec(dllimport) #define sxinpx13_API __declspec(dllimport)
#endif #endif
#include "XInput13.h" #include "XInput13.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
sxinpx13_API DWORD WINAPI XInputGetState sxinpx13_API DWORD WINAPI XInputGetState
( (
__in DWORD dwUserIndex, // Index of the gamer associated with the device __in DWORD dwUserIndex, // Index of the gamer associated with the device
__out XINPUT_STATE* pState // Receives the current state __out XINPUT_STATE* pState // Receives the current state
); );
sxinpx13_API DWORD WINAPI XInputSetState sxinpx13_API DWORD WINAPI XInputSetState
( (
__in DWORD dwUserIndex, // Index of the gamer associated with the device __in DWORD dwUserIndex, // Index of the gamer associated with the device
__in XINPUT_VIBRATION* pVibration // The vibration information to send to the controller __in XINPUT_VIBRATION* pVibration // The vibration information to send to the controller
); );
sxinpx13_API DWORD WINAPI XInputGetCapabilities sxinpx13_API DWORD WINAPI XInputGetCapabilities
( (
__in DWORD dwUserIndex, // Index of the gamer associated with the device __in DWORD dwUserIndex, // Index of the gamer associated with the device
__in DWORD dwFlags, // Input flags that identify the device type __in DWORD dwFlags, // Input flags that identify the device type
__out XINPUT_CAPABILITIES* pCapabilities // Receives the capabilities __out XINPUT_CAPABILITIES* pCapabilities // Receives the capabilities
); );
sxinpx13_API void WINAPI XInputEnable sxinpx13_API void WINAPI XInputEnable
( (
__in BOOL enable // [in] Indicates whether xinput is enabled or disabled. __in BOOL enable // [in] Indicates whether xinput is enabled or disabled.
); );
sxinpx13_API DWORD WINAPI XInputGetDSoundAudioDeviceGuids sxinpx13_API DWORD WINAPI XInputGetDSoundAudioDeviceGuids
( (
__in DWORD dwUserIndex, // Index of the gamer associated with the device __in DWORD dwUserIndex, // Index of the gamer associated with the device
__out GUID* pDSoundRenderGuid, // DSound device ID for render __out GUID* pDSoundRenderGuid, // DSound device ID for render
__out GUID* pDSoundCaptureGuid // DSound device ID for capture __out GUID* pDSoundCaptureGuid // DSound device ID for capture
); );
sxinpx13_API DWORD WINAPI XInputGetBatteryInformation sxinpx13_API DWORD WINAPI XInputGetBatteryInformation
( (
__in DWORD dwUserIndex, // Index of the gamer associated with the device __in DWORD dwUserIndex, // Index of the gamer associated with the device
__in BYTE devType, // Which device on this user index __in BYTE devType, // Which device on this user index
__out XINPUT_BATTERY_INFORMATION* pBatteryInformation // Contains the level and types of batteries __out XINPUT_BATTERY_INFORMATION* pBatteryInformation // Contains the level and types of batteries
); );
sxinpx13_API DWORD WINAPI XInputGetKeystroke sxinpx13_API DWORD WINAPI XInputGetKeystroke
( (
__in DWORD dwUserIndex, // Index of the gamer associated with the device __in DWORD dwUserIndex, // Index of the gamer associated with the device
__reserved DWORD dwReserved, // Reserved for future use __reserved DWORD dwReserved, // Reserved for future use
__out PXINPUT_KEYSTROKE pKeystroke // Pointer to an XINPUT_KEYSTROKE structure that receives an input event. __out PXINPUT_KEYSTROKE pKeystroke // Pointer to an XINPUT_KEYSTROKE structure that receives an input event.
); );
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -83,7 +83,7 @@ public:
virtual void screensaver(bool activate) = 0; virtual void screensaver(bool activate) = 0;
virtual void resetOptions() = 0; virtual void resetOptions() = 0;
virtual void setOptions(const COptionsList& options) = 0; virtual void setOptions(const COptionsList& options) = 0;
virtual void fileChunkSending(UInt8 mark, const UInt8* data) = 0; virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize) = 0;
virtual CString getName() const; virtual CString getName() const;
private: private:

View File

@ -89,7 +89,7 @@ public:
virtual void gameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2) = 0; virtual void gameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2) = 0;
virtual void gameDeviceTimingReq() = 0; virtual void gameDeviceTimingReq() = 0;
virtual void cryptoIv(const UInt8* iv) = 0; virtual void cryptoIv(const UInt8* iv) = 0;
virtual void fileChunkSending(UInt8 mark, const UInt8* data) = 0; virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize) = 0;
private: private:
synergy::IStream* m_stream; synergy::IStream* m_stream;

View File

@ -394,7 +394,7 @@ CClientProxy1_0::cryptoIv(const UInt8* iv)
} }
void void
CClientProxy1_0::fileChunkSending(UInt8 mark, const UInt8* iv) CClientProxy1_0::fileChunkSending(UInt8 mark, char* data, size_t dataSize)
{ {
// ignore -- not supported in protocol 1.0 // ignore -- not supported in protocol 1.0
LOG((CLOG_DEBUG "fileChunkSending not supported")); LOG((CLOG_DEBUG "fileChunkSending not supported"));

View File

@ -64,7 +64,7 @@ public:
virtual void gameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2); virtual void gameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2);
virtual void gameDeviceTimingReq(); virtual void gameDeviceTimingReq();
virtual void cryptoIv(const UInt8* iv); virtual void cryptoIv(const UInt8* iv);
virtual void fileChunkSending(UInt8 mark, const UInt8* data); virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize);
protected: protected:
virtual bool parseHandshakeMessage(const UInt8* code); virtual bool parseHandshakeMessage(const UInt8* code);

View File

@ -42,7 +42,6 @@ protected:
private: private:
void handleKeepAlive(const CEvent&, void*); void handleKeepAlive(const CEvent&, void*);
private: private:
double m_keepAliveRate; double m_keepAliveRate;
CEventQueueTimer* m_keepAliveTimer; CEventQueueTimer* m_keepAliveTimer;

View File

@ -29,6 +29,14 @@ public:
CClientProxy1_4(const CString& name, synergy::IStream* adoptedStream, CServer* server, IEventQueue* events); CClientProxy1_4(const CString& name, synergy::IStream* adoptedStream, CServer* server, IEventQueue* events);
~CClientProxy1_4(); ~CClientProxy1_4();
//! @name accessors
//@{
//! get server pointer
CServer* getServer() { return m_server; }
//@}
// IClient overrides // IClient overrides
virtual void gameDeviceButtons(GameDeviceID id, GameDeviceButton buttons); virtual void gameDeviceButtons(GameDeviceID id, GameDeviceButton buttons);
virtual void gameDeviceSticks(GameDeviceID id, SInt16 x1, SInt16 y1, SInt16 x2, SInt16 y2); virtual void gameDeviceSticks(GameDeviceID id, SInt16 x1, SInt16 y1, SInt16 x2, SInt16 y2);

View File

@ -19,13 +19,15 @@
#include "CProtocolUtil.h" #include "CProtocolUtil.h"
#include "CLog.h" #include "CLog.h"
#include "IStream.h" #include "IStream.h"
#include "CServer.h"
// //
// CClientProxy1_5 // CClientProxy1_5
// //
CClientProxy1_5::CClientProxy1_5(const CString& name, synergy::IStream* stream, CServer* server, IEventQueue* events) : CClientProxy1_5::CClientProxy1_5(const CString& name, synergy::IStream* stream, CServer* server, IEventQueue* events) :
CClientProxy1_4(name, stream, server, events) CClientProxy1_4(name, stream, server, events),
m_events(events)
{ {
} }
@ -34,23 +36,64 @@ CClientProxy1_5::~CClientProxy1_5()
} }
void void
CClientProxy1_5::fileChunkSending(UInt8 mark, const UInt8* data) CClientProxy1_5::fileChunkSending(UInt8 mark, char* data, size_t dataSize)
{ {
CString chunk(reinterpret_cast<const char*>(data)); CString chunk(data, dataSize);
switch (mark) { switch (mark) {
case '0': case kFileStart:
LOG((CLOG_DEBUG2 "file sending start: file size = %s", data)); LOG((CLOG_DEBUG2 "file sending start: size=%s", data));
break; break;
case '1': case kFileChunk:
LOG((CLOG_DEBUG2 "file chunk sending: %s", data)); LOG((CLOG_DEBUG2 "file chunk sending: size=%i", chunk.size()));
break; break;
case '2': case kFileEnd:
LOG((CLOG_DEBUG2 "file sending finished")); LOG((CLOG_DEBUG2 "file sending finished"));
break; break;
} }
CProtocolUtil::writef(getStream(), kMsgDFileTransfer, mark, &chunk); CProtocolUtil::writef(getStream(), kMsgDFileTransfer, mark, &chunk);
} }
bool
CClientProxy1_5::parseMessage(const UInt8* code)
{
if (memcmp(code, kMsgDFileTransfer, 4) == 0) {
fileChunkReceived();
}
else {
return CClientProxy1_4::parseMessage(code);
}
return true;
}
void
CClientProxy1_5::fileChunkReceived()
{
// parse
UInt8 mark;
CString content;
CProtocolUtil::readf(getStream(), kMsgDFileTransfer + 4, &mark, &content);
CServer* server = getServer();
switch (mark) {
case kFileStart:
LOG((CLOG_DEBUG2 "recv file data from client: file size=%s", content.c_str()));
server->clearReceivedFileData();
server->setExpectedFileSize(content);
break;
case kFileChunk:
LOG((CLOG_DEBUG2 "recv file data from client: chunck size=%i", content.size()));
server->fileChunkReceived(content);
break;
case kFileEnd:
LOG((CLOG_DEBUG2 "file data transfer finished"));
m_events->addEvent(CEvent(m_events->forIScreen().fileRecieveComplete(), server));
break;
}
}

View File

@ -28,5 +28,10 @@ public:
CClientProxy1_5(const CString& name, synergy::IStream* adoptedStream, CServer* server, IEventQueue* events); CClientProxy1_5(const CString& name, synergy::IStream* adoptedStream, CServer* server, IEventQueue* events);
~CClientProxy1_5(); ~CClientProxy1_5();
virtual void fileChunkSending(UInt8 mark, const UInt8* data); virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize);
virtual bool parseMessage(const UInt8* code);
void fileChunkReceived();
private:
IEventQueue* m_events;
}; };

View File

@ -274,7 +274,7 @@ CPrimaryClient::screensaver(bool)
} }
void void
CPrimaryClient::fileChunkSending(UInt8 mark, const UInt8* data) CPrimaryClient::fileChunkSending(UInt8 mark, char* data, size_t dataSize)
{ {
// ignore // ignore
} }

View File

@ -148,7 +148,7 @@ public:
virtual void screensaver(bool activate); virtual void screensaver(bool activate);
virtual void resetOptions(); virtual void resetOptions();
virtual void setOptions(const COptionsList& options); virtual void setOptions(const COptionsList& options);
virtual void fileChunkSending(UInt8 mark, const UInt8* data); virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize);
private: private:
CScreen* m_screen; CScreen* m_screen;

View File

@ -33,14 +33,22 @@
#include "TMethodEventJob.h" #include "TMethodEventJob.h"
#include "CArch.h" #include "CArch.h"
#include "CKeyState.h" #include "CKeyState.h"
#include "CScreen.h"
#include "CThread.h"
#include "TMethodJob.h"
#include "CFileChunker.h"
#include <cstring> #include <cstring>
#include <cstdlib> #include <cstdlib>
#include "CScreen.h" #include <sstream>
#include <fstream>
#include <sstream>
// //
// CServer // CServer
// //
const size_t CServer::m_chunkSize = 1024 * 512; // 512kb
CServer::CServer(CConfig& config, CPrimaryClient* primaryClient, CScreen* screen, IEventQueue* events) : CServer::CServer(CConfig& config, CPrimaryClient* primaryClient, CScreen* screen, IEventQueue* events) :
m_events(events), m_events(events),
m_mock(false), m_mock(false),
@ -177,6 +185,10 @@ CServer::CServer(CConfig& config, CPrimaryClient* primaryClient, CScreen* screen
this, this,
new TMethodEventJob<CServer>(this, new TMethodEventJob<CServer>(this,
&CServer::handleFileChunkSendingEvent)); &CServer::handleFileChunkSendingEvent));
m_events->adoptHandler(m_events->forIScreen().fileRecieveComplete(),
this,
new TMethodEventJob<CServer>(this,
&CServer::handleFileRecieveCompleteEvent));
// add connection // add connection
addClient(m_primaryClient); addClient(m_primaryClient);
@ -1516,8 +1528,13 @@ CServer::handleFakeInputEndEvent(const CEvent&, void*)
void void
CServer::handleFileChunkSendingEvent(const CEvent& event, void*) CServer::handleFileChunkSendingEvent(const CEvent& event, void*)
{ {
UInt8* data = reinterpret_cast<UInt8*>(event.getData()); onFileChunkSending(event.getData());
onFileChunkSending(data); }
void
CServer::handleFileRecieveCompleteEvent(const CEvent& event, void*)
{
onFileRecieveComplete();
} }
void void
@ -1981,13 +1998,32 @@ CServer::onGameDeviceTimingReq()
} }
void void
CServer::onFileChunkSending(const UInt8* data) CServer::onFileChunkSending(const void* data)
{ {
CFileChunker::CFileChunk* fileChunk = reinterpret_cast<CFileChunker::CFileChunk*>(const_cast<void*>(data));
LOG((CLOG_DEBUG1 "onFileChunkSending")); LOG((CLOG_DEBUG1 "onFileChunkSending"));
assert(m_active != NULL); assert(m_active != NULL);
// relay // relay
m_active->fileChunkSending(data[0], &data[1]); m_active->fileChunkSending(fileChunk->m_chunk[0], &(fileChunk->m_chunk[1]), fileChunk->m_dataSize);
}
void
CServer::onFileRecieveComplete()
{
if (isReceivedFileSizeValid()) {
if (!m_fileTransferDes.empty()) {
std::fstream file;
file.open(m_fileTransferDes.c_str(), std::ios::out | std::ios::binary);
if (!file.is_open()) {
// TODO: file open failed
}
file.write(m_receivedFileData.c_str(), m_receivedFileData.size());
file.close();
}
}
} }
bool bool
@ -2260,3 +2296,49 @@ CServer::CKeyboardBroadcastInfo::alloc(State state, const CString& screens)
strcpy(info->m_screens, screens.c_str()); strcpy(info->m_screens, screens.c_str());
return info; return info;
} }
void
CServer::clearReceivedFileData()
{
m_receivedFileData.clear();
}
void
CServer::setExpectedFileSize(CString data)
{
std::istringstream iss(data);
iss >> m_expectedFileSize;
}
void
CServer::fileChunkReceived(CString data)
{
m_receivedFileData += data;
}
bool
CServer::isReceivedFileSizeValid()
{
return m_expectedFileSize == m_receivedFileData.size();
}
void
CServer::sendFileToClient(const char* filename)
{
CThread* thread = new CThread(
new TMethodJob<CServer>(
this, &CServer::sendFileThread,
reinterpret_cast<void*>(const_cast<char*>(filename))));
}
void
CServer::sendFileThread(void* filename)
{
try {
char* name = reinterpret_cast<char*>(filename);
CFileChunker::sendFileChunks(name, m_events, this);
}
catch (std::runtime_error error) {
LOG((CLOG_ERR "failed sending file chunks: %s", error.what()));
}
}

View File

@ -144,6 +144,21 @@ public:
//! Notify of game device feedback //! Notify of game device feedback
void gameDeviceFeedback(GameDeviceID id, UInt16 m1, UInt16 m2); void gameDeviceFeedback(GameDeviceID id, UInt16 m1, UInt16 m2);
//! Clears the file buffer
void clearReceivedFileData();
//! Set the expected size of receiving file
void setExpectedFileSize(CString data);
//! Set
void setFileTransferDes(CString& des) { m_fileTransferDes = des; }
//! Received a chunk of file data
void fileChunkReceived(CString data);
//! Create a new thread and use it to send file to client
void sendFileToClient(const char* filename);
//@} //@}
//! @name accessors //! @name accessors
//@{ //@{
@ -159,6 +174,9 @@ public:
Set the \c list to the names of the currently connected clients. Set the \c list to the names of the currently connected clients.
*/ */
void getClients(std::vector<CString>& list) const; void getClients(std::vector<CString>& list) const;
//! Return true if recieved file size is valid
bool isReceivedFileSizeValid();
//@} //@}
@ -299,6 +317,7 @@ private:
void handleFakeInputBeginEvent(const CEvent&, void*); void handleFakeInputBeginEvent(const CEvent&, void*);
void handleFakeInputEndEvent(const CEvent&, void*); void handleFakeInputEndEvent(const CEvent&, void*);
void handleFileChunkSendingEvent(const CEvent&, void*); void handleFileChunkSendingEvent(const CEvent&, void*);
void handleFileRecieveCompleteEvent(const CEvent&, void*);
// event processing // event processing
void onClipboardChanged(CBaseClientProxy* sender, void onClipboardChanged(CBaseClientProxy* sender,
@ -318,7 +337,8 @@ private:
void onGameDeviceSticks(GameDeviceID id, SInt16 x1, SInt16 y1, SInt16 x2, SInt16 y2); void onGameDeviceSticks(GameDeviceID id, SInt16 x1, SInt16 y1, SInt16 x2, SInt16 y2);
void onGameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2); void onGameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2);
void onGameDeviceTimingReq(); void onGameDeviceTimingReq();
void onFileChunkSending(const UInt8* data); void onFileChunkSending(const void* data);
void onFileRecieveComplete();
// add client to list and attach event handlers for client // add client to list and attach event handlers for client
bool addClient(CBaseClientProxy*); bool addClient(CBaseClientProxy*);
@ -343,6 +363,9 @@ private:
// force the cursor off of \p client // force the cursor off of \p client
void forceLeaveClient(CBaseClientProxy* client); void forceLeaveClient(CBaseClientProxy* client);
// thread funciton for sending file
void sendFileThread(void*);
public: public:
bool m_mock; bool m_mock;
@ -438,6 +461,13 @@ private:
CScreen* m_screen; CScreen* m_screen;
IEventQueue* m_events; IEventQueue* m_events;
// file transfer
size_t m_expectedFileSize;
CString m_receivedFileData;
static const size_t m_chunkSize;
CString m_fileTransferSrc;
CString m_fileTransferDes;
}; };
#endif #endif

View File

@ -170,6 +170,14 @@ CApp::parseArg(const int& argc, const char* const* argv, int& i)
else if (isArg(i, argc, argv, NULL, "--crypto-mode")) { else if (isArg(i, argc, argv, NULL, "--crypto-mode")) {
argsBase().m_crypto.setMode(argv[++i]); argsBase().m_crypto.setMode(argv[++i]);
} }
else if (isArg(i, argc, argv, NULL, "--filetransfer-src")) {
m_fileTransferSrc = argv[++i];
}
else if (isArg(i, argc, argv, NULL, "--filetransfer-des")) {
m_fileTransferDes = argv[++i];
}
else { else {
// option not supported here // option not supported here

View File

@ -101,6 +101,9 @@ public:
void setSocketMultiplexer(CSocketMultiplexer* sm) { m_socketMultiplexer = sm; } void setSocketMultiplexer(CSocketMultiplexer* sm) { m_socketMultiplexer = sm; }
CSocketMultiplexer* getSocketMultiplexer() const { return m_socketMultiplexer; } CSocketMultiplexer* getSocketMultiplexer() const { return m_socketMultiplexer; }
CString& getFileTransferSrc() { return m_fileTransferSrc; }
CString& getFileTransferDes() { return m_fileTransferDes; }
private: private:
void handleIpcMessage(const CEvent&, void*); void handleIpcMessage(const CEvent&, void*);
@ -122,6 +125,8 @@ private:
CIpcClient* m_ipcClient; CIpcClient* m_ipcClient;
IEventQueue* m_events; IEventQueue* m_events;
CSocketMultiplexer* m_socketMultiplexer; CSocketMultiplexer* m_socketMultiplexer;
CString m_fileTransferSrc;
CString m_fileTransferDes;
}; };
#define BYE "\nTry `%s --help' for more information." #define BYE "\nTry `%s --help' for more information."

View File

@ -349,6 +349,14 @@ CClientApp::handleClientConnected(const CEvent&, void*)
LOG((CLOG_NOTE "connected to server")); LOG((CLOG_NOTE "connected to server"));
resetRestartTimeout(); resetRestartTimeout();
updateStatus(); updateStatus();
/*
// TODO: remove testing code for relase
CString fileFullDir = getFileTransferSrc();
if (!fileFullDir.empty()) {
s_client->sendFileToServer(getFileTransferSrc().c_str());
}
*/
} }
@ -473,6 +481,7 @@ CClientApp::startClient()
#endif #endif
s_client->connect(); s_client->connect();
updateStatus(); updateStatus();
return true; return true;
} }

View File

@ -0,0 +1,100 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2013 Bolton Software Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CFileChunker.h"
#include "BasicTypes.h"
#include "ProtocolTypes.h"
#include "CEvent.h"
#include "IEventQueue.h"
#include "CEventTypes.h"
#include "CLOG.h"
#include <fstream>
#include <sstream>
using namespace std;
const size_t CFileChunker::m_chunkSize = 512 * 1024; // 512kb
void
CFileChunker::sendFileChunks(char* filename, IEventQueue* events, void* eventTarget)
{
std::fstream file(reinterpret_cast<char*>(filename), std::ios::in | std::ios::binary);
if (!file.is_open()) {
throw runtime_error("failed to open file");
}
// check file size
file.seekg (0, std::ios::end);
size_t size = (size_t)file.tellg();
// send first message (file size)
CString fileSize = intToString(size);
UInt32 sizeLength = fileSize.size();
CFileChunk* sizeMessage = new CFileChunk(sizeLength + 2);
char* chunkData = sizeMessage->m_chunk;
chunkData[0] = kFileStart;
memcpy(&chunkData[1], fileSize.c_str(), sizeLength);
chunkData[sizeLength + 1] = '\0';
events->addEvent(CEvent(events->forIScreen().fileChunkSending(), eventTarget, sizeMessage));
// send chunk messages with a fixed chunk size
size_t sentLength = 0;
size_t chunkSize = m_chunkSize;
file.seekg (0, std::ios::beg);
while (true) {
// make sure we don't read too much from the mock data.
if (sentLength + chunkSize > size) {
chunkSize = size - sentLength;
}
// for fileChunk->m_chunk, the first byte is the chunk mark, last is \0
CFileChunk* fileChunk = new CFileChunk(chunkSize + 2);
char* chunkData = fileChunk->m_chunk;
chunkData[0] = kFileChunk;
file.read(&chunkData[1], chunkSize);
chunkData[chunkSize + 1] = '\0';
events->addEvent(CEvent(events->forIScreen().fileChunkSending(), eventTarget, fileChunk));
sentLength += chunkSize;
file.seekg (sentLength, std::ios::beg);
if (sentLength == size) {
break;
}
}
// send last message
CFileChunk* transferFinished = new CFileChunk(2);
chunkData = transferFinished->m_chunk;
chunkData[0] = kFileEnd;
chunkData[1] = '\0';
events->addEvent(CEvent(events->forIScreen().fileChunkSending(), eventTarget, transferFinished));
file.close();
}
CString
CFileChunker::intToString(size_t i)
{
stringstream ss;
ss << i;
return ss.str();
}

View File

@ -0,0 +1,46 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2013 Bolton Software Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "CString.h"
class IEventQueue;
class CFileChunker {
public:
//! FileChunk data
class CFileChunk {
public:
CFileChunk(size_t chunkSize) : m_dataSize(chunkSize - 2)
{
m_chunk = new char[chunkSize];
}
~CFileChunk() { delete[] m_chunk; }
public:
const size_t m_dataSize;
char* m_chunk;
};
static void sendFileChunks(char* filename, IEventQueue* events, void* eventTarget);
static CString intToString(size_t i);
private:
static const size_t m_chunkSize;
};

View File

@ -49,6 +49,7 @@ set(inc
CArgsBase.h CArgsBase.h
IAppUtil.h IAppUtil.h
CEventGameDevice.h CEventGameDevice.h
CFileChunker.h
) )
set(src set(src
@ -74,23 +75,24 @@ set(src
XSynergy.cpp XSynergy.cpp
CDaemonApp.cpp CDaemonApp.cpp
CAppUtil.cpp CAppUtil.cpp
CArgsBase.cpp CArgsBase.cpp
CEventGameDevice.cpp CEventGameDevice.cpp
CGameDevice.cpp CGameDevice.cpp
) CFileChunker.cpp
)
if (WIN32)
if (WIN32)
list(APPEND inc list(APPEND inc
CAppUtilWindows.h CAppUtilWindows.h
CGameDevice.h CGameDevice.h
) )
list(APPEND src list(APPEND src
${inc} ${inc}
CAppUtilWindows.cpp CAppUtilWindows.cpp
) )
elseif(UNIX) elseif(UNIX)
list(APPEND src list(APPEND src
CAppUtilUnix.cpp CAppUtilUnix.cpp
) )
endif() endif()

View File

@ -228,7 +228,12 @@ CProtocolUtil::vreadf(synergy::IStream* stream, const char* fmt, va_list args)
} }
throw; throw;
} }
LOG((CLOG_DEBUG2 "readf: read %d byte string: %.*s", len, len, sBuffer));
// don't cause buffer overrun, using +100 chars in case
// someone modifies this log message in future.
if (len + 100 < kLogMessageLength) {
LOG((CLOG_DEBUG2 "readf: read %d byte string: %.*s", len, len, sBuffer));
}
// save the data // save the data
CString* dst = va_arg(args, CString*); CString* dst = va_arg(args, CString*);

View File

@ -688,7 +688,7 @@ CServer*
CServerApp::openServer(CConfig& config, CPrimaryClient* primaryClient) CServerApp::openServer(CConfig& config, CPrimaryClient* primaryClient)
{ {
CServer* server = new CServer(config, primaryClient, s_serverScreen, m_events); CServer* server = new CServer(config, primaryClient, s_serverScreen, m_events);
server->setFileTransferDes(getFileTransferDes());
try { try {
m_events->adoptHandler( m_events->adoptHandler(
m_events->forCServer().disconnected(), server, m_events->forCServer().disconnected(), server,

View File

@ -31,7 +31,7 @@
This interface defines the methods common to all platform dependent This interface defines the methods common to all platform dependent
primary screen implementations. primary screen implementations.
*/ */
class IPrimaryScreen : public IInterface { class IPrimaryScreen : public IInterface {
public: public:
//! Button event data //! Button event data
class CButtonInfo { class CButtonInfo {

View File

@ -30,7 +30,7 @@ class IClipboard;
/*! /*!
This interface defines the methods common to all screens. This interface defines the methods common to all screens.
*/ */
class IScreen : public IInterface { class IScreen : public IInterface {
public: public:
struct CClipboardInfo { struct CClipboardInfo {
public: public:

View File

@ -68,6 +68,13 @@ enum EDirectionMask {
kBottomMask = 1 << kBottom kBottomMask = 1 << kBottom
}; };
// file transfer constants
enum EFileTransfer {
kFileStart = 1,
kFileChunk = 2,
kFileEnd = 3
};
// //
// message codes (trailing NUL is not part of code). in comments, $n // message codes (trailing NUL is not part of code). in comments, $n

View File

@ -1,420 +1,420 @@
/* /*
uSynergy client -- Interface for the embedded Synergy client library uSynergy client -- Interface for the embedded Synergy client library
version 1.0.0, July 7th, 2012 version 1.0.0, July 7th, 2012
Copyright (C) 2012 Bolton Software Ltd. Copyright (C) 2012 Bolton Software Ltd.
Copyright (c) 2012 Alex Evans Copyright (c) 2012 Alex Evans
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
arising from the use of this software. arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions: freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not 1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be in a product, an acknowledgment in the product documentation would be
appreciated but is not required. appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source 3. This notice may not be removed or altered from any source
distribution. distribution.
*/ */
#include <stdint.h> #include <stdint.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
// Configuration // Configuration
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
/** /**
@brief Determine endianness @brief Determine endianness
**/ **/
#if defined(USYNERGY_LITTLE_ENDIAN) && defined(USYNERGY_BIG_ENDIAN) #if defined(USYNERGY_LITTLE_ENDIAN) && defined(USYNERGY_BIG_ENDIAN)
/* Ambiguous: both endians specified */ /* Ambiguous: both endians specified */
#error "Can't define both USYNERGY_LITTLE_ENDIAN and USYNERGY_BIG_ENDIAN" #error "Can't define both USYNERGY_LITTLE_ENDIAN and USYNERGY_BIG_ENDIAN"
#elif !defined(USYNERGY_LITTLE_ENDIAN) && !defined(USYNERGY_BIG_ENDIAN) #elif !defined(USYNERGY_LITTLE_ENDIAN) && !defined(USYNERGY_BIG_ENDIAN)
/* Attempt to auto detect */ /* Attempt to auto detect */
#if defined(__LITTLE_ENDIAN__) || defined(LITTLE_ENDIAN) || (_BYTE_ORDER == _LITTLE_ENDIAN) #if defined(__LITTLE_ENDIAN__) || defined(LITTLE_ENDIAN) || (_BYTE_ORDER == _LITTLE_ENDIAN)
#define USYNERGY_LITTLE_ENDIAN #define USYNERGY_LITTLE_ENDIAN
#elif defined(__BIG_ENDIAN__) || defined(BIG_ENDIAN) || (_BYTE_ORDER == _BIG_ENDIAN) #elif defined(__BIG_ENDIAN__) || defined(BIG_ENDIAN) || (_BYTE_ORDER == _BIG_ENDIAN)
#define USYNERGY_BIG_ENDIAN #define USYNERGY_BIG_ENDIAN
#else #else
#error "Can't detect endian-nes, please defined either USYNERGY_LITTLE_ENDIAN or USYNERGY_BIG_ENDIAN"; #error "Can't detect endian-nes, please defined either USYNERGY_LITTLE_ENDIAN or USYNERGY_BIG_ENDIAN";
#endif #endif
#else #else
/* User-specified endian-nes, nothing to do for us */ /* User-specified endian-nes, nothing to do for us */
#endif #endif
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
// Types and Constants // Types and Constants
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
/** /**
@brief Boolean type @brief Boolean type
**/ **/
typedef int uSynergyBool; typedef int uSynergyBool;
#define USYNERGY_FALSE 0 /* False value */ #define USYNERGY_FALSE 0 /* False value */
#define USYNERGY_TRUE 1 /* True value */ #define USYNERGY_TRUE 1 /* True value */
/** /**
@brief User context type @brief User context type
The uSynergyCookie type is an opaque type that is used by uSynergy to communicate to the client. It is passed along to The uSynergyCookie type is an opaque type that is used by uSynergy to communicate to the client. It is passed along to
callback functions as context. callback functions as context.
**/ **/
typedef struct { int ignored; } * uSynergyCookie; typedef struct { int ignored; } * uSynergyCookie;
/** /**
@brief Clipboard types @brief Clipboard types
**/ **/
enum uSynergyClipboardFormat enum uSynergyClipboardFormat
{ {
USYNERGY_CLIPBOARD_FORMAT_TEXT = 0, /* Text format, UTF-8, newline is LF */ USYNERGY_CLIPBOARD_FORMAT_TEXT = 0, /* Text format, UTF-8, newline is LF */
USYNERGY_CLIPBOARD_FORMAT_BITMAP = 1, /* Bitmap format, BMP 24/32bpp, BI_RGB */ USYNERGY_CLIPBOARD_FORMAT_BITMAP = 1, /* Bitmap format, BMP 24/32bpp, BI_RGB */
USYNERGY_CLIPBOARD_FORMAT_HTML = 2, /* HTML format, HTML fragment, UTF-8, newline is LF */ USYNERGY_CLIPBOARD_FORMAT_HTML = 2, /* HTML format, HTML fragment, UTF-8, newline is LF */
}; };
/** /**
@brief Constants and limits @brief Constants and limits
**/ **/
#define USYNERGY_NUM_JOYSTICKS 4 /* Maximum number of supported joysticks */ #define USYNERGY_NUM_JOYSTICKS 4 /* Maximum number of supported joysticks */
#define USYNERGY_PROTOCOL_MAJOR 1 /* Major protocol version */ #define USYNERGY_PROTOCOL_MAJOR 1 /* Major protocol version */
#define USYNERGY_PROTOCOL_MINOR 4 /* Minor protocol version */ #define USYNERGY_PROTOCOL_MINOR 4 /* Minor protocol version */
#define USYNERGY_IDLE_TIMEOUT 2000 /* Timeout in milliseconds before reconnecting */ #define USYNERGY_IDLE_TIMEOUT 2000 /* Timeout in milliseconds before reconnecting */
#define USYNERGY_TRACE_BUFFER_SIZE 1024 /* Maximum length of traced message */ #define USYNERGY_TRACE_BUFFER_SIZE 1024 /* Maximum length of traced message */
#define USYNERGY_REPLY_BUFFER_SIZE 1024 /* Maximum size of a reply packet */ #define USYNERGY_REPLY_BUFFER_SIZE 1024 /* Maximum size of a reply packet */
#define USYNERGY_RECEIVE_BUFFER_SIZE 4096 /* Maximum size of an incoming packet */ #define USYNERGY_RECEIVE_BUFFER_SIZE 4096 /* Maximum size of an incoming packet */
/** /**
@brief Keyboard constants @brief Keyboard constants
**/ **/
#define USYNERGY_MODIFIER_SHIFT 0x0001 /* Shift key modifier */ #define USYNERGY_MODIFIER_SHIFT 0x0001 /* Shift key modifier */
#define USYNERGY_MODIFIER_CTRL 0x0002 /* Ctrl key modifier */ #define USYNERGY_MODIFIER_CTRL 0x0002 /* Ctrl key modifier */
#define USYNERGY_MODIFIER_ALT 0x0004 /* Alt key modifier */ #define USYNERGY_MODIFIER_ALT 0x0004 /* Alt key modifier */
#define USYNERGY_MODIFIER_META 0x0008 /* Meta key modifier */ #define USYNERGY_MODIFIER_META 0x0008 /* Meta key modifier */
#define USYNERGY_MODIFIER_WIN 0x0010 /* Windows key modifier */ #define USYNERGY_MODIFIER_WIN 0x0010 /* Windows key modifier */
#define USYNERGY_MODIFIER_ALT_GR 0x0020 /* AltGr key modifier */ #define USYNERGY_MODIFIER_ALT_GR 0x0020 /* AltGr key modifier */
#define USYNERGY_MODIFIER_LEVEL5LOCK 0x0040 /* Level5Lock key modifier */ #define USYNERGY_MODIFIER_LEVEL5LOCK 0x0040 /* Level5Lock key modifier */
#define USYNERGY_MODIFIER_CAPSLOCK 0x1000 /* CapsLock key modifier */ #define USYNERGY_MODIFIER_CAPSLOCK 0x1000 /* CapsLock key modifier */
#define USYNERGY_MODIFIER_NUMLOCK 0x2000 /* NumLock key modifier */ #define USYNERGY_MODIFIER_NUMLOCK 0x2000 /* NumLock key modifier */
#define USYNERGY_MODIFIER_SCROLLOCK 0x4000 /* ScrollLock key modifier */ #define USYNERGY_MODIFIER_SCROLLOCK 0x4000 /* ScrollLock key modifier */
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
// Functions and Callbacks // Functions and Callbacks
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
/** /**
@brief Connect function @brief Connect function
This function is called when uSynergy needs to connect to the host. It doesn't imply a network implementation or This function is called when uSynergy needs to connect to the host. It doesn't imply a network implementation or
destination address, that must all be handled on the user side. The function should return USYNERGY_TRUE if a destination address, that must all be handled on the user side. The function should return USYNERGY_TRUE if a
connection was established or USYNERGY_FALSE if it could not connect. connection was established or USYNERGY_FALSE if it could not connect.
When network errors occur (e.g. uSynergySend or uSynergyReceive fail) then the connect call will be called again When network errors occur (e.g. uSynergySend or uSynergyReceive fail) then the connect call will be called again
so the implementation of the function must close any old connections and clean up resources before retrying. so the implementation of the function must close any old connections and clean up resources before retrying.
@param cookie Cookie supplied in the Synergy context @param cookie Cookie supplied in the Synergy context
**/ **/
typedef uSynergyBool (*uSynergyConnectFunc)(uSynergyCookie cookie); typedef uSynergyBool (*uSynergyConnectFunc)(uSynergyCookie cookie);
/** /**
@brief Send function @brief Send function
This function is called when uSynergy needs to send something over the default connection. It should return This function is called when uSynergy needs to send something over the default connection. It should return
USYNERGY_TRUE if sending succeeded and USYNERGY_FALSE otherwise. This function should block until the send USYNERGY_TRUE if sending succeeded and USYNERGY_FALSE otherwise. This function should block until the send
operation is completed. operation is completed.
@param cookie Cookie supplied in the Synergy context @param cookie Cookie supplied in the Synergy context
@param buffer Address of buffer to send @param buffer Address of buffer to send
@param length Length of buffer to send @param length Length of buffer to send
**/ **/
typedef uSynergyBool (*uSynergySendFunc)(uSynergyCookie cookie, const uint8_t *buffer, int length); typedef uSynergyBool (*uSynergySendFunc)(uSynergyCookie cookie, const uint8_t *buffer, int length);
/** /**
@brief Receive function @brief Receive function
This function is called when uSynergy needs to receive data from the default connection. It should return This function is called when uSynergy needs to receive data from the default connection. It should return
USYNERGY_TRUE if receiving data succeeded and USYNERGY_FALSE otherwise. This function should block until data USYNERGY_TRUE if receiving data succeeded and USYNERGY_FALSE otherwise. This function should block until data
has been received and wait for data to become available. If @a outLength is set to 0 upon completion it is has been received and wait for data to become available. If @a outLength is set to 0 upon completion it is
assumed that the connection is alive, but still in a connecting state and needs time to settle. assumed that the connection is alive, but still in a connecting state and needs time to settle.
@param cookie Cookie supplied in the Synergy context @param cookie Cookie supplied in the Synergy context
@param buffer Address of buffer to receive data into @param buffer Address of buffer to receive data into
@param maxLength Maximum amount of bytes to write into the receive buffer @param maxLength Maximum amount of bytes to write into the receive buffer
@param outLength Address of integer that receives the actual amount of bytes written into @a buffer @param outLength Address of integer that receives the actual amount of bytes written into @a buffer
**/ **/
typedef uSynergyBool (*uSynergyReceiveFunc)(uSynergyCookie cookie, uint8_t *buffer, int maxLength, int* outLength); typedef uSynergyBool (*uSynergyReceiveFunc)(uSynergyCookie cookie, uint8_t *buffer, int maxLength, int* outLength);
/** /**
@brief Thread sleep function @brief Thread sleep function
This function is called when uSynergy wants to suspend operation for a while before retrying an operation. It This function is called when uSynergy wants to suspend operation for a while before retrying an operation. It
is mostly used when a socket times out or disconnect occurs to prevent uSynergy from continuously hammering a is mostly used when a socket times out or disconnect occurs to prevent uSynergy from continuously hammering a
network connection in case the network is down. network connection in case the network is down.
@param cookie Cookie supplied in the Synergy context @param cookie Cookie supplied in the Synergy context
@param timeMs Time to sleep the current thread (in milliseconds) @param timeMs Time to sleep the current thread (in milliseconds)
**/ **/
typedef void (*uSynergySleepFunc)(uSynergyCookie cookie, int timeMs); typedef void (*uSynergySleepFunc)(uSynergyCookie cookie, int timeMs);
/** /**
@brief Get time function @brief Get time function
This function is called when uSynergy needs to know the current time. This is used to determine when timeouts This function is called when uSynergy needs to know the current time. This is used to determine when timeouts
have occured. The time base should be a cyclic millisecond time value. have occured. The time base should be a cyclic millisecond time value.
@returns Time value in milliseconds @returns Time value in milliseconds
**/ **/
typedef uint32_t (*uSynergyGetTimeFunc)(); typedef uint32_t (*uSynergyGetTimeFunc)();
/** /**
@brief Trace function @brief Trace function
This function is called when uSynergy wants to trace something. It is optional to show these messages, but they This function is called when uSynergy wants to trace something. It is optional to show these messages, but they
are often useful when debugging. uSynergy only traces major events like connecting and disconnecting. Usually are often useful when debugging. uSynergy only traces major events like connecting and disconnecting. Usually
only a single trace is shown when the connection is established and no more trace are called. only a single trace is shown when the connection is established and no more trace are called.
@param cookie Cookie supplied in the Synergy context @param cookie Cookie supplied in the Synergy context
@param text Text to be traced @param text Text to be traced
**/ **/
typedef void (*uSynergyTraceFunc)(uSynergyCookie cookie, const char *text); typedef void (*uSynergyTraceFunc)(uSynergyCookie cookie, const char *text);
/** /**
@brief Screen active callback @brief Screen active callback
This callback is called when Synergy makes the screen active or inactive. This This callback is called when Synergy makes the screen active or inactive. This
callback is usually sent when the mouse enters or leaves the screen. callback is usually sent when the mouse enters or leaves the screen.
@param cookie Cookie supplied in the Synergy context @param cookie Cookie supplied in the Synergy context
@param active Activation flag, 1 if the screen has become active, 0 if the screen has become inactive @param active Activation flag, 1 if the screen has become active, 0 if the screen has become inactive
**/ **/
typedef void (*uSynergyScreenActiveCallback)(uSynergyCookie cookie, uSynergyBool active); typedef void (*uSynergyScreenActiveCallback)(uSynergyCookie cookie, uSynergyBool active);
/** /**
@brief Mouse callback @brief Mouse callback
This callback is called when a mouse events happens. The mouse X and Y position, This callback is called when a mouse events happens. The mouse X and Y position,
wheel and button state is communicated in the message. It's up to the user to wheel and button state is communicated in the message. It's up to the user to
interpret if this is a mouse up, down, double-click or other message. interpret if this is a mouse up, down, double-click or other message.
@param cookie Cookie supplied in the Synergy context @param cookie Cookie supplied in the Synergy context
@param x Mouse X position @param x Mouse X position
@param y Mouse Y position @param y Mouse Y position
@param wheelX Mouse wheel X position @param wheelX Mouse wheel X position
@param wheelY Mouse wheel Y position @param wheelY Mouse wheel Y position
@param buttonLeft Left button pressed status, 0 for released, 1 for pressed @param buttonLeft Left button pressed status, 0 for released, 1 for pressed
@param buttonMiddle Middle button pressed status, 0 for released, 1 for pressed @param buttonMiddle Middle button pressed status, 0 for released, 1 for pressed
@param buttonRight Right button pressed status, 0 for released, 1 for pressed @param buttonRight Right button pressed status, 0 for released, 1 for pressed
**/ **/
typedef void (*uSynergyMouseCallback)(uSynergyCookie cookie, uint16_t x, uint16_t y, int16_t wheelX, int16_t wheelY, uSynergyBool buttonLeft, uSynergyBool buttonRight, uSynergyBool buttonMiddle); typedef void (*uSynergyMouseCallback)(uSynergyCookie cookie, uint16_t x, uint16_t y, int16_t wheelX, int16_t wheelY, uSynergyBool buttonLeft, uSynergyBool buttonRight, uSynergyBool buttonMiddle);
/** /**
@brief Key event callback @brief Key event callback
This callback is called when a key is pressed or released. This callback is called when a key is pressed or released.
@param cookie Cookie supplied in the Synergy context @param cookie Cookie supplied in the Synergy context
@param key Key code of key that was pressed or released @param key Key code of key that was pressed or released
@param modifiers Status of modifier keys (alt, shift, etc.) @param modifiers Status of modifier keys (alt, shift, etc.)
@param down Down or up status, 1 is key is pressed down, 0 if key is released (up) @param down Down or up status, 1 is key is pressed down, 0 if key is released (up)
@param repeat Repeat flag, 1 if the key is down because the key is repeating, 0 if the key is initially pressed by the user @param repeat Repeat flag, 1 if the key is down because the key is repeating, 0 if the key is initially pressed by the user
**/ **/
typedef void (*uSynergyKeyboardCallback)(uSynergyCookie cookie, uint16_t key, uint16_t modifiers, uSynergyBool down, uSynergyBool repeat); typedef void (*uSynergyKeyboardCallback)(uSynergyCookie cookie, uint16_t key, uint16_t modifiers, uSynergyBool down, uSynergyBool repeat);
/** /**
@brief Joystick event callback @brief Joystick event callback
This callback is called when a joystick stick or button changes. It is possible that multiple callbacks are This callback is called when a joystick stick or button changes. It is possible that multiple callbacks are
fired when different sticks or buttons change as these are individual messages in the packet stream. Each fired when different sticks or buttons change as these are individual messages in the packet stream. Each
callback will contain all the valid state for the different axes and buttons. The last callback received will callback will contain all the valid state for the different axes and buttons. The last callback received will
represent the most current joystick state. represent the most current joystick state.
@param cookie Cookie supplied in the Synergy context @param cookie Cookie supplied in the Synergy context
@param joyNum Joystick number, always in the range [0 ... USYNERGY_NUM_JOYSTICKS> @param joyNum Joystick number, always in the range [0 ... USYNERGY_NUM_JOYSTICKS>
@param buttons Button pressed mask @param buttons Button pressed mask
@param leftStickX Left stick X position, in range [-127 ... 127] @param leftStickX Left stick X position, in range [-127 ... 127]
@param leftStickY Left stick Y position, in range [-127 ... 127] @param leftStickY Left stick Y position, in range [-127 ... 127]
@param rightStickX Right stick X position, in range [-127 ... 127] @param rightStickX Right stick X position, in range [-127 ... 127]
@param rightStickY Right stick Y position, in range [-127 ... 127] @param rightStickY Right stick Y position, in range [-127 ... 127]
**/ **/
typedef void (*uSynergyJoystickCallback)(uSynergyCookie cookie, uint8_t joyNum, uint16_t buttons, int8_t leftStickX, int8_t leftStickY, int8_t rightStickX, int8_t rightStickY); typedef void (*uSynergyJoystickCallback)(uSynergyCookie cookie, uint8_t joyNum, uint16_t buttons, int8_t leftStickX, int8_t leftStickY, int8_t rightStickX, int8_t rightStickY);
/** /**
@brief Clipboard event callback @brief Clipboard event callback
This callback is called when something is placed on the clipboard. Multiple callbacks may be fired for This callback is called when something is placed on the clipboard. Multiple callbacks may be fired for
multiple clipboard formats if they are supported. The data provided is read-only and may not be modified multiple clipboard formats if they are supported. The data provided is read-only and may not be modified
by the application. by the application.
@param cookie Cookie supplied in the Synergy context @param cookie Cookie supplied in the Synergy context
@param format Clipboard format @param format Clipboard format
@param data Memory area containing the clipboard raw data @param data Memory area containing the clipboard raw data
@param size Size of clipboard data @param size Size of clipboard data
**/ **/
typedef void (*uSynergyClipboardCallback)(uSynergyCookie cookie, enum uSynergyClipboardFormat format, const uint8_t *data, uint32_t size); typedef void (*uSynergyClipboardCallback)(uSynergyCookie cookie, enum uSynergyClipboardFormat format, const uint8_t *data, uint32_t size);
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
// Context // Context
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
/** /**
@brief uSynergy context @brief uSynergy context
**/ **/
typedef struct typedef struct
{ {
/* Mandatory configuration data, filled in by client */ /* Mandatory configuration data, filled in by client */
uSynergyConnectFunc m_connectFunc; /* Connect function */ uSynergyConnectFunc m_connectFunc; /* Connect function */
uSynergySendFunc m_sendFunc; /* Send data function */ uSynergySendFunc m_sendFunc; /* Send data function */
uSynergyReceiveFunc m_receiveFunc; /* Receive data function */ uSynergyReceiveFunc m_receiveFunc; /* Receive data function */
uSynergySleepFunc m_sleepFunc; /* Thread sleep function */ uSynergySleepFunc m_sleepFunc; /* Thread sleep function */
uSynergyGetTimeFunc m_getTimeFunc; /* Get current time function */ uSynergyGetTimeFunc m_getTimeFunc; /* Get current time function */
const char* m_clientName; /* Name of Synergy Screen / Client */ const char* m_clientName; /* Name of Synergy Screen / Client */
uint16_t m_clientWidth; /* Width of screen */ uint16_t m_clientWidth; /* Width of screen */
uint16_t m_clientHeight; /* Height of screen */ uint16_t m_clientHeight; /* Height of screen */
/* Optional configuration data, filled in by client */ /* Optional configuration data, filled in by client */
uSynergyCookie m_cookie; /* Cookie pointer passed to callback functions (can be NULL) */ uSynergyCookie m_cookie; /* Cookie pointer passed to callback functions (can be NULL) */
uSynergyTraceFunc m_traceFunc; /* Function for tracing status (can be NULL) */ uSynergyTraceFunc m_traceFunc; /* Function for tracing status (can be NULL) */
uSynergyScreenActiveCallback m_screenActiveCallback; /* Callback for entering and leaving screen */ uSynergyScreenActiveCallback m_screenActiveCallback; /* Callback for entering and leaving screen */
uSynergyMouseCallback m_mouseCallback; /* Callback for mouse events */ uSynergyMouseCallback m_mouseCallback; /* Callback for mouse events */
uSynergyKeyboardCallback m_keyboardCallback; /* Callback for keyboard events */ uSynergyKeyboardCallback m_keyboardCallback; /* Callback for keyboard events */
uSynergyJoystickCallback m_joystickCallback; /* Callback for joystick events */ uSynergyJoystickCallback m_joystickCallback; /* Callback for joystick events */
uSynergyClipboardCallback m_clipboardCallback; /* Callback for clipboard events */ uSynergyClipboardCallback m_clipboardCallback; /* Callback for clipboard events */
/* State data, used internall by client, initialized by uSynergyInit() */ /* State data, used internall by client, initialized by uSynergyInit() */
uSynergyBool m_connected; /* Is our socket connected? */ uSynergyBool m_connected; /* Is our socket connected? */
uSynergyBool m_hasReceivedHello; /* Have we received a 'Hello' from the server? */ uSynergyBool m_hasReceivedHello; /* Have we received a 'Hello' from the server? */
uSynergyBool m_isCaptured; /* Is Synergy active (i.e. this client is receiving input messages?) */ uSynergyBool m_isCaptured; /* Is Synergy active (i.e. this client is receiving input messages?) */
uint32_t m_lastMessageTime; /* Time at which last message was received */ uint32_t m_lastMessageTime; /* Time at which last message was received */
uint32_t m_sequenceNumber; /* Packet sequence number */ uint32_t m_sequenceNumber; /* Packet sequence number */
uint8_t m_receiveBuffer[USYNERGY_RECEIVE_BUFFER_SIZE]; /* Receive buffer */ uint8_t m_receiveBuffer[USYNERGY_RECEIVE_BUFFER_SIZE]; /* Receive buffer */
int m_receiveOfs; /* Receive buffer offset */ int m_receiveOfs; /* Receive buffer offset */
uint8_t m_replyBuffer[USYNERGY_REPLY_BUFFER_SIZE]; /* Reply buffer */ uint8_t m_replyBuffer[USYNERGY_REPLY_BUFFER_SIZE]; /* Reply buffer */
uint8_t* m_replyCur; /* Write offset into reply buffer */ uint8_t* m_replyCur; /* Write offset into reply buffer */
uint16_t m_mouseX; /* Mouse X position */ uint16_t m_mouseX; /* Mouse X position */
uint16_t m_mouseY; /* Mouse Y position */ uint16_t m_mouseY; /* Mouse Y position */
int16_t m_mouseWheelX; /* Mouse wheel X position */ int16_t m_mouseWheelX; /* Mouse wheel X position */
int16_t m_mouseWheelY; /* Mouse wheel Y position */ int16_t m_mouseWheelY; /* Mouse wheel Y position */
uSynergyBool m_mouseButtonLeft; /* Mouse left button */ uSynergyBool m_mouseButtonLeft; /* Mouse left button */
uSynergyBool m_mouseButtonRight; /* Mouse right button */ uSynergyBool m_mouseButtonRight; /* Mouse right button */
uSynergyBool m_mouseButtonMiddle; /* Mouse middle button */ uSynergyBool m_mouseButtonMiddle; /* Mouse middle button */
int8_t m_joystickSticks[USYNERGY_NUM_JOYSTICKS][4]; /* Joystick stick position in 2 axes for 2 sticks */ int8_t m_joystickSticks[USYNERGY_NUM_JOYSTICKS][4]; /* Joystick stick position in 2 axes for 2 sticks */
uint16_t m_joystickButtons[USYNERGY_NUM_JOYSTICKS]; /* Joystick button state */ uint16_t m_joystickButtons[USYNERGY_NUM_JOYSTICKS]; /* Joystick button state */
} uSynergyContext; } uSynergyContext;
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
// Interface // Interface
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
/** /**
@brief Initialize uSynergy context @brief Initialize uSynergy context
This function initializes @a context for use. Call this function directly after This function initializes @a context for use. Call this function directly after
creating the context, before filling in any configuration data in it. Not calling creating the context, before filling in any configuration data in it. Not calling
this function will cause undefined behavior. this function will cause undefined behavior.
@param context Context to be initialized @param context Context to be initialized
**/ **/
extern void uSynergyInit(uSynergyContext *context); extern void uSynergyInit(uSynergyContext *context);
/** /**
@brief Update uSynergy @brief Update uSynergy
This function updates uSynergy and does the bulk of the work. It does connection management, This function updates uSynergy and does the bulk of the work. It does connection management,
receiving data, reconnecting after errors or timeouts and so on. It assumes that networking receiving data, reconnecting after errors or timeouts and so on. It assumes that networking
operations are blocking and it can suspend the current thread if it needs to wait. It is operations are blocking and it can suspend the current thread if it needs to wait. It is
best practice to call uSynergyUpdate from a background thread so it is responsive. best practice to call uSynergyUpdate from a background thread so it is responsive.
Because uSynergy relies mostly on blocking calls it will mostly stay in thread sleep state Because uSynergy relies mostly on blocking calls it will mostly stay in thread sleep state
waiting for system mutexes and won't eat much memory. waiting for system mutexes and won't eat much memory.
uSynergyUpdate doesn't do any memory allocations or have any side effects beyond those of uSynergyUpdate doesn't do any memory allocations or have any side effects beyond those of
the callbacks it calls. the callbacks it calls.
@param context Context to be updated @param context Context to be updated
**/ **/
extern void uSynergyUpdate(uSynergyContext *context); extern void uSynergyUpdate(uSynergyContext *context);
/** /**
@brief Send clipboard data @brief Send clipboard data
This function sets new clipboard data and sends it to the server. Use this function if This function sets new clipboard data and sends it to the server. Use this function if
your client cuts or copies data onto the clipboard that it needs to share with the your client cuts or copies data onto the clipboard that it needs to share with the
server. server.
Currently there is only support for plaintext, but HTML and image data could be Currently there is only support for plaintext, but HTML and image data could be
supported with some effort. supported with some effort.
@param context Context to send clipboard data to @param context Context to send clipboard data to
@param text Text to set to the clipboard @param text Text to set to the clipboard
**/ **/
extern void uSynergySendClipboard(uSynergyContext *context, const char *text); extern void uSynergySendClipboard(uSynergyContext *context, const char *text);
#ifdef __cplusplus #ifdef __cplusplus
}; };
#endif #endif

View File

@ -19,15 +19,15 @@
#include "winmmjoy.h" #include "winmmjoy.h"
#include <MMSystem.h> #include <MMSystem.h>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#pragma comment(lib, "winmm.lib") #pragma comment(lib, "winmm.lib")
std::stringstream _logStream; std::stringstream _logStream;
#define LOG(s) \ #define LOG(s) \
_logStream.str(""); \ _logStream.str(""); \
_logStream << "winmmjoy: " << s << std::endl; \ _logStream << "winmmjoy: " << s << std::endl; \
s_log( _logStream.str().c_str()) s_log( _logStream.str().c_str())
static bool s_running = true; static bool s_running = true;
@ -64,7 +64,7 @@ mainLoop(void* data)
const char* triggersEvent = "IPrimaryScreen::getGameDeviceTriggersEvent"; const char* triggersEvent = "IPrimaryScreen::getGameDeviceTriggersEvent";
JOYINFOEX joyInfo; JOYINFOEX joyInfo;
ZeroMemory(&joyInfo, sizeof(joyInfo)); ZeroMemory(&joyInfo, sizeof(joyInfo));
joyInfo.dwSize = sizeof(joyInfo); joyInfo.dwSize = sizeof(joyInfo);
joyInfo.dwFlags = JOY_RETURNALL; joyInfo.dwFlags = JOY_RETURNALL;

View File

@ -1,47 +1,47 @@
/* /*
* synergy -- mouse and keyboard sharing utility * synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012 Bolton Software Ltd. * Copyright (C) 2012 Bolton Software Ltd.
* Copyright (C) 2012 Nick Bolton * Copyright (C) 2012 Nick Bolton
* *
* This package is free software; you can redistribute it and/or * This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file. * found in the file COPYING that should have accompanied this file.
* *
* This package is distributed in the hope that it will be useful, * This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "VersionCheckerTests.h" #include "VersionCheckerTests.h"
#include "VersionChecker.cpp" #include "VersionChecker.cpp"
#include "../../gui/tmp/debug/moc_VersionChecker.cpp" #include "../../gui/tmp/debug/moc_VersionChecker.cpp"
#include <QtTest/QTest> #include <QtTest/QTest>
void VersionCheckerTests::compareVersions() void VersionCheckerTests::compareVersions()
{ {
VersionChecker versionChecker; VersionChecker versionChecker;
// compare majors // compare majors
QCOMPARE(versionChecker.compareVersions("1.0.0", "2.0.0"), 1); QCOMPARE(versionChecker.compareVersions("1.0.0", "2.0.0"), 1);
QCOMPARE(versionChecker.compareVersions("2.0.0", "1.0.0"), -1); QCOMPARE(versionChecker.compareVersions("2.0.0", "1.0.0"), -1);
QCOMPARE(versionChecker.compareVersions("1.0.0", "1.0.0"), 0); QCOMPARE(versionChecker.compareVersions("1.0.0", "1.0.0"), 0);
QCOMPARE(versionChecker.compareVersions("1.4.8", "2.4.7"), 1); QCOMPARE(versionChecker.compareVersions("1.4.8", "2.4.7"), 1);
QCOMPARE(versionChecker.compareVersions("2.4.7", "1.4.8"), -1); QCOMPARE(versionChecker.compareVersions("2.4.7", "1.4.8"), -1);
// compare minors // compare minors
QCOMPARE(versionChecker.compareVersions("1.3.0", "1.4.0"), 1); QCOMPARE(versionChecker.compareVersions("1.3.0", "1.4.0"), 1);
QCOMPARE(versionChecker.compareVersions("1.4.0", "1.3.0"), -1); QCOMPARE(versionChecker.compareVersions("1.4.0", "1.3.0"), -1);
QCOMPARE(versionChecker.compareVersions("1.4.0", "1.4.0"), 0); QCOMPARE(versionChecker.compareVersions("1.4.0", "1.4.0"), 0);
QCOMPARE(versionChecker.compareVersions("1.3.8", "1.4.7"), 1); QCOMPARE(versionChecker.compareVersions("1.3.8", "1.4.7"), 1);
QCOMPARE(versionChecker.compareVersions("1.4.7", "1.3.8"), -1); QCOMPARE(versionChecker.compareVersions("1.4.7", "1.3.8"), -1);
// compare revs // compare revs
QCOMPARE(versionChecker.compareVersions("1.4.7", "1.4.8"), 1); QCOMPARE(versionChecker.compareVersions("1.4.7", "1.4.8"), 1);
QCOMPARE(versionChecker.compareVersions("1.4.8", "1.4.7"), -1); QCOMPARE(versionChecker.compareVersions("1.4.8", "1.4.7"), -1);
QCOMPARE(versionChecker.compareVersions("1.4.7", "1.4.7"), 0); QCOMPARE(versionChecker.compareVersions("1.4.7", "1.4.7"), 0);
} }

View File

@ -1,26 +1,26 @@
/* /*
* synergy -- mouse and keyboard sharing utility * synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012 Bolton Software Ltd. * Copyright (C) 2012 Bolton Software Ltd.
* Copyright (C) 2012 Nick Bolton * Copyright (C) 2012 Nick Bolton
* *
* This package is free software; you can redistribute it and/or * This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file. * found in the file COPYING that should have accompanied this file.
* *
* This package is distributed in the hope that it will be useful, * This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "QObject.h" #include "QObject.h"
class VersionCheckerTests : public QObject class VersionCheckerTests : public QObject
{ {
Q_OBJECT Q_OBJECT
private slots: private slots:
void compareVersions(); void compareVersions();
}; };

View File

@ -1,26 +1,26 @@
/* /*
* synergy -- mouse and keyboard sharing utility * synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012 Bolton Software Ltd. * Copyright (C) 2012 Bolton Software Ltd.
* Copyright (C) 2012 Nick Bolton * Copyright (C) 2012 Nick Bolton
* *
* This package is free software; you can redistribute it and/or * This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file. * found in the file COPYING that should have accompanied this file.
* *
* This package is distributed in the hope that it will be useful, * This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <QtTest/QTest> #include <QtTest/QTest>
#include "VersionCheckerTests.h" #include "VersionCheckerTests.h"
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
VersionCheckerTests versionCheckerTests; VersionCheckerTests versionCheckerTests;
QTest::qExec(&versionCheckerTests, argc, argv); QTest::qExec(&versionCheckerTests, argc, argv);
} }

View File

@ -19,6 +19,7 @@
#include "CLog.h" #include "CLog.h"
#include "TMethodEventJob.h" #include "TMethodEventJob.h"
#include "CSimpleEventQueueBuffer.h" #include "CSimpleEventQueueBuffer.h"
#include <stdexcept>
void void
CTestEventQueue::raiseQuitEvent() CTestEventQueue::raiseQuitEvent()
@ -47,6 +48,5 @@ CTestEventQueue::cleanupQuitTimeout()
void void
CTestEventQueue::handleQuitTimeout(const CEvent&, void* vclient) CTestEventQueue::handleQuitTimeout(const CEvent&, void* vclient)
{ {
LOG((CLOG_ERR "timeout")); throw std::runtime_error("test event queue timeout");
raiseQuitEvent();
} }

View File

@ -16,8 +16,11 @@
*/ */
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <iostream> #include <stdexcept>
#include <sstream>
#include <fstream> #include <fstream>
#include <iostream>
#include <stdio.h>
#define TEST_ENV #define TEST_ENV
@ -33,42 +36,74 @@
#include "CTCPSocketFactory.h" #include "CTCPSocketFactory.h"
#include "CCryptoOptions.h" #include "CCryptoOptions.h"
#include "CSocketMultiplexer.h" #include "CSocketMultiplexer.h"
#include "CMSWindowsScreen.h"
#include "CGameDevice.h"
#include "CThread.h"
#include "TMethodJob.h"
#include "CTestEventQueue.h" #include "CTestEventQueue.h"
#include "server/CMockInputFilter.h" #include "server/CMockInputFilter.h"
#include "TMethodJob.h"
#include "CThread.h"
#include "CFileChunker.h"
using namespace std;
using ::testing::_; using ::testing::_;
using ::testing::NiceMock; using ::testing::NiceMock;
using ::testing::Return; using ::testing::Return;
using ::testing::Invoke; using ::testing::Invoke;
#define TEST_PORT 24803 #define TEST_PORT 24803
#define TEST_HOST "localhost" #define TEST_HOST "localhost"
const int klargeDataSize = 512; const size_t kMockDataSize = 1024 * 1024 * 10; // 10MB
char g_largeData[klargeDataSize] = "large data:head.1221412312341244213123fdsfasdawdwadwadacwdd.12321412312341244213123fdsfasdawdwadwadacwdawddawdwacawdawd232141231awddawdwacawdawd2321412312341244213123fdsfasdawdwadacwdawddawdwacawdtrtetawdawdwaewe1213412321412312341244213123fdsfasdawdwadacwdawddawdwacawdawdawdwaewe121341awdwaewedacwdawddawdwacawdawd2321412312341244213123fdsfasdawdwadacwdawddawdwacawdtrtetawdawdwaewe1213412321412312341244213123fdsfasdawdwadacwdawddawdwacawdawdawdwaewe121341awdwaewe12134123njk1u31i2nm3e123hu23oi132213njk.tail"; const UInt16 kMockDataChunkIncrement = 1024; // 1KB
const char* kMockFilename = "NetworkTests.mock";
const size_t kMockFileSize = 1024 * 1024 * 10; // 10MB
void sendFileToClient_getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h); void getScreenShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h);
void sendFileToClient_getCursorPos(SInt32& x, SInt32& y); void getCursorPos(SInt32& x, SInt32& y);
CString intToString(size_t i);
UInt8* newMockData(size_t size);
void createFile(fstream& file, const char* filename, size_t size);
class NetworkTests : public ::testing::Test class NetworkTests : public ::testing::Test
{ {
public: public:
NetworkTests() { } NetworkTests() :
m_mockData(NULL),
m_mockDataSize(0),
m_mockFileSize(0)
{
m_mockData = newMockData(kMockDataSize);
createFile(m_mockFile, kMockFilename, kMockFileSize);
}
void sendData(CServer* server); ~NetworkTests()
{
remove(kMockFilename);
delete[] m_mockData;
}
void sendMockData(void* eventTarget);
void sendFileToClient_handleClientConnected(const CEvent&, void* vlistener); void sendToClient_mockData_handleClientConnected(const CEvent&, void* vlistener);
void sendFileToClient_fileRecieveComplete(const CEvent&, void*); void sendToClient_mockData_fileRecieveComplete(const CEvent&, void*);
void sendToClient_mockFile_handleClientConnected(const CEvent&, void* vlistener);
void sendToClient_mockFile_fileRecieveComplete(const CEvent& event, void*);
void sendToServer_mockData_handleClientConnected(const CEvent&, void* vlistener);
void sendToServer_mockData_fileRecieveComplete(const CEvent& event, void*);
void sendToServer_mockFile_handleClientConnected(const CEvent&, void* vlistener);
void sendToServer_mockFile_fileRecieveComplete(const CEvent& event, void*);
public: public:
CTestEventQueue m_events; CTestEventQueue m_events;
UInt8* m_mockData;
size_t m_mockDataSize;
fstream m_mockFile;
size_t m_mockFileSize;
}; };
TEST_F(NetworkTests, sendFileToClient) TEST_F(NetworkTests, sendToClient_mockData)
{ {
// server and client // server and client
CNetworkAddress serverAddress(TEST_HOST, TEST_PORT); CNetworkAddress serverAddress(TEST_HOST, TEST_PORT);
@ -88,7 +123,7 @@ TEST_F(NetworkTests, sendFileToClient)
m_events.adoptHandler( m_events.adoptHandler(
m_events.forCClientListener().connected(), &listener, m_events.forCClientListener().connected(), &listener,
new TMethodEventJob<NetworkTests>( new TMethodEventJob<NetworkTests>(
this, &NetworkTests::sendFileToClient_handleClientConnected, &listener)); this, &NetworkTests::sendToClient_mockData_handleClientConnected, &listener));
ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true)); ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true));
ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter)); ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter));
@ -102,43 +137,196 @@ TEST_F(NetworkTests, sendFileToClient)
CSocketMultiplexer clientSocketMultiplexer; CSocketMultiplexer clientSocketMultiplexer;
CTCPSocketFactory* clientSocketFactory = new CTCPSocketFactory(&m_events, &clientSocketMultiplexer); CTCPSocketFactory* clientSocketFactory = new CTCPSocketFactory(&m_events, &clientSocketMultiplexer);
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(sendFileToClient_getShape)); ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape));
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(sendFileToClient_getCursorPos)); ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
CClient client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions); CClient client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions);
m_events.adoptHandler( m_events.adoptHandler(
m_events.forIScreen().fileRecieveComplete(), &client, m_events.forIScreen().fileRecieveComplete(), &client,
new TMethodEventJob<NetworkTests>( new TMethodEventJob<NetworkTests>(
this, &NetworkTests::sendFileToClient_fileRecieveComplete)); this, &NetworkTests::sendToClient_mockData_fileRecieveComplete));
client.connect(); client.connect();
m_events.initQuitTimeout(10); m_events.initQuitTimeout(5);
m_events.loop();
m_events.cleanupQuitTimeout();
}
TEST_F(NetworkTests, sendToClient_mockFile)
{
// server and client
CNetworkAddress serverAddress(TEST_HOST, TEST_PORT);
CCryptoOptions cryptoOptions;
serverAddress.resolve();
// server
CSocketMultiplexer serverSocketMultiplexer;
CTCPSocketFactory* serverSocketFactory = new CTCPSocketFactory(&m_events, &serverSocketMultiplexer);
CClientListener listener(serverAddress, serverSocketFactory, NULL, cryptoOptions, &m_events);
NiceMock<CMockScreen> serverScreen;
NiceMock<CMockPrimaryClient> primaryClient;
NiceMock<CMockConfig> serverConfig;
NiceMock<CMockInputFilter> serverInputFilter;
m_events.adoptHandler(
m_events.forCClientListener().connected(), &listener,
new TMethodEventJob<NetworkTests>(
this, &NetworkTests::sendToClient_mockFile_handleClientConnected, &listener));
ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true));
ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter));
CServer server(serverConfig, &primaryClient, &serverScreen, &m_events);
server.m_mock = true;
listener.setServer(&server);
// client
NiceMock<CMockScreen> clientScreen;
CSocketMultiplexer clientSocketMultiplexer;
CTCPSocketFactory* clientSocketFactory = new CTCPSocketFactory(&m_events, &clientSocketMultiplexer);
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape));
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
CClient client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions);
m_events.adoptHandler(
m_events.forIScreen().fileRecieveComplete(), &client,
new TMethodEventJob<NetworkTests>(
this, &NetworkTests::sendToClient_mockFile_fileRecieveComplete));
client.connect();
m_events.initQuitTimeout(5);
m_events.loop();
m_events.cleanupQuitTimeout();
}
TEST_F(NetworkTests, sendToServer_mockData)
{
// server and client
CNetworkAddress serverAddress(TEST_HOST, TEST_PORT);
CCryptoOptions cryptoOptions;
serverAddress.resolve();
// server
CSocketMultiplexer serverSocketMultiplexer;
CTCPSocketFactory* serverSocketFactory = new CTCPSocketFactory(&m_events, &serverSocketMultiplexer);
CClientListener listener(serverAddress, serverSocketFactory, NULL, cryptoOptions, &m_events);
NiceMock<CMockScreen> serverScreen;
NiceMock<CMockPrimaryClient> primaryClient;
NiceMock<CMockConfig> serverConfig;
NiceMock<CMockInputFilter> serverInputFilter;
ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true));
ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter));
CServer server(serverConfig, &primaryClient, &serverScreen, &m_events);
server.m_mock = true;
listener.setServer(&server);
// client
NiceMock<CMockScreen> clientScreen;
CSocketMultiplexer clientSocketMultiplexer;
CTCPSocketFactory* clientSocketFactory = new CTCPSocketFactory(&m_events, &clientSocketMultiplexer);
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape));
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
CClient client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions);
m_events.adoptHandler(
m_events.forCClientListener().connected(), &listener,
new TMethodEventJob<NetworkTests>(
this, &NetworkTests::sendToServer_mockData_handleClientConnected, &client));
m_events.adoptHandler(
m_events.forIScreen().fileRecieveComplete(), &server,
new TMethodEventJob<NetworkTests>(
this, &NetworkTests::sendToServer_mockData_fileRecieveComplete));
client.connect();
m_events.initQuitTimeout(5);
m_events.loop();
m_events.cleanupQuitTimeout();
}
TEST_F(NetworkTests, sendToServer_mockFile)
{
// server and client
CNetworkAddress serverAddress(TEST_HOST, TEST_PORT);
CCryptoOptions cryptoOptions;
serverAddress.resolve();
// server
CSocketMultiplexer serverSocketMultiplexer;
CTCPSocketFactory* serverSocketFactory = new CTCPSocketFactory(&m_events, &serverSocketMultiplexer);
CClientListener listener(serverAddress, serverSocketFactory, NULL, cryptoOptions, &m_events);
NiceMock<CMockScreen> serverScreen;
NiceMock<CMockPrimaryClient> primaryClient;
NiceMock<CMockConfig> serverConfig;
NiceMock<CMockInputFilter> serverInputFilter;
ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true));
ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter));
CServer server(serverConfig, &primaryClient, &serverScreen, &m_events);
server.m_mock = true;
listener.setServer(&server);
// client
NiceMock<CMockScreen> clientScreen;
CSocketMultiplexer clientSocketMultiplexer;
CTCPSocketFactory* clientSocketFactory = new CTCPSocketFactory(&m_events, &clientSocketMultiplexer);
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape));
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
CClient client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions);
m_events.adoptHandler(
m_events.forCClientListener().connected(), &listener,
new TMethodEventJob<NetworkTests>(
this, &NetworkTests::sendToServer_mockFile_handleClientConnected, &client));
m_events.adoptHandler(
m_events.forIScreen().fileRecieveComplete(), &server,
new TMethodEventJob<NetworkTests>(
this, &NetworkTests::sendToServer_mockFile_fileRecieveComplete));
client.connect();
m_events.initQuitTimeout(5);
m_events.loop(); m_events.loop();
m_events.cleanupQuitTimeout(); m_events.cleanupQuitTimeout();
} }
void void
NetworkTests::sendFileToClient_handleClientConnected(const CEvent&, void* vlistener) NetworkTests::sendToClient_mockData_handleClientConnected(const CEvent&, void* vlistener)
{ {
CClientListener* listener = reinterpret_cast<CClientListener*>(vlistener); CClientListener* listener = reinterpret_cast<CClientListener*>(vlistener);
CServer* server = listener->getServer(); CServer* server = listener->getServer();
CClientProxy* client = listener->getNextClient(); CClientProxy* client = listener->getNextClient();
if (client == NULL) { if (client == NULL) {
throw std::exception("client is null"); throw runtime_error("client is null");
} }
CBaseClientProxy* bcp = reinterpret_cast<CBaseClientProxy*>(client); CBaseClientProxy* bcp = reinterpret_cast<CBaseClientProxy*>(client);
server->adoptClient(bcp); server->adoptClient(bcp);
server->setActive(bcp); server->setActive(bcp);
sendData(server); sendMockData(server);
} }
void void
NetworkTests::sendFileToClient_fileRecieveComplete(const CEvent& event, void*) NetworkTests::sendToClient_mockData_fileRecieveComplete(const CEvent& event, void*)
{ {
CClient* client = reinterpret_cast<CClient*>(event.getTarget()); CClient* client = reinterpret_cast<CClient*>(event.getTarget());
EXPECT_TRUE(client->isReceivedFileSizeValid()); EXPECT_TRUE(client->isReceivedFileSizeValid());
@ -147,32 +335,166 @@ NetworkTests::sendFileToClient_fileRecieveComplete(const CEvent& event, void*)
} }
void void
NetworkTests::sendData(CServer* server) NetworkTests::sendToClient_mockFile_handleClientConnected(const CEvent&, void* vlistener)
{ {
UInt8* largeDataSize = new UInt8[5]; CClientListener* listener = reinterpret_cast<CClientListener*>(vlistener);
largeDataSize[0] = '0'; CServer* server = listener->getServer();
largeDataSize[1] = '5';
largeDataSize[2] = '1';
largeDataSize[3] = '1';
largeDataSize[4] = '\0';
// transfer data from server -> client
m_events.addEvent(CEvent(m_events.forIScreen().fileChunkSending(), server, largeDataSize));
UInt8* largeData = new UInt8[klargeDataSize + 1];
largeData[0] = '1';
memcpy(&largeData[1], g_largeData, klargeDataSize);
m_events.addEvent(CEvent(m_events.forIScreen().fileChunkSending(), server, (UInt8*)largeData));
UInt8* transferFinished = new UInt8[2]; CClientProxy* client = listener->getNextClient();
transferFinished[0] = '2'; if (client == NULL) {
transferFinished[1] = '\0'; throw runtime_error("client is null");
}
m_events.addEvent(CEvent(m_events.forIScreen().fileChunkSending(), server, transferFinished)); CBaseClientProxy* bcp = reinterpret_cast<CBaseClientProxy*>(client);
server->adoptClient(bcp);
server->setActive(bcp);
server->sendFileToClient(kMockFilename);
}
void
NetworkTests::sendToClient_mockFile_fileRecieveComplete(const CEvent& event, void*)
{
CClient* client = reinterpret_cast<CClient*>(event.getTarget());
EXPECT_TRUE(client->isReceivedFileSizeValid());
m_events.raiseQuitEvent();
}
void
NetworkTests::sendToServer_mockData_handleClientConnected(const CEvent&, void* vclient)
{
CClient* client = reinterpret_cast<CClient*>(vclient);
sendMockData(client);
}
void
NetworkTests::sendToServer_mockData_fileRecieveComplete(const CEvent& event, void*)
{
CServer* server = reinterpret_cast<CServer*>(event.getTarget());
EXPECT_TRUE(server->isReceivedFileSizeValid());
m_events.raiseQuitEvent();
}
void
NetworkTests::sendToServer_mockFile_handleClientConnected(const CEvent&, void* vclient)
{
CClient* client = reinterpret_cast<CClient*>(vclient);
client->sendFileToServer(kMockFilename);
}
void
NetworkTests::sendToServer_mockFile_fileRecieveComplete(const CEvent& event, void*)
{
CServer* server = reinterpret_cast<CServer*>(event.getTarget());
EXPECT_TRUE(server->isReceivedFileSizeValid());
m_events.raiseQuitEvent();
}
void
NetworkTests::sendMockData(void* eventTarget)
{
// send first message (file size)
CString size = intToString(kMockDataSize);
UInt32 sizeLength = size.size();
CFileChunker::CFileChunk* sizeMessage = new CFileChunker::CFileChunk(sizeLength + 2);
char* chunkData = sizeMessage->m_chunk;
chunkData[0] = kFileStart;
memcpy(&chunkData[1], size.c_str(), sizeLength);
chunkData[sizeLength + 1] = '\0';
m_events.addEvent(CEvent(m_events.forIScreen().fileChunkSending(), eventTarget, sizeMessage));
// send chunk messages with incrementing chunk size
size_t lastSize = 0;
size_t sentLength = 0;
while (true) {
size_t chunkSize = lastSize + kMockDataChunkIncrement;
// make sure we don't read too much from the mock data.
if (sentLength + chunkSize > kMockDataSize) {
chunkSize = kMockDataSize - sentLength;
}
// first byte is the chunk mark, last is \0
CFileChunker::CFileChunk* fileChunk = new CFileChunker::CFileChunk(chunkSize + 2);
char* chunkData = fileChunk->m_chunk;
chunkData[0] = kFileChunk;
memcpy(&chunkData[1], &m_mockData[sentLength], chunkSize);
chunkData[chunkSize + 1] = '\0';
m_events.addEvent(CEvent(m_events.forIScreen().fileChunkSending(), eventTarget, fileChunk));
sentLength += chunkSize;
lastSize = chunkSize;
if (sentLength == kMockDataSize) {
break;
}
}
// send last message
CFileChunker::CFileChunk* transferFinished = new CFileChunker::CFileChunk(2);
chunkData = transferFinished->m_chunk;
chunkData[0] = kFileEnd;
chunkData[1] = '\0';
m_events.addEvent(CEvent(m_events.forIScreen().fileChunkSending(), eventTarget, transferFinished));
}
UInt8*
newMockData(size_t size)
{
UInt8* buffer = new UInt8[size];
UInt8* data = buffer;
const UInt8 head[] = "mock head... ";
size_t headSize = sizeof(head) - 1;
const UInt8 tail[] = "... mock tail";
size_t tailSize = sizeof(tail) - 1;
const UInt8 synergyRocks[] = "synergy\0 rocks! ";
size_t synergyRocksSize = sizeof(synergyRocks) - 1;
memcpy(data, head, headSize);
data += headSize;
SInt32 times = (size - headSize - tailSize) / synergyRocksSize;
for (SInt32 i = 0; i < times; ++i) {
memcpy(data, synergyRocks, synergyRocksSize);
data += synergyRocksSize;
}
SInt32 remainder = (size - headSize - tailSize) % synergyRocksSize;
if (remainder != 0) {
memset(data, '.', remainder);
data += remainder;
}
memcpy(data, tail, tailSize);
return buffer;
} }
void void
sendFileToClient_getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) createFile(fstream& file, const char* filename, size_t size)
{
UInt8* buffer = newMockData(size);
file.open(filename, ios::out | ios::binary);
if (!file.is_open()) {
throw runtime_error("file not open");
}
file.write(reinterpret_cast<char*>(buffer), size);
file.close();
delete[] buffer;
}
void
getScreenShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h)
{ {
x = 0; x = 0;
y = 0; y = 0;
@ -181,8 +503,16 @@ sendFileToClient_getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h)
} }
void void
sendFileToClient_getCursorPos(SInt32& x, SInt32& y) getCursorPos(SInt32& x, SInt32& y)
{ {
x = 0; x = 0;
y = 0; y = 0;
} }
CString
intToString(size_t i)
{
stringstream ss;
ss << i;
return ss.str();
}

View File

@ -20,8 +20,8 @@
#include <gmock/gmock.h> #include <gmock/gmock.h>
#include "COSXKeyState.h" #include "COSXKeyState.h"
#include "CMockKeyMap.h" #include "synergy/CMockKeyMap.h"
#include "CMockEventQueue.h" #include "synergy/CMockEventQueue.h"
#include "CLog.h" #include "CLog.h"

View File

@ -22,8 +22,8 @@
#define TEST_ENV #define TEST_ENV
#include "Global.h" #include "Global.h"
#include "CMockKeyMap.h" #include "synergy/CMockKeyMap.h"
#include "CMockEventQueue.h" #include "synergy/CMockEventQueue.h"
#include "CXWindowsKeyState.h" #include "CXWindowsKeyState.h"
#include "CLog.h" #include "CLog.h"
#include <errno.h> #include <errno.h>

View File

@ -18,7 +18,7 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "CXWindowsScreen.h" #include "CXWindowsScreen.h"
#include "CMockEventQueue.h" #include "synergy/CMockEventQueue.h"
using ::testing::_; using ::testing::_;

View File

@ -48,8 +48,8 @@ TEST(CServerProxyTests, mouseMove)
g_mouseMove_bufferIndex = 0; g_mouseMove_bufferIndex = 0;
NiceMock<CMockEventQueue> eventQueue; NiceMock<CMockEventQueue> eventQueue;
NiceMock<CMockClient> client;
NiceMock<CMockStream> stream; NiceMock<CMockStream> stream;
NiceMock<CMockClient> client;
IStreamEvents streamEvents; IStreamEvents streamEvents;
streamEvents.setEvents(&eventQueue); streamEvents.setEvents(&eventQueue);