diff --git a/CMakeLists.txt b/CMakeLists.txt
index bc23d25a..d46e5c78 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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()
+
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 4ee77129..930d4ca8 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -13,11 +13,11 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-
-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)
diff --git a/src/cmd/synergyp/synergyp.cpp b/src/cmd/synergyp/synergyp.cpp
index af1d1886..a6f6b1db 100644
--- a/src/cmd/synergyp/synergyp.cpp
+++ b/src/cmd/synergyp/synergyp.cpp
@@ -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;
}
diff --git a/src/gui/src/CryptoMode.h b/src/gui/src/CryptoMode.h
index 5db9964c..bd5f9a6c 100644
--- a/src/gui/src/CryptoMode.h
+++ b/src/gui/src/CryptoMode.h
@@ -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 .
- */
-
-#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 .
+ */
+
+#pragma once
+
+enum CryptoMode {
+ Disabled,
+ OFB,
+ CFB,
+ CTR,
+ GCM
+};
diff --git a/src/gui/src/Ipc.cpp b/src/gui/src/Ipc.cpp
index 4f7d9316..4b7cec65 100644
--- a/src/gui/src/Ipc.cpp
+++ b/src/gui/src/Ipc.cpp
@@ -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 .
- */
-
-// 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 .
+ */
+
+// 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";
diff --git a/src/gui/src/Ipc.h b/src/gui/src/Ipc.h
index 0bae0733..0af53b18 100644
--- a/src/gui/src/Ipc.h
+++ b/src/gui/src/Ipc.h
@@ -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 .
- */
-
-// 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 .
+ */
+
+// 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;
diff --git a/src/gui/src/IpcClient.cpp b/src/gui/src/IpcClient.cpp
index 0eeb5d29..c899e677 100644
--- a/src/gui/src/IpcClient.cpp
+++ b/src/gui/src/IpcClient.cpp
@@ -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 .
- */
-
-#include "IpcClient.h"
-#include
-#include
-#include
-#include
-#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 .
+ */
+
+#include "IpcClient.h"
+#include
+#include
+#include
+#include
+#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.
+ }
+}
diff --git a/src/gui/src/IpcClient.h b/src/gui/src/IpcClient.h
index 6830483b..b417b356 100644
--- a/src/gui/src/IpcClient.h
+++ b/src/gui/src/IpcClient.h
@@ -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 .
- */
-
-#pragma once
-
-#include
-#include
-
-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 .
+ */
+
+#pragma once
+
+#include
+#include
+
+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;
+};
diff --git a/src/gui/src/IpcReader.cpp b/src/gui/src/IpcReader.cpp
index 288fb432..87bb8041 100644
--- a/src/gui/src/IpcReader.cpp
+++ b/src/gui/src/IpcReader.cpp
@@ -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 .
- */
-
-#include "IpcReader.h"
-#include
-#include "Ipc.h"
-#include
-#include
-#include
-
-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 .
+ */
+
+#include "IpcReader.h"
+#include
+#include "Ipc.h"
+#include
+#include
+#include
+
+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;
+ }
+}
diff --git a/src/gui/src/IpcReader.h b/src/gui/src/IpcReader.h
index 9c9f2942..067500a4 100644
--- a/src/gui/src/IpcReader.h
+++ b/src/gui/src/IpcReader.h
@@ -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 .
- */
-
-#pragma once
-
-#include
-#include
-
-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 .
+ */
+
+#pragma once
+
+#include
+#include
+
+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;
+};
diff --git a/src/gui/src/QUtility.cpp b/src/gui/src/QUtility.cpp
index 6c27af9b..dc9e0e90 100644
--- a/src/gui/src/QUtility.cpp
+++ b/src/gui/src/QUtility.cpp
@@ -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 .
- */
-
-#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 .
+ */
+
+#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;
+}
diff --git a/src/gui/src/QUtility.h b/src/gui/src/QUtility.h
index fa435c82..77e9b916 100644
--- a/src/gui/src/QUtility.h
+++ b/src/gui/src/QUtility.h
@@ -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 .
- */
-
-#pragma once
-
-#include
-#include
-#include
-#include
-
-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 .
+ */
+
+#pragma once
+
+#include
+#include
+#include
+#include
+
+void setIndexFromItemData(QComboBox* comboBox, const QVariant& itemData);
+QString hash(const QString& string);
+QString getFirstMacAddress();
diff --git a/src/gui/src/SetupWizard.cpp b/src/gui/src/SetupWizard.cpp
index f2a438b9..dc2e19ca 100644
--- a/src/gui/src/SetupWizard.cpp
+++ b/src/gui/src/SetupWizard.cpp
@@ -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 .
- */
-
-#include "SetupWizard.h"
-#include "MainWindow.h"
-#include "QSynergyApplication.h"
-#include "QUtility.h"
-
-#include
-#include
-#include
-#include
-#include
-
-//#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 .
+ */
+
+#include "SetupWizard.h"
+#include "MainWindow.h"
+#include "QSynergyApplication.h"
+#include "QUtility.h"
+
+#include
+#include
+#include
+#include
+#include
+
+//#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;
+}
diff --git a/src/gui/src/SetupWizard.h b/src/gui/src/SetupWizard.h
index 4c217cda..2d13484e 100644
--- a/src/gui/src/SetupWizard.h
+++ b/src/gui/src/SetupWizard.h
@@ -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 .
- */
-
-#pragma once
-
-#include "ui_SetupWizardBase.h"
-#include "CryptoMode.h"
-#include "SynergyLocale.h"
-
-#include
-#include
-
-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 .
+ */
+
+#pragma once
+
+#include "ui_SetupWizardBase.h"
+#include "CryptoMode.h"
+#include "SynergyLocale.h"
+
+#include
+#include
+
+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);
+};
diff --git a/src/gui/src/SynergyLocale.cpp b/src/gui/src/SynergyLocale.cpp
index 6c6598bb..db4e941a 100644
--- a/src/gui/src/SynergyLocale.cpp
+++ b/src/gui/src/SynergyLocale.cpp
@@ -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
- */
-
-#include "SynergyLocale.h"
-
-#include
-#include
-#include
-
-SynergyLocale::SynergyLocale()
-{
- loadLanguages();
-}
-
-void SynergyLocale::loadLanguages()
-{
- QResource resource(":/res/lang/Languages.xml");
- QByteArray bytes(reinterpret_cast(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::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
+ */
+
+#include "SynergyLocale.h"
+
+#include
+#include
+#include
+
+SynergyLocale::SynergyLocale()
+{
+ loadLanguages();
+}
+
+void SynergyLocale::loadLanguages()
+{
+ QResource resource(":/res/lang/Languages.xml");
+ QByteArray bytes(reinterpret_cast(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::iterator it;
+ for (it = m_Languages.begin(); it != m_Languages.end(); ++it)
+ {
+ comboBox->addItem((*it).m_Name, (*it).m_IetfCode);
+ }
+ comboBox->blockSignals(false);
+}
diff --git a/src/gui/src/SynergyLocale.h b/src/gui/src/SynergyLocale.h
index ccbbe817..ae816305 100644
--- a/src/gui/src/SynergyLocale.h
+++ b/src/gui/src/SynergyLocale.h
@@ -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 .
- */
-
-#pragma once
-
-#include
-#include
-#include
-
-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 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 .
+ */
+
+#pragma once
+
+#include
+#include
+#include
+
+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 m_Languages;
+};
diff --git a/src/gui/src/TcpSocketReader.cpp b/src/gui/src/TcpSocketReader.cpp
index f5d7750c..ea381085 100644
--- a/src/gui/src/TcpSocketReader.cpp
+++ b/src/gui/src/TcpSocketReader.cpp
@@ -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 .
- */
-
-#include "TcpSocketReader.h"
-#include
-
-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 .
+ */
+
+#include "TcpSocketReader.h"
+#include
+
+IpcReader::IpcReader(QTcpSocket& socket) :
+m_Socket(socket)
+{
+ connect(m_Socket, SIGNAL(readyRead()), this, SLOT(read()));
+}
+
+IpcReader::~IpcReader()
+{
+}
diff --git a/src/gui/src/VersionChecker.cpp b/src/gui/src/VersionChecker.cpp
index cd811d3f..b784adf2 100644
--- a/src/gui/src/VersionChecker.cpp
+++ b/src/gui/src/VersionChecker.cpp
@@ -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 .
- */
-
-#include "VersionChecker.h"
-
-#include
-#include
-#include
-#include
-#include
-
-#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 .
+ */
+
+#include "VersionChecker.h"
+
+#include
+#include
+#include
+#include
+#include
+
+#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");
+}
diff --git a/src/gui/src/VersionChecker.h b/src/gui/src/VersionChecker.h
index a35eb738..941ee760 100644
--- a/src/gui/src/VersionChecker.h
+++ b/src/gui/src/VersionChecker.h
@@ -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 .
- */
-
-#pragma once
-
-#include
-#include
-
-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 .
+ */
+
+#pragma once
+
+#include
+#include
+
+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;
+};
diff --git a/src/lib/arch/CArchNetworkBSD.cpp b/src/lib/arch/CArchNetworkBSD.cpp
index a9d1c978..f0c74d68 100644
--- a/src/lib/arch/CArchNetworkBSD.cpp
+++ b/src/lib/arch/CArchNetworkBSD.cpp
@@ -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) {
diff --git a/src/lib/arch/CArchNetworkBSD.h b/src/lib/arch/CArchNetworkBSD.h
index 9ae4a25c..f524915f 100644
--- a/src/lib/arch/CArchNetworkBSD.h
+++ b/src/lib/arch/CArchNetworkBSD.h
@@ -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);
diff --git a/src/lib/base/CEventQueue.cpp b/src/lib/base/CEventQueue.cpp
index 0de4575d..0502ec27 100644
--- a/src/lib/base/CEventQueue.cpp
+++ b/src/lib/base/CEventQueue.cpp
@@ -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),
diff --git a/src/lib/base/CLog.cpp b/src/lib/base/CLog.cpp
index d58587c3..e2974ea5 100644
--- a/src/lib/base/CLog.cpp
+++ b/src/lib/base/CLog.cpp
@@ -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;
diff --git a/src/lib/base/CLog.h b/src/lib/base/CLog.h
index 6f5adcdd..1eb8c82b 100644
--- a/src/lib/base/CLog.h
+++ b/src/lib/base/CLog.h
@@ -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
diff --git a/src/lib/client/CClient.cpp b/src/lib/client/CClient.cpp
index fdf34721..72f31fb5 100644
--- a/src/lib/client/CClient.cpp
+++ b/src/lib/client/CClient.cpp
@@ -33,14 +33,20 @@
#include "CArch.h"
#include "IPlatformScreen.h"
#include "CCryptoStream.h"
+#include "CThread.h"
+#include "TMethodJob.h"
+#include "CFileChunker.h"
#include
#include
#include
+#include
//
// 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(const_cast(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(
+ this, &CClient::sendFileThread,
+ reinterpret_cast(const_cast(filename))));
+}
+
+void
+CClient::sendFileThread(void* filename)
+{
+ try {
+ char* name = reinterpret_cast(filename);
+ CFileChunker::sendFileChunks(name, m_events, this);
+ }
+ catch (std::runtime_error error) {
+ LOG((CLOG_ERR "failed sending file chunks: %s", error.what()));
+ }
+}
diff --git a/src/lib/client/CClient.h b/src/lib/client/CClient.h
index c4db7e9c..030e64b7 100644
--- a/src/lib/client/CClient.h
+++ b/src/lib/client/CClient.h
@@ -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
diff --git a/src/lib/client/CServerProxy.cpp b/src/lib/client/CServerProxy.cpp
index dff281ce..c8475cb6 100644
--- a/src/lib/client/CServerProxy.cpp
+++ b/src/lib/client/CServerProxy.cpp
@@ -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);
+}
diff --git a/src/lib/client/CServerProxy.h b/src/lib/client/CServerProxy.h
index a1afa4e4..74255fa8 100644
--- a/src/lib/client/CServerProxy.h
+++ b/src/lib/client/CServerProxy.h
@@ -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
diff --git a/src/lib/platform/CMSWindowsDebugOutputter.h b/src/lib/platform/CMSWindowsDebugOutputter.h
index aaf08117..f89c470e 100644
--- a/src/lib/platform/CMSWindowsDebugOutputter.h
+++ b/src/lib/platform/CMSWindowsDebugOutputter.h
@@ -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 .
- */
-
-#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 .
+ */
+
+#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();
+};
diff --git a/src/lib/platform/CMSWindowsRelauncher.cpp b/src/lib/platform/CMSWindowsRelauncher.cpp
index 84fc181d..d7b563b0 100644
--- a/src/lib/platform/CMSWindowsRelauncher.cpp
+++ b/src/lib/platform/CMSWindowsRelauncher.cpp
@@ -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);
-}
+}
diff --git a/src/lib/platform/CXWindowsUtil.cpp b/src/lib/platform/CXWindowsUtil.cpp
index 3b8244bf..ca0178f4 100644
--- a/src/lib/platform/CXWindowsUtil.cpp
+++ b/src/lib/platform/CXWindowsUtil.cpp
@@ -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;
diff --git a/src/lib/platform/HookDLL.cpp b/src/lib/platform/HookDLL.cpp
index 3818cfdc..c151133e 100644
--- a/src/lib/platform/HookDLL.cpp
+++ b/src/lib/platform/HookDLL.cpp
@@ -14,329 +14,329 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
- */
-
-/*--------------------------------------------------------------------------------------------------------
- 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
-#include
-#include "HookDLL.h"
-
-#include
-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
+#include
+#include "HookDLL.h"
+
+#include
+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;
+}
+
diff --git a/src/lib/platform/HookDLL.h b/src/lib/platform/HookDLL.h
index ded57198..2d3e843d 100644
--- a/src/lib/platform/HookDLL.h
+++ b/src/lib/platform/HookDLL.h
@@ -14,68 +14,68 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
- */
-
-/*--------------------------------------------------------------------------------------------------------
- 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
-
-#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
+
+#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 );
diff --git a/src/lib/platform/XInput13.h b/src/lib/platform/XInput13.h
index ee434893..a1d5a180 100644
--- a/src/lib/platform/XInput13.h
+++ b/src/lib/platform/XInput13.h
@@ -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
-
-// 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
+
+// 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_
diff --git a/src/lib/platform/XInputHook.cpp b/src/lib/platform/XInputHook.cpp
index f606d4ac..d80079d3 100644
--- a/src/lib/platform/XInputHook.cpp
+++ b/src/lib/platform/XInputHook.cpp
@@ -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 .
- */
+ * 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 .
+ */
-#define WIN32_LEAN_AND_MEAN
-#define SYNERGY_EXPORT_XINPUT_HOOKS
-#define REQUIRED_XINPUT_DLL "xinput1_3.dll"
-#define HOOK_TIMEOUT 10000 // 10 sec
-
-#include
-#include
-#include "XInputHook.h"
-#include "HookDLL.h"
-#include
-
-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
-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
+#include
+#include "XInputHook.h"
+#include "HookDLL.h"
+#include
+
+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
+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");
+}
diff --git a/src/lib/platform/XInputHook.h b/src/lib/platform/XInputHook.h
index eb98c29e..08f3f66d 100644
--- a/src/lib/platform/XInputHook.h
+++ b/src/lib/platform/XInputHook.h
@@ -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 .
- */
-
-#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 .
+ */
+
+#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
diff --git a/src/lib/platform/XInputProxy13.cpp b/src/lib/platform/XInputProxy13.cpp
index ab1cb79d..f3bac29f 100644
--- a/src/lib/platform/XInputProxy13.cpp
+++ b/src/lib/platform/XInputProxy13.cpp
@@ -18,7 +18,7 @@
#define SYNERGY_EXPORT_XINPUT_HOOKS
#define WIN32_LEAN_AND_MEAN
-
+
#include
#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;
}
diff --git a/src/lib/platform/XInputProxy13.h b/src/lib/platform/XInputProxy13.h
index 7e585635..1d0cdb94 100644
--- a/src/lib/platform/XInputProxy13.h
+++ b/src/lib/platform/XInputProxy13.h
@@ -14,67 +14,67 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
- */
-
-#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
\ No newline at end of file
diff --git a/src/lib/server/CBaseClientProxy.h b/src/lib/server/CBaseClientProxy.h
index 03502fb5..6f72b44d 100644
--- a/src/lib/server/CBaseClientProxy.h
+++ b/src/lib/server/CBaseClientProxy.h
@@ -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:
diff --git a/src/lib/server/CClientProxy.h b/src/lib/server/CClientProxy.h
index 4cebabc2..d2b952e2 100644
--- a/src/lib/server/CClientProxy.h
+++ b/src/lib/server/CClientProxy.h
@@ -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;
diff --git a/src/lib/server/CClientProxy1_0.cpp b/src/lib/server/CClientProxy1_0.cpp
index 319fd6ce..1dd3cc8f 100644
--- a/src/lib/server/CClientProxy1_0.cpp
+++ b/src/lib/server/CClientProxy1_0.cpp
@@ -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"));
diff --git a/src/lib/server/CClientProxy1_0.h b/src/lib/server/CClientProxy1_0.h
index 62e46a46..bed12e9d 100644
--- a/src/lib/server/CClientProxy1_0.h
+++ b/src/lib/server/CClientProxy1_0.h
@@ -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);
diff --git a/src/lib/server/CClientProxy1_3.h b/src/lib/server/CClientProxy1_3.h
index 82c87c9f..251cac36 100644
--- a/src/lib/server/CClientProxy1_3.h
+++ b/src/lib/server/CClientProxy1_3.h
@@ -42,7 +42,6 @@ protected:
private:
void handleKeepAlive(const CEvent&, void*);
-
private:
double m_keepAliveRate;
CEventQueueTimer* m_keepAliveTimer;
diff --git a/src/lib/server/CClientProxy1_4.h b/src/lib/server/CClientProxy1_4.h
index 587b6470..bdd33622 100644
--- a/src/lib/server/CClientProxy1_4.h
+++ b/src/lib/server/CClientProxy1_4.h
@@ -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);
diff --git a/src/lib/server/CClientProxy1_5.cpp b/src/lib/server/CClientProxy1_5.cpp
index 0f1fdeb1..0fdd7d8a 100644
--- a/src/lib/server/CClientProxy1_5.cpp
+++ b/src/lib/server/CClientProxy1_5.cpp
@@ -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(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;
+ }
+}
diff --git a/src/lib/server/CClientProxy1_5.h b/src/lib/server/CClientProxy1_5.h
index e88d91c3..65ae94d2 100644
--- a/src/lib/server/CClientProxy1_5.h
+++ b/src/lib/server/CClientProxy1_5.h
@@ -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;
};
diff --git a/src/lib/server/CPrimaryClient.cpp b/src/lib/server/CPrimaryClient.cpp
index c010d48d..a76f77c0 100644
--- a/src/lib/server/CPrimaryClient.cpp
+++ b/src/lib/server/CPrimaryClient.cpp
@@ -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
}
diff --git a/src/lib/server/CPrimaryClient.h b/src/lib/server/CPrimaryClient.h
index a2a0f6b2..663362b0 100644
--- a/src/lib/server/CPrimaryClient.h
+++ b/src/lib/server/CPrimaryClient.h
@@ -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;
diff --git a/src/lib/server/CServer.cpp b/src/lib/server/CServer.cpp
index 320a69a3..b2a49753 100644
--- a/src/lib/server/CServer.cpp
+++ b/src/lib/server/CServer.cpp
@@ -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
#include
-#include "CScreen.h"
+#include
+#include
+#include
//
// 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(this,
&CServer::handleFileChunkSendingEvent));
+ m_events->adoptHandler(m_events->forIScreen().fileRecieveComplete(),
+ this,
+ new TMethodEventJob(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(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(const_cast(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(
+ this, &CServer::sendFileThread,
+ reinterpret_cast(const_cast(filename))));
+}
+
+void
+CServer::sendFileThread(void* filename)
+{
+ try {
+ char* name = reinterpret_cast(filename);
+ CFileChunker::sendFileChunks(name, m_events, this);
+ }
+ catch (std::runtime_error error) {
+ LOG((CLOG_ERR "failed sending file chunks: %s", error.what()));
+ }
+}
diff --git a/src/lib/server/CServer.h b/src/lib/server/CServer.h
index 91258924..c848f317 100644
--- a/src/lib/server/CServer.h
+++ b/src/lib/server/CServer.h
@@ -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& 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
diff --git a/src/lib/synergy/CApp.cpp b/src/lib/synergy/CApp.cpp
index a8f3cc8e..b86d276a 100644
--- a/src/lib/synergy/CApp.cpp
+++ b/src/lib/synergy/CApp.cpp
@@ -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
diff --git a/src/lib/synergy/CApp.h b/src/lib/synergy/CApp.h
index e335ecf3..330fb025 100644
--- a/src/lib/synergy/CApp.h
+++ b/src/lib/synergy/CApp.h
@@ -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."
diff --git a/src/lib/synergy/CClientApp.cpp b/src/lib/synergy/CClientApp.cpp
index e0107dc0..31a19cdd 100644
--- a/src/lib/synergy/CClientApp.cpp
+++ b/src/lib/synergy/CClientApp.cpp
@@ -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;
}
diff --git a/src/lib/synergy/CFileChunker.cpp b/src/lib/synergy/CFileChunker.cpp
new file mode 100644
index 00000000..e65ea7b9
--- /dev/null
+++ b/src/lib/synergy/CFileChunker.cpp
@@ -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 .
+ */
+
+#include "CFileChunker.h"
+#include "BasicTypes.h"
+#include "ProtocolTypes.h"
+#include "CEvent.h"
+#include "IEventQueue.h"
+#include "CEventTypes.h"
+#include "CLOG.h"
+#include
+#include
+
+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(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();
+}
diff --git a/src/lib/synergy/CFileChunker.h b/src/lib/synergy/CFileChunker.h
new file mode 100644
index 00000000..0e49c778
--- /dev/null
+++ b/src/lib/synergy/CFileChunker.h
@@ -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 .
+ */
+
+#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;
+};
diff --git a/src/lib/synergy/CMakeLists.txt b/src/lib/synergy/CMakeLists.txt
index 84da6be3..d7b0eba5 100644
--- a/src/lib/synergy/CMakeLists.txt
+++ b/src/lib/synergy/CMakeLists.txt
@@ -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()
diff --git a/src/lib/synergy/CProtocolUtil.cpp b/src/lib/synergy/CProtocolUtil.cpp
index 3445bebc..dd171230 100644
--- a/src/lib/synergy/CProtocolUtil.cpp
+++ b/src/lib/synergy/CProtocolUtil.cpp
@@ -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*);
diff --git a/src/lib/synergy/CServerApp.cpp b/src/lib/synergy/CServerApp.cpp
index 239dd946..9421bad2 100644
--- a/src/lib/synergy/CServerApp.cpp
+++ b/src/lib/synergy/CServerApp.cpp
@@ -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,
diff --git a/src/lib/synergy/IPrimaryScreen.h b/src/lib/synergy/IPrimaryScreen.h
index 586897ae..a8aa830e 100644
--- a/src/lib/synergy/IPrimaryScreen.h
+++ b/src/lib/synergy/IPrimaryScreen.h
@@ -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 {
diff --git a/src/lib/synergy/IScreen.h b/src/lib/synergy/IScreen.h
index 361b3400..30a4c3bb 100644
--- a/src/lib/synergy/IScreen.h
+++ b/src/lib/synergy/IScreen.h
@@ -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:
diff --git a/src/lib/synergy/ProtocolTypes.h b/src/lib/synergy/ProtocolTypes.h
index bff4b701..85ebe960 100644
--- a/src/lib/synergy/ProtocolTypes.h
+++ b/src/lib/synergy/ProtocolTypes.h
@@ -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
diff --git a/src/micro/uSynergy.h b/src/micro/uSynergy.h
index 18a17162..ef1efaa6 100644
--- a/src/micro/uSynergy.h
+++ b/src/micro/uSynergy.h
@@ -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
-
-#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
+
+#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
diff --git a/src/plugin/winmmjoy/winmmjoy.cpp b/src/plugin/winmmjoy/winmmjoy.cpp
index a1de587a..51e69a56 100644
--- a/src/plugin/winmmjoy/winmmjoy.cpp
+++ b/src/plugin/winmmjoy/winmmjoy.cpp
@@ -19,15 +19,15 @@
#include "winmmjoy.h"
#include
-#include
+#include
#include
#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;
diff --git a/src/test/guitests/src/VersionCheckerTests.cpp b/src/test/guitests/src/VersionCheckerTests.cpp
index d01fbeec..38bd3804 100644
--- a/src/test/guitests/src/VersionCheckerTests.cpp
+++ b/src/test/guitests/src/VersionCheckerTests.cpp
@@ -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 .
- */
-
-#include "VersionCheckerTests.h"
-#include "VersionChecker.cpp"
-#include "../../gui/tmp/debug/moc_VersionChecker.cpp"
-
-#include
-
-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 .
+ */
+
+#include "VersionCheckerTests.h"
+#include "VersionChecker.cpp"
+#include "../../gui/tmp/debug/moc_VersionChecker.cpp"
+
+#include
+
+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);
+}
diff --git a/src/test/guitests/src/VersionCheckerTests.h b/src/test/guitests/src/VersionCheckerTests.h
index 79cb78e4..db6c899d 100644
--- a/src/test/guitests/src/VersionCheckerTests.h
+++ b/src/test/guitests/src/VersionCheckerTests.h
@@ -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 .
- */
-
-#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 .
+ */
+
+#include "QObject.h"
+
+class VersionCheckerTests : public QObject
+{
+ Q_OBJECT
+private slots:
+ void compareVersions();
+};
diff --git a/src/test/guitests/src/main.cpp b/src/test/guitests/src/main.cpp
index c466529f..2fd81fe9 100644
--- a/src/test/guitests/src/main.cpp
+++ b/src/test/guitests/src/main.cpp
@@ -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 .
- */
-
-#include
-#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 .
+ */
+
+#include
+#include "VersionCheckerTests.h"
+
+int main(int argc, char *argv[])
+{
+ VersionCheckerTests versionCheckerTests;
+ QTest::qExec(&versionCheckerTests, argc, argv);
+}
diff --git a/src/test/integtests/CTestEventQueue.cpp b/src/test/integtests/CTestEventQueue.cpp
index f6cde4da..c92176cf 100644
--- a/src/test/integtests/CTestEventQueue.cpp
+++ b/src/test/integtests/CTestEventQueue.cpp
@@ -19,6 +19,7 @@
#include "CLog.h"
#include "TMethodEventJob.h"
#include "CSimpleEventQueueBuffer.h"
+#include
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");
}
diff --git a/src/test/integtests/NetworkTests.cpp b/src/test/integtests/NetworkTests.cpp
index 195ad80c..4b173a13 100644
--- a/src/test/integtests/NetworkTests.cpp
+++ b/src/test/integtests/NetworkTests.cpp
@@ -16,8 +16,11 @@
*/
#include
-#include
+#include
+#include
#include
+#include
+#include
#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(
- 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(
- 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 serverScreen;
+ NiceMock primaryClient;
+ NiceMock serverConfig;
+ NiceMock serverInputFilter;
+
+ m_events.adoptHandler(
+ m_events.forCClientListener().connected(), &listener,
+ new TMethodEventJob(
+ 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 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(
+ 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 serverScreen;
+ NiceMock primaryClient;
+ NiceMock serverConfig;
+ NiceMock 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 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(
+ this, &NetworkTests::sendToServer_mockData_handleClientConnected, &client));
+
+ m_events.adoptHandler(
+ m_events.forIScreen().fileRecieveComplete(), &server,
+ new TMethodEventJob(
+ 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 serverScreen;
+ NiceMock primaryClient;
+ NiceMock serverConfig;
+ NiceMock 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 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(
+ this, &NetworkTests::sendToServer_mockFile_handleClientConnected, &client));
+
+ m_events.adoptHandler(
+ m_events.forIScreen().fileRecieveComplete(), &server,
+ new TMethodEventJob(
+ 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(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(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(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(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(client);
+ server->adoptClient(bcp);
+ server->setActive(bcp);
+
+ server->sendFileToClient(kMockFilename);
+}
+
+void
+NetworkTests::sendToClient_mockFile_fileRecieveComplete(const CEvent& event, void*)
+{
+ CClient* client = reinterpret_cast(event.getTarget());
+ EXPECT_TRUE(client->isReceivedFileSizeValid());
+
+ m_events.raiseQuitEvent();
+}
+
+void
+NetworkTests::sendToServer_mockData_handleClientConnected(const CEvent&, void* vclient)
+{
+ CClient* client = reinterpret_cast(vclient);
+ sendMockData(client);
+}
+
+void
+NetworkTests::sendToServer_mockData_fileRecieveComplete(const CEvent& event, void*)
+{
+ CServer* server = reinterpret_cast(event.getTarget());
+ EXPECT_TRUE(server->isReceivedFileSizeValid());
+
+ m_events.raiseQuitEvent();
+}
+
+void
+NetworkTests::sendToServer_mockFile_handleClientConnected(const CEvent&, void* vclient)
+{
+ CClient* client = reinterpret_cast(vclient);
+ client->sendFileToServer(kMockFilename);
+}
+
+void
+NetworkTests::sendToServer_mockFile_fileRecieveComplete(const CEvent& event, void*)
+{
+ CServer* server = reinterpret_cast(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(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();
+}
diff --git a/src/test/integtests/platform/COSXKeyStateTests.cpp b/src/test/integtests/platform/COSXKeyStateTests.cpp
index 372e549f..f74bc2d7 100644
--- a/src/test/integtests/platform/COSXKeyStateTests.cpp
+++ b/src/test/integtests/platform/COSXKeyStateTests.cpp
@@ -20,8 +20,8 @@
#include
#include "COSXKeyState.h"
-#include "CMockKeyMap.h"
-#include "CMockEventQueue.h"
+#include "synergy/CMockKeyMap.h"
+#include "synergy/CMockEventQueue.h"
#include "CLog.h"
diff --git a/src/test/integtests/platform/CXWindowsKeyStateTests.cpp b/src/test/integtests/platform/CXWindowsKeyStateTests.cpp
index 45d45a04..35c45b3c 100644
--- a/src/test/integtests/platform/CXWindowsKeyStateTests.cpp
+++ b/src/test/integtests/platform/CXWindowsKeyStateTests.cpp
@@ -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
diff --git a/src/test/integtests/platform/CXWindowsScreenTests.cpp b/src/test/integtests/platform/CXWindowsScreenTests.cpp
index 846e35b0..e694b4c9 100644
--- a/src/test/integtests/platform/CXWindowsScreenTests.cpp
+++ b/src/test/integtests/platform/CXWindowsScreenTests.cpp
@@ -18,7 +18,7 @@
#include
#include "CXWindowsScreen.h"
-#include "CMockEventQueue.h"
+#include "synergy/CMockEventQueue.h"
using ::testing::_;
diff --git a/src/test/unittests/client/CServerProxyTests.cpp b/src/test/unittests/client/CServerProxyTests.cpp
index 09139131..8c985924 100644
--- a/src/test/unittests/client/CServerProxyTests.cpp
+++ b/src/test/unittests/client/CServerProxyTests.cpp
@@ -48,8 +48,8 @@ TEST(CServerProxyTests, mouseMove)
g_mouseMove_bufferIndex = 0;
NiceMock eventQueue;
- NiceMock client;
NiceMock stream;
+ NiceMock client;
IStreamEvents streamEvents;
streamEvents.setEvents(&eventQueue);