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

View File

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

View File

@ -64,17 +64,17 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, INT nCmdSh
}
if (!server && !client) {
MessageBox(NULL,
"Either the --server argument or the --client argument must be provided.",
"Server or client?", MB_OK);
MessageBox(NULL,
"Either the --server argument or the --client argument must be provided.",
"Server or client?", MB_OK);
return 1;
}
if (argc <= 2) {
MessageBox(NULL,
"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.",
"No additional arguments", MB_OK);
MessageBox(NULL,
"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.",
"No additional arguments", MB_OK);
return 1;
}

View File

@ -1,26 +1,26 @@
/*
* 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
enum CryptoMode {
Disabled,
OFB,
CFB,
CTR,
GCM
};
/*
* 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
enum CryptoMode {
Disabled,
OFB,
CFB,
CTR,
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 Nick Bolton
*
* 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/>.
*/
// this class is a duplicate of /src/lib/ipc/Ipc.cpp
#include "Ipc.h"
const char* kIpcMsgHello = "IHEL%1i";
const char* kIpcMsgLogLine = "ILOG%s";
const char* kIpcMsgCommand = "ICMD%s%1i";
const char* kIpcMsgShutdown = "ISDN";
* Copyright (C) 2012 Nick Bolton
*
* 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/>.
*/
// this class is a duplicate of /src/lib/ipc/Ipc.cpp
#include "Ipc.h"
const char* kIpcMsgHello = "IHEL%1i";
const char* kIpcMsgLogLine = "ILOG%s";
const char* kIpcMsgCommand = "ICMD%s%1i";
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 Nick Bolton
*
* 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/>.
*/
// this class is a duplicate of /src/lib/ipc/Ipc.h
#pragma once
#define IPC_HOST "127.0.0.1"
#define IPC_PORT 24801
enum qIpcMessageType {
kIpcHello,
kIpcLogLine,
kIpcCommand,
kIpcShutdown,
};
enum qIpcClientType {
kIpcClientUnknown,
kIpcClientGui,
kIpcClientNode,
};
extern const char* kIpcMsgHello;
extern const char* kIpcMsgLogLine;
extern const char* kIpcMsgCommand;
extern const char* kIpcMsgShutdown;
* Copyright (C) 2012 Nick Bolton
*
* 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/>.
*/
// this class is a duplicate of /src/lib/ipc/Ipc.h
#pragma once
#define IPC_HOST "127.0.0.1"
#define IPC_PORT 24801
enum qIpcMessageType {
kIpcHello,
kIpcLogLine,
kIpcCommand,
kIpcShutdown,
};
enum qIpcClientType {
kIpcClientUnknown,
kIpcClientGui,
kIpcClientNode,
};
extern const char* kIpcMsgHello;
extern const char* kIpcMsgLogLine;
extern const char* kIpcMsgCommand;
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 Nick Bolton
*
* 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 "IpcClient.h"
#include <QTcpSocket>
#include <QHostAddress>
#include <iostream>
#include <QTimer>
#include "IpcReader.h"
#include "Ipc.h"
IpcClient::IpcClient() :
m_ReaderStarted(false),
m_Enabled(false)
{
m_Socket = new QTcpSocket(this);
connect(m_Socket, SIGNAL(connected()), this, SLOT(connected()));
connect(m_Socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error(QAbstractSocket::SocketError)));
m_Reader = new IpcReader(m_Socket);
connect(m_Reader, SIGNAL(readLogLine(const QString&)), this, SLOT(handleReadLogLine(const QString&)));
}
IpcClient::~IpcClient()
{
}
void IpcClient::connected()
{
char typeBuf[1];
typeBuf[0] = kIpcClientGui;
sendHello();
infoMessage("connection established");
}
void IpcClient::connectToHost()
{
m_Enabled = true;
infoMessage("connecting to service...");
m_Socket->connectToHost(QHostAddress(QHostAddress::LocalHost), IPC_PORT);
if (!m_ReaderStarted) {
m_Reader->start();
m_ReaderStarted = true;
}
}
void IpcClient::disconnectFromHost()
{
infoMessage("service disconnect");
m_Reader->stop();
m_Socket->close();
}
void IpcClient::error(QAbstractSocket::SocketError error)
{
QString text;
switch (error) {
case 0: text = "connection refused"; break;
case 1: text = "remote host closed"; break;
default: text = QString("code=%1").arg(error); break;
}
errorMessage(QString("ipc connection error, %1").arg(text));
QTimer::singleShot(1000, this, SLOT(retryConnect()));
}
void IpcClient::retryConnect()
{
if (m_Enabled) {
connectToHost();
}
}
void IpcClient::sendHello()
{
QDataStream stream(m_Socket);
stream.writeRawData(kIpcMsgHello, 4);
char typeBuf[1];
typeBuf[0] = kIpcClientGui;
stream.writeRawData(typeBuf, 1);
}
void IpcClient::sendCommand(const QString& command, bool elevate)
{
QDataStream stream(m_Socket);
stream.writeRawData(kIpcMsgCommand, 4);
std::string stdStringCommand = command.toStdString();
const char* charCommand = stdStringCommand.c_str();
int length = strlen(charCommand);
char lenBuf[4];
intToBytes(length, lenBuf, 4);
stream.writeRawData(lenBuf, 4);
stream.writeRawData(charCommand, length);
char elevateBuf[1];
elevateBuf[0] = elevate ? 1 : 0;
stream.writeRawData(elevateBuf, 1);
}
void IpcClient::handleReadLogLine(const QString& text)
{
readLogLine(text);
}
// TODO: qt must have a built in way of converting int to bytes.
void IpcClient::intToBytes(int value, char *buffer, int size)
{
if (size == 1) {
buffer[0] = value & 0xff;
}
else if (size == 2) {
buffer[0] = (value >> 8) & 0xff;
buffer[1] = value & 0xff;
}
else if (size == 4) {
buffer[0] = (value >> 24) & 0xff;
buffer[1] = (value >> 16) & 0xff;
buffer[2] = (value >> 8) & 0xff;
buffer[3] = value & 0xff;
}
else {
// TODO: other sizes, if needed.
}
}
* Copyright (C) 2012 Nick Bolton
*
* 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 "IpcClient.h"
#include <QTcpSocket>
#include <QHostAddress>
#include <iostream>
#include <QTimer>
#include "IpcReader.h"
#include "Ipc.h"
IpcClient::IpcClient() :
m_ReaderStarted(false),
m_Enabled(false)
{
m_Socket = new QTcpSocket(this);
connect(m_Socket, SIGNAL(connected()), this, SLOT(connected()));
connect(m_Socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error(QAbstractSocket::SocketError)));
m_Reader = new IpcReader(m_Socket);
connect(m_Reader, SIGNAL(readLogLine(const QString&)), this, SLOT(handleReadLogLine(const QString&)));
}
IpcClient::~IpcClient()
{
}
void IpcClient::connected()
{
char typeBuf[1];
typeBuf[0] = kIpcClientGui;
sendHello();
infoMessage("connection established");
}
void IpcClient::connectToHost()
{
m_Enabled = true;
infoMessage("connecting to service...");
m_Socket->connectToHost(QHostAddress(QHostAddress::LocalHost), IPC_PORT);
if (!m_ReaderStarted) {
m_Reader->start();
m_ReaderStarted = true;
}
}
void IpcClient::disconnectFromHost()
{
infoMessage("service disconnect");
m_Reader->stop();
m_Socket->close();
}
void IpcClient::error(QAbstractSocket::SocketError error)
{
QString text;
switch (error) {
case 0: text = "connection refused"; break;
case 1: text = "remote host closed"; break;
default: text = QString("code=%1").arg(error); break;
}
errorMessage(QString("ipc connection error, %1").arg(text));
QTimer::singleShot(1000, this, SLOT(retryConnect()));
}
void IpcClient::retryConnect()
{
if (m_Enabled) {
connectToHost();
}
}
void IpcClient::sendHello()
{
QDataStream stream(m_Socket);
stream.writeRawData(kIpcMsgHello, 4);
char typeBuf[1];
typeBuf[0] = kIpcClientGui;
stream.writeRawData(typeBuf, 1);
}
void IpcClient::sendCommand(const QString& command, bool elevate)
{
QDataStream stream(m_Socket);
stream.writeRawData(kIpcMsgCommand, 4);
std::string stdStringCommand = command.toStdString();
const char* charCommand = stdStringCommand.c_str();
int length = strlen(charCommand);
char lenBuf[4];
intToBytes(length, lenBuf, 4);
stream.writeRawData(lenBuf, 4);
stream.writeRawData(charCommand, length);
char elevateBuf[1];
elevateBuf[0] = elevate ? 1 : 0;
stream.writeRawData(elevateBuf, 1);
}
void IpcClient::handleReadLogLine(const QString& text)
{
readLogLine(text);
}
// TODO: qt must have a built in way of converting int to bytes.
void IpcClient::intToBytes(int value, char *buffer, int size)
{
if (size == 1) {
buffer[0] = value & 0xff;
}
else if (size == 2) {
buffer[0] = (value >> 8) & 0xff;
buffer[1] = value & 0xff;
}
else if (size == 4) {
buffer[0] = (value >> 24) & 0xff;
buffer[1] = (value >> 16) & 0xff;
buffer[2] = (value >> 8) & 0xff;
buffer[3] = value & 0xff;
}
else {
// 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 Nick Bolton
*
* 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 <QObject>
#include <QAbstractSocket>
class QTcpSocket;
class IpcReader;
class IpcClient : public QObject
{
Q_OBJECT
public:
IpcClient();
virtual ~IpcClient();
void sendHello();
void sendCommand(const QString& command, bool elevate);
void connectToHost();
void disconnectFromHost();
public slots:
void retryConnect();
private:
void intToBytes(int value, char* buffer, int size);
private slots:
void connected();
void error(QAbstractSocket::SocketError error);
void handleReadLogLine(const QString& text);
signals:
void readLogLine(const QString& text);
void infoMessage(const QString& text);
void errorMessage(const QString& text);
private:
QTcpSocket* m_Socket;
IpcReader* m_Reader;
bool m_ReaderStarted;
bool m_Enabled;
};
* Copyright (C) 2012 Nick Bolton
*
* 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 <QObject>
#include <QAbstractSocket>
class QTcpSocket;
class IpcReader;
class IpcClient : public QObject
{
Q_OBJECT
public:
IpcClient();
virtual ~IpcClient();
void sendHello();
void sendCommand(const QString& command, bool elevate);
void connectToHost();
void disconnectFromHost();
public slots:
void retryConnect();
private:
void intToBytes(int value, char* buffer, int size);
private slots:
void connected();
void error(QAbstractSocket::SocketError error);
void handleReadLogLine(const QString& text);
signals:
void readLogLine(const QString& text);
void infoMessage(const QString& text);
void errorMessage(const QString& text);
private:
QTcpSocket* m_Socket;
IpcReader* m_Reader;
bool m_ReaderStarted;
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 Nick Bolton
*
* 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 "IpcReader.h"
#include <QTcpSocket>
#include "Ipc.h"
#include <iostream>
#include <QMutex>
#include <QByteArray>
IpcReader::IpcReader(QTcpSocket* socket) :
m_Socket(socket)
{
}
IpcReader::~IpcReader()
{
}
void IpcReader::start()
{
connect(m_Socket, SIGNAL(readyRead()), this, SLOT(read()));
}
void IpcReader::stop()
{
disconnect(m_Socket, SIGNAL(readyRead()), this, SLOT(read()));
}
void IpcReader::read()
{
QMutexLocker locker(&m_Mutex);
std::cout << "ready read" << std::endl;
while (m_Socket->bytesAvailable()) {
std::cout << "bytes available" << std::endl;
char codeBuf[5];
readStream(codeBuf, 4);
codeBuf[4] = 0;
std::cout << "ipc read: " << codeBuf << std::endl;
if (memcmp(codeBuf, kIpcMsgLogLine, 4) == 0) {
std::cout << "reading log line" << std::endl;
char lenBuf[4];
readStream(lenBuf, 4);
int len = bytesToInt(lenBuf, 4);
char* data = new char[len];
readStream(data, len);
QString line = QString::fromUtf8(data, len);
delete data;
readLogLine(line);
}
else {
std::cerr << "aborting, message invalid" << std::endl;
return;
}
}
std::cout << "read done" << std::endl;
}
bool IpcReader::readStream(char* buffer, int length)
{
std::cout << "reading stream" << std::endl;
int read = 0;
while (read < length) {
int ask = length - read;
if (m_Socket->bytesAvailable() < ask) {
std::cout << "buffer too short, waiting" << std::endl;
m_Socket->waitForReadyRead(-1);
}
int got = m_Socket->read(buffer, ask);
read += got;
std::cout << "> ask=" << ask << " got=" << got
<< " read=" << read << std::endl;
if (got == -1) {
std::cout << "socket ended, aborting" << std::endl;
return false;
}
else if (length - read > 0) {
std::cout << "more remains, seek to " << got << std::endl;
buffer += got;
}
}
return true;
}
int IpcReader::bytesToInt(const char *buffer, int size)
{
if (size == 1) {
return (unsigned char)buffer[0];
}
else if (size == 2) {
return
(((unsigned char)buffer[0]) << 8) +
(unsigned char)buffer[1];
}
else if (size == 4) {
return
(((unsigned char)buffer[0]) << 24) +
(((unsigned char)buffer[1]) << 16) +
(((unsigned char)buffer[2]) << 8) +
(unsigned char)buffer[3];
}
else {
return 0;
}
}
* Copyright (C) 2012 Nick Bolton
*
* 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 "IpcReader.h"
#include <QTcpSocket>
#include "Ipc.h"
#include <iostream>
#include <QMutex>
#include <QByteArray>
IpcReader::IpcReader(QTcpSocket* socket) :
m_Socket(socket)
{
}
IpcReader::~IpcReader()
{
}
void IpcReader::start()
{
connect(m_Socket, SIGNAL(readyRead()), this, SLOT(read()));
}
void IpcReader::stop()
{
disconnect(m_Socket, SIGNAL(readyRead()), this, SLOT(read()));
}
void IpcReader::read()
{
QMutexLocker locker(&m_Mutex);
std::cout << "ready read" << std::endl;
while (m_Socket->bytesAvailable()) {
std::cout << "bytes available" << std::endl;
char codeBuf[5];
readStream(codeBuf, 4);
codeBuf[4] = 0;
std::cout << "ipc read: " << codeBuf << std::endl;
if (memcmp(codeBuf, kIpcMsgLogLine, 4) == 0) {
std::cout << "reading log line" << std::endl;
char lenBuf[4];
readStream(lenBuf, 4);
int len = bytesToInt(lenBuf, 4);
char* data = new char[len];
readStream(data, len);
QString line = QString::fromUtf8(data, len);
delete data;
readLogLine(line);
}
else {
std::cerr << "aborting, message invalid" << std::endl;
return;
}
}
std::cout << "read done" << std::endl;
}
bool IpcReader::readStream(char* buffer, int length)
{
std::cout << "reading stream" << std::endl;
int read = 0;
while (read < length) {
int ask = length - read;
if (m_Socket->bytesAvailable() < ask) {
std::cout << "buffer too short, waiting" << std::endl;
m_Socket->waitForReadyRead(-1);
}
int got = m_Socket->read(buffer, ask);
read += got;
std::cout << "> ask=" << ask << " got=" << got
<< " read=" << read << std::endl;
if (got == -1) {
std::cout << "socket ended, aborting" << std::endl;
return false;
}
else if (length - read > 0) {
std::cout << "more remains, seek to " << got << std::endl;
buffer += got;
}
}
return true;
}
int IpcReader::bytesToInt(const char *buffer, int size)
{
if (size == 1) {
return (unsigned char)buffer[0];
}
else if (size == 2) {
return
(((unsigned char)buffer[0]) << 8) +
(unsigned char)buffer[1];
}
else if (size == 4) {
return
(((unsigned char)buffer[0]) << 24) +
(((unsigned char)buffer[1]) << 16) +
(((unsigned char)buffer[2]) << 8) +
(unsigned char)buffer[3];
}
else {
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 Nick Bolton
*
* 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 <QObject>
#include <QMutex>
class QTcpSocket;
class IpcReader : public QObject
{
Q_OBJECT;
public:
IpcReader(QTcpSocket* socket);
virtual ~IpcReader();
void start();
void stop();
signals:
void readLogLine(const QString& text);
private:
bool readStream(char* buffer, int length);
int bytesToInt(const char* buffer, int size);
private slots:
void read();
private:
QTcpSocket* m_Socket;
QMutex m_Mutex;
};
* Copyright (C) 2012 Nick Bolton
*
* 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 <QObject>
#include <QMutex>
class QTcpSocket;
class IpcReader : public QObject
{
Q_OBJECT;
public:
IpcReader(QTcpSocket* socket);
virtual ~IpcReader();
void start();
void stop();
signals:
void readLogLine(const QString& text);
private:
bool readStream(char* buffer, int length);
int bytesToInt(const char* buffer, int size);
private slots:
void read();
private:
QTcpSocket* m_Socket;
QMutex m_Mutex;
};

View File

@ -1,51 +1,51 @@
/*
* 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 "QUtility.h"
void setIndexFromItemData(QComboBox* comboBox, const QVariant& itemData)
{
for (int i = 0; i < comboBox->count(); ++i)
{
if (comboBox->itemData(i) == itemData)
{
comboBox->setCurrentIndex(i);
return;
}
}
}
QString hash(const QString& string)
{
QByteArray data = string.toUtf8();
QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Md5);
return hash.toHex();
}
QString getFirstMacAddress()
{
QString mac;
foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces())
{
mac = interface.hardwareAddress();
if (mac.size() != 0)
{
break;
}
}
return mac;
}
/*
* 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 "QUtility.h"
void setIndexFromItemData(QComboBox* comboBox, const QVariant& itemData)
{
for (int i = 0; i < comboBox->count(); ++i)
{
if (comboBox->itemData(i) == itemData)
{
comboBox->setCurrentIndex(i);
return;
}
}
}
QString hash(const QString& string)
{
QByteArray data = string.toUtf8();
QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Md5);
return hash.toHex();
}
QString getFirstMacAddress()
{
QString mac;
foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces())
{
mac = interface.hardwareAddress();
if (mac.size() != 0)
{
break;
}
}
return mac;
}

View File

@ -1,27 +1,27 @@
/*
* 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 <QComboBox>
#include <QVariant>
#include <QCryptographicHash>
#include <QNetworkInterface>
void setIndexFromItemData(QComboBox* comboBox, const QVariant& itemData);
QString hash(const QString& string);
QString getFirstMacAddress();
/*
* 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 <QComboBox>
#include <QVariant>
#include <QCryptographicHash>
#include <QNetworkInterface>
void setIndexFromItemData(QComboBox* comboBox, const QVariant& itemData);
QString hash(const QString& string);
QString getFirstMacAddress();

View File

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

View File

@ -1,57 +1,57 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012 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 "ui_SetupWizardBase.h"
#include "CryptoMode.h"
#include "SynergyLocale.h"
#include <QWizard>
#include <QNetworkAccessManager>
class MainWindow;
class QMessageBox;
class SetupWizard : public QWizard, public Ui::SetupWizardBase
{
Q_OBJECT
public:
SetupWizard(MainWindow& mainWindow, bool startMain);
virtual ~SetupWizard();
bool validateCurrentPage();
protected:
void changeEvent(QEvent* event);
void accept();
void reject();
private:
CryptoMode parseCryptoMode(const QString& s);
bool isPremiumLoginValid(QMessageBox& message);
private:
MainWindow& m_MainWindow;
bool m_StartMain;
SynergyLocale m_Locale;
QNetworkAccessManager m_Network;
private slots:
void on_m_pComboCryptoMode_currentIndexChanged(int index);
void on_m_pComboLanguage_currentIndexChanged(int index);
void on_m_pRadioButtonPremiumLogin_toggled(bool checked);
};
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012 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 "ui_SetupWizardBase.h"
#include "CryptoMode.h"
#include "SynergyLocale.h"
#include <QWizard>
#include <QNetworkAccessManager>
class MainWindow;
class QMessageBox;
class SetupWizard : public QWizard, public Ui::SetupWizardBase
{
Q_OBJECT
public:
SetupWizard(MainWindow& mainWindow, bool startMain);
virtual ~SetupWizard();
bool validateCurrentPage();
protected:
void changeEvent(QEvent* event);
void accept();
void reject();
private:
CryptoMode parseCryptoMode(const QString& s);
bool isPremiumLoginValid(QMessageBox& message);
private:
MainWindow& m_MainWindow;
bool m_StartMain;
SynergyLocale m_Locale;
QNetworkAccessManager m_Network;
private slots:
void on_m_pComboCryptoMode_currentIndexChanged(int index);
void on_m_pComboLanguage_currentIndexChanged(int index);
void on_m_pRadioButtonPremiumLogin_toggled(bool checked);
};

View File

@ -1,68 +1,68 @@
/*
* 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 "SynergyLocale.h"
#include <QResource>
#include <QtXml/QXmlStreamReader>
#include <QDebug>
SynergyLocale::SynergyLocale()
{
loadLanguages();
}
void SynergyLocale::loadLanguages()
{
QResource resource(":/res/lang/Languages.xml");
QByteArray bytes(reinterpret_cast<const char*>(resource.data()), resource.size());
QXmlStreamReader xml(bytes);
while (!xml.atEnd())
{
QXmlStreamReader::TokenType token = xml.readNext();
if (xml.hasError())
{
qCritical() << xml.errorString();
throw std::exception();
}
if (xml.name() == "language" && token == QXmlStreamReader::StartElement)
{
QXmlStreamAttributes attributes = xml.attributes();
addLanguage(
attributes.value("ietfCode").toString(),
attributes.value("name").toString());
}
}
}
void SynergyLocale::addLanguage(const QString& ietfCode, const QString& name)
{
m_Languages.push_back(SynergyLocale::Language(ietfCode, name));
}
void SynergyLocale::fillLanguageComboBox(QComboBox* comboBox)
{
comboBox->blockSignals(true);
QVector<SynergyLocale::Language>::iterator it;
for (it = m_Languages.begin(); it != m_Languages.end(); ++it)
{
comboBox->addItem((*it).m_Name, (*it).m_IetfCode);
}
comboBox->blockSignals(false);
}
/*
* 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 "SynergyLocale.h"
#include <QResource>
#include <QtXml/QXmlStreamReader>
#include <QDebug>
SynergyLocale::SynergyLocale()
{
loadLanguages();
}
void SynergyLocale::loadLanguages()
{
QResource resource(":/res/lang/Languages.xml");
QByteArray bytes(reinterpret_cast<const char*>(resource.data()), resource.size());
QXmlStreamReader xml(bytes);
while (!xml.atEnd())
{
QXmlStreamReader::TokenType token = xml.readNext();
if (xml.hasError())
{
qCritical() << xml.errorString();
throw std::exception();
}
if (xml.name() == "language" && token == QXmlStreamReader::StartElement)
{
QXmlStreamAttributes attributes = xml.attributes();
addLanguage(
attributes.value("ietfCode").toString(),
attributes.value("name").toString());
}
}
}
void SynergyLocale::addLanguage(const QString& ietfCode, const QString& name)
{
m_Languages.push_back(SynergyLocale::Language(ietfCode, name));
}
void SynergyLocale::fillLanguageComboBox(QComboBox* comboBox)
{
comboBox->blockSignals(true);
QVector<SynergyLocale::Language>::iterator it;
for (it = m_Languages.begin(); it != m_Languages.end(); ++it)
{
comboBox->addItem((*it).m_Name, (*it).m_IetfCode);
}
comboBox->blockSignals(false);
}

View File

@ -1,48 +1,48 @@
/*
* 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 <QString>
#include <QVector>
#include <QComboBox>
class SynergyLocale
{
class Language
{
public:
Language() { }
Language(const QString& IetfCode, const QString& name)
: m_IetfCode(IetfCode), m_Name(name) { }
public:
QString m_IetfCode;
QString m_Name;
};
public:
SynergyLocale();
void fillLanguageComboBox(QComboBox* comboBox);
private:
void loadLanguages();
void addLanguage(const QString& IetfCode, const QString& name);
private:
QVector<Language> m_Languages;
};
/*
* 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 <QString>
#include <QVector>
#include <QComboBox>
class SynergyLocale
{
class Language
{
public:
Language() { }
Language(const QString& IetfCode, const QString& name)
: m_IetfCode(IetfCode), m_Name(name) { }
public:
QString m_IetfCode;
QString m_Name;
};
public:
SynergyLocale();
void fillLanguageComboBox(QComboBox* comboBox);
private:
void loadLanguages();
void addLanguage(const QString& IetfCode, const QString& name);
private:
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 Nick Bolton
*
* 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 "TcpSocketReader.h"
#include <QTcpSocket>
IpcReader::IpcReader(QTcpSocket& socket) :
m_Socket(socket)
{
connect(m_Socket, SIGNAL(readyRead()), this, SLOT(read()));
}
IpcReader::~IpcReader()
{
}
* Copyright (C) 2012 Nick Bolton
*
* 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 "TcpSocketReader.h"
#include <QTcpSocket>
IpcReader::IpcReader(QTcpSocket& socket) :
m_Socket(socket)
{
connect(m_Socket, SIGNAL(readyRead()), this, SLOT(read()));
}
IpcReader::~IpcReader()
{
}

View File

@ -1,103 +1,103 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012 Bolton Software Ltd.
* Copyright (C) 2012 Nick Bolton
*
* 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 "VersionChecker.h"
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QProcess>
#include <QLocale>
#define VERSION_REGEX "(\\d+\\.\\d+\\.\\d+)"
#define VERSION_URL "http://synergy-foss.org/version/"
VersionChecker::VersionChecker()
{
m_manager = new QNetworkAccessManager(this);
connect(m_manager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(replyFinished(QNetworkReply*)));
}
VersionChecker::~VersionChecker()
{
delete m_manager;
}
void VersionChecker::checkLatest()
{
m_manager->get(QNetworkRequest(QUrl(VERSION_URL)));
}
void VersionChecker::replyFinished(QNetworkReply* reply)
{
QString newestVersion = QString(reply->readAll());
if (!newestVersion.isEmpty())
{
QString currentVersion = getVersion();
if (compareVersions(currentVersion, newestVersion) > 0)
emit updateFound(newestVersion);
}
}
int VersionChecker::compareVersions(const QString& left, const QString& right)
{
if (left.compare(right) == 0)
return 0; // versions are same.
QStringList leftSplit = left.split(QRegExp("\\."));
if (leftSplit.size() != 3)
return 1; // assume right wins.
QStringList rightSplit = right.split(QRegExp("\\."));
if (rightSplit.size() != 3)
return -1; // assume left wins.
int leftMajor = leftSplit.at(0).toInt();
int leftMinor = leftSplit.at(1).toInt();
int leftRev = leftSplit.at(2).toInt();
int rightMajor = rightSplit.at(0).toInt();
int rightMinor = rightSplit.at(1).toInt();
int rightRev = rightSplit.at(2).toInt();
bool rightWins =
(rightMajor > leftMajor) ||
((rightMajor >= leftMajor) && (rightMinor > leftMinor)) ||
((rightMajor >= leftMajor) && (rightMinor >= leftMinor) && (rightRev > leftRev));
return rightWins ? 1 : -1;
}
QString VersionChecker::getVersion()
{
QProcess process;
process.start(m_app, QStringList() << "--version");
process.setReadChannel(QProcess::StandardOutput);
if (process.waitForStarted() && process.waitForFinished())
{
QRegExp rx(VERSION_REGEX);
QString text = process.readLine();
if (rx.indexIn(text) != -1)
return rx.cap(1);
}
return tr("Unknown");
}
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012 Bolton Software Ltd.
* Copyright (C) 2012 Nick Bolton
*
* 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 "VersionChecker.h"
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QProcess>
#include <QLocale>
#define VERSION_REGEX "(\\d+\\.\\d+\\.\\d+)"
#define VERSION_URL "http://synergy-foss.org/version/"
VersionChecker::VersionChecker()
{
m_manager = new QNetworkAccessManager(this);
connect(m_manager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(replyFinished(QNetworkReply*)));
}
VersionChecker::~VersionChecker()
{
delete m_manager;
}
void VersionChecker::checkLatest()
{
m_manager->get(QNetworkRequest(QUrl(VERSION_URL)));
}
void VersionChecker::replyFinished(QNetworkReply* reply)
{
QString newestVersion = QString(reply->readAll());
if (!newestVersion.isEmpty())
{
QString currentVersion = getVersion();
if (compareVersions(currentVersion, newestVersion) > 0)
emit updateFound(newestVersion);
}
}
int VersionChecker::compareVersions(const QString& left, const QString& right)
{
if (left.compare(right) == 0)
return 0; // versions are same.
QStringList leftSplit = left.split(QRegExp("\\."));
if (leftSplit.size() != 3)
return 1; // assume right wins.
QStringList rightSplit = right.split(QRegExp("\\."));
if (rightSplit.size() != 3)
return -1; // assume left wins.
int leftMajor = leftSplit.at(0).toInt();
int leftMinor = leftSplit.at(1).toInt();
int leftRev = leftSplit.at(2).toInt();
int rightMajor = rightSplit.at(0).toInt();
int rightMinor = rightSplit.at(1).toInt();
int rightRev = rightSplit.at(2).toInt();
bool rightWins =
(rightMajor > leftMajor) ||
((rightMajor >= leftMajor) && (rightMinor > leftMinor)) ||
((rightMajor >= leftMajor) && (rightMinor >= leftMinor) && (rightRev > leftRev));
return rightWins ? 1 : -1;
}
QString VersionChecker::getVersion()
{
QProcess process;
process.start(m_app, QStringList() << "--version");
process.setReadChannel(QProcess::StandardOutput);
if (process.waitForStarted() && process.waitForFinished())
{
QRegExp rx(VERSION_REGEX);
QString text = process.readLine();
if (rx.indexIn(text) != -1)
return rx.cap(1);
}
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 Nick Bolton
*
* 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 <QObject>
#include <QString>
class QNetworkAccessManager;
class QNetworkReply;
class VersionChecker : public QObject
{
Q_OBJECT
public:
VersionChecker();
virtual ~VersionChecker();
void checkLatest();
QString getVersion();
void setApp(const QString& app) { m_app = app; }
int compareVersions(const QString& left, const QString& right);
public slots:
void replyFinished(QNetworkReply* reply);
signals:
void updateFound(const QString& version);
private:
QNetworkAccessManager* m_manager;
QString m_app;
};
* Copyright (C) 2012 Nick Bolton
*
* 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 <QObject>
#include <QString>
class QNetworkAccessManager;
class QNetworkReply;
class VersionChecker : public QObject
{
Q_OBJECT
public:
VersionChecker();
virtual ~VersionChecker();
void checkLatest();
QString getVersion();
void setApp(const QString& app) { m_app = app; }
int compareVersions(const QString& left, const QString& right);
public slots:
void replyFinished(QNetworkReply* reply);
signals:
void updateFound(const QString& version);
private:
QNetworkAccessManager* m_manager;
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()
{
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
int fd = socket(s_family[family], s_type[type], 0);
if (fd == -1) {

View File

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

View File

@ -60,7 +60,7 @@ interrupt(CArch::ESignal, void* data)
CEventQueue::CEventQueue() :
m_systemTarget(0),
m_nextType(CEvent::kLast),
m_nextType(CEvent::kLast),
m_typesForCClient(NULL),
m_typesForIStream(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)
if (priority != kPRINT) {
char message[2048];
char message[kLogMessageLength];
#ifndef NDEBUG
struct tm *tm;

View File

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

View File

@ -33,14 +33,20 @@
#include "CArch.h"
#include "IPlatformScreen.h"
#include "CCryptoStream.h"
#include "CThread.h"
#include "TMethodJob.h"
#include "CFileChunker.h"
#include <cstring>
#include <cstdlib>
#include <sstream>
#include <fstream>
//
// CClient
//
const size_t CClient::m_chunkSize = 1024 * 512; // 512kb
CClient::CClient(IEventQueue* events,
const CString& name, const CNetworkAddress& address,
ISocketFactory* socketFactory,
@ -438,6 +444,17 @@ CClient::sendConnectionFailedEvent(const char* msg)
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
CClient::setupConnecting()
{
@ -737,6 +754,7 @@ CClient::handleGameDeviceFeedback(const CEvent& event, void*)
void
CClient::handleFileChunkSending(const CEvent& event, void*)
{
sendFileChunk(event.getData());
}
void
@ -763,3 +781,24 @@ CClient::isReceivedFileSizeValid()
{
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
void fileChunkReceived(CString data);
//! Return true if recieved file size is valid
bool isReceivedFileSizeValid();
//! Create a new thread and use it to send file to Server
void sendFileToServer(const char* filename);
//@}
//! @name accessors
@ -128,6 +128,9 @@ public:
*/
CNetworkAddress getServerAddress() const;
//! Return true if recieved file size is valid
bool isReceivedFileSizeValid();
//@}
// IScreen overrides
@ -167,6 +170,8 @@ private:
void sendClipboard(ClipboardID);
void sendEvent(CEvent::Type, void*);
void sendConnectionFailedEvent(const char* msg);
void sendFileChunk(const void* data);
void sendFileThread(void*);
void setupConnecting();
void setupConnection();
void setupScreen();
@ -188,7 +193,7 @@ private:
void handleGameDeviceTimingResp(const CEvent& event, void*);
void handleGameDeviceFeedback(const CEvent& event, void*);
void handleFileChunkSending(const CEvent&, void*);
public:
bool m_mock;
@ -214,6 +219,7 @@ private:
CCryptoOptions m_crypto;
std::size_t m_expectedFileSize;
CString m_receivedFileData;
static const size_t m_chunkSize;
};
#endif

View File

@ -935,7 +935,8 @@ CServerProxy::infoAcknowledgment()
m_ignoreMouse = false;
}
void CServerProxy::fileChunkReceived()
void
CServerProxy::fileChunkReceived()
{
// parse
UInt8 mark;
@ -943,20 +944,42 @@ void CServerProxy::fileChunkReceived()
CProtocolUtil::readf(m_stream, kMsgDFileTransfer + 4, &mark, &content);
switch (mark) {
case '0':
LOG((CLOG_DEBUG2 "recv file data: file size = %s", content));
case kFileStart:
LOG((CLOG_DEBUG2 "recv file data from server: size=%s", content.c_str()));
m_client->clearReceivedFileData();
m_client->setExpectedFileSize(content);
break;
case '1':
LOG((CLOG_DEBUG2 "recv file data: chunck size = %i", content.size()));
case kFileChunk:
LOG((CLOG_DEBUG2 "recv file data from server: size=%i", content.size()));
m_client->fileChunkReceived(content);
break;
case '2':
case kFileEnd:
LOG((CLOG_DEBUG2 "file data transfer finished"));
m_events->addEvent(CEvent(m_events->forIScreen().fileRecieveComplete(), m_client));
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
void handleDataForTest() { handleData(CEvent(), NULL); }
#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 Nick Bolton
*
* 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 "ILogOutputter.h"
//! Write log to debugger
/*!
This outputter writes output to the debugger. In Visual Studio, this
can be seen in the Output window.
*/
class CMSWindowsDebugOutputter : public ILogOutputter {
public:
CMSWindowsDebugOutputter();
virtual ~CMSWindowsDebugOutputter();
// ILogOutputter overrides
virtual void open(const char* title);
virtual void close();
virtual void show(bool showIfEmpty);
virtual bool write(ELevel level, const char* message);
virtual void flush();
};
* Copyright (C) 2012 Nick Bolton
*
* 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 "ILogOutputter.h"
//! Write log to debugger
/*!
This outputter writes output to the debugger. In Visual Studio, this
can be seen in the Output window.
*/
class CMSWindowsDebugOutputter : public ILogOutputter {
public:
CMSWindowsDebugOutputter();
virtual ~CMSWindowsDebugOutputter();
// ILogOutputter overrides
virtual void open(const char* title);
virtual void close();
virtual void show(bool showIfEmpty);
virtual bool write(ELevel level, const char* message);
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()));
return NULL;
}
LOG((CLOG_DEBUG "got token %i, duplicating", sourceToken));
HANDLE newToken;
@ -216,7 +216,7 @@ CMSWindowsRelauncher::duplicateProcessToken(HANDLE process, LPSECURITY_ATTRIBUTE
sourceToken, GetLastError()));
return NULL;
}
LOG((CLOG_DEBUG "duplicated, new token: %i", newToken));
return newToken;
}
@ -265,7 +265,7 @@ CMSWindowsRelauncher::getSessionToken(DWORD sessionId, LPSECURITY_ATTRIBUTES sec
LOG((CLOG_ERR "could not duplicate token (error: %i)", GetLastError()));
return 0;
}
LOG((CLOG_DEBUG "duplicated, new token: %i", newToken));
return newToken;
}
@ -284,10 +284,10 @@ CMSWindowsRelauncher::mainLoop(void*)
DWORD sessionId = -1;
bool launched = false;
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
if (!CreatePipe(&m_stdOutRead, &m_stdOutWrite, &saAttr, 0)) {
@ -308,27 +308,27 @@ CMSWindowsRelauncher::mainLoop(void*)
sendSasEvent = CreateEvent(NULL, FALSE, FALSE, "Global\\SendSAS");
}
DWORD newSessionId = getSessionId();
bool running = false;
if (launched) {
DWORD exitCode;
GetExitCodeProcess(pi.hProcess, &exitCode);
running = (exitCode == STILL_ACTIVE);
if (!running) {
failures++;
LOG((CLOG_INFO "detected application not running, pid=%d, failures=%d", pi.dwProcessId, failures));
// increasing backoff period, maximum of 10 seconds.
int timeout = (failures * 2) < 10 ? (failures * 2) : 10;
LOG((CLOG_DEBUG "waiting, backoff period is %d seconds", timeout));
ARCH->sleep(timeout);
// double check, in case process started after we waited.
GetExitCodeProcess(pi.hProcess, &exitCode);
running = (exitCode == STILL_ACTIVE);
DWORD newSessionId = getSessionId();
bool running = false;
if (launched) {
DWORD exitCode;
GetExitCodeProcess(pi.hProcess, &exitCode);
running = (exitCode == STILL_ACTIVE);
if (!running) {
failures++;
LOG((CLOG_INFO "detected application not running, pid=%d, failures=%d", pi.dwProcessId, failures));
// increasing backoff period, maximum of 10 seconds.
int timeout = (failures * 2) < 10 ? (failures * 2) : 10;
LOG((CLOG_DEBUG "waiting, backoff period is %d seconds", timeout));
ARCH->sleep(timeout);
// double check, in case process started after we waited.
GetExitCodeProcess(pi.hProcess, &exitCode);
running = (exitCode == STILL_ACTIVE);
}
else {
// reset failures when running.
@ -383,7 +383,7 @@ CMSWindowsRelauncher::mainLoop(void*)
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = "winsta0\\Default"; // TODO: maybe this should be \winlogon if we have logonui.exe?
si.hStdError = m_stdOutWrite;
si.hStdOutput = m_stdOutWrite;
si.hStdOutput = m_stdOutWrite;
si.dwFlags |= STARTF_USESTDHANDLES;
LPVOID environment;
@ -502,45 +502,45 @@ CMSWindowsRelauncher::outputLoop(void*)
}
}
}
void
CMSWindowsRelauncher::shutdownProcess(HANDLE handle, DWORD pid, int timeout)
{
DWORD exitCode;
GetExitCodeProcess(handle, &exitCode);
if (exitCode != STILL_ACTIVE)
return;
CIpcShutdownMessage shutdown;
m_ipcServer.send(shutdown, kIpcClientNode);
// wait for process to exit gracefully.
double start = ARCH->time();
while (true)
{
GetExitCodeProcess(handle, &exitCode);
if (exitCode != STILL_ACTIVE) {
// yay, we got a graceful shutdown. there should be no hook in use errors!
LOG((CLOG_INFO "process %d was shutdown gracefully", pid));
break;
}
else {
double elapsed = (ARCH->time() - start);
if (elapsed > timeout) {
// if timeout reached, kill forcefully.
// calling TerminateProcess on synergy is very bad!
// it causes the hook DLL to stay loaded in some apps,
// making it impossible to start synergy again.
LOG((CLOG_WARN "shutdown timed out after %d secs, forcefully terminating", (int)elapsed));
TerminateProcess(handle, kExitSuccess);
break;
}
ARCH->sleep(1);
}
}
}
void
CMSWindowsRelauncher::shutdownProcess(HANDLE handle, DWORD pid, int timeout)
{
DWORD exitCode;
GetExitCodeProcess(handle, &exitCode);
if (exitCode != STILL_ACTIVE)
return;
CIpcShutdownMessage shutdown;
m_ipcServer.send(shutdown, kIpcClientNode);
// wait for process to exit gracefully.
double start = ARCH->time();
while (true)
{
GetExitCodeProcess(handle, &exitCode);
if (exitCode != STILL_ACTIVE) {
// yay, we got a graceful shutdown. there should be no hook in use errors!
LOG((CLOG_INFO "process %d was shutdown gracefully", pid));
break;
}
else {
double elapsed = (ARCH->time() - start);
if (elapsed > timeout) {
// if timeout reached, kill forcefully.
// calling TerminateProcess on synergy is very bad!
// it causes the hook DLL to stay loaded in some apps,
// making it impossible to start synergy again.
LOG((CLOG_WARN "shutdown timed out after %d secs, forcefully terminating", (int)elapsed));
TerminateProcess(handle, kExitSuccess);
break;
}
ARCH->sleep(1);
}
}
}
void
@ -597,4 +597,4 @@ CMSWindowsRelauncher::shutdownExistingProcesses()
}
CloseHandle(snapshot);
}
}

View File

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

View File

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

View File

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

View File

@ -1,229 +1,229 @@
/***************************************************************************
* *
* XInput.h -- This module defines XBOX controller APIs *
* and constansts for the Windows platform. *
* *
/***************************************************************************
* *
* XInput.h -- This module defines XBOX controller APIs *
* and constansts for the Windows platform. *
* *
* Copyright (C) 2012 Bolton Software Ltd.
* Copyright (c) Microsoft Corp. All rights reserved. *
* *
***************************************************************************/
#ifndef _XINPUT_H_
#define _XINPUT_H_
#include <windef.h>
// Current name of the DLL shipped in the same SDK as this header.
// The name reflects the current version
#ifndef XINPUT_USE_9_1_0
#define XINPUT_DLL_A "xinput1_3.dll"
#define XINPUT_DLL_W L"xinput1_3.dll"
#else
#define XINPUT_DLL_A "xinput9_1_0.dll"
#define XINPUT_DLL_W L"xinput9_1_0.dll"
#endif
#ifdef UNICODE
#define XINPUT_DLL XINPUT_DLL_W
#else
#define XINPUT_DLL XINPUT_DLL_A
#endif
//
// Device types available in XINPUT_CAPABILITIES
//
#define XINPUT_DEVTYPE_GAMEPAD 0x01
//
// Device subtypes available in XINPUT_CAPABILITIES
//
#define XINPUT_DEVSUBTYPE_GAMEPAD 0x01
#ifndef XINPUT_USE_9_1_0
#define XINPUT_DEVSUBTYPE_WHEEL 0x02
#define XINPUT_DEVSUBTYPE_ARCADE_STICK 0x03
#define XINPUT_DEVSUBTYPE_FLIGHT_SICK 0x04
#define XINPUT_DEVSUBTYPE_DANCE_PAD 0x05
#define XINPUT_DEVSUBTYPE_GUITAR 0x06
#define XINPUT_DEVSUBTYPE_DRUM_KIT 0x08
#endif // !XINPUT_USE_9_1_0
//
// Flags for XINPUT_CAPABILITIES
//
#define XINPUT_CAPS_VOICE_SUPPORTED 0x0004
//
// Constants for gamepad buttons
//
#define XINPUT_GAMEPAD_DPAD_UP 0x0001
#define XINPUT_GAMEPAD_DPAD_DOWN 0x0002
#define XINPUT_GAMEPAD_DPAD_LEFT 0x0004
#define XINPUT_GAMEPAD_DPAD_RIGHT 0x0008
#define XINPUT_GAMEPAD_START 0x0010
#define XINPUT_GAMEPAD_BACK 0x0020
#define XINPUT_GAMEPAD_LEFT_THUMB 0x0040
#define XINPUT_GAMEPAD_RIGHT_THUMB 0x0080
#define XINPUT_GAMEPAD_LEFT_SHOULDER 0x0100
#define XINPUT_GAMEPAD_RIGHT_SHOULDER 0x0200
#define XINPUT_GAMEPAD_A 0x1000
#define XINPUT_GAMEPAD_B 0x2000
#define XINPUT_GAMEPAD_X 0x4000
#define XINPUT_GAMEPAD_Y 0x8000
//
// Gamepad thresholds
//
#define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE 7849
#define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689
#define XINPUT_GAMEPAD_TRIGGER_THRESHOLD 30
//
// Flags to pass to XInputGetCapabilities
//
#define XINPUT_FLAG_GAMEPAD 0x00000001
#ifndef XINPUT_USE_9_1_0
//
// Devices that support batteries
//
#define BATTERY_DEVTYPE_GAMEPAD 0x00
#define BATTERY_DEVTYPE_HEADSET 0x01
//
// Flags for battery status level
//
#define BATTERY_TYPE_DISCONNECTED 0x00 // This device is not connected
#define BATTERY_TYPE_WIRED 0x01 // Wired device, no battery
#define BATTERY_TYPE_ALKALINE 0x02 // Alkaline battery source
#define BATTERY_TYPE_NIMH 0x03 // Nickel Metal Hydride battery source
#define BATTERY_TYPE_UNKNOWN 0xFF // Cannot determine the battery type
// These are only valid for wireless, connected devices, with known battery types
// The amount of use time remaining depends on the type of device.
#define BATTERY_LEVEL_EMPTY 0x00
#define BATTERY_LEVEL_LOW 0x01
#define BATTERY_LEVEL_MEDIUM 0x02
#define BATTERY_LEVEL_FULL 0x03
// User index definitions
#define XUSER_MAX_COUNT 4
#define XUSER_INDEX_ANY 0x000000FF
//
// Codes returned for the gamepad keystroke
//
#define VK_PAD_A 0x5800
#define VK_PAD_B 0x5801
#define VK_PAD_X 0x5802
#define VK_PAD_Y 0x5803
#define VK_PAD_RSHOULDER 0x5804
#define VK_PAD_LSHOULDER 0x5805
#define VK_PAD_LTRIGGER 0x5806
#define VK_PAD_RTRIGGER 0x5807
#define VK_PAD_DPAD_UP 0x5810
#define VK_PAD_DPAD_DOWN 0x5811
#define VK_PAD_DPAD_LEFT 0x5812
#define VK_PAD_DPAD_RIGHT 0x5813
#define VK_PAD_START 0x5814
#define VK_PAD_BACK 0x5815
#define VK_PAD_LTHUMB_PRESS 0x5816
#define VK_PAD_RTHUMB_PRESS 0x5817
#define VK_PAD_LTHUMB_UP 0x5820
#define VK_PAD_LTHUMB_DOWN 0x5821
#define VK_PAD_LTHUMB_RIGHT 0x5822
#define VK_PAD_LTHUMB_LEFT 0x5823
#define VK_PAD_LTHUMB_UPLEFT 0x5824
#define VK_PAD_LTHUMB_UPRIGHT 0x5825
#define VK_PAD_LTHUMB_DOWNRIGHT 0x5826
#define VK_PAD_LTHUMB_DOWNLEFT 0x5827
#define VK_PAD_RTHUMB_UP 0x5830
#define VK_PAD_RTHUMB_DOWN 0x5831
#define VK_PAD_RTHUMB_RIGHT 0x5832
#define VK_PAD_RTHUMB_LEFT 0x5833
#define VK_PAD_RTHUMB_UPLEFT 0x5834
#define VK_PAD_RTHUMB_UPRIGHT 0x5835
#define VK_PAD_RTHUMB_DOWNRIGHT 0x5836
#define VK_PAD_RTHUMB_DOWNLEFT 0x5837
//
// Flags used in XINPUT_KEYSTROKE
//
#define XINPUT_KEYSTROKE_KEYDOWN 0x0001
#define XINPUT_KEYSTROKE_KEYUP 0x0002
#define XINPUT_KEYSTROKE_REPEAT 0x0004
#endif //!XINPUT_USE_9_1_0
//
// Structures used by XInput APIs
//
typedef struct _XINPUT_GAMEPAD
{
WORD wButtons;
BYTE bLeftTrigger;
BYTE bRightTrigger;
SHORT sThumbLX;
SHORT sThumbLY;
SHORT sThumbRX;
SHORT sThumbRY;
} XINPUT_GAMEPAD, *PXINPUT_GAMEPAD;
typedef struct _XINPUT_STATE
{
DWORD dwPacketNumber;
XINPUT_GAMEPAD Gamepad;
} XINPUT_STATE, *PXINPUT_STATE;
typedef struct _XINPUT_VIBRATION
{
WORD wLeftMotorSpeed;
WORD wRightMotorSpeed;
} XINPUT_VIBRATION, *PXINPUT_VIBRATION;
typedef struct _XINPUT_CAPABILITIES
{
BYTE Type;
BYTE SubType;
WORD Flags;
XINPUT_GAMEPAD Gamepad;
XINPUT_VIBRATION Vibration;
} XINPUT_CAPABILITIES, *PXINPUT_CAPABILITIES;
#ifndef XINPUT_USE_9_1_0
typedef struct _XINPUT_BATTERY_INFORMATION
{
BYTE BatteryType;
BYTE BatteryLevel;
} XINPUT_BATTERY_INFORMATION, *PXINPUT_BATTERY_INFORMATION;
typedef struct _XINPUT_KEYSTROKE
{
WORD VirtualKey;
WCHAR Unicode;
WORD Flags;
BYTE UserIndex;
BYTE HidCode;
} XINPUT_KEYSTROKE, *PXINPUT_KEYSTROKE;
#endif // !XINPUT_USE_9_1_0
//
// XInput APIs
//
// now defined in proxy class.
#endif //_XINPUT_H_
* Copyright (c) Microsoft Corp. All rights reserved. *
* *
***************************************************************************/
#ifndef _XINPUT_H_
#define _XINPUT_H_
#include <windef.h>
// Current name of the DLL shipped in the same SDK as this header.
// The name reflects the current version
#ifndef XINPUT_USE_9_1_0
#define XINPUT_DLL_A "xinput1_3.dll"
#define XINPUT_DLL_W L"xinput1_3.dll"
#else
#define XINPUT_DLL_A "xinput9_1_0.dll"
#define XINPUT_DLL_W L"xinput9_1_0.dll"
#endif
#ifdef UNICODE
#define XINPUT_DLL XINPUT_DLL_W
#else
#define XINPUT_DLL XINPUT_DLL_A
#endif
//
// Device types available in XINPUT_CAPABILITIES
//
#define XINPUT_DEVTYPE_GAMEPAD 0x01
//
// Device subtypes available in XINPUT_CAPABILITIES
//
#define XINPUT_DEVSUBTYPE_GAMEPAD 0x01
#ifndef XINPUT_USE_9_1_0
#define XINPUT_DEVSUBTYPE_WHEEL 0x02
#define XINPUT_DEVSUBTYPE_ARCADE_STICK 0x03
#define XINPUT_DEVSUBTYPE_FLIGHT_SICK 0x04
#define XINPUT_DEVSUBTYPE_DANCE_PAD 0x05
#define XINPUT_DEVSUBTYPE_GUITAR 0x06
#define XINPUT_DEVSUBTYPE_DRUM_KIT 0x08
#endif // !XINPUT_USE_9_1_0
//
// Flags for XINPUT_CAPABILITIES
//
#define XINPUT_CAPS_VOICE_SUPPORTED 0x0004
//
// Constants for gamepad buttons
//
#define XINPUT_GAMEPAD_DPAD_UP 0x0001
#define XINPUT_GAMEPAD_DPAD_DOWN 0x0002
#define XINPUT_GAMEPAD_DPAD_LEFT 0x0004
#define XINPUT_GAMEPAD_DPAD_RIGHT 0x0008
#define XINPUT_GAMEPAD_START 0x0010
#define XINPUT_GAMEPAD_BACK 0x0020
#define XINPUT_GAMEPAD_LEFT_THUMB 0x0040
#define XINPUT_GAMEPAD_RIGHT_THUMB 0x0080
#define XINPUT_GAMEPAD_LEFT_SHOULDER 0x0100
#define XINPUT_GAMEPAD_RIGHT_SHOULDER 0x0200
#define XINPUT_GAMEPAD_A 0x1000
#define XINPUT_GAMEPAD_B 0x2000
#define XINPUT_GAMEPAD_X 0x4000
#define XINPUT_GAMEPAD_Y 0x8000
//
// Gamepad thresholds
//
#define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE 7849
#define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689
#define XINPUT_GAMEPAD_TRIGGER_THRESHOLD 30
//
// Flags to pass to XInputGetCapabilities
//
#define XINPUT_FLAG_GAMEPAD 0x00000001
#ifndef XINPUT_USE_9_1_0
//
// Devices that support batteries
//
#define BATTERY_DEVTYPE_GAMEPAD 0x00
#define BATTERY_DEVTYPE_HEADSET 0x01
//
// Flags for battery status level
//
#define BATTERY_TYPE_DISCONNECTED 0x00 // This device is not connected
#define BATTERY_TYPE_WIRED 0x01 // Wired device, no battery
#define BATTERY_TYPE_ALKALINE 0x02 // Alkaline battery source
#define BATTERY_TYPE_NIMH 0x03 // Nickel Metal Hydride battery source
#define BATTERY_TYPE_UNKNOWN 0xFF // Cannot determine the battery type
// These are only valid for wireless, connected devices, with known battery types
// The amount of use time remaining depends on the type of device.
#define BATTERY_LEVEL_EMPTY 0x00
#define BATTERY_LEVEL_LOW 0x01
#define BATTERY_LEVEL_MEDIUM 0x02
#define BATTERY_LEVEL_FULL 0x03
// User index definitions
#define XUSER_MAX_COUNT 4
#define XUSER_INDEX_ANY 0x000000FF
//
// Codes returned for the gamepad keystroke
//
#define VK_PAD_A 0x5800
#define VK_PAD_B 0x5801
#define VK_PAD_X 0x5802
#define VK_PAD_Y 0x5803
#define VK_PAD_RSHOULDER 0x5804
#define VK_PAD_LSHOULDER 0x5805
#define VK_PAD_LTRIGGER 0x5806
#define VK_PAD_RTRIGGER 0x5807
#define VK_PAD_DPAD_UP 0x5810
#define VK_PAD_DPAD_DOWN 0x5811
#define VK_PAD_DPAD_LEFT 0x5812
#define VK_PAD_DPAD_RIGHT 0x5813
#define VK_PAD_START 0x5814
#define VK_PAD_BACK 0x5815
#define VK_PAD_LTHUMB_PRESS 0x5816
#define VK_PAD_RTHUMB_PRESS 0x5817
#define VK_PAD_LTHUMB_UP 0x5820
#define VK_PAD_LTHUMB_DOWN 0x5821
#define VK_PAD_LTHUMB_RIGHT 0x5822
#define VK_PAD_LTHUMB_LEFT 0x5823
#define VK_PAD_LTHUMB_UPLEFT 0x5824
#define VK_PAD_LTHUMB_UPRIGHT 0x5825
#define VK_PAD_LTHUMB_DOWNRIGHT 0x5826
#define VK_PAD_LTHUMB_DOWNLEFT 0x5827
#define VK_PAD_RTHUMB_UP 0x5830
#define VK_PAD_RTHUMB_DOWN 0x5831
#define VK_PAD_RTHUMB_RIGHT 0x5832
#define VK_PAD_RTHUMB_LEFT 0x5833
#define VK_PAD_RTHUMB_UPLEFT 0x5834
#define VK_PAD_RTHUMB_UPRIGHT 0x5835
#define VK_PAD_RTHUMB_DOWNRIGHT 0x5836
#define VK_PAD_RTHUMB_DOWNLEFT 0x5837
//
// Flags used in XINPUT_KEYSTROKE
//
#define XINPUT_KEYSTROKE_KEYDOWN 0x0001
#define XINPUT_KEYSTROKE_KEYUP 0x0002
#define XINPUT_KEYSTROKE_REPEAT 0x0004
#endif //!XINPUT_USE_9_1_0
//
// Structures used by XInput APIs
//
typedef struct _XINPUT_GAMEPAD
{
WORD wButtons;
BYTE bLeftTrigger;
BYTE bRightTrigger;
SHORT sThumbLX;
SHORT sThumbLY;
SHORT sThumbRX;
SHORT sThumbRY;
} XINPUT_GAMEPAD, *PXINPUT_GAMEPAD;
typedef struct _XINPUT_STATE
{
DWORD dwPacketNumber;
XINPUT_GAMEPAD Gamepad;
} XINPUT_STATE, *PXINPUT_STATE;
typedef struct _XINPUT_VIBRATION
{
WORD wLeftMotorSpeed;
WORD wRightMotorSpeed;
} XINPUT_VIBRATION, *PXINPUT_VIBRATION;
typedef struct _XINPUT_CAPABILITIES
{
BYTE Type;
BYTE SubType;
WORD Flags;
XINPUT_GAMEPAD Gamepad;
XINPUT_VIBRATION Vibration;
} XINPUT_CAPABILITIES, *PXINPUT_CAPABILITIES;
#ifndef XINPUT_USE_9_1_0
typedef struct _XINPUT_BATTERY_INFORMATION
{
BYTE BatteryType;
BYTE BatteryLevel;
} XINPUT_BATTERY_INFORMATION, *PXINPUT_BATTERY_INFORMATION;
typedef struct _XINPUT_KEYSTROKE
{
WORD VirtualKey;
WCHAR Unicode;
WORD Flags;
BYTE UserIndex;
BYTE HidCode;
} XINPUT_KEYSTROKE, *PXINPUT_KEYSTROKE;
#endif // !XINPUT_USE_9_1_0
//
// XInput APIs
//
// now defined in proxy class.
#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) 2011 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
* Copyright (C) 2011 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define WIN32_LEAN_AND_MEAN
#define SYNERGY_EXPORT_XINPUT_HOOKS
#define REQUIRED_XINPUT_DLL "xinput1_3.dll"
#define HOOK_TIMEOUT 10000 // 10 sec
#include <Windows.h>
#include <XInput.h>
#include "XInputHook.h"
#include "HookDLL.h"
#include <iostream>
HINSTANCE dll;
char name[256];
#pragma data_seg(".SHARED")
HHOOK s_hook = NULL;
// @todo use a struct for multiple gamepad support
WORD s_buttons = 0;
SHORT s_leftStickX = 0;
SHORT s_leftStickY = 0;
SHORT s_rightStickX = 0;
SHORT s_rightStickY = 0;
BYTE s_leftTrigger = 0;
BYTE s_rightTrigger = 0;
BOOL s_timingReqQueued = FALSE;
BOOL s_timingRespQueued = FALSE;
DWORD s_lastFakeMillis = 0;
WORD s_fakeFreqMillis = 0;
DWORD s_packetNumber = 0;
WORD s_leftMotor = 0;
WORD s_rightMotor = 0;
BOOL s_feedbackQueued = FALSE;
#pragma data_seg()
#pragma comment(linker, "/SECTION:.SHARED,RWS")
#include <sstream>
std::stringstream _xInputHookLogStream;
#define LOG(s) \
_xInputHookLogStream.str(""); \
_xInputHookLogStream << "Synergy XInputHook: " << s << endl; \
OutputDebugString( _xInputHookLogStream.str().c_str())
using namespace std;
SDLLHook s_xInputHook =
{
XINPUT_DLL,
false, NULL,
{
{ (char*)(0x80000002), HookXInputGetState },
{ (char*)(0x80000003), HookXInputSetState },
{ (char*)(0x80000004), HookXInputGetCapabilities },
}
};
BOOL APIENTRY
DllMain(HINSTANCE module, DWORD reason, LPVOID reserved)
{
if (reason == DLL_PROCESS_ATTACH)
{
dll = module;
// disable unwanted thread notifications to reduce overhead
DisableThreadLibraryCalls(dll);
GetModuleFileName(GetModuleHandle(NULL), name, sizeof(name));
// don't hook synergys (this needs to detect real input)
if (string(name).find("synergy") == string::npos)
{
LOG("checking '" << name << "' for " << XINPUT_DLL);
HookAPICalls(&s_xInputHook);
}
}
return TRUE;
}
void
SetXInputButtons(DWORD userIndex, WORD buttons)
{
s_buttons = buttons;
s_packetNumber++;
LOG("SetXInputButtons: idx=" << userIndex << ", btns=" << buttons);
}
void
SetXInputSticks(DWORD userIndex, SHORT lx, SHORT ly, SHORT rx, SHORT ry)
{
s_leftStickX = lx;
s_leftStickY = ly;
s_rightStickX = rx;
s_rightStickY = ry;
s_packetNumber++;
LOG("SetXInputSticks:" <<
" l=" << s_leftStickX << "," << s_leftStickY <<
" r=" << s_rightStickX << "," << s_rightStickY);
}
void
SetXInputTriggers(DWORD userIndex, BYTE left, BYTE right)
{
s_leftTrigger = left;
s_rightTrigger = right;
s_packetNumber++;
LOG("SetXInputTriggers: " <<
"l=" << (int)left << " r=" << (int)right);
}
void
QueueXInputTimingReq()
{
s_timingReqQueued = TRUE;
}
BOOL
DequeueXInputTimingResp()
{
BOOL result = s_timingRespQueued;
s_timingRespQueued = FALSE;
return result;
}
BOOL
DequeueXInputFeedback(WORD* leftMotor, WORD* rightMotor)
{
if (s_feedbackQueued)
{
*leftMotor = s_leftMotor;
*rightMotor = s_rightMotor;
s_feedbackQueued = FALSE;
return TRUE;
}
return FALSE;
}
WORD
GetXInputFakeFreqMillis()
{
return s_fakeFreqMillis;
}
DWORD WINAPI
HookXInputGetState(DWORD userIndex, XINPUT_STATE* state)
{
// @todo multiple device support
if (userIndex != 0)
{
return ERROR_DEVICE_NOT_CONNECTED;
}
DWORD now = GetTickCount();
s_fakeFreqMillis = (WORD)(now - s_lastFakeMillis);
s_lastFakeMillis = now;
state->dwPacketNumber = s_packetNumber;
state->Gamepad.wButtons = s_buttons;
state->Gamepad.bLeftTrigger = s_leftTrigger;
state->Gamepad.bRightTrigger = s_rightTrigger;
state->Gamepad.sThumbLX = s_leftStickX;
state->Gamepad.sThumbLY = s_leftStickY;
state->Gamepad.sThumbRX = s_rightStickX;
state->Gamepad.sThumbRY = s_rightStickY;
LOG("HookXInputGetState"
<< ", idx=" << userIndex
<< ", pkt=" << state->dwPacketNumber
<< ", btn=" << state->Gamepad.wButtons
<< ", t1=" << (int)state->Gamepad.bLeftTrigger
<< ", t2=" << (int)state->Gamepad.bRightTrigger
<< ", s1=" << state->Gamepad.sThumbLX << "," << state->Gamepad.sThumbLY
<< ", s2=" << state->Gamepad.sThumbRX << "," << state->Gamepad.sThumbRY);
if (s_timingReqQueued)
{
s_timingRespQueued = TRUE;
s_timingReqQueued = FALSE;
LOG("timing response queued");
}
return ERROR_SUCCESS;
}
DWORD WINAPI
HookXInputSetState(DWORD userIndex, XINPUT_VIBRATION* vibration)
{
// @todo multiple device support
if (userIndex != 0)
{
return ERROR_DEVICE_NOT_CONNECTED;
}
// only change values and queue feedback change if
// feedback has actually changed.
if ((s_leftMotor != vibration->wLeftMotorSpeed) ||
(s_rightMotor != vibration->wRightMotorSpeed))
{
s_leftMotor = vibration->wLeftMotorSpeed;
s_rightMotor = vibration->wRightMotorSpeed;
s_feedbackQueued = TRUE;
LOG("HookXInputSetState"
", idx=" << userIndex <<
", lm=" << s_leftMotor <<
", rm=" << s_rightMotor);
}
return ERROR_SUCCESS;
}
DWORD WINAPI
HookXInputGetCapabilities(DWORD userIndex, DWORD flags, XINPUT_CAPABILITIES* capabilities)
{
// @todo multiple device support
if (userIndex != 0)
{
return ERROR_DEVICE_NOT_CONNECTED;
}
LOG("HookXInputGetCapabilities"
", idx=" << userIndex <<
", flags=" << flags);
capabilities->Type = 1;
capabilities->SubType = 1;
capabilities->Flags = 4;
capabilities->Gamepad.bLeftTrigger = 1;
capabilities->Gamepad.bRightTrigger = 1;
capabilities->Gamepad.sThumbLX = 1;
capabilities->Gamepad.sThumbLY = 1;
capabilities->Gamepad.sThumbRX = 1;
capabilities->Gamepad.sThumbRY = 1;
capabilities->Gamepad.wButtons = 62463;
capabilities->Vibration.wLeftMotorSpeed = 1;
capabilities->Vibration.wRightMotorSpeed = 1;
return ERROR_SUCCESS;
}
synxinhk_API LRESULT CALLBACK
HookProc(int code, WPARAM wParam, LPARAM lParam)
{
return CallNextHookEx(s_hook, code, wParam, lParam);
}
synxinhk_API BOOL
InstallXInputHook()
{
if (_stricmp(XINPUT_DLL, REQUIRED_XINPUT_DLL) != 0)
{
LOG("DLL not supported: " << XINPUT_DLL);
return FALSE;
}
LOG("installing hook");
s_hook = SetWindowsHookEx(WH_CBT, HookProc, dll, 0);
LOG("hook installed");
return TRUE;
}
synxinhk_API void
RemoveXInputHook()
{
LOG("removing hook");
UnhookWindowsHookEx(s_hook);
LOG("hook removed");
}
#define WIN32_LEAN_AND_MEAN
#define SYNERGY_EXPORT_XINPUT_HOOKS
#define REQUIRED_XINPUT_DLL "xinput1_3.dll"
#define HOOK_TIMEOUT 10000 // 10 sec
#include <Windows.h>
#include <XInput.h>
#include "XInputHook.h"
#include "HookDLL.h"
#include <iostream>
HINSTANCE dll;
char name[256];
#pragma data_seg(".SHARED")
HHOOK s_hook = NULL;
// @todo use a struct for multiple gamepad support
WORD s_buttons = 0;
SHORT s_leftStickX = 0;
SHORT s_leftStickY = 0;
SHORT s_rightStickX = 0;
SHORT s_rightStickY = 0;
BYTE s_leftTrigger = 0;
BYTE s_rightTrigger = 0;
BOOL s_timingReqQueued = FALSE;
BOOL s_timingRespQueued = FALSE;
DWORD s_lastFakeMillis = 0;
WORD s_fakeFreqMillis = 0;
DWORD s_packetNumber = 0;
WORD s_leftMotor = 0;
WORD s_rightMotor = 0;
BOOL s_feedbackQueued = FALSE;
#pragma data_seg()
#pragma comment(linker, "/SECTION:.SHARED,RWS")
#include <sstream>
std::stringstream _xInputHookLogStream;
#define LOG(s) \
_xInputHookLogStream.str(""); \
_xInputHookLogStream << "Synergy XInputHook: " << s << endl; \
OutputDebugString( _xInputHookLogStream.str().c_str())
using namespace std;
SDLLHook s_xInputHook =
{
XINPUT_DLL,
false, NULL,
{
{ (char*)(0x80000002), HookXInputGetState },
{ (char*)(0x80000003), HookXInputSetState },
{ (char*)(0x80000004), HookXInputGetCapabilities },
}
};
BOOL APIENTRY
DllMain(HINSTANCE module, DWORD reason, LPVOID reserved)
{
if (reason == DLL_PROCESS_ATTACH)
{
dll = module;
// disable unwanted thread notifications to reduce overhead
DisableThreadLibraryCalls(dll);
GetModuleFileName(GetModuleHandle(NULL), name, sizeof(name));
// don't hook synergys (this needs to detect real input)
if (string(name).find("synergy") == string::npos)
{
LOG("checking '" << name << "' for " << XINPUT_DLL);
HookAPICalls(&s_xInputHook);
}
}
return TRUE;
}
void
SetXInputButtons(DWORD userIndex, WORD buttons)
{
s_buttons = buttons;
s_packetNumber++;
LOG("SetXInputButtons: idx=" << userIndex << ", btns=" << buttons);
}
void
SetXInputSticks(DWORD userIndex, SHORT lx, SHORT ly, SHORT rx, SHORT ry)
{
s_leftStickX = lx;
s_leftStickY = ly;
s_rightStickX = rx;
s_rightStickY = ry;
s_packetNumber++;
LOG("SetXInputSticks:" <<
" l=" << s_leftStickX << "," << s_leftStickY <<
" r=" << s_rightStickX << "," << s_rightStickY);
}
void
SetXInputTriggers(DWORD userIndex, BYTE left, BYTE right)
{
s_leftTrigger = left;
s_rightTrigger = right;
s_packetNumber++;
LOG("SetXInputTriggers: " <<
"l=" << (int)left << " r=" << (int)right);
}
void
QueueXInputTimingReq()
{
s_timingReqQueued = TRUE;
}
BOOL
DequeueXInputTimingResp()
{
BOOL result = s_timingRespQueued;
s_timingRespQueued = FALSE;
return result;
}
BOOL
DequeueXInputFeedback(WORD* leftMotor, WORD* rightMotor)
{
if (s_feedbackQueued)
{
*leftMotor = s_leftMotor;
*rightMotor = s_rightMotor;
s_feedbackQueued = FALSE;
return TRUE;
}
return FALSE;
}
WORD
GetXInputFakeFreqMillis()
{
return s_fakeFreqMillis;
}
DWORD WINAPI
HookXInputGetState(DWORD userIndex, XINPUT_STATE* state)
{
// @todo multiple device support
if (userIndex != 0)
{
return ERROR_DEVICE_NOT_CONNECTED;
}
DWORD now = GetTickCount();
s_fakeFreqMillis = (WORD)(now - s_lastFakeMillis);
s_lastFakeMillis = now;
state->dwPacketNumber = s_packetNumber;
state->Gamepad.wButtons = s_buttons;
state->Gamepad.bLeftTrigger = s_leftTrigger;
state->Gamepad.bRightTrigger = s_rightTrigger;
state->Gamepad.sThumbLX = s_leftStickX;
state->Gamepad.sThumbLY = s_leftStickY;
state->Gamepad.sThumbRX = s_rightStickX;
state->Gamepad.sThumbRY = s_rightStickY;
LOG("HookXInputGetState"
<< ", idx=" << userIndex
<< ", pkt=" << state->dwPacketNumber
<< ", btn=" << state->Gamepad.wButtons
<< ", t1=" << (int)state->Gamepad.bLeftTrigger
<< ", t2=" << (int)state->Gamepad.bRightTrigger
<< ", s1=" << state->Gamepad.sThumbLX << "," << state->Gamepad.sThumbLY
<< ", s2=" << state->Gamepad.sThumbRX << "," << state->Gamepad.sThumbRY);
if (s_timingReqQueued)
{
s_timingRespQueued = TRUE;
s_timingReqQueued = FALSE;
LOG("timing response queued");
}
return ERROR_SUCCESS;
}
DWORD WINAPI
HookXInputSetState(DWORD userIndex, XINPUT_VIBRATION* vibration)
{
// @todo multiple device support
if (userIndex != 0)
{
return ERROR_DEVICE_NOT_CONNECTED;
}
// only change values and queue feedback change if
// feedback has actually changed.
if ((s_leftMotor != vibration->wLeftMotorSpeed) ||
(s_rightMotor != vibration->wRightMotorSpeed))
{
s_leftMotor = vibration->wLeftMotorSpeed;
s_rightMotor = vibration->wRightMotorSpeed;
s_feedbackQueued = TRUE;
LOG("HookXInputSetState"
", idx=" << userIndex <<
", lm=" << s_leftMotor <<
", rm=" << s_rightMotor);
}
return ERROR_SUCCESS;
}
DWORD WINAPI
HookXInputGetCapabilities(DWORD userIndex, DWORD flags, XINPUT_CAPABILITIES* capabilities)
{
// @todo multiple device support
if (userIndex != 0)
{
return ERROR_DEVICE_NOT_CONNECTED;
}
LOG("HookXInputGetCapabilities"
", idx=" << userIndex <<
", flags=" << flags);
capabilities->Type = 1;
capabilities->SubType = 1;
capabilities->Flags = 4;
capabilities->Gamepad.bLeftTrigger = 1;
capabilities->Gamepad.bRightTrigger = 1;
capabilities->Gamepad.sThumbLX = 1;
capabilities->Gamepad.sThumbLY = 1;
capabilities->Gamepad.sThumbRX = 1;
capabilities->Gamepad.sThumbRY = 1;
capabilities->Gamepad.wButtons = 62463;
capabilities->Vibration.wLeftMotorSpeed = 1;
capabilities->Vibration.wRightMotorSpeed = 1;
return ERROR_SUCCESS;
}
synxinhk_API LRESULT CALLBACK
HookProc(int code, WPARAM wParam, LPARAM lParam)
{
return CallNextHookEx(s_hook, code, wParam, lParam);
}
synxinhk_API BOOL
InstallXInputHook()
{
if (_stricmp(XINPUT_DLL, REQUIRED_XINPUT_DLL) != 0)
{
LOG("DLL not supported: " << XINPUT_DLL);
return FALSE;
}
LOG("installing hook");
s_hook = SetWindowsHookEx(WH_CBT, HookProc, dll, 0);
LOG("hook installed");
return TRUE;
}
synxinhk_API void
RemoveXInputHook()
{
LOG("removing hook");
UnhookWindowsHookEx(s_hook);
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) 2011 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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
#ifdef synxinhk_EXPORTS
#define synxinhk_API __declspec(dllexport)
#else
#define synxinhk_API __declspec(dllimport)
#endif
synxinhk_API LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam);
synxinhk_API BOOL InstallXInputHook();
synxinhk_API void RemoveXInputHook();
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 SetXInputTriggers(DWORD userIndex, BYTE left, BYTE right);
synxinhk_API void QueueXInputTimingReq();
synxinhk_API BOOL DequeueXInputTimingResp();
synxinhk_API WORD GetXInputFakeFreqMillis();
synxinhk_API BOOL DequeueXInputFeedback(WORD* leftMotor, WORD* rightMotor);
#ifdef SYNERGY_EXPORT_XINPUT_HOOKS
synxinhk_API DWORD WINAPI HookXInputGetState(DWORD dwUserIndex, XINPUT_STATE* pState);
synxinhk_API DWORD WINAPI HookXInputSetState(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration);
synxinhk_API DWORD WINAPI HookXInputGetCapabilities(DWORD userIndex, DWORD flags, XINPUT_CAPABILITIES* capabilities);
#endif
* Copyright (C) 2011 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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
#ifdef synxinhk_EXPORTS
#define synxinhk_API __declspec(dllexport)
#else
#define synxinhk_API __declspec(dllimport)
#endif
synxinhk_API LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam);
synxinhk_API BOOL InstallXInputHook();
synxinhk_API void RemoveXInputHook();
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 SetXInputTriggers(DWORD userIndex, BYTE left, BYTE right);
synxinhk_API void QueueXInputTimingReq();
synxinhk_API BOOL DequeueXInputTimingResp();
synxinhk_API WORD GetXInputFakeFreqMillis();
synxinhk_API BOOL DequeueXInputFeedback(WORD* leftMotor, WORD* rightMotor);
#ifdef SYNERGY_EXPORT_XINPUT_HOOKS
synxinhk_API DWORD WINAPI HookXInputGetState(DWORD dwUserIndex, XINPUT_STATE* pState);
synxinhk_API DWORD WINAPI HookXInputSetState(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration);
synxinhk_API DWORD WINAPI HookXInputGetCapabilities(DWORD userIndex, DWORD flags, XINPUT_CAPABILITIES* capabilities);
#endif

View File

@ -18,7 +18,7 @@
#define SYNERGY_EXPORT_XINPUT_HOOKS
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include "XInputProxy13.h"
#include "XInputHook.h"
@ -31,43 +31,43 @@
#pragma comment(linker, "/EXPORT:XInputGetBatteryInformation=_XInputGetBatteryInformation@12,@7")
#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
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;
}

View File

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

View File

@ -83,7 +83,7 @@ public:
virtual void screensaver(bool activate) = 0;
virtual void resetOptions() = 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;
private:

View File

@ -89,7 +89,7 @@ public:
virtual void gameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2) = 0;
virtual void gameDeviceTimingReq() = 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:
synergy::IStream* m_stream;

View File

@ -394,7 +394,7 @@ CClientProxy1_0::cryptoIv(const UInt8* iv)
}
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
LOG((CLOG_DEBUG "fileChunkSending not supported"));

View File

@ -64,7 +64,7 @@ public:
virtual void gameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2);
virtual void gameDeviceTimingReq();
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:
virtual bool parseHandshakeMessage(const UInt8* code);

View File

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

View File

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

View File

@ -19,13 +19,15 @@
#include "CProtocolUtil.h"
#include "CLog.h"
#include "IStream.h"
#include "CServer.h"
//
// CClientProxy1_5
//
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
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) {
case '0':
LOG((CLOG_DEBUG2 "file sending start: file size = %s", data));
case kFileStart:
LOG((CLOG_DEBUG2 "file sending start: size=%s", data));
break;
case '1':
LOG((CLOG_DEBUG2 "file chunk sending: %s", data));
case kFileChunk:
LOG((CLOG_DEBUG2 "file chunk sending: size=%i", chunk.size()));
break;
case '2':
case kFileEnd:
LOG((CLOG_DEBUG2 "file sending finished"));
break;
}
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();
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
CPrimaryClient::fileChunkSending(UInt8 mark, const UInt8* data)
CPrimaryClient::fileChunkSending(UInt8 mark, char* data, size_t dataSize)
{
// ignore
}

View File

@ -148,7 +148,7 @@ public:
virtual void screensaver(bool activate);
virtual void resetOptions();
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:
CScreen* m_screen;

View File

@ -33,14 +33,22 @@
#include "TMethodEventJob.h"
#include "CArch.h"
#include "CKeyState.h"
#include "CScreen.h"
#include "CThread.h"
#include "TMethodJob.h"
#include "CFileChunker.h"
#include <cstring>
#include <cstdlib>
#include "CScreen.h"
#include <sstream>
#include <fstream>
#include <sstream>
//
// CServer
//
const size_t CServer::m_chunkSize = 1024 * 512; // 512kb
CServer::CServer(CConfig& config, CPrimaryClient* primaryClient, CScreen* screen, IEventQueue* events) :
m_events(events),
m_mock(false),
@ -177,6 +185,10 @@ CServer::CServer(CConfig& config, CPrimaryClient* primaryClient, CScreen* screen
this,
new TMethodEventJob<CServer>(this,
&CServer::handleFileChunkSendingEvent));
m_events->adoptHandler(m_events->forIScreen().fileRecieveComplete(),
this,
new TMethodEventJob<CServer>(this,
&CServer::handleFileRecieveCompleteEvent));
// add connection
addClient(m_primaryClient);
@ -1516,8 +1528,13 @@ CServer::handleFakeInputEndEvent(const CEvent&, void*)
void
CServer::handleFileChunkSendingEvent(const CEvent& event, void*)
{
UInt8* data = reinterpret_cast<UInt8*>(event.getData());
onFileChunkSending(data);
onFileChunkSending(event.getData());
}
void
CServer::handleFileRecieveCompleteEvent(const CEvent& event, void*)
{
onFileRecieveComplete();
}
void
@ -1981,13 +1998,32 @@ CServer::onGameDeviceTimingReq()
}
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"));
assert(m_active != NULL);
// 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
@ -2260,3 +2296,49 @@ CServer::CKeyboardBroadcastInfo::alloc(State state, const CString& screens)
strcpy(info->m_screens, screens.c_str());
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
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
//@{
@ -159,6 +174,9 @@ public:
Set the \c list to the names of the currently connected clients.
*/
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 handleFakeInputEndEvent(const CEvent&, void*);
void handleFileChunkSendingEvent(const CEvent&, void*);
void handleFileRecieveCompleteEvent(const CEvent&, void*);
// event processing
void onClipboardChanged(CBaseClientProxy* sender,
@ -318,7 +337,8 @@ private:
void onGameDeviceSticks(GameDeviceID id, SInt16 x1, SInt16 y1, SInt16 x2, SInt16 y2);
void onGameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2);
void onGameDeviceTimingReq();
void onFileChunkSending(const UInt8* data);
void onFileChunkSending(const void* data);
void onFileRecieveComplete();
// add client to list and attach event handlers for client
bool addClient(CBaseClientProxy*);
@ -343,6 +363,9 @@ private:
// force the cursor off of \p client
void forceLeaveClient(CBaseClientProxy* client);
// thread funciton for sending file
void sendFileThread(void*);
public:
bool m_mock;
@ -438,6 +461,13 @@ private:
CScreen* m_screen;
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

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")) {
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 {
// option not supported here

View File

@ -101,6 +101,9 @@ public:
void setSocketMultiplexer(CSocketMultiplexer* sm) { m_socketMultiplexer = sm; }
CSocketMultiplexer* getSocketMultiplexer() const { return m_socketMultiplexer; }
CString& getFileTransferSrc() { return m_fileTransferSrc; }
CString& getFileTransferDes() { return m_fileTransferDes; }
private:
void handleIpcMessage(const CEvent&, void*);
@ -122,6 +125,8 @@ private:
CIpcClient* m_ipcClient;
IEventQueue* m_events;
CSocketMultiplexer* m_socketMultiplexer;
CString m_fileTransferSrc;
CString m_fileTransferDes;
};
#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"));
resetRestartTimeout();
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
s_client->connect();
updateStatus();
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
IAppUtil.h
CEventGameDevice.h
CFileChunker.h
)
set(src
@ -74,23 +75,24 @@ set(src
XSynergy.cpp
CDaemonApp.cpp
CAppUtil.cpp
CArgsBase.cpp
CEventGameDevice.cpp
CGameDevice.cpp
)
if (WIN32)
CArgsBase.cpp
CEventGameDevice.cpp
CGameDevice.cpp
CFileChunker.cpp
)
if (WIN32)
list(APPEND inc
CAppUtilWindows.h
CGameDevice.h
)
list(APPEND src
${inc}
CAppUtilWindows.cpp
)
elseif(UNIX)
list(APPEND src
list(APPEND src
${inc}
CAppUtilWindows.cpp
)
elseif(UNIX)
list(APPEND src
CAppUtilUnix.cpp
)
endif()

View File

@ -228,7 +228,12 @@ CProtocolUtil::vreadf(synergy::IStream* stream, const char* fmt, va_list args)
}
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
CString* dst = va_arg(args, CString*);

View File

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

View File

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

View File

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

View File

@ -68,6 +68,13 @@ enum EDirectionMask {
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

View File

@ -1,420 +1,420 @@
/*
uSynergy client -- Interface for the embedded Synergy client library
version 1.0.0, July 7th, 2012
/*
uSynergy client -- Interface for the embedded Synergy client library
version 1.0.0, July 7th, 2012
Copyright (C) 2012 Bolton Software Ltd.
Copyright (c) 2012 Alex Evans
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
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
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
//---------------------------------------------------------------------------------------------------------------------
// Configuration
//---------------------------------------------------------------------------------------------------------------------
/**
@brief Determine endianness
**/
#if defined(USYNERGY_LITTLE_ENDIAN) && defined(USYNERGY_BIG_ENDIAN)
/* Ambiguous: both endians specified */
#error "Can't define both USYNERGY_LITTLE_ENDIAN and USYNERGY_BIG_ENDIAN"
#elif !defined(USYNERGY_LITTLE_ENDIAN) && !defined(USYNERGY_BIG_ENDIAN)
/* Attempt to auto detect */
#if defined(__LITTLE_ENDIAN__) || defined(LITTLE_ENDIAN) || (_BYTE_ORDER == _LITTLE_ENDIAN)
#define USYNERGY_LITTLE_ENDIAN
#elif defined(__BIG_ENDIAN__) || defined(BIG_ENDIAN) || (_BYTE_ORDER == _BIG_ENDIAN)
#define USYNERGY_BIG_ENDIAN
#else
#error "Can't detect endian-nes, please defined either USYNERGY_LITTLE_ENDIAN or USYNERGY_BIG_ENDIAN";
#endif
#else
/* User-specified endian-nes, nothing to do for us */
#endif
//---------------------------------------------------------------------------------------------------------------------
// Types and Constants
//---------------------------------------------------------------------------------------------------------------------
/**
@brief Boolean type
**/
typedef int uSynergyBool;
#define USYNERGY_FALSE 0 /* False value */
#define USYNERGY_TRUE 1 /* True value */
/**
@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
callback functions as context.
**/
typedef struct { int ignored; } * uSynergyCookie;
/**
@brief Clipboard types
**/
enum uSynergyClipboardFormat
{
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_HTML = 2, /* HTML format, HTML fragment, UTF-8, newline is LF */
};
/**
@brief Constants and limits
**/
#define USYNERGY_NUM_JOYSTICKS 4 /* Maximum number of supported joysticks */
#define USYNERGY_PROTOCOL_MAJOR 1 /* Major protocol version */
#define USYNERGY_PROTOCOL_MINOR 4 /* Minor protocol version */
#define USYNERGY_IDLE_TIMEOUT 2000 /* Timeout in milliseconds before reconnecting */
#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_RECEIVE_BUFFER_SIZE 4096 /* Maximum size of an incoming packet */
/**
@brief Keyboard constants
**/
#define USYNERGY_MODIFIER_SHIFT 0x0001 /* Shift key modifier */
#define USYNERGY_MODIFIER_CTRL 0x0002 /* Ctrl key modifier */
#define USYNERGY_MODIFIER_ALT 0x0004 /* Alt key modifier */
Copyright (c) 2012 Alex Evans
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
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
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
//---------------------------------------------------------------------------------------------------------------------
// Configuration
//---------------------------------------------------------------------------------------------------------------------
/**
@brief Determine endianness
**/
#if defined(USYNERGY_LITTLE_ENDIAN) && defined(USYNERGY_BIG_ENDIAN)
/* Ambiguous: both endians specified */
#error "Can't define both USYNERGY_LITTLE_ENDIAN and USYNERGY_BIG_ENDIAN"
#elif !defined(USYNERGY_LITTLE_ENDIAN) && !defined(USYNERGY_BIG_ENDIAN)
/* Attempt to auto detect */
#if defined(__LITTLE_ENDIAN__) || defined(LITTLE_ENDIAN) || (_BYTE_ORDER == _LITTLE_ENDIAN)
#define USYNERGY_LITTLE_ENDIAN
#elif defined(__BIG_ENDIAN__) || defined(BIG_ENDIAN) || (_BYTE_ORDER == _BIG_ENDIAN)
#define USYNERGY_BIG_ENDIAN
#else
#error "Can't detect endian-nes, please defined either USYNERGY_LITTLE_ENDIAN or USYNERGY_BIG_ENDIAN";
#endif
#else
/* User-specified endian-nes, nothing to do for us */
#endif
//---------------------------------------------------------------------------------------------------------------------
// Types and Constants
//---------------------------------------------------------------------------------------------------------------------
/**
@brief Boolean type
**/
typedef int uSynergyBool;
#define USYNERGY_FALSE 0 /* False value */
#define USYNERGY_TRUE 1 /* True value */
/**
@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
callback functions as context.
**/
typedef struct { int ignored; } * uSynergyCookie;
/**
@brief Clipboard types
**/
enum uSynergyClipboardFormat
{
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_HTML = 2, /* HTML format, HTML fragment, UTF-8, newline is LF */
};
/**
@brief Constants and limits
**/
#define USYNERGY_NUM_JOYSTICKS 4 /* Maximum number of supported joysticks */
#define USYNERGY_PROTOCOL_MAJOR 1 /* Major protocol version */
#define USYNERGY_PROTOCOL_MINOR 4 /* Minor protocol version */
#define USYNERGY_IDLE_TIMEOUT 2000 /* Timeout in milliseconds before reconnecting */
#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_RECEIVE_BUFFER_SIZE 4096 /* Maximum size of an incoming packet */
/**
@brief Keyboard constants
**/
#define USYNERGY_MODIFIER_SHIFT 0x0001 /* Shift key modifier */
#define USYNERGY_MODIFIER_CTRL 0x0002 /* Ctrl key modifier */
#define USYNERGY_MODIFIER_ALT 0x0004 /* Alt 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_LEVEL5LOCK 0x0040 /* Level5Lock key modifier */
#define USYNERGY_MODIFIER_CAPSLOCK 0x1000 /* CapsLock key modifier */
#define USYNERGY_MODIFIER_NUMLOCK 0x2000 /* NumLock key modifier */
#define USYNERGY_MODIFIER_SCROLLOCK 0x4000 /* ScrollLock key modifier */
//---------------------------------------------------------------------------------------------------------------------
// Functions and Callbacks
//---------------------------------------------------------------------------------------------------------------------
/**
@brief Connect function
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
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
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
**/
typedef uSynergyBool (*uSynergyConnectFunc)(uSynergyCookie cookie);
/**
@brief Send function
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
operation is completed.
@param cookie Cookie supplied in the Synergy context
@param buffer Address of buffer to send
@param length Length of buffer to send
**/
typedef uSynergyBool (*uSynergySendFunc)(uSynergyCookie cookie, const uint8_t *buffer, int length);
/**
@brief Receive function
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
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.
@param cookie Cookie supplied in the Synergy context
@param buffer Address of buffer to receive data into
@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
**/
typedef uSynergyBool (*uSynergyReceiveFunc)(uSynergyCookie cookie, uint8_t *buffer, int maxLength, int* outLength);
/**
@brief Thread sleep function
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
network connection in case the network is down.
@param cookie Cookie supplied in the Synergy context
@param timeMs Time to sleep the current thread (in milliseconds)
**/
typedef void (*uSynergySleepFunc)(uSynergyCookie cookie, int timeMs);
/**
@brief Get time function
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.
@returns Time value in milliseconds
**/
typedef uint32_t (*uSynergyGetTimeFunc)();
/**
@brief Trace function
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
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 text Text to be traced
**/
typedef void (*uSynergyTraceFunc)(uSynergyCookie cookie, const char *text);
/**
@brief Screen active callback
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.
@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
**/
typedef void (*uSynergyScreenActiveCallback)(uSynergyCookie cookie, uSynergyBool active);
/**
@brief Mouse callback
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
interpret if this is a mouse up, down, double-click or other message.
@param cookie Cookie supplied in the Synergy context
@param x Mouse X position
@param y Mouse Y position
@param wheelX Mouse wheel X position
@param wheelY Mouse wheel Y position
@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 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);
/**
@brief Key event callback
This callback is called when a key is pressed or released.
@param cookie Cookie supplied in the Synergy context
@param key Key code of key that was pressed or released
@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 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);
/**
@brief Joystick event callback
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
callback will contain all the valid state for the different axes and buttons. The last callback received will
represent the most current joystick state.
@param cookie Cookie supplied in the Synergy context
@param joyNum Joystick number, always in the range [0 ... USYNERGY_NUM_JOYSTICKS>
@param buttons Button pressed mask
@param leftStickX Left stick X 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 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);
/**
@brief Clipboard event callback
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
by the application.
@param cookie Cookie supplied in the Synergy context
@param format Clipboard format
@param data Memory area containing the clipboard raw data
@param size Size of clipboard data
**/
typedef void (*uSynergyClipboardCallback)(uSynergyCookie cookie, enum uSynergyClipboardFormat format, const uint8_t *data, uint32_t size);
//---------------------------------------------------------------------------------------------------------------------
// Context
//---------------------------------------------------------------------------------------------------------------------
/**
@brief uSynergy context
**/
typedef struct
{
/* Mandatory configuration data, filled in by client */
uSynergyConnectFunc m_connectFunc; /* Connect function */
uSynergySendFunc m_sendFunc; /* Send data function */
uSynergyReceiveFunc m_receiveFunc; /* Receive data function */
uSynergySleepFunc m_sleepFunc; /* Thread sleep function */
uSynergyGetTimeFunc m_getTimeFunc; /* Get current time function */
const char* m_clientName; /* Name of Synergy Screen / Client */
uint16_t m_clientWidth; /* Width of screen */
uint16_t m_clientHeight; /* Height of screen */
/* Optional configuration data, filled in by client */
uSynergyCookie m_cookie; /* Cookie pointer passed to callback functions (can be NULL) */
uSynergyTraceFunc m_traceFunc; /* Function for tracing status (can be NULL) */
uSynergyScreenActiveCallback m_screenActiveCallback; /* Callback for entering and leaving screen */
uSynergyMouseCallback m_mouseCallback; /* Callback for mouse events */
uSynergyKeyboardCallback m_keyboardCallback; /* Callback for keyboard events */
uSynergyJoystickCallback m_joystickCallback; /* Callback for joystick events */
uSynergyClipboardCallback m_clipboardCallback; /* Callback for clipboard events */
/* State data, used internall by client, initialized by uSynergyInit() */
uSynergyBool m_connected; /* Is our socket connected? */
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?) */
uint32_t m_lastMessageTime; /* Time at which last message was received */
uint32_t m_sequenceNumber; /* Packet sequence number */
uint8_t m_receiveBuffer[USYNERGY_RECEIVE_BUFFER_SIZE]; /* Receive buffer */
int m_receiveOfs; /* Receive buffer offset */
uint8_t m_replyBuffer[USYNERGY_REPLY_BUFFER_SIZE]; /* Reply buffer */
uint8_t* m_replyCur; /* Write offset into reply buffer */
uint16_t m_mouseX; /* Mouse X position */
uint16_t m_mouseY; /* Mouse Y position */
int16_t m_mouseWheelX; /* Mouse wheel X position */
int16_t m_mouseWheelY; /* Mouse wheel Y position */
uSynergyBool m_mouseButtonLeft; /* Mouse left button */
uSynergyBool m_mouseButtonRight; /* Mouse right button */
uSynergyBool m_mouseButtonMiddle; /* Mouse middle button */
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 */
} uSynergyContext;
//---------------------------------------------------------------------------------------------------------------------
// Interface
//---------------------------------------------------------------------------------------------------------------------
/**
@brief Initialize uSynergy context
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
this function will cause undefined behavior.
@param context Context to be initialized
**/
extern void uSynergyInit(uSynergyContext *context);
/**
@brief Update uSynergy
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
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.
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.
uSynergyUpdate doesn't do any memory allocations or have any side effects beyond those of
the callbacks it calls.
@param context Context to be updated
**/
extern void uSynergyUpdate(uSynergyContext *context);
/**
@brief Send clipboard data
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
server.
Currently there is only support for plaintext, but HTML and image data could be
supported with some effort.
@param context Context to send clipboard data to
@param text Text to set to the clipboard
**/
extern void uSynergySendClipboard(uSynergyContext *context, const char *text);
#ifdef __cplusplus
};
#endif
//---------------------------------------------------------------------------------------------------------------------
// Functions and Callbacks
//---------------------------------------------------------------------------------------------------------------------
/**
@brief Connect function
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
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
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
**/
typedef uSynergyBool (*uSynergyConnectFunc)(uSynergyCookie cookie);
/**
@brief Send function
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
operation is completed.
@param cookie Cookie supplied in the Synergy context
@param buffer Address of buffer to send
@param length Length of buffer to send
**/
typedef uSynergyBool (*uSynergySendFunc)(uSynergyCookie cookie, const uint8_t *buffer, int length);
/**
@brief Receive function
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
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.
@param cookie Cookie supplied in the Synergy context
@param buffer Address of buffer to receive data into
@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
**/
typedef uSynergyBool (*uSynergyReceiveFunc)(uSynergyCookie cookie, uint8_t *buffer, int maxLength, int* outLength);
/**
@brief Thread sleep function
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
network connection in case the network is down.
@param cookie Cookie supplied in the Synergy context
@param timeMs Time to sleep the current thread (in milliseconds)
**/
typedef void (*uSynergySleepFunc)(uSynergyCookie cookie, int timeMs);
/**
@brief Get time function
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.
@returns Time value in milliseconds
**/
typedef uint32_t (*uSynergyGetTimeFunc)();
/**
@brief Trace function
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
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 text Text to be traced
**/
typedef void (*uSynergyTraceFunc)(uSynergyCookie cookie, const char *text);
/**
@brief Screen active callback
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.
@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
**/
typedef void (*uSynergyScreenActiveCallback)(uSynergyCookie cookie, uSynergyBool active);
/**
@brief Mouse callback
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
interpret if this is a mouse up, down, double-click or other message.
@param cookie Cookie supplied in the Synergy context
@param x Mouse X position
@param y Mouse Y position
@param wheelX Mouse wheel X position
@param wheelY Mouse wheel Y position
@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 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);
/**
@brief Key event callback
This callback is called when a key is pressed or released.
@param cookie Cookie supplied in the Synergy context
@param key Key code of key that was pressed or released
@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 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);
/**
@brief Joystick event callback
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
callback will contain all the valid state for the different axes and buttons. The last callback received will
represent the most current joystick state.
@param cookie Cookie supplied in the Synergy context
@param joyNum Joystick number, always in the range [0 ... USYNERGY_NUM_JOYSTICKS>
@param buttons Button pressed mask
@param leftStickX Left stick X 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 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);
/**
@brief Clipboard event callback
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
by the application.
@param cookie Cookie supplied in the Synergy context
@param format Clipboard format
@param data Memory area containing the clipboard raw data
@param size Size of clipboard data
**/
typedef void (*uSynergyClipboardCallback)(uSynergyCookie cookie, enum uSynergyClipboardFormat format, const uint8_t *data, uint32_t size);
//---------------------------------------------------------------------------------------------------------------------
// Context
//---------------------------------------------------------------------------------------------------------------------
/**
@brief uSynergy context
**/
typedef struct
{
/* Mandatory configuration data, filled in by client */
uSynergyConnectFunc m_connectFunc; /* Connect function */
uSynergySendFunc m_sendFunc; /* Send data function */
uSynergyReceiveFunc m_receiveFunc; /* Receive data function */
uSynergySleepFunc m_sleepFunc; /* Thread sleep function */
uSynergyGetTimeFunc m_getTimeFunc; /* Get current time function */
const char* m_clientName; /* Name of Synergy Screen / Client */
uint16_t m_clientWidth; /* Width of screen */
uint16_t m_clientHeight; /* Height of screen */
/* Optional configuration data, filled in by client */
uSynergyCookie m_cookie; /* Cookie pointer passed to callback functions (can be NULL) */
uSynergyTraceFunc m_traceFunc; /* Function for tracing status (can be NULL) */
uSynergyScreenActiveCallback m_screenActiveCallback; /* Callback for entering and leaving screen */
uSynergyMouseCallback m_mouseCallback; /* Callback for mouse events */
uSynergyKeyboardCallback m_keyboardCallback; /* Callback for keyboard events */
uSynergyJoystickCallback m_joystickCallback; /* Callback for joystick events */
uSynergyClipboardCallback m_clipboardCallback; /* Callback for clipboard events */
/* State data, used internall by client, initialized by uSynergyInit() */
uSynergyBool m_connected; /* Is our socket connected? */
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?) */
uint32_t m_lastMessageTime; /* Time at which last message was received */
uint32_t m_sequenceNumber; /* Packet sequence number */
uint8_t m_receiveBuffer[USYNERGY_RECEIVE_BUFFER_SIZE]; /* Receive buffer */
int m_receiveOfs; /* Receive buffer offset */
uint8_t m_replyBuffer[USYNERGY_REPLY_BUFFER_SIZE]; /* Reply buffer */
uint8_t* m_replyCur; /* Write offset into reply buffer */
uint16_t m_mouseX; /* Mouse X position */
uint16_t m_mouseY; /* Mouse Y position */
int16_t m_mouseWheelX; /* Mouse wheel X position */
int16_t m_mouseWheelY; /* Mouse wheel Y position */
uSynergyBool m_mouseButtonLeft; /* Mouse left button */
uSynergyBool m_mouseButtonRight; /* Mouse right button */
uSynergyBool m_mouseButtonMiddle; /* Mouse middle button */
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 */
} uSynergyContext;
//---------------------------------------------------------------------------------------------------------------------
// Interface
//---------------------------------------------------------------------------------------------------------------------
/**
@brief Initialize uSynergy context
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
this function will cause undefined behavior.
@param context Context to be initialized
**/
extern void uSynergyInit(uSynergyContext *context);
/**
@brief Update uSynergy
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
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.
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.
uSynergyUpdate doesn't do any memory allocations or have any side effects beyond those of
the callbacks it calls.
@param context Context to be updated
**/
extern void uSynergyUpdate(uSynergyContext *context);
/**
@brief Send clipboard data
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
server.
Currently there is only support for plaintext, but HTML and image data could be
supported with some effort.
@param context Context to send clipboard data to
@param text Text to set to the clipboard
**/
extern void uSynergySendClipboard(uSynergyContext *context, const char *text);
#ifdef __cplusplus
};
#endif

View File

@ -19,15 +19,15 @@
#include "winmmjoy.h"
#include <MMSystem.h>
#include <iostream>
#include <iostream>
#include <sstream>
#pragma comment(lib, "winmm.lib")
std::stringstream _logStream;
#define LOG(s) \
_logStream.str(""); \
_logStream << "winmmjoy: " << s << std::endl; \
std::stringstream _logStream;
#define LOG(s) \
_logStream.str(""); \
_logStream << "winmmjoy: " << s << std::endl; \
s_log( _logStream.str().c_str())
static bool s_running = true;
@ -64,7 +64,7 @@ mainLoop(void* data)
const char* triggersEvent = "IPrimaryScreen::getGameDeviceTriggersEvent";
JOYINFOEX joyInfo;
ZeroMemory(&joyInfo, sizeof(joyInfo));
ZeroMemory(&joyInfo, sizeof(joyInfo));
joyInfo.dwSize = sizeof(joyInfo);
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 Nick Bolton
*
* 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 "VersionCheckerTests.h"
#include "VersionChecker.cpp"
#include "../../gui/tmp/debug/moc_VersionChecker.cpp"
#include <QtTest/QTest>
void VersionCheckerTests::compareVersions()
{
VersionChecker versionChecker;
// compare majors
QCOMPARE(versionChecker.compareVersions("1.0.0", "2.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.4.8", "2.4.7"), 1);
QCOMPARE(versionChecker.compareVersions("2.4.7", "1.4.8"), -1);
// compare minors
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.4.0"), 0);
QCOMPARE(versionChecker.compareVersions("1.3.8", "1.4.7"), 1);
QCOMPARE(versionChecker.compareVersions("1.4.7", "1.3.8"), -1);
// compare revs
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.7", "1.4.7"), 0);
}
* Copyright (C) 2012 Nick Bolton
*
* 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 "VersionCheckerTests.h"
#include "VersionChecker.cpp"
#include "../../gui/tmp/debug/moc_VersionChecker.cpp"
#include <QtTest/QTest>
void VersionCheckerTests::compareVersions()
{
VersionChecker versionChecker;
// compare majors
QCOMPARE(versionChecker.compareVersions("1.0.0", "2.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.4.8", "2.4.7"), 1);
QCOMPARE(versionChecker.compareVersions("2.4.7", "1.4.8"), -1);
// compare minors
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.4.0"), 0);
QCOMPARE(versionChecker.compareVersions("1.3.8", "1.4.7"), 1);
QCOMPARE(versionChecker.compareVersions("1.4.7", "1.3.8"), -1);
// compare revs
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.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 Nick Bolton
*
* 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 "QObject.h"
class VersionCheckerTests : public QObject
{
Q_OBJECT
private slots:
void compareVersions();
};
* Copyright (C) 2012 Nick Bolton
*
* 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 "QObject.h"
class VersionCheckerTests : public QObject
{
Q_OBJECT
private slots:
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 Nick Bolton
*
* 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 <QtTest/QTest>
#include "VersionCheckerTests.h"
int main(int argc, char *argv[])
{
VersionCheckerTests versionCheckerTests;
QTest::qExec(&versionCheckerTests, argc, argv);
}
* Copyright (C) 2012 Nick Bolton
*
* 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 <QtTest/QTest>
#include "VersionCheckerTests.h"
int main(int argc, char *argv[])
{
VersionCheckerTests versionCheckerTests;
QTest::qExec(&versionCheckerTests, argc, argv);
}

View File

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

View File

@ -16,8 +16,11 @@
*/
#include <gtest/gtest.h>
#include <iostream>
#include <stdexcept>
#include <sstream>
#include <fstream>
#include <iostream>
#include <stdio.h>
#define TEST_ENV
@ -33,42 +36,74 @@
#include "CTCPSocketFactory.h"
#include "CCryptoOptions.h"
#include "CSocketMultiplexer.h"
#include "CMSWindowsScreen.h"
#include "CGameDevice.h"
#include "CThread.h"
#include "TMethodJob.h"
#include "CTestEventQueue.h"
#include "server/CMockInputFilter.h"
#include "TMethodJob.h"
#include "CThread.h"
#include "CFileChunker.h"
using namespace std;
using ::testing::_;
using ::testing::NiceMock;
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::Invoke;
#define TEST_PORT 24803
#define TEST_HOST "localhost"
const int klargeDataSize = 512;
char g_largeData[klargeDataSize] = "large data:head.1221412312341244213123fdsfasdawdwadwadacwdd.12321412312341244213123fdsfasdawdwadwadacwdawddawdwacawdawd232141231awddawdwacawdawd2321412312341244213123fdsfasdawdwadacwdawddawdwacawdtrtetawdawdwaewe1213412321412312341244213123fdsfasdawdwadacwdawddawdwacawdawdawdwaewe121341awdwaewedacwdawddawdwacawdawd2321412312341244213123fdsfasdawdwadacwdawddawdwacawdtrtetawdawdwaewe1213412321412312341244213123fdsfasdawdwadacwdawddawdwacawdawdawdwaewe121341awdwaewe12134123njk1u31i2nm3e123hu23oi132213njk.tail";
const size_t kMockDataSize = 1024 * 1024 * 10; // 10MB
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 sendFileToClient_getCursorPos(SInt32& x, SInt32& y);
void getScreenShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h);
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
{
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 sendFileToClient_fileRecieveComplete(const CEvent&, void*);
void sendToClient_mockData_handleClientConnected(const CEvent&, void* vlistener);
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:
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
CNetworkAddress serverAddress(TEST_HOST, TEST_PORT);
@ -88,7 +123,7 @@ TEST_F(NetworkTests, sendFileToClient)
m_events.adoptHandler(
m_events.forCClientListener().connected(), &listener,
new TMethodEventJob<NetworkTests>(
this, &NetworkTests::sendFileToClient_handleClientConnected, &listener));
this, &NetworkTests::sendToClient_mockData_handleClientConnected, &listener));
ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true));
ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter));
@ -102,43 +137,196 @@ TEST_F(NetworkTests, sendFileToClient)
CSocketMultiplexer clientSocketMultiplexer;
CTCPSocketFactory* clientSocketFactory = new CTCPSocketFactory(&m_events, &clientSocketMultiplexer);
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(sendFileToClient_getShape));
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(sendFileToClient_getCursorPos));
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::sendFileToClient_fileRecieveComplete));
this, &NetworkTests::sendToClient_mockData_fileRecieveComplete));
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.cleanupQuitTimeout();
}
void
NetworkTests::sendFileToClient_handleClientConnected(const CEvent&, void* vlistener)
NetworkTests::sendToClient_mockData_handleClientConnected(const CEvent&, void* vlistener)
{
CClientListener* listener = reinterpret_cast<CClientListener*>(vlistener);
CServer* server = listener->getServer();
CClientProxy* client = listener->getNextClient();
if (client == NULL) {
throw std::exception("client is null");
throw runtime_error("client is null");
}
CBaseClientProxy* bcp = reinterpret_cast<CBaseClientProxy*>(client);
server->adoptClient(bcp);
server->setActive(bcp);
sendData(server);
sendMockData(server);
}
void
NetworkTests::sendFileToClient_fileRecieveComplete(const CEvent& event, void*)
NetworkTests::sendToClient_mockData_fileRecieveComplete(const CEvent& event, void*)
{
CClient* client = reinterpret_cast<CClient*>(event.getTarget());
EXPECT_TRUE(client->isReceivedFileSizeValid());
@ -147,32 +335,166 @@ NetworkTests::sendFileToClient_fileRecieveComplete(const CEvent& event, void*)
}
void
NetworkTests::sendData(CServer* server)
NetworkTests::sendToClient_mockFile_handleClientConnected(const CEvent&, void* vlistener)
{
UInt8* largeDataSize = new UInt8[5];
largeDataSize[0] = '0';
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));
CClientListener* listener = reinterpret_cast<CClientListener*>(vlistener);
CServer* server = listener->getServer();
UInt8* transferFinished = new UInt8[2];
transferFinished[0] = '2';
transferFinished[1] = '\0';
CClientProxy* client = listener->getNextClient();
if (client == NULL) {
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
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;
y = 0;
@ -181,8 +503,16 @@ sendFileToClient_getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h)
}
void
sendFileToClient_getCursorPos(SInt32& x, SInt32& y)
getCursorPos(SInt32& x, SInt32& y)
{
x = 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 "COSXKeyState.h"
#include "CMockKeyMap.h"
#include "CMockEventQueue.h"
#include "synergy/CMockKeyMap.h"
#include "synergy/CMockEventQueue.h"
#include "CLog.h"

View File

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

View File

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

View File

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