Patch by Jerry:
- Fixed line endings - Integ test for file transfer - Fixed crashed problem when log info is larger than 2048 bytes - Fixed compile error caused by std exception (by Feng ye) - Fixed include path on Mac and linux (by Feng ye)
This commit is contained in:
parent
c368013f13
commit
394ece004a
|
@ -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()
|
||||
|
||||
|
|
|
@ -13,11 +13,11 @@
|
|||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
add_subdirectory(lib)
|
||||
add_subdirectory(cmd)
|
||||
if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "IRIX")
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
add_subdirectory(plugin)
|
||||
add_subdirectory(micro)
|
||||
|
||||
add_subdirectory(lib)
|
||||
add_subdirectory(cmd)
|
||||
if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "IRIX")
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
add_subdirectory(plugin)
|
||||
add_subdirectory(micro)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2013 Bolton Software Ltd.
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
enum CryptoMode {
|
||||
Disabled,
|
||||
OFB,
|
||||
CFB,
|
||||
CTR,
|
||||
GCM
|
||||
};
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2013 Bolton Software Ltd.
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
enum CryptoMode {
|
||||
Disabled,
|
||||
OFB,
|
||||
CFB,
|
||||
CTR,
|
||||
GCM
|
||||
};
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012 Bolton Software Ltd.
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// this class is a duplicate of /src/lib/ipc/Ipc.cpp
|
||||
|
||||
#include "Ipc.h"
|
||||
|
||||
const char* kIpcMsgHello = "IHEL%1i";
|
||||
const char* kIpcMsgLogLine = "ILOG%s";
|
||||
const char* kIpcMsgCommand = "ICMD%s%1i";
|
||||
const char* kIpcMsgShutdown = "ISDN";
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// this class is a duplicate of /src/lib/ipc/Ipc.cpp
|
||||
|
||||
#include "Ipc.h"
|
||||
|
||||
const char* kIpcMsgHello = "IHEL%1i";
|
||||
const char* kIpcMsgLogLine = "ILOG%s";
|
||||
const char* kIpcMsgCommand = "ICMD%s%1i";
|
||||
const char* kIpcMsgShutdown = "ISDN";
|
||||
|
|
|
@ -1,42 +1,42 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012 Bolton Software Ltd.
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// this class is a duplicate of /src/lib/ipc/Ipc.h
|
||||
|
||||
#pragma once
|
||||
|
||||
#define IPC_HOST "127.0.0.1"
|
||||
#define IPC_PORT 24801
|
||||
|
||||
enum qIpcMessageType {
|
||||
kIpcHello,
|
||||
kIpcLogLine,
|
||||
kIpcCommand,
|
||||
kIpcShutdown,
|
||||
};
|
||||
|
||||
enum qIpcClientType {
|
||||
kIpcClientUnknown,
|
||||
kIpcClientGui,
|
||||
kIpcClientNode,
|
||||
};
|
||||
|
||||
extern const char* kIpcMsgHello;
|
||||
extern const char* kIpcMsgLogLine;
|
||||
extern const char* kIpcMsgCommand;
|
||||
extern const char* kIpcMsgShutdown;
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// this class is a duplicate of /src/lib/ipc/Ipc.h
|
||||
|
||||
#pragma once
|
||||
|
||||
#define IPC_HOST "127.0.0.1"
|
||||
#define IPC_PORT 24801
|
||||
|
||||
enum qIpcMessageType {
|
||||
kIpcHello,
|
||||
kIpcLogLine,
|
||||
kIpcCommand,
|
||||
kIpcShutdown,
|
||||
};
|
||||
|
||||
enum qIpcClientType {
|
||||
kIpcClientUnknown,
|
||||
kIpcClientGui,
|
||||
kIpcClientNode,
|
||||
};
|
||||
|
||||
extern const char* kIpcMsgHello;
|
||||
extern const char* kIpcMsgLogLine;
|
||||
extern const char* kIpcMsgCommand;
|
||||
extern const char* kIpcMsgShutdown;
|
||||
|
|
|
@ -1,147 +1,147 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012 Bolton Software Ltd.
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "IpcClient.h"
|
||||
#include <QTcpSocket>
|
||||
#include <QHostAddress>
|
||||
#include <iostream>
|
||||
#include <QTimer>
|
||||
#include "IpcReader.h"
|
||||
#include "Ipc.h"
|
||||
|
||||
IpcClient::IpcClient() :
|
||||
m_ReaderStarted(false),
|
||||
m_Enabled(false)
|
||||
{
|
||||
m_Socket = new QTcpSocket(this);
|
||||
connect(m_Socket, SIGNAL(connected()), this, SLOT(connected()));
|
||||
connect(m_Socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error(QAbstractSocket::SocketError)));
|
||||
|
||||
m_Reader = new IpcReader(m_Socket);
|
||||
connect(m_Reader, SIGNAL(readLogLine(const QString&)), this, SLOT(handleReadLogLine(const QString&)));
|
||||
}
|
||||
|
||||
IpcClient::~IpcClient()
|
||||
{
|
||||
}
|
||||
|
||||
void IpcClient::connected()
|
||||
{
|
||||
char typeBuf[1];
|
||||
typeBuf[0] = kIpcClientGui;
|
||||
sendHello();
|
||||
|
||||
infoMessage("connection established");
|
||||
}
|
||||
|
||||
void IpcClient::connectToHost()
|
||||
{
|
||||
m_Enabled = true;
|
||||
|
||||
infoMessage("connecting to service...");
|
||||
m_Socket->connectToHost(QHostAddress(QHostAddress::LocalHost), IPC_PORT);
|
||||
|
||||
if (!m_ReaderStarted) {
|
||||
m_Reader->start();
|
||||
m_ReaderStarted = true;
|
||||
}
|
||||
}
|
||||
|
||||
void IpcClient::disconnectFromHost()
|
||||
{
|
||||
infoMessage("service disconnect");
|
||||
m_Reader->stop();
|
||||
m_Socket->close();
|
||||
}
|
||||
|
||||
void IpcClient::error(QAbstractSocket::SocketError error)
|
||||
{
|
||||
QString text;
|
||||
switch (error) {
|
||||
case 0: text = "connection refused"; break;
|
||||
case 1: text = "remote host closed"; break;
|
||||
default: text = QString("code=%1").arg(error); break;
|
||||
}
|
||||
|
||||
errorMessage(QString("ipc connection error, %1").arg(text));
|
||||
|
||||
QTimer::singleShot(1000, this, SLOT(retryConnect()));
|
||||
}
|
||||
|
||||
void IpcClient::retryConnect()
|
||||
{
|
||||
if (m_Enabled) {
|
||||
connectToHost();
|
||||
}
|
||||
}
|
||||
|
||||
void IpcClient::sendHello()
|
||||
{
|
||||
QDataStream stream(m_Socket);
|
||||
stream.writeRawData(kIpcMsgHello, 4);
|
||||
|
||||
char typeBuf[1];
|
||||
typeBuf[0] = kIpcClientGui;
|
||||
stream.writeRawData(typeBuf, 1);
|
||||
}
|
||||
|
||||
void IpcClient::sendCommand(const QString& command, bool elevate)
|
||||
{
|
||||
QDataStream stream(m_Socket);
|
||||
|
||||
stream.writeRawData(kIpcMsgCommand, 4);
|
||||
|
||||
std::string stdStringCommand = command.toStdString();
|
||||
const char* charCommand = stdStringCommand.c_str();
|
||||
int length = strlen(charCommand);
|
||||
|
||||
char lenBuf[4];
|
||||
intToBytes(length, lenBuf, 4);
|
||||
stream.writeRawData(lenBuf, 4);
|
||||
stream.writeRawData(charCommand, length);
|
||||
|
||||
char elevateBuf[1];
|
||||
elevateBuf[0] = elevate ? 1 : 0;
|
||||
stream.writeRawData(elevateBuf, 1);
|
||||
}
|
||||
|
||||
void IpcClient::handleReadLogLine(const QString& text)
|
||||
{
|
||||
readLogLine(text);
|
||||
}
|
||||
|
||||
// TODO: qt must have a built in way of converting int to bytes.
|
||||
void IpcClient::intToBytes(int value, char *buffer, int size)
|
||||
{
|
||||
if (size == 1) {
|
||||
buffer[0] = value & 0xff;
|
||||
}
|
||||
else if (size == 2) {
|
||||
buffer[0] = (value >> 8) & 0xff;
|
||||
buffer[1] = value & 0xff;
|
||||
}
|
||||
else if (size == 4) {
|
||||
buffer[0] = (value >> 24) & 0xff;
|
||||
buffer[1] = (value >> 16) & 0xff;
|
||||
buffer[2] = (value >> 8) & 0xff;
|
||||
buffer[3] = value & 0xff;
|
||||
}
|
||||
else {
|
||||
// TODO: other sizes, if needed.
|
||||
}
|
||||
}
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "IpcClient.h"
|
||||
#include <QTcpSocket>
|
||||
#include <QHostAddress>
|
||||
#include <iostream>
|
||||
#include <QTimer>
|
||||
#include "IpcReader.h"
|
||||
#include "Ipc.h"
|
||||
|
||||
IpcClient::IpcClient() :
|
||||
m_ReaderStarted(false),
|
||||
m_Enabled(false)
|
||||
{
|
||||
m_Socket = new QTcpSocket(this);
|
||||
connect(m_Socket, SIGNAL(connected()), this, SLOT(connected()));
|
||||
connect(m_Socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error(QAbstractSocket::SocketError)));
|
||||
|
||||
m_Reader = new IpcReader(m_Socket);
|
||||
connect(m_Reader, SIGNAL(readLogLine(const QString&)), this, SLOT(handleReadLogLine(const QString&)));
|
||||
}
|
||||
|
||||
IpcClient::~IpcClient()
|
||||
{
|
||||
}
|
||||
|
||||
void IpcClient::connected()
|
||||
{
|
||||
char typeBuf[1];
|
||||
typeBuf[0] = kIpcClientGui;
|
||||
sendHello();
|
||||
|
||||
infoMessage("connection established");
|
||||
}
|
||||
|
||||
void IpcClient::connectToHost()
|
||||
{
|
||||
m_Enabled = true;
|
||||
|
||||
infoMessage("connecting to service...");
|
||||
m_Socket->connectToHost(QHostAddress(QHostAddress::LocalHost), IPC_PORT);
|
||||
|
||||
if (!m_ReaderStarted) {
|
||||
m_Reader->start();
|
||||
m_ReaderStarted = true;
|
||||
}
|
||||
}
|
||||
|
||||
void IpcClient::disconnectFromHost()
|
||||
{
|
||||
infoMessage("service disconnect");
|
||||
m_Reader->stop();
|
||||
m_Socket->close();
|
||||
}
|
||||
|
||||
void IpcClient::error(QAbstractSocket::SocketError error)
|
||||
{
|
||||
QString text;
|
||||
switch (error) {
|
||||
case 0: text = "connection refused"; break;
|
||||
case 1: text = "remote host closed"; break;
|
||||
default: text = QString("code=%1").arg(error); break;
|
||||
}
|
||||
|
||||
errorMessage(QString("ipc connection error, %1").arg(text));
|
||||
|
||||
QTimer::singleShot(1000, this, SLOT(retryConnect()));
|
||||
}
|
||||
|
||||
void IpcClient::retryConnect()
|
||||
{
|
||||
if (m_Enabled) {
|
||||
connectToHost();
|
||||
}
|
||||
}
|
||||
|
||||
void IpcClient::sendHello()
|
||||
{
|
||||
QDataStream stream(m_Socket);
|
||||
stream.writeRawData(kIpcMsgHello, 4);
|
||||
|
||||
char typeBuf[1];
|
||||
typeBuf[0] = kIpcClientGui;
|
||||
stream.writeRawData(typeBuf, 1);
|
||||
}
|
||||
|
||||
void IpcClient::sendCommand(const QString& command, bool elevate)
|
||||
{
|
||||
QDataStream stream(m_Socket);
|
||||
|
||||
stream.writeRawData(kIpcMsgCommand, 4);
|
||||
|
||||
std::string stdStringCommand = command.toStdString();
|
||||
const char* charCommand = stdStringCommand.c_str();
|
||||
int length = strlen(charCommand);
|
||||
|
||||
char lenBuf[4];
|
||||
intToBytes(length, lenBuf, 4);
|
||||
stream.writeRawData(lenBuf, 4);
|
||||
stream.writeRawData(charCommand, length);
|
||||
|
||||
char elevateBuf[1];
|
||||
elevateBuf[0] = elevate ? 1 : 0;
|
||||
stream.writeRawData(elevateBuf, 1);
|
||||
}
|
||||
|
||||
void IpcClient::handleReadLogLine(const QString& text)
|
||||
{
|
||||
readLogLine(text);
|
||||
}
|
||||
|
||||
// TODO: qt must have a built in way of converting int to bytes.
|
||||
void IpcClient::intToBytes(int value, char *buffer, int size)
|
||||
{
|
||||
if (size == 1) {
|
||||
buffer[0] = value & 0xff;
|
||||
}
|
||||
else if (size == 2) {
|
||||
buffer[0] = (value >> 8) & 0xff;
|
||||
buffer[1] = value & 0xff;
|
||||
}
|
||||
else if (size == 4) {
|
||||
buffer[0] = (value >> 24) & 0xff;
|
||||
buffer[1] = (value >> 16) & 0xff;
|
||||
buffer[2] = (value >> 8) & 0xff;
|
||||
buffer[3] = value & 0xff;
|
||||
}
|
||||
else {
|
||||
// TODO: other sizes, if needed.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,61 +1,61 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012 Bolton Software Ltd.
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QAbstractSocket>
|
||||
|
||||
class QTcpSocket;
|
||||
class IpcReader;
|
||||
|
||||
class IpcClient : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
IpcClient();
|
||||
virtual ~IpcClient();
|
||||
|
||||
void sendHello();
|
||||
void sendCommand(const QString& command, bool elevate);
|
||||
void connectToHost();
|
||||
void disconnectFromHost();
|
||||
|
||||
public slots:
|
||||
void retryConnect();
|
||||
|
||||
private:
|
||||
void intToBytes(int value, char* buffer, int size);
|
||||
|
||||
private slots:
|
||||
void connected();
|
||||
void error(QAbstractSocket::SocketError error);
|
||||
void handleReadLogLine(const QString& text);
|
||||
|
||||
signals:
|
||||
void readLogLine(const QString& text);
|
||||
void infoMessage(const QString& text);
|
||||
void errorMessage(const QString& text);
|
||||
|
||||
private:
|
||||
QTcpSocket* m_Socket;
|
||||
IpcReader* m_Reader;
|
||||
bool m_ReaderStarted;
|
||||
bool m_Enabled;
|
||||
};
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QAbstractSocket>
|
||||
|
||||
class QTcpSocket;
|
||||
class IpcReader;
|
||||
|
||||
class IpcClient : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
IpcClient();
|
||||
virtual ~IpcClient();
|
||||
|
||||
void sendHello();
|
||||
void sendCommand(const QString& command, bool elevate);
|
||||
void connectToHost();
|
||||
void disconnectFromHost();
|
||||
|
||||
public slots:
|
||||
void retryConnect();
|
||||
|
||||
private:
|
||||
void intToBytes(int value, char* buffer, int size);
|
||||
|
||||
private slots:
|
||||
void connected();
|
||||
void error(QAbstractSocket::SocketError error);
|
||||
void handleReadLogLine(const QString& text);
|
||||
|
||||
signals:
|
||||
void readLogLine(const QString& text);
|
||||
void infoMessage(const QString& text);
|
||||
void errorMessage(const QString& text);
|
||||
|
||||
private:
|
||||
QTcpSocket* m_Socket;
|
||||
IpcReader* m_Reader;
|
||||
bool m_ReaderStarted;
|
||||
bool m_Enabled;
|
||||
};
|
||||
|
|
|
@ -1,131 +1,131 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012 Bolton Software Ltd.
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "IpcReader.h"
|
||||
#include <QTcpSocket>
|
||||
#include "Ipc.h"
|
||||
#include <iostream>
|
||||
#include <QMutex>
|
||||
#include <QByteArray>
|
||||
|
||||
IpcReader::IpcReader(QTcpSocket* socket) :
|
||||
m_Socket(socket)
|
||||
{
|
||||
}
|
||||
|
||||
IpcReader::~IpcReader()
|
||||
{
|
||||
}
|
||||
|
||||
void IpcReader::start()
|
||||
{
|
||||
connect(m_Socket, SIGNAL(readyRead()), this, SLOT(read()));
|
||||
}
|
||||
|
||||
void IpcReader::stop()
|
||||
{
|
||||
disconnect(m_Socket, SIGNAL(readyRead()), this, SLOT(read()));
|
||||
}
|
||||
|
||||
void IpcReader::read()
|
||||
{
|
||||
QMutexLocker locker(&m_Mutex);
|
||||
std::cout << "ready read" << std::endl;
|
||||
|
||||
while (m_Socket->bytesAvailable()) {
|
||||
std::cout << "bytes available" << std::endl;
|
||||
|
||||
char codeBuf[5];
|
||||
readStream(codeBuf, 4);
|
||||
codeBuf[4] = 0;
|
||||
std::cout << "ipc read: " << codeBuf << std::endl;
|
||||
|
||||
if (memcmp(codeBuf, kIpcMsgLogLine, 4) == 0) {
|
||||
std::cout << "reading log line" << std::endl;
|
||||
|
||||
char lenBuf[4];
|
||||
readStream(lenBuf, 4);
|
||||
int len = bytesToInt(lenBuf, 4);
|
||||
|
||||
char* data = new char[len];
|
||||
readStream(data, len);
|
||||
QString line = QString::fromUtf8(data, len);
|
||||
delete data;
|
||||
|
||||
readLogLine(line);
|
||||
}
|
||||
else {
|
||||
std::cerr << "aborting, message invalid" << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "read done" << std::endl;
|
||||
}
|
||||
|
||||
bool IpcReader::readStream(char* buffer, int length)
|
||||
{
|
||||
std::cout << "reading stream" << std::endl;
|
||||
|
||||
int read = 0;
|
||||
while (read < length) {
|
||||
int ask = length - read;
|
||||
if (m_Socket->bytesAvailable() < ask) {
|
||||
std::cout << "buffer too short, waiting" << std::endl;
|
||||
m_Socket->waitForReadyRead(-1);
|
||||
}
|
||||
|
||||
int got = m_Socket->read(buffer, ask);
|
||||
read += got;
|
||||
|
||||
std::cout << "> ask=" << ask << " got=" << got
|
||||
<< " read=" << read << std::endl;
|
||||
|
||||
if (got == -1) {
|
||||
std::cout << "socket ended, aborting" << std::endl;
|
||||
return false;
|
||||
}
|
||||
else if (length - read > 0) {
|
||||
std::cout << "more remains, seek to " << got << std::endl;
|
||||
buffer += got;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int IpcReader::bytesToInt(const char *buffer, int size)
|
||||
{
|
||||
if (size == 1) {
|
||||
return (unsigned char)buffer[0];
|
||||
}
|
||||
else if (size == 2) {
|
||||
return
|
||||
(((unsigned char)buffer[0]) << 8) +
|
||||
(unsigned char)buffer[1];
|
||||
}
|
||||
else if (size == 4) {
|
||||
return
|
||||
(((unsigned char)buffer[0]) << 24) +
|
||||
(((unsigned char)buffer[1]) << 16) +
|
||||
(((unsigned char)buffer[2]) << 8) +
|
||||
(unsigned char)buffer[3];
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "IpcReader.h"
|
||||
#include <QTcpSocket>
|
||||
#include "Ipc.h"
|
||||
#include <iostream>
|
||||
#include <QMutex>
|
||||
#include <QByteArray>
|
||||
|
||||
IpcReader::IpcReader(QTcpSocket* socket) :
|
||||
m_Socket(socket)
|
||||
{
|
||||
}
|
||||
|
||||
IpcReader::~IpcReader()
|
||||
{
|
||||
}
|
||||
|
||||
void IpcReader::start()
|
||||
{
|
||||
connect(m_Socket, SIGNAL(readyRead()), this, SLOT(read()));
|
||||
}
|
||||
|
||||
void IpcReader::stop()
|
||||
{
|
||||
disconnect(m_Socket, SIGNAL(readyRead()), this, SLOT(read()));
|
||||
}
|
||||
|
||||
void IpcReader::read()
|
||||
{
|
||||
QMutexLocker locker(&m_Mutex);
|
||||
std::cout << "ready read" << std::endl;
|
||||
|
||||
while (m_Socket->bytesAvailable()) {
|
||||
std::cout << "bytes available" << std::endl;
|
||||
|
||||
char codeBuf[5];
|
||||
readStream(codeBuf, 4);
|
||||
codeBuf[4] = 0;
|
||||
std::cout << "ipc read: " << codeBuf << std::endl;
|
||||
|
||||
if (memcmp(codeBuf, kIpcMsgLogLine, 4) == 0) {
|
||||
std::cout << "reading log line" << std::endl;
|
||||
|
||||
char lenBuf[4];
|
||||
readStream(lenBuf, 4);
|
||||
int len = bytesToInt(lenBuf, 4);
|
||||
|
||||
char* data = new char[len];
|
||||
readStream(data, len);
|
||||
QString line = QString::fromUtf8(data, len);
|
||||
delete data;
|
||||
|
||||
readLogLine(line);
|
||||
}
|
||||
else {
|
||||
std::cerr << "aborting, message invalid" << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "read done" << std::endl;
|
||||
}
|
||||
|
||||
bool IpcReader::readStream(char* buffer, int length)
|
||||
{
|
||||
std::cout << "reading stream" << std::endl;
|
||||
|
||||
int read = 0;
|
||||
while (read < length) {
|
||||
int ask = length - read;
|
||||
if (m_Socket->bytesAvailable() < ask) {
|
||||
std::cout << "buffer too short, waiting" << std::endl;
|
||||
m_Socket->waitForReadyRead(-1);
|
||||
}
|
||||
|
||||
int got = m_Socket->read(buffer, ask);
|
||||
read += got;
|
||||
|
||||
std::cout << "> ask=" << ask << " got=" << got
|
||||
<< " read=" << read << std::endl;
|
||||
|
||||
if (got == -1) {
|
||||
std::cout << "socket ended, aborting" << std::endl;
|
||||
return false;
|
||||
}
|
||||
else if (length - read > 0) {
|
||||
std::cout << "more remains, seek to " << got << std::endl;
|
||||
buffer += got;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int IpcReader::bytesToInt(const char *buffer, int size)
|
||||
{
|
||||
if (size == 1) {
|
||||
return (unsigned char)buffer[0];
|
||||
}
|
||||
else if (size == 2) {
|
||||
return
|
||||
(((unsigned char)buffer[0]) << 8) +
|
||||
(unsigned char)buffer[1];
|
||||
}
|
||||
else if (size == 4) {
|
||||
return
|
||||
(((unsigned char)buffer[0]) << 24) +
|
||||
(((unsigned char)buffer[1]) << 16) +
|
||||
(((unsigned char)buffer[2]) << 8) +
|
||||
(unsigned char)buffer[3];
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,49 +1,49 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012 Bolton Software Ltd.
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QMutex>
|
||||
|
||||
class QTcpSocket;
|
||||
|
||||
class IpcReader : public QObject
|
||||
{
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
IpcReader(QTcpSocket* socket);
|
||||
virtual ~IpcReader();
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
signals:
|
||||
void readLogLine(const QString& text);
|
||||
|
||||
private:
|
||||
bool readStream(char* buffer, int length);
|
||||
int bytesToInt(const char* buffer, int size);
|
||||
|
||||
private slots:
|
||||
void read();
|
||||
|
||||
private:
|
||||
QTcpSocket* m_Socket;
|
||||
QMutex m_Mutex;
|
||||
};
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QMutex>
|
||||
|
||||
class QTcpSocket;
|
||||
|
||||
class IpcReader : public QObject
|
||||
{
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
IpcReader(QTcpSocket* socket);
|
||||
virtual ~IpcReader();
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
signals:
|
||||
void readLogLine(const QString& text);
|
||||
|
||||
private:
|
||||
bool readStream(char* buffer, int length);
|
||||
int bytesToInt(const char* buffer, int size);
|
||||
|
||||
private slots:
|
||||
void read();
|
||||
|
||||
private:
|
||||
QTcpSocket* m_Socket;
|
||||
QMutex m_Mutex;
|
||||
};
|
||||
|
|
|
@ -1,51 +1,51 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2013 Bolton Software Ltd.
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "QUtility.h"
|
||||
|
||||
void setIndexFromItemData(QComboBox* comboBox, const QVariant& itemData)
|
||||
{
|
||||
for (int i = 0; i < comboBox->count(); ++i)
|
||||
{
|
||||
if (comboBox->itemData(i) == itemData)
|
||||
{
|
||||
comboBox->setCurrentIndex(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString hash(const QString& string)
|
||||
{
|
||||
QByteArray data = string.toUtf8();
|
||||
QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Md5);
|
||||
return hash.toHex();
|
||||
}
|
||||
|
||||
QString getFirstMacAddress()
|
||||
{
|
||||
QString mac;
|
||||
foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces())
|
||||
{
|
||||
mac = interface.hardwareAddress();
|
||||
if (mac.size() != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return mac;
|
||||
}
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2013 Bolton Software Ltd.
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "QUtility.h"
|
||||
|
||||
void setIndexFromItemData(QComboBox* comboBox, const QVariant& itemData)
|
||||
{
|
||||
for (int i = 0; i < comboBox->count(); ++i)
|
||||
{
|
||||
if (comboBox->itemData(i) == itemData)
|
||||
{
|
||||
comboBox->setCurrentIndex(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString hash(const QString& string)
|
||||
{
|
||||
QByteArray data = string.toUtf8();
|
||||
QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Md5);
|
||||
return hash.toHex();
|
||||
}
|
||||
|
||||
QString getFirstMacAddress()
|
||||
{
|
||||
QString mac;
|
||||
foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces())
|
||||
{
|
||||
mac = interface.hardwareAddress();
|
||||
if (mac.size() != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return mac;
|
||||
}
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2013 Bolton Software Ltd.
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QVariant>
|
||||
#include <QCryptographicHash>
|
||||
#include <QNetworkInterface>
|
||||
|
||||
void setIndexFromItemData(QComboBox* comboBox, const QVariant& itemData);
|
||||
QString hash(const QString& string);
|
||||
QString getFirstMacAddress();
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2013 Bolton Software Ltd.
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QVariant>
|
||||
#include <QCryptographicHash>
|
||||
#include <QNetworkInterface>
|
||||
|
||||
void setIndexFromItemData(QComboBox* comboBox, const QVariant& itemData);
|
||||
QString hash(const QString& string);
|
||||
QString getFirstMacAddress();
|
||||
|
|
|
@ -1,334 +1,334 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012 Bolton Software Ltd.
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "SetupWizard.h"
|
||||
#include "MainWindow.h"
|
||||
#include "QSynergyApplication.h"
|
||||
#include "QUtility.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QDesktopServices>
|
||||
#include <QUrl>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
|
||||
//#define PREMIUM_AUTH_URL "http://localhost/synergy/premium/json/auth/"
|
||||
#define PREMIUM_AUTH_URL "https://synergy-foss.org/premium/json/auth/"
|
||||
#define PREMIUM_REGISTER_URL "https://synergy-foss.org/premium/register/?source=gui-wizard"
|
||||
|
||||
SetupWizard::SetupWizard(MainWindow& mainWindow, bool startMain) :
|
||||
m_MainWindow(mainWindow),
|
||||
m_StartMain(startMain)
|
||||
{
|
||||
setupUi(this);
|
||||
|
||||
#if defined(Q_OS_MAC)
|
||||
|
||||
// the mac style needs a little more room because of the
|
||||
// graphic on the left.
|
||||
resize(600, 500);
|
||||
setMinimumSize(size());
|
||||
|
||||
#elif defined(Q_OS_WIN)
|
||||
|
||||
// when areo is disabled on windows, the next/back buttons
|
||||
// are hidden (must be a qt bug) -- resizing the window
|
||||
// to +1 of the original height seems to fix this.
|
||||
// NOTE: calling setMinimumSize after this will break
|
||||
// it again, so don't do that.
|
||||
resize(size().width(), size().height() + 1);
|
||||
|
||||
#endif
|
||||
|
||||
connect(m_pServerRadioButton, SIGNAL(toggled(bool)), m_MainWindow.m_pGroupServer, SLOT(setChecked(bool)));
|
||||
connect(m_pClientRadioButton, SIGNAL(toggled(bool)), m_MainWindow.m_pGroupClient, SLOT(setChecked(bool)));
|
||||
|
||||
m_Locale.fillLanguageComboBox(m_pComboLanguage);
|
||||
setIndexFromItemData(m_pComboLanguage, m_MainWindow.appConfig().language());
|
||||
AppConfig& appConfig = m_MainWindow.appConfig();
|
||||
QString premiumEmail = appConfig.premiumEmail();
|
||||
if (!premiumEmail.isEmpty())
|
||||
{
|
||||
m_pRadioButtonPremiumLogin->setChecked(true);
|
||||
m_pLineEditPremiumEmail->setText(premiumEmail);
|
||||
}
|
||||
}
|
||||
|
||||
SetupWizard::~SetupWizard()
|
||||
{
|
||||
}
|
||||
|
||||
bool SetupWizard::validateCurrentPage()
|
||||
{
|
||||
QMessageBox message;
|
||||
message.setWindowTitle(tr("Setup Synergy"));
|
||||
message.setIcon(QMessageBox::Information);
|
||||
|
||||
if (currentPage() == m_pNodePage)
|
||||
{
|
||||
bool result = m_pClientRadioButton->isChecked() ||
|
||||
m_pServerRadioButton->isChecked();
|
||||
|
||||
if (!result)
|
||||
{
|
||||
message.setText(tr("Please select an option."));
|
||||
message.exec();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (currentPage() == m_pPremiumUserPage)
|
||||
{
|
||||
if (m_pRadioButtonPremiumLogin->isChecked())
|
||||
{
|
||||
if (m_pLineEditPremiumEmail->text().isEmpty() ||
|
||||
m_pLineEditPremiumPassword->text().isEmpty())
|
||||
{
|
||||
message.setText(tr("Please enter your email address and password."));
|
||||
message.exec();
|
||||
return false;
|
||||
}
|
||||
else if (!isPremiumLoginValid(message))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pComboCryptoMode->setCurrentIndex(0);
|
||||
m_pComboCryptoMode->setEnabled(true);
|
||||
}
|
||||
}
|
||||
else if (m_pRadioButtonPremiumRegister->isChecked())
|
||||
{
|
||||
const QUrl url(QString(PREMIUM_REGISTER_URL));
|
||||
QDesktopServices::openUrl(url);
|
||||
m_pRadioButtonPremiumLogin->setChecked(true);
|
||||
return false;
|
||||
}
|
||||
else if (m_pRadioButtonPremiumLater->isChecked())
|
||||
{
|
||||
int size = m_pComboCryptoMode->count();
|
||||
m_pComboCryptoMode->setCurrentIndex(size - 1);
|
||||
m_pComboCryptoMode->setEnabled(false);
|
||||
}
|
||||
else {
|
||||
message.setText(tr("Please select an option."));
|
||||
message.exec();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (currentPage() == m_pCryptoPage)
|
||||
{
|
||||
QString modeText = m_pComboCryptoMode->currentText();
|
||||
if (modeText.isEmpty())
|
||||
{
|
||||
message.setText(tr("Encryption mode required."));
|
||||
message.exec();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parseCryptoMode(modeText) != Disabled)
|
||||
{
|
||||
if (m_pLineEditCryptoPassword1->text().isEmpty())
|
||||
{
|
||||
message.setText(tr("Encryption password required."));
|
||||
message.exec();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_pLineEditCryptoPassword1->text() != m_pLineEditCryptoPassword2->text())
|
||||
{
|
||||
message.setText(tr("Encryption password and confirmation do not match."));
|
||||
message.exec();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SetupWizard::changeEvent(QEvent* event)
|
||||
{
|
||||
if (event != 0)
|
||||
{
|
||||
switch (event->type())
|
||||
{
|
||||
case QEvent::LanguageChange:
|
||||
{
|
||||
m_pComboLanguage->blockSignals(true);
|
||||
retranslateUi(this);
|
||||
m_pComboLanguage->blockSignals(false);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
QWizard::changeEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetupWizard::accept()
|
||||
{
|
||||
AppConfig& appConfig = m_MainWindow.appConfig();
|
||||
|
||||
appConfig.setCryptoMode(parseCryptoMode(m_pComboCryptoMode->currentText()));
|
||||
appConfig.setCryptoPass(m_pLineEditCryptoPassword1->text());
|
||||
appConfig.setLanguage(m_pComboLanguage->itemData(m_pComboLanguage->currentIndex()).toString());
|
||||
appConfig.setPremiumEmail(m_pLineEditPremiumEmail->text());
|
||||
|
||||
if (!m_pRadioButtonPremiumLogin->isChecked())
|
||||
{
|
||||
appConfig.setPremiumToken("");
|
||||
}
|
||||
else
|
||||
{
|
||||
QString mac = getFirstMacAddress();
|
||||
QString hashSrc = m_pLineEditPremiumEmail->text() + mac;
|
||||
QString hashResult = hash(hashSrc);
|
||||
appConfig.setPremiumToken(hashResult);
|
||||
}
|
||||
|
||||
appConfig.setWizardHasRun();
|
||||
appConfig.saveSettings();
|
||||
|
||||
QSettings& settings = m_MainWindow.settings();
|
||||
if (m_pServerRadioButton->isChecked())
|
||||
{
|
||||
settings.setValue("groupServerChecked", true);
|
||||
settings.setValue("groupClientChecked", false);
|
||||
}
|
||||
if (m_pClientRadioButton->isChecked())
|
||||
{
|
||||
settings.setValue("groupClientChecked", true);
|
||||
settings.setValue("groupServerChecked", false);
|
||||
}
|
||||
|
||||
settings.sync();
|
||||
|
||||
if (m_StartMain)
|
||||
{
|
||||
m_MainWindow.start(true);
|
||||
}
|
||||
|
||||
QWizard::accept();
|
||||
}
|
||||
|
||||
void SetupWizard::reject()
|
||||
{
|
||||
QSynergyApplication::getInstance()->switchTranslator(m_MainWindow.appConfig().language());
|
||||
|
||||
if (m_StartMain)
|
||||
{
|
||||
m_MainWindow.start(true);
|
||||
}
|
||||
|
||||
QWizard::reject();
|
||||
}
|
||||
|
||||
void SetupWizard::on_m_pComboCryptoMode_currentIndexChanged(int index)
|
||||
{
|
||||
bool enabled = parseCryptoMode(m_pComboCryptoMode->currentText()) != Disabled;
|
||||
m_pLineEditCryptoPassword1->setEnabled(enabled);
|
||||
m_pLineEditCryptoPassword2->setEnabled(enabled);
|
||||
}
|
||||
|
||||
CryptoMode SetupWizard::parseCryptoMode(const QString& s)
|
||||
{
|
||||
if (s.startsWith("OFB"))
|
||||
{
|
||||
return OFB;
|
||||
}
|
||||
else if (s.startsWith("CFB"))
|
||||
{
|
||||
return CFB;
|
||||
}
|
||||
else if (s.startsWith("CTR"))
|
||||
{
|
||||
return CTR;
|
||||
}
|
||||
else if (s.startsWith("GCM"))
|
||||
{
|
||||
return GCM;
|
||||
}
|
||||
|
||||
return Disabled;
|
||||
}
|
||||
|
||||
void SetupWizard::on_m_pComboLanguage_currentIndexChanged(int index)
|
||||
{
|
||||
QString ietfCode = m_pComboLanguage->itemData(index).toString();
|
||||
QSynergyApplication::getInstance()->switchTranslator(ietfCode);
|
||||
}
|
||||
|
||||
void SetupWizard::on_m_pRadioButtonPremiumLogin_toggled(bool checked)
|
||||
{
|
||||
m_pLineEditPremiumEmail->setEnabled(checked);
|
||||
m_pLineEditPremiumPassword->setEnabled(checked);
|
||||
}
|
||||
|
||||
bool SetupWizard::isPremiumLoginValid(QMessageBox& message)
|
||||
{
|
||||
QString email = m_pLineEditPremiumEmail->text();
|
||||
QString password = m_pLineEditPremiumPassword->text();
|
||||
|
||||
QString requestJson = "{\"email\":\"" + email + "\",\"password\":\"" + password + "\"}";
|
||||
QByteArray requestData(requestJson.toStdString().c_str());
|
||||
|
||||
QString version = m_MainWindow.versionChecker().getVersion();
|
||||
QString userAgent = "Synergy GUI " + version;
|
||||
QByteArray userAgentData(userAgent.toStdString().c_str());
|
||||
|
||||
QNetworkRequest request(QUrl(PREMIUM_AUTH_URL));
|
||||
request.setRawHeader("User-Agent", userAgentData);
|
||||
|
||||
QUrl params;
|
||||
params.addEncodedQueryItem("json", requestData);
|
||||
QNetworkReply* reply = m_Network.post(request, params.encodedQuery());
|
||||
|
||||
// use loop instead of waitForReadyRead (which doesnt seem to work).
|
||||
QEventLoop loop;
|
||||
connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
|
||||
loop.exec();
|
||||
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
message.setText(tr("Login failed, an error occurred.\n\nError: %1").arg(reply->errorString()));
|
||||
message.exec();
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray responseData = reply->readAll();
|
||||
QString responseJson(responseData);
|
||||
|
||||
// this feels like a lot of work, but its cheaper than getting a json
|
||||
// parsing library involved.
|
||||
QRegExp regex(".*\"result\":\\s*([^,}\\s]+).*");
|
||||
if (regex.exactMatch(responseJson)) {
|
||||
QString boolString = regex.cap(1);
|
||||
if (boolString == "true") {
|
||||
return true;
|
||||
}
|
||||
else if (boolString == "false") {
|
||||
message.setText(tr("Login failed, invalid email or password."));
|
||||
message.exec();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
message.setText(tr("Login failed, an error occurred.\n\nServer response:\n\n%1").arg(responseJson.trimmed()));
|
||||
message.exec();
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012 Bolton Software Ltd.
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "SetupWizard.h"
|
||||
#include "MainWindow.h"
|
||||
#include "QSynergyApplication.h"
|
||||
#include "QUtility.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QDesktopServices>
|
||||
#include <QUrl>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
|
||||
//#define PREMIUM_AUTH_URL "http://localhost/synergy/premium/json/auth/"
|
||||
#define PREMIUM_AUTH_URL "https://synergy-foss.org/premium/json/auth/"
|
||||
#define PREMIUM_REGISTER_URL "https://synergy-foss.org/premium/register/?source=gui-wizard"
|
||||
|
||||
SetupWizard::SetupWizard(MainWindow& mainWindow, bool startMain) :
|
||||
m_MainWindow(mainWindow),
|
||||
m_StartMain(startMain)
|
||||
{
|
||||
setupUi(this);
|
||||
|
||||
#if defined(Q_OS_MAC)
|
||||
|
||||
// the mac style needs a little more room because of the
|
||||
// graphic on the left.
|
||||
resize(600, 500);
|
||||
setMinimumSize(size());
|
||||
|
||||
#elif defined(Q_OS_WIN)
|
||||
|
||||
// when areo is disabled on windows, the next/back buttons
|
||||
// are hidden (must be a qt bug) -- resizing the window
|
||||
// to +1 of the original height seems to fix this.
|
||||
// NOTE: calling setMinimumSize after this will break
|
||||
// it again, so don't do that.
|
||||
resize(size().width(), size().height() + 1);
|
||||
|
||||
#endif
|
||||
|
||||
connect(m_pServerRadioButton, SIGNAL(toggled(bool)), m_MainWindow.m_pGroupServer, SLOT(setChecked(bool)));
|
||||
connect(m_pClientRadioButton, SIGNAL(toggled(bool)), m_MainWindow.m_pGroupClient, SLOT(setChecked(bool)));
|
||||
|
||||
m_Locale.fillLanguageComboBox(m_pComboLanguage);
|
||||
setIndexFromItemData(m_pComboLanguage, m_MainWindow.appConfig().language());
|
||||
AppConfig& appConfig = m_MainWindow.appConfig();
|
||||
QString premiumEmail = appConfig.premiumEmail();
|
||||
if (!premiumEmail.isEmpty())
|
||||
{
|
||||
m_pRadioButtonPremiumLogin->setChecked(true);
|
||||
m_pLineEditPremiumEmail->setText(premiumEmail);
|
||||
}
|
||||
}
|
||||
|
||||
SetupWizard::~SetupWizard()
|
||||
{
|
||||
}
|
||||
|
||||
bool SetupWizard::validateCurrentPage()
|
||||
{
|
||||
QMessageBox message;
|
||||
message.setWindowTitle(tr("Setup Synergy"));
|
||||
message.setIcon(QMessageBox::Information);
|
||||
|
||||
if (currentPage() == m_pNodePage)
|
||||
{
|
||||
bool result = m_pClientRadioButton->isChecked() ||
|
||||
m_pServerRadioButton->isChecked();
|
||||
|
||||
if (!result)
|
||||
{
|
||||
message.setText(tr("Please select an option."));
|
||||
message.exec();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (currentPage() == m_pPremiumUserPage)
|
||||
{
|
||||
if (m_pRadioButtonPremiumLogin->isChecked())
|
||||
{
|
||||
if (m_pLineEditPremiumEmail->text().isEmpty() ||
|
||||
m_pLineEditPremiumPassword->text().isEmpty())
|
||||
{
|
||||
message.setText(tr("Please enter your email address and password."));
|
||||
message.exec();
|
||||
return false;
|
||||
}
|
||||
else if (!isPremiumLoginValid(message))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pComboCryptoMode->setCurrentIndex(0);
|
||||
m_pComboCryptoMode->setEnabled(true);
|
||||
}
|
||||
}
|
||||
else if (m_pRadioButtonPremiumRegister->isChecked())
|
||||
{
|
||||
const QUrl url(QString(PREMIUM_REGISTER_URL));
|
||||
QDesktopServices::openUrl(url);
|
||||
m_pRadioButtonPremiumLogin->setChecked(true);
|
||||
return false;
|
||||
}
|
||||
else if (m_pRadioButtonPremiumLater->isChecked())
|
||||
{
|
||||
int size = m_pComboCryptoMode->count();
|
||||
m_pComboCryptoMode->setCurrentIndex(size - 1);
|
||||
m_pComboCryptoMode->setEnabled(false);
|
||||
}
|
||||
else {
|
||||
message.setText(tr("Please select an option."));
|
||||
message.exec();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (currentPage() == m_pCryptoPage)
|
||||
{
|
||||
QString modeText = m_pComboCryptoMode->currentText();
|
||||
if (modeText.isEmpty())
|
||||
{
|
||||
message.setText(tr("Encryption mode required."));
|
||||
message.exec();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parseCryptoMode(modeText) != Disabled)
|
||||
{
|
||||
if (m_pLineEditCryptoPassword1->text().isEmpty())
|
||||
{
|
||||
message.setText(tr("Encryption password required."));
|
||||
message.exec();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_pLineEditCryptoPassword1->text() != m_pLineEditCryptoPassword2->text())
|
||||
{
|
||||
message.setText(tr("Encryption password and confirmation do not match."));
|
||||
message.exec();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SetupWizard::changeEvent(QEvent* event)
|
||||
{
|
||||
if (event != 0)
|
||||
{
|
||||
switch (event->type())
|
||||
{
|
||||
case QEvent::LanguageChange:
|
||||
{
|
||||
m_pComboLanguage->blockSignals(true);
|
||||
retranslateUi(this);
|
||||
m_pComboLanguage->blockSignals(false);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
QWizard::changeEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetupWizard::accept()
|
||||
{
|
||||
AppConfig& appConfig = m_MainWindow.appConfig();
|
||||
|
||||
appConfig.setCryptoMode(parseCryptoMode(m_pComboCryptoMode->currentText()));
|
||||
appConfig.setCryptoPass(m_pLineEditCryptoPassword1->text());
|
||||
appConfig.setLanguage(m_pComboLanguage->itemData(m_pComboLanguage->currentIndex()).toString());
|
||||
appConfig.setPremiumEmail(m_pLineEditPremiumEmail->text());
|
||||
|
||||
if (!m_pRadioButtonPremiumLogin->isChecked())
|
||||
{
|
||||
appConfig.setPremiumToken("");
|
||||
}
|
||||
else
|
||||
{
|
||||
QString mac = getFirstMacAddress();
|
||||
QString hashSrc = m_pLineEditPremiumEmail->text() + mac;
|
||||
QString hashResult = hash(hashSrc);
|
||||
appConfig.setPremiumToken(hashResult);
|
||||
}
|
||||
|
||||
appConfig.setWizardHasRun();
|
||||
appConfig.saveSettings();
|
||||
|
||||
QSettings& settings = m_MainWindow.settings();
|
||||
if (m_pServerRadioButton->isChecked())
|
||||
{
|
||||
settings.setValue("groupServerChecked", true);
|
||||
settings.setValue("groupClientChecked", false);
|
||||
}
|
||||
if (m_pClientRadioButton->isChecked())
|
||||
{
|
||||
settings.setValue("groupClientChecked", true);
|
||||
settings.setValue("groupServerChecked", false);
|
||||
}
|
||||
|
||||
settings.sync();
|
||||
|
||||
if (m_StartMain)
|
||||
{
|
||||
m_MainWindow.start(true);
|
||||
}
|
||||
|
||||
QWizard::accept();
|
||||
}
|
||||
|
||||
void SetupWizard::reject()
|
||||
{
|
||||
QSynergyApplication::getInstance()->switchTranslator(m_MainWindow.appConfig().language());
|
||||
|
||||
if (m_StartMain)
|
||||
{
|
||||
m_MainWindow.start(true);
|
||||
}
|
||||
|
||||
QWizard::reject();
|
||||
}
|
||||
|
||||
void SetupWizard::on_m_pComboCryptoMode_currentIndexChanged(int index)
|
||||
{
|
||||
bool enabled = parseCryptoMode(m_pComboCryptoMode->currentText()) != Disabled;
|
||||
m_pLineEditCryptoPassword1->setEnabled(enabled);
|
||||
m_pLineEditCryptoPassword2->setEnabled(enabled);
|
||||
}
|
||||
|
||||
CryptoMode SetupWizard::parseCryptoMode(const QString& s)
|
||||
{
|
||||
if (s.startsWith("OFB"))
|
||||
{
|
||||
return OFB;
|
||||
}
|
||||
else if (s.startsWith("CFB"))
|
||||
{
|
||||
return CFB;
|
||||
}
|
||||
else if (s.startsWith("CTR"))
|
||||
{
|
||||
return CTR;
|
||||
}
|
||||
else if (s.startsWith("GCM"))
|
||||
{
|
||||
return GCM;
|
||||
}
|
||||
|
||||
return Disabled;
|
||||
}
|
||||
|
||||
void SetupWizard::on_m_pComboLanguage_currentIndexChanged(int index)
|
||||
{
|
||||
QString ietfCode = m_pComboLanguage->itemData(index).toString();
|
||||
QSynergyApplication::getInstance()->switchTranslator(ietfCode);
|
||||
}
|
||||
|
||||
void SetupWizard::on_m_pRadioButtonPremiumLogin_toggled(bool checked)
|
||||
{
|
||||
m_pLineEditPremiumEmail->setEnabled(checked);
|
||||
m_pLineEditPremiumPassword->setEnabled(checked);
|
||||
}
|
||||
|
||||
bool SetupWizard::isPremiumLoginValid(QMessageBox& message)
|
||||
{
|
||||
QString email = m_pLineEditPremiumEmail->text();
|
||||
QString password = m_pLineEditPremiumPassword->text();
|
||||
|
||||
QString requestJson = "{\"email\":\"" + email + "\",\"password\":\"" + password + "\"}";
|
||||
QByteArray requestData(requestJson.toStdString().c_str());
|
||||
|
||||
QString version = m_MainWindow.versionChecker().getVersion();
|
||||
QString userAgent = "Synergy GUI " + version;
|
||||
QByteArray userAgentData(userAgent.toStdString().c_str());
|
||||
|
||||
QNetworkRequest request(QUrl(PREMIUM_AUTH_URL));
|
||||
request.setRawHeader("User-Agent", userAgentData);
|
||||
|
||||
QUrl params;
|
||||
params.addEncodedQueryItem("json", requestData);
|
||||
QNetworkReply* reply = m_Network.post(request, params.encodedQuery());
|
||||
|
||||
// use loop instead of waitForReadyRead (which doesnt seem to work).
|
||||
QEventLoop loop;
|
||||
connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
|
||||
loop.exec();
|
||||
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
message.setText(tr("Login failed, an error occurred.\n\nError: %1").arg(reply->errorString()));
|
||||
message.exec();
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray responseData = reply->readAll();
|
||||
QString responseJson(responseData);
|
||||
|
||||
// this feels like a lot of work, but its cheaper than getting a json
|
||||
// parsing library involved.
|
||||
QRegExp regex(".*\"result\":\\s*([^,}\\s]+).*");
|
||||
if (regex.exactMatch(responseJson)) {
|
||||
QString boolString = regex.cap(1);
|
||||
if (boolString == "true") {
|
||||
return true;
|
||||
}
|
||||
else if (boolString == "false") {
|
||||
message.setText(tr("Login failed, invalid email or password."));
|
||||
message.exec();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
message.setText(tr("Login failed, an error occurred.\n\nServer response:\n\n%1").arg(responseJson.trimmed()));
|
||||
message.exec();
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,57 +1,57 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012 Bolton Software Ltd.
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ui_SetupWizardBase.h"
|
||||
#include "CryptoMode.h"
|
||||
#include "SynergyLocale.h"
|
||||
|
||||
#include <QWizard>
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
class MainWindow;
|
||||
class QMessageBox;
|
||||
|
||||
class SetupWizard : public QWizard, public Ui::SetupWizardBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SetupWizard(MainWindow& mainWindow, bool startMain);
|
||||
virtual ~SetupWizard();
|
||||
bool validateCurrentPage();
|
||||
|
||||
protected:
|
||||
void changeEvent(QEvent* event);
|
||||
void accept();
|
||||
void reject();
|
||||
|
||||
private:
|
||||
CryptoMode parseCryptoMode(const QString& s);
|
||||
bool isPremiumLoginValid(QMessageBox& message);
|
||||
|
||||
private:
|
||||
MainWindow& m_MainWindow;
|
||||
bool m_StartMain;
|
||||
SynergyLocale m_Locale;
|
||||
QNetworkAccessManager m_Network;
|
||||
|
||||
private slots:
|
||||
void on_m_pComboCryptoMode_currentIndexChanged(int index);
|
||||
void on_m_pComboLanguage_currentIndexChanged(int index);
|
||||
void on_m_pRadioButtonPremiumLogin_toggled(bool checked);
|
||||
};
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012 Bolton Software Ltd.
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ui_SetupWizardBase.h"
|
||||
#include "CryptoMode.h"
|
||||
#include "SynergyLocale.h"
|
||||
|
||||
#include <QWizard>
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
class MainWindow;
|
||||
class QMessageBox;
|
||||
|
||||
class SetupWizard : public QWizard, public Ui::SetupWizardBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SetupWizard(MainWindow& mainWindow, bool startMain);
|
||||
virtual ~SetupWizard();
|
||||
bool validateCurrentPage();
|
||||
|
||||
protected:
|
||||
void changeEvent(QEvent* event);
|
||||
void accept();
|
||||
void reject();
|
||||
|
||||
private:
|
||||
CryptoMode parseCryptoMode(const QString& s);
|
||||
bool isPremiumLoginValid(QMessageBox& message);
|
||||
|
||||
private:
|
||||
MainWindow& m_MainWindow;
|
||||
bool m_StartMain;
|
||||
SynergyLocale m_Locale;
|
||||
QNetworkAccessManager m_Network;
|
||||
|
||||
private slots:
|
||||
void on_m_pComboCryptoMode_currentIndexChanged(int index);
|
||||
void on_m_pComboLanguage_currentIndexChanged(int index);
|
||||
void on_m_pRadioButtonPremiumLogin_toggled(bool checked);
|
||||
};
|
||||
|
|
|
@ -1,68 +1,68 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2013 Bolton Software Ltd.
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "SynergyLocale.h"
|
||||
|
||||
#include <QResource>
|
||||
#include <QtXml/QXmlStreamReader>
|
||||
#include <QDebug>
|
||||
|
||||
SynergyLocale::SynergyLocale()
|
||||
{
|
||||
loadLanguages();
|
||||
}
|
||||
|
||||
void SynergyLocale::loadLanguages()
|
||||
{
|
||||
QResource resource(":/res/lang/Languages.xml");
|
||||
QByteArray bytes(reinterpret_cast<const char*>(resource.data()), resource.size());
|
||||
QXmlStreamReader xml(bytes);
|
||||
|
||||
while (!xml.atEnd())
|
||||
{
|
||||
QXmlStreamReader::TokenType token = xml.readNext();
|
||||
if (xml.hasError())
|
||||
{
|
||||
qCritical() << xml.errorString();
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
if (xml.name() == "language" && token == QXmlStreamReader::StartElement)
|
||||
{
|
||||
QXmlStreamAttributes attributes = xml.attributes();
|
||||
addLanguage(
|
||||
attributes.value("ietfCode").toString(),
|
||||
attributes.value("name").toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SynergyLocale::addLanguage(const QString& ietfCode, const QString& name)
|
||||
{
|
||||
m_Languages.push_back(SynergyLocale::Language(ietfCode, name));
|
||||
}
|
||||
|
||||
void SynergyLocale::fillLanguageComboBox(QComboBox* comboBox)
|
||||
{
|
||||
comboBox->blockSignals(true);
|
||||
QVector<SynergyLocale::Language>::iterator it;
|
||||
for (it = m_Languages.begin(); it != m_Languages.end(); ++it)
|
||||
{
|
||||
comboBox->addItem((*it).m_Name, (*it).m_IetfCode);
|
||||
}
|
||||
comboBox->blockSignals(false);
|
||||
}
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2013 Bolton Software Ltd.
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "SynergyLocale.h"
|
||||
|
||||
#include <QResource>
|
||||
#include <QtXml/QXmlStreamReader>
|
||||
#include <QDebug>
|
||||
|
||||
SynergyLocale::SynergyLocale()
|
||||
{
|
||||
loadLanguages();
|
||||
}
|
||||
|
||||
void SynergyLocale::loadLanguages()
|
||||
{
|
||||
QResource resource(":/res/lang/Languages.xml");
|
||||
QByteArray bytes(reinterpret_cast<const char*>(resource.data()), resource.size());
|
||||
QXmlStreamReader xml(bytes);
|
||||
|
||||
while (!xml.atEnd())
|
||||
{
|
||||
QXmlStreamReader::TokenType token = xml.readNext();
|
||||
if (xml.hasError())
|
||||
{
|
||||
qCritical() << xml.errorString();
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
if (xml.name() == "language" && token == QXmlStreamReader::StartElement)
|
||||
{
|
||||
QXmlStreamAttributes attributes = xml.attributes();
|
||||
addLanguage(
|
||||
attributes.value("ietfCode").toString(),
|
||||
attributes.value("name").toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SynergyLocale::addLanguage(const QString& ietfCode, const QString& name)
|
||||
{
|
||||
m_Languages.push_back(SynergyLocale::Language(ietfCode, name));
|
||||
}
|
||||
|
||||
void SynergyLocale::fillLanguageComboBox(QComboBox* comboBox)
|
||||
{
|
||||
comboBox->blockSignals(true);
|
||||
QVector<SynergyLocale::Language>::iterator it;
|
||||
for (it = m_Languages.begin(); it != m_Languages.end(); ++it)
|
||||
{
|
||||
comboBox->addItem((*it).m_Name, (*it).m_IetfCode);
|
||||
}
|
||||
comboBox->blockSignals(false);
|
||||
}
|
||||
|
|
|
@ -1,48 +1,48 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2013 Bolton Software Ltd.
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
#include <QComboBox>
|
||||
|
||||
class SynergyLocale
|
||||
{
|
||||
class Language
|
||||
{
|
||||
public:
|
||||
Language() { }
|
||||
Language(const QString& IetfCode, const QString& name)
|
||||
: m_IetfCode(IetfCode), m_Name(name) { }
|
||||
|
||||
public:
|
||||
QString m_IetfCode;
|
||||
QString m_Name;
|
||||
};
|
||||
|
||||
public:
|
||||
SynergyLocale();
|
||||
void fillLanguageComboBox(QComboBox* comboBox);
|
||||
|
||||
private:
|
||||
void loadLanguages();
|
||||
void addLanguage(const QString& IetfCode, const QString& name);
|
||||
|
||||
private:
|
||||
QVector<Language> m_Languages;
|
||||
};
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2013 Bolton Software Ltd.
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
#include <QComboBox>
|
||||
|
||||
class SynergyLocale
|
||||
{
|
||||
class Language
|
||||
{
|
||||
public:
|
||||
Language() { }
|
||||
Language(const QString& IetfCode, const QString& name)
|
||||
: m_IetfCode(IetfCode), m_Name(name) { }
|
||||
|
||||
public:
|
||||
QString m_IetfCode;
|
||||
QString m_Name;
|
||||
};
|
||||
|
||||
public:
|
||||
SynergyLocale();
|
||||
void fillLanguageComboBox(QComboBox* comboBox);
|
||||
|
||||
private:
|
||||
void loadLanguages();
|
||||
void addLanguage(const QString& IetfCode, const QString& name);
|
||||
|
||||
private:
|
||||
QVector<Language> m_Languages;
|
||||
};
|
||||
|
|
|
@ -1,30 +1,30 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012 Bolton Software Ltd.
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "TcpSocketReader.h"
|
||||
#include <QTcpSocket>
|
||||
|
||||
IpcReader::IpcReader(QTcpSocket& socket) :
|
||||
m_Socket(socket)
|
||||
{
|
||||
connect(m_Socket, SIGNAL(readyRead()), this, SLOT(read()));
|
||||
}
|
||||
|
||||
IpcReader::~IpcReader()
|
||||
{
|
||||
}
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "TcpSocketReader.h"
|
||||
#include <QTcpSocket>
|
||||
|
||||
IpcReader::IpcReader(QTcpSocket& socket) :
|
||||
m_Socket(socket)
|
||||
{
|
||||
connect(m_Socket, SIGNAL(readyRead()), this, SLOT(read()));
|
||||
}
|
||||
|
||||
IpcReader::~IpcReader()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -1,103 +1,103 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012 Bolton Software Ltd.
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "VersionChecker.h"
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
#include <QProcess>
|
||||
#include <QLocale>
|
||||
|
||||
#define VERSION_REGEX "(\\d+\\.\\d+\\.\\d+)"
|
||||
#define VERSION_URL "http://synergy-foss.org/version/"
|
||||
|
||||
VersionChecker::VersionChecker()
|
||||
{
|
||||
m_manager = new QNetworkAccessManager(this);
|
||||
|
||||
connect(m_manager, SIGNAL(finished(QNetworkReply*)),
|
||||
this, SLOT(replyFinished(QNetworkReply*)));
|
||||
}
|
||||
|
||||
VersionChecker::~VersionChecker()
|
||||
{
|
||||
delete m_manager;
|
||||
}
|
||||
|
||||
void VersionChecker::checkLatest()
|
||||
{
|
||||
m_manager->get(QNetworkRequest(QUrl(VERSION_URL)));
|
||||
}
|
||||
|
||||
void VersionChecker::replyFinished(QNetworkReply* reply)
|
||||
{
|
||||
QString newestVersion = QString(reply->readAll());
|
||||
if (!newestVersion.isEmpty())
|
||||
{
|
||||
QString currentVersion = getVersion();
|
||||
if (compareVersions(currentVersion, newestVersion) > 0)
|
||||
emit updateFound(newestVersion);
|
||||
}
|
||||
}
|
||||
|
||||
int VersionChecker::compareVersions(const QString& left, const QString& right)
|
||||
{
|
||||
if (left.compare(right) == 0)
|
||||
return 0; // versions are same.
|
||||
|
||||
QStringList leftSplit = left.split(QRegExp("\\."));
|
||||
if (leftSplit.size() != 3)
|
||||
return 1; // assume right wins.
|
||||
|
||||
QStringList rightSplit = right.split(QRegExp("\\."));
|
||||
if (rightSplit.size() != 3)
|
||||
return -1; // assume left wins.
|
||||
|
||||
int leftMajor = leftSplit.at(0).toInt();
|
||||
int leftMinor = leftSplit.at(1).toInt();
|
||||
int leftRev = leftSplit.at(2).toInt();
|
||||
|
||||
int rightMajor = rightSplit.at(0).toInt();
|
||||
int rightMinor = rightSplit.at(1).toInt();
|
||||
int rightRev = rightSplit.at(2).toInt();
|
||||
|
||||
bool rightWins =
|
||||
(rightMajor > leftMajor) ||
|
||||
((rightMajor >= leftMajor) && (rightMinor > leftMinor)) ||
|
||||
((rightMajor >= leftMajor) && (rightMinor >= leftMinor) && (rightRev > leftRev));
|
||||
|
||||
return rightWins ? 1 : -1;
|
||||
}
|
||||
|
||||
QString VersionChecker::getVersion()
|
||||
{
|
||||
QProcess process;
|
||||
process.start(m_app, QStringList() << "--version");
|
||||
|
||||
process.setReadChannel(QProcess::StandardOutput);
|
||||
if (process.waitForStarted() && process.waitForFinished())
|
||||
{
|
||||
QRegExp rx(VERSION_REGEX);
|
||||
QString text = process.readLine();
|
||||
if (rx.indexIn(text) != -1)
|
||||
return rx.cap(1);
|
||||
}
|
||||
|
||||
return tr("Unknown");
|
||||
}
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012 Bolton Software Ltd.
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "VersionChecker.h"
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
#include <QProcess>
|
||||
#include <QLocale>
|
||||
|
||||
#define VERSION_REGEX "(\\d+\\.\\d+\\.\\d+)"
|
||||
#define VERSION_URL "http://synergy-foss.org/version/"
|
||||
|
||||
VersionChecker::VersionChecker()
|
||||
{
|
||||
m_manager = new QNetworkAccessManager(this);
|
||||
|
||||
connect(m_manager, SIGNAL(finished(QNetworkReply*)),
|
||||
this, SLOT(replyFinished(QNetworkReply*)));
|
||||
}
|
||||
|
||||
VersionChecker::~VersionChecker()
|
||||
{
|
||||
delete m_manager;
|
||||
}
|
||||
|
||||
void VersionChecker::checkLatest()
|
||||
{
|
||||
m_manager->get(QNetworkRequest(QUrl(VERSION_URL)));
|
||||
}
|
||||
|
||||
void VersionChecker::replyFinished(QNetworkReply* reply)
|
||||
{
|
||||
QString newestVersion = QString(reply->readAll());
|
||||
if (!newestVersion.isEmpty())
|
||||
{
|
||||
QString currentVersion = getVersion();
|
||||
if (compareVersions(currentVersion, newestVersion) > 0)
|
||||
emit updateFound(newestVersion);
|
||||
}
|
||||
}
|
||||
|
||||
int VersionChecker::compareVersions(const QString& left, const QString& right)
|
||||
{
|
||||
if (left.compare(right) == 0)
|
||||
return 0; // versions are same.
|
||||
|
||||
QStringList leftSplit = left.split(QRegExp("\\."));
|
||||
if (leftSplit.size() != 3)
|
||||
return 1; // assume right wins.
|
||||
|
||||
QStringList rightSplit = right.split(QRegExp("\\."));
|
||||
if (rightSplit.size() != 3)
|
||||
return -1; // assume left wins.
|
||||
|
||||
int leftMajor = leftSplit.at(0).toInt();
|
||||
int leftMinor = leftSplit.at(1).toInt();
|
||||
int leftRev = leftSplit.at(2).toInt();
|
||||
|
||||
int rightMajor = rightSplit.at(0).toInt();
|
||||
int rightMinor = rightSplit.at(1).toInt();
|
||||
int rightRev = rightSplit.at(2).toInt();
|
||||
|
||||
bool rightWins =
|
||||
(rightMajor > leftMajor) ||
|
||||
((rightMajor >= leftMajor) && (rightMinor > leftMinor)) ||
|
||||
((rightMajor >= leftMajor) && (rightMinor >= leftMinor) && (rightRev > leftRev));
|
||||
|
||||
return rightWins ? 1 : -1;
|
||||
}
|
||||
|
||||
QString VersionChecker::getVersion()
|
||||
{
|
||||
QProcess process;
|
||||
process.start(m_app, QStringList() << "--version");
|
||||
|
||||
process.setReadChannel(QProcess::StandardOutput);
|
||||
if (process.waitForStarted() && process.waitForFinished())
|
||||
{
|
||||
QRegExp rx(VERSION_REGEX);
|
||||
QString text = process.readLine();
|
||||
if (rx.indexIn(text) != -1)
|
||||
return rx.cap(1);
|
||||
}
|
||||
|
||||
return tr("Unknown");
|
||||
}
|
||||
|
|
|
@ -1,44 +1,44 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012 Bolton Software Ltd.
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
class QNetworkAccessManager;
|
||||
class QNetworkReply;
|
||||
|
||||
class VersionChecker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
VersionChecker();
|
||||
virtual ~VersionChecker();
|
||||
void checkLatest();
|
||||
QString getVersion();
|
||||
void setApp(const QString& app) { m_app = app; }
|
||||
int compareVersions(const QString& left, const QString& right);
|
||||
public slots:
|
||||
void replyFinished(QNetworkReply* reply);
|
||||
signals:
|
||||
void updateFound(const QString& version);
|
||||
private:
|
||||
QNetworkAccessManager* m_manager;
|
||||
QString m_app;
|
||||
};
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
class QNetworkAccessManager;
|
||||
class QNetworkReply;
|
||||
|
||||
class VersionChecker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
VersionChecker();
|
||||
virtual ~VersionChecker();
|
||||
void checkLatest();
|
||||
QString getVersion();
|
||||
void setApp(const QString& app) { m_app = app; }
|
||||
int compareVersions(const QString& left, const QString& right);
|
||||
public slots:
|
||||
void replyFinished(QNetworkReply* reply);
|
||||
signals:
|
||||
void updateFound(const QString& version);
|
||||
private:
|
||||
QNetworkAccessManager* m_manager;
|
||||
QString m_app;
|
||||
};
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -33,14 +33,20 @@
|
|||
#include "CArch.h"
|
||||
#include "IPlatformScreen.h"
|
||||
#include "CCryptoStream.h"
|
||||
#include "CThread.h"
|
||||
#include "TMethodJob.h"
|
||||
#include "CFileChunker.h"
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
//
|
||||
// CClient
|
||||
//
|
||||
|
||||
const size_t CClient::m_chunkSize = 1024 * 512; // 512kb
|
||||
|
||||
CClient::CClient(IEventQueue* events,
|
||||
const CString& name, const CNetworkAddress& address,
|
||||
ISocketFactory* socketFactory,
|
||||
|
@ -438,6 +444,17 @@ CClient::sendConnectionFailedEvent(const char* msg)
|
|||
m_events->addEvent(event);
|
||||
}
|
||||
|
||||
void
|
||||
CClient::sendFileChunk(const void* data)
|
||||
{
|
||||
CFileChunker::CFileChunk* fileChunk = reinterpret_cast<CFileChunker::CFileChunk*>(const_cast<void*>(data));
|
||||
LOG((CLOG_DEBUG1 "sendFileChunk"));
|
||||
assert(m_server != NULL);
|
||||
|
||||
// relay
|
||||
m_server->fileChunkSending(fileChunk->m_chunk[0], &(fileChunk->m_chunk[1]), fileChunk->m_dataSize);
|
||||
}
|
||||
|
||||
void
|
||||
CClient::setupConnecting()
|
||||
{
|
||||
|
@ -737,6 +754,7 @@ CClient::handleGameDeviceFeedback(const CEvent& event, void*)
|
|||
void
|
||||
CClient::handleFileChunkSending(const CEvent& event, void*)
|
||||
{
|
||||
sendFileChunk(event.getData());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -763,3 +781,24 @@ CClient::isReceivedFileSizeValid()
|
|||
{
|
||||
return m_expectedFileSize == m_receivedFileData.size();
|
||||
}
|
||||
|
||||
void
|
||||
CClient::sendFileToServer(const char* filename)
|
||||
{
|
||||
CThread* thread = new CThread(
|
||||
new TMethodJob<CClient>(
|
||||
this, &CClient::sendFileThread,
|
||||
reinterpret_cast<void*>(const_cast<char*>(filename))));
|
||||
}
|
||||
|
||||
void
|
||||
CClient::sendFileThread(void* filename)
|
||||
{
|
||||
try {
|
||||
char* name = reinterpret_cast<char*>(filename);
|
||||
CFileChunker::sendFileChunks(name, m_events, this);
|
||||
}
|
||||
catch (std::runtime_error error) {
|
||||
LOG((CLOG_ERR "failed sending file chunks: %s", error.what()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,39 +1,39 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012 Bolton Software Ltd.
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ILogOutputter.h"
|
||||
|
||||
//! Write log to debugger
|
||||
/*!
|
||||
This outputter writes output to the debugger. In Visual Studio, this
|
||||
can be seen in the Output window.
|
||||
*/
|
||||
class CMSWindowsDebugOutputter : public ILogOutputter {
|
||||
public:
|
||||
CMSWindowsDebugOutputter();
|
||||
virtual ~CMSWindowsDebugOutputter();
|
||||
|
||||
// ILogOutputter overrides
|
||||
virtual void open(const char* title);
|
||||
virtual void close();
|
||||
virtual void show(bool showIfEmpty);
|
||||
virtual bool write(ELevel level, const char* message);
|
||||
virtual void flush();
|
||||
};
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ILogOutputter.h"
|
||||
|
||||
//! Write log to debugger
|
||||
/*!
|
||||
This outputter writes output to the debugger. In Visual Studio, this
|
||||
can be seen in the Output window.
|
||||
*/
|
||||
class CMSWindowsDebugOutputter : public ILogOutputter {
|
||||
public:
|
||||
CMSWindowsDebugOutputter();
|
||||
virtual ~CMSWindowsDebugOutputter();
|
||||
|
||||
// ILogOutputter overrides
|
||||
virtual void open(const char* title);
|
||||
virtual void close();
|
||||
virtual void show(bool showIfEmpty);
|
||||
virtual bool write(ELevel level, const char* message);
|
||||
virtual void flush();
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -14,329 +14,329 @@
|
|||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*--------------------------------------------------------------------------------------------------------
|
||||
Original comment:
|
||||
|
||||
APIHIJACK.CPP - Based on DelayLoadProfileDLL.CPP, by Matt Pietrek for MSJ February 2000.
|
||||
http://msdn.microsoft.com/library/periodic/period00/hood0200.htm
|
||||
Adapted by Wade Brainerd, wadeb@wadeb.com
|
||||
--------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include "HookDLL.h"
|
||||
|
||||
#include <sstream>
|
||||
std::stringstream _hookDllLogStream;
|
||||
#define LOG(s) \
|
||||
_hookDllLogStream.str(""); \
|
||||
_hookDllLogStream << "Synergy HookDLL: " << s << std::endl; \
|
||||
OutputDebugString( _hookDllLogStream.str().c_str() );
|
||||
|
||||
//===========================================================================
|
||||
// Called from the DLPD_IAT_STUB stubs. Increments "count" field of the stub
|
||||
|
||||
void __cdecl DefaultHook( PVOID dummy )
|
||||
{
|
||||
// asm only supported on 32-bit
|
||||
#ifdef _M_IX86
|
||||
__asm pushad // Save all general purpose registers
|
||||
|
||||
// Get return address, then subtract 5 (size of a CALL X instruction)
|
||||
// The result points at a DLPD_IAT_STUB
|
||||
|
||||
// pointer math! &dummy-1 really subtracts sizeof(PVOID)
|
||||
PDWORD pRetAddr = (PDWORD)(&dummy - 1);
|
||||
|
||||
DLPD_IAT_STUB * pDLPDStub = (DLPD_IAT_STUB *)(*pRetAddr - 5);
|
||||
|
||||
pDLPDStub->count++;
|
||||
|
||||
#if 0
|
||||
// Remove the above conditional to get a cheezy API trace from
|
||||
// the loader process. It's slow!
|
||||
if ( !IMAGE_SNAP_BY_ORDINAL( pDLPDStub->pszNameOrOrdinal) )
|
||||
{
|
||||
LOG( "Called hooked function: " );
|
||||
LOG( (PSTR)pDLPDStub->pszNameOrOrdinal );
|
||||
}
|
||||
#endif
|
||||
|
||||
__asm popad // Restore all general purpose registers
|
||||
#endif
|
||||
}
|
||||
|
||||
// This function must be __cdecl!!!
|
||||
void __cdecl DelayLoadProfileDLL_UpdateCount( PVOID dummy );
|
||||
|
||||
PIMAGE_IMPORT_DESCRIPTOR g_pFirstImportDesc;
|
||||
|
||||
//===========================================================================
|
||||
// Given an HMODULE, returns a pointer to the PE header
|
||||
|
||||
PIMAGE_NT_HEADERS PEHeaderFromHModule(HMODULE hModule)
|
||||
{
|
||||
PIMAGE_NT_HEADERS pNTHeader = 0;
|
||||
|
||||
__try
|
||||
{
|
||||
if ( PIMAGE_DOS_HEADER(hModule)->e_magic != IMAGE_DOS_SIGNATURE )
|
||||
__leave;
|
||||
|
||||
pNTHeader = PIMAGE_NT_HEADERS(PBYTE(hModule)
|
||||
+ PIMAGE_DOS_HEADER(hModule)->e_lfanew);
|
||||
|
||||
if ( pNTHeader->Signature != IMAGE_NT_SIGNATURE )
|
||||
pNTHeader = 0;
|
||||
}
|
||||
__except( EXCEPTION_EXECUTE_HANDLER )
|
||||
{
|
||||
}
|
||||
|
||||
return pNTHeader;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Builds stubs for and redirects the IAT for one DLL (pImportDesc)
|
||||
|
||||
bool RedirectIAT( SDLLHook* DLLHook, PIMAGE_IMPORT_DESCRIPTOR pImportDesc, PVOID pBaseLoadAddr )
|
||||
{
|
||||
PIMAGE_THUNK_DATA pIAT; // Ptr to import address table
|
||||
PIMAGE_THUNK_DATA pINT; // Ptr to import names table
|
||||
PIMAGE_THUNK_DATA pIteratingIAT;
|
||||
|
||||
// Figure out which OS platform we're on
|
||||
OSVERSIONINFO osvi;
|
||||
osvi.dwOSVersionInfoSize = sizeof(osvi);
|
||||
GetVersionEx( &osvi );
|
||||
|
||||
// If no import names table, we can't redirect this, so bail
|
||||
if ( pImportDesc->OriginalFirstThunk == 0 )
|
||||
{
|
||||
LOG( "no IAT available." );
|
||||
return false;
|
||||
}
|
||||
|
||||
pIAT = MakePtr( PIMAGE_THUNK_DATA, pBaseLoadAddr, pImportDesc->FirstThunk );
|
||||
pINT = MakePtr( PIMAGE_THUNK_DATA, pBaseLoadAddr, pImportDesc->OriginalFirstThunk );
|
||||
|
||||
// Count how many entries there are in this IAT. Array is 0 terminated
|
||||
pIteratingIAT = pIAT;
|
||||
unsigned cFuncs = 0;
|
||||
while ( pIteratingIAT->u1.Function )
|
||||
{
|
||||
cFuncs++;
|
||||
pIteratingIAT++;
|
||||
}
|
||||
|
||||
if ( cFuncs == 0 ) // If no imported functions, we're done!
|
||||
{
|
||||
LOG( "no imported functions" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// These next few lines ensure that we'll be able to modify the IAT,
|
||||
// which is often in a read-only section in the EXE.
|
||||
DWORD flOldProtect, flNewProtect, flDontCare;
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
|
||||
// Get the current protection attributes
|
||||
VirtualQuery( pIAT, &mbi, sizeof(mbi) );
|
||||
|
||||
// remove ReadOnly and ExecuteRead attributes, add on ReadWrite flag
|
||||
flNewProtect = mbi.Protect;
|
||||
flNewProtect &= ~(PAGE_READONLY | PAGE_EXECUTE_READ);
|
||||
flNewProtect |= (PAGE_READWRITE);
|
||||
|
||||
if ( !VirtualProtect( pIAT, sizeof(PVOID) * cFuncs,
|
||||
flNewProtect, &flOldProtect) )
|
||||
{
|
||||
LOG( "could not remove ReadOnly and ExecuteRead attributes, or add ReadWrite flag" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the Default hook is enabled, build an array of redirection stubs in the processes memory.
|
||||
DLPD_IAT_STUB * pStubs = 0;
|
||||
if ( DLLHook->UseDefault )
|
||||
{
|
||||
// Allocate memory for the redirection stubs. Make one extra stub at the
|
||||
// end to be a sentinel
|
||||
pStubs = new DLPD_IAT_STUB[ cFuncs + 1];
|
||||
if ( !pStubs )
|
||||
{
|
||||
LOG( "could not allocate memory for redirection stubs" );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Scan through the IAT, completing the stubs and redirecting the IAT
|
||||
// entries to point to the stubs
|
||||
pIteratingIAT = pIAT;
|
||||
|
||||
while ( pIteratingIAT->u1.Function )
|
||||
{
|
||||
void* HookFn = 0; // Set to either the SFunctionHook or pStubs.
|
||||
|
||||
if ( !IMAGE_SNAP_BY_ORDINAL( pINT->u1.Ordinal ) ) // import by name
|
||||
{
|
||||
PIMAGE_IMPORT_BY_NAME pImportName = MakePtr( PIMAGE_IMPORT_BY_NAME, pBaseLoadAddr, pINT->u1.AddressOfData );
|
||||
|
||||
LOG( "checking function with name: " << pImportName->Name );
|
||||
|
||||
// Iterate through the hook functions, searching for this import.
|
||||
SFunctionHook* FHook = DLLHook->Functions;
|
||||
while ( FHook->Name )
|
||||
{
|
||||
if ( lstrcmpi( FHook->Name, (char*)pImportName->Name ) == 0 )
|
||||
{
|
||||
// Save the old function in the SFunctionHook structure and get the new one.
|
||||
FHook->OrigFn = (void*)pIteratingIAT->u1.Function;
|
||||
HookFn = FHook->HookFn;
|
||||
|
||||
LOG( "hooked function: " << pImportName->Name );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
FHook++;
|
||||
}
|
||||
|
||||
// If the default function is enabled, store the name for the user.
|
||||
if ( DLLHook->UseDefault )
|
||||
pStubs->pszNameOrOrdinal = (DWORD)&pImportName->Name;
|
||||
}
|
||||
else // added comparison for ordinal
|
||||
{
|
||||
LOG( "checking function at ordinal: " << pINT->u1.Ordinal );
|
||||
|
||||
SFunctionHook* FHook = DLLHook->Functions;
|
||||
while ( FHook->Name )
|
||||
{
|
||||
if ( (DWORD)FHook->Name == pINT->u1.Ordinal )
|
||||
{
|
||||
// Save the old function in the SFunctionHook structure and get the new one.
|
||||
FHook->OrigFn = (void*)pIteratingIAT->u1.Function;
|
||||
HookFn = FHook->HookFn;
|
||||
|
||||
LOG( "hooked ordinal: " << pINT->u1.Ordinal );
|
||||
|
||||
break;
|
||||
}
|
||||
FHook++;
|
||||
}
|
||||
// If the default function is enabled, store the ordinal for the user.
|
||||
if ( DLLHook->UseDefault )
|
||||
pStubs->pszNameOrOrdinal = (DWORD)pINT->u1.Ordinal;
|
||||
}
|
||||
|
||||
// If the default function is enabled, fill in the fields to the stub code.
|
||||
if ( DLLHook->UseDefault )
|
||||
{
|
||||
pStubs->data_call = (DWORD)(PDWORD)DLLHook->DefaultFn
|
||||
- (DWORD)(PDWORD)&pStubs->instr_JMP;
|
||||
pStubs->data_JMP = *(PDWORD)pIteratingIAT - (DWORD)(PDWORD)&pStubs->count;
|
||||
|
||||
// If it wasn't manually hooked, use the Stub function.
|
||||
if ( !HookFn )
|
||||
HookFn = (void*)pStubs;
|
||||
}
|
||||
|
||||
// Replace the IAT function pointer if we have a hook.
|
||||
if ( HookFn )
|
||||
{
|
||||
// Cheez-o hack to see if what we're importing is code or data.
|
||||
// If it's code, we shouldn't be able to write to it
|
||||
if ( IsBadWritePtr( (PVOID)pIteratingIAT->u1.Function, 1 ) )
|
||||
{
|
||||
pIteratingIAT->u1.Function = (DWORD)(PDWORD)HookFn;
|
||||
}
|
||||
else if ( osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
|
||||
{
|
||||
// Special hack for Win9X, which builds stubs for imported
|
||||
// functions in system DLLs (Loaded above 2GB). These stubs are
|
||||
// writeable, so we have to explicitly check for this case
|
||||
if ( pIteratingIAT->u1.Function > (DWORD)(PDWORD)0x80000000 )
|
||||
pIteratingIAT->u1.Function = (DWORD)(PDWORD)HookFn;
|
||||
}
|
||||
}
|
||||
|
||||
if ( DLLHook->UseDefault )
|
||||
pStubs++; // Advance to next stub
|
||||
|
||||
pIteratingIAT++; // Advance to next IAT entry
|
||||
pINT++; // Advance to next INT entry
|
||||
}
|
||||
|
||||
if ( DLLHook->UseDefault )
|
||||
pStubs->pszNameOrOrdinal = 0; // Final stub is a sentinel
|
||||
|
||||
// Put the page attributes back the way they were.
|
||||
VirtualProtect( pIAT, sizeof(PVOID) * cFuncs, flOldProtect, &flDontCare);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Top level routine to find the EXE's imports, and redirect them
|
||||
bool HookAPICalls( SDLLHook* hook )
|
||||
{
|
||||
if ( !hook )
|
||||
{
|
||||
LOG("no hook");
|
||||
return false;
|
||||
}
|
||||
|
||||
HMODULE hModEXE = GetModuleHandle( 0 );
|
||||
|
||||
PIMAGE_NT_HEADERS pExeNTHdr = PEHeaderFromHModule( hModEXE );
|
||||
|
||||
if ( !pExeNTHdr )
|
||||
{
|
||||
LOG("no PE header");
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD importRVA = pExeNTHdr->OptionalHeader.DataDirectory
|
||||
[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
|
||||
if ( !importRVA )
|
||||
{
|
||||
LOG("no virtual address for image directory entry import");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert imports RVA to a usable pointer
|
||||
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = MakePtr( PIMAGE_IMPORT_DESCRIPTOR,
|
||||
hModEXE, importRVA );
|
||||
|
||||
// Save off imports address in a global for later use
|
||||
g_pFirstImportDesc = pImportDesc;
|
||||
|
||||
// Iterate through each import descriptor, and redirect if appropriate
|
||||
while ( pImportDesc->FirstThunk )
|
||||
{
|
||||
PSTR pszImportModuleName = MakePtr( PSTR, hModEXE, pImportDesc->Name);
|
||||
|
||||
if ( lstrcmpi( pszImportModuleName, hook->Name ) == 0 )
|
||||
{
|
||||
LOG( "found " << hook->Name << " in process" );
|
||||
|
||||
if ( RedirectIAT( hook, pImportDesc, (PVOID)hModEXE ) )
|
||||
{
|
||||
LOG( "redirected IAT ok" );
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG( "failed to redirect IAT" );
|
||||
}
|
||||
}
|
||||
|
||||
pImportDesc++; // Advance to next import descriptor
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
/*--------------------------------------------------------------------------------------------------------
|
||||
Original comment:
|
||||
|
||||
APIHIJACK.CPP - Based on DelayLoadProfileDLL.CPP, by Matt Pietrek for MSJ February 2000.
|
||||
http://msdn.microsoft.com/library/periodic/period00/hood0200.htm
|
||||
Adapted by Wade Brainerd, wadeb@wadeb.com
|
||||
--------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include "HookDLL.h"
|
||||
|
||||
#include <sstream>
|
||||
std::stringstream _hookDllLogStream;
|
||||
#define LOG(s) \
|
||||
_hookDllLogStream.str(""); \
|
||||
_hookDllLogStream << "Synergy HookDLL: " << s << std::endl; \
|
||||
OutputDebugString( _hookDllLogStream.str().c_str() );
|
||||
|
||||
//===========================================================================
|
||||
// Called from the DLPD_IAT_STUB stubs. Increments "count" field of the stub
|
||||
|
||||
void __cdecl DefaultHook( PVOID dummy )
|
||||
{
|
||||
// asm only supported on 32-bit
|
||||
#ifdef _M_IX86
|
||||
__asm pushad // Save all general purpose registers
|
||||
|
||||
// Get return address, then subtract 5 (size of a CALL X instruction)
|
||||
// The result points at a DLPD_IAT_STUB
|
||||
|
||||
// pointer math! &dummy-1 really subtracts sizeof(PVOID)
|
||||
PDWORD pRetAddr = (PDWORD)(&dummy - 1);
|
||||
|
||||
DLPD_IAT_STUB * pDLPDStub = (DLPD_IAT_STUB *)(*pRetAddr - 5);
|
||||
|
||||
pDLPDStub->count++;
|
||||
|
||||
#if 0
|
||||
// Remove the above conditional to get a cheezy API trace from
|
||||
// the loader process. It's slow!
|
||||
if ( !IMAGE_SNAP_BY_ORDINAL( pDLPDStub->pszNameOrOrdinal) )
|
||||
{
|
||||
LOG( "Called hooked function: " );
|
||||
LOG( (PSTR)pDLPDStub->pszNameOrOrdinal );
|
||||
}
|
||||
#endif
|
||||
|
||||
__asm popad // Restore all general purpose registers
|
||||
#endif
|
||||
}
|
||||
|
||||
// This function must be __cdecl!!!
|
||||
void __cdecl DelayLoadProfileDLL_UpdateCount( PVOID dummy );
|
||||
|
||||
PIMAGE_IMPORT_DESCRIPTOR g_pFirstImportDesc;
|
||||
|
||||
//===========================================================================
|
||||
// Given an HMODULE, returns a pointer to the PE header
|
||||
|
||||
PIMAGE_NT_HEADERS PEHeaderFromHModule(HMODULE hModule)
|
||||
{
|
||||
PIMAGE_NT_HEADERS pNTHeader = 0;
|
||||
|
||||
__try
|
||||
{
|
||||
if ( PIMAGE_DOS_HEADER(hModule)->e_magic != IMAGE_DOS_SIGNATURE )
|
||||
__leave;
|
||||
|
||||
pNTHeader = PIMAGE_NT_HEADERS(PBYTE(hModule)
|
||||
+ PIMAGE_DOS_HEADER(hModule)->e_lfanew);
|
||||
|
||||
if ( pNTHeader->Signature != IMAGE_NT_SIGNATURE )
|
||||
pNTHeader = 0;
|
||||
}
|
||||
__except( EXCEPTION_EXECUTE_HANDLER )
|
||||
{
|
||||
}
|
||||
|
||||
return pNTHeader;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Builds stubs for and redirects the IAT for one DLL (pImportDesc)
|
||||
|
||||
bool RedirectIAT( SDLLHook* DLLHook, PIMAGE_IMPORT_DESCRIPTOR pImportDesc, PVOID pBaseLoadAddr )
|
||||
{
|
||||
PIMAGE_THUNK_DATA pIAT; // Ptr to import address table
|
||||
PIMAGE_THUNK_DATA pINT; // Ptr to import names table
|
||||
PIMAGE_THUNK_DATA pIteratingIAT;
|
||||
|
||||
// Figure out which OS platform we're on
|
||||
OSVERSIONINFO osvi;
|
||||
osvi.dwOSVersionInfoSize = sizeof(osvi);
|
||||
GetVersionEx( &osvi );
|
||||
|
||||
// If no import names table, we can't redirect this, so bail
|
||||
if ( pImportDesc->OriginalFirstThunk == 0 )
|
||||
{
|
||||
LOG( "no IAT available." );
|
||||
return false;
|
||||
}
|
||||
|
||||
pIAT = MakePtr( PIMAGE_THUNK_DATA, pBaseLoadAddr, pImportDesc->FirstThunk );
|
||||
pINT = MakePtr( PIMAGE_THUNK_DATA, pBaseLoadAddr, pImportDesc->OriginalFirstThunk );
|
||||
|
||||
// Count how many entries there are in this IAT. Array is 0 terminated
|
||||
pIteratingIAT = pIAT;
|
||||
unsigned cFuncs = 0;
|
||||
while ( pIteratingIAT->u1.Function )
|
||||
{
|
||||
cFuncs++;
|
||||
pIteratingIAT++;
|
||||
}
|
||||
|
||||
if ( cFuncs == 0 ) // If no imported functions, we're done!
|
||||
{
|
||||
LOG( "no imported functions" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// These next few lines ensure that we'll be able to modify the IAT,
|
||||
// which is often in a read-only section in the EXE.
|
||||
DWORD flOldProtect, flNewProtect, flDontCare;
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
|
||||
// Get the current protection attributes
|
||||
VirtualQuery( pIAT, &mbi, sizeof(mbi) );
|
||||
|
||||
// remove ReadOnly and ExecuteRead attributes, add on ReadWrite flag
|
||||
flNewProtect = mbi.Protect;
|
||||
flNewProtect &= ~(PAGE_READONLY | PAGE_EXECUTE_READ);
|
||||
flNewProtect |= (PAGE_READWRITE);
|
||||
|
||||
if ( !VirtualProtect( pIAT, sizeof(PVOID) * cFuncs,
|
||||
flNewProtect, &flOldProtect) )
|
||||
{
|
||||
LOG( "could not remove ReadOnly and ExecuteRead attributes, or add ReadWrite flag" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the Default hook is enabled, build an array of redirection stubs in the processes memory.
|
||||
DLPD_IAT_STUB * pStubs = 0;
|
||||
if ( DLLHook->UseDefault )
|
||||
{
|
||||
// Allocate memory for the redirection stubs. Make one extra stub at the
|
||||
// end to be a sentinel
|
||||
pStubs = new DLPD_IAT_STUB[ cFuncs + 1];
|
||||
if ( !pStubs )
|
||||
{
|
||||
LOG( "could not allocate memory for redirection stubs" );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Scan through the IAT, completing the stubs and redirecting the IAT
|
||||
// entries to point to the stubs
|
||||
pIteratingIAT = pIAT;
|
||||
|
||||
while ( pIteratingIAT->u1.Function )
|
||||
{
|
||||
void* HookFn = 0; // Set to either the SFunctionHook or pStubs.
|
||||
|
||||
if ( !IMAGE_SNAP_BY_ORDINAL( pINT->u1.Ordinal ) ) // import by name
|
||||
{
|
||||
PIMAGE_IMPORT_BY_NAME pImportName = MakePtr( PIMAGE_IMPORT_BY_NAME, pBaseLoadAddr, pINT->u1.AddressOfData );
|
||||
|
||||
LOG( "checking function with name: " << pImportName->Name );
|
||||
|
||||
// Iterate through the hook functions, searching for this import.
|
||||
SFunctionHook* FHook = DLLHook->Functions;
|
||||
while ( FHook->Name )
|
||||
{
|
||||
if ( lstrcmpi( FHook->Name, (char*)pImportName->Name ) == 0 )
|
||||
{
|
||||
// Save the old function in the SFunctionHook structure and get the new one.
|
||||
FHook->OrigFn = (void*)pIteratingIAT->u1.Function;
|
||||
HookFn = FHook->HookFn;
|
||||
|
||||
LOG( "hooked function: " << pImportName->Name );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
FHook++;
|
||||
}
|
||||
|
||||
// If the default function is enabled, store the name for the user.
|
||||
if ( DLLHook->UseDefault )
|
||||
pStubs->pszNameOrOrdinal = (DWORD)&pImportName->Name;
|
||||
}
|
||||
else // added comparison for ordinal
|
||||
{
|
||||
LOG( "checking function at ordinal: " << pINT->u1.Ordinal );
|
||||
|
||||
SFunctionHook* FHook = DLLHook->Functions;
|
||||
while ( FHook->Name )
|
||||
{
|
||||
if ( (DWORD)FHook->Name == pINT->u1.Ordinal )
|
||||
{
|
||||
// Save the old function in the SFunctionHook structure and get the new one.
|
||||
FHook->OrigFn = (void*)pIteratingIAT->u1.Function;
|
||||
HookFn = FHook->HookFn;
|
||||
|
||||
LOG( "hooked ordinal: " << pINT->u1.Ordinal );
|
||||
|
||||
break;
|
||||
}
|
||||
FHook++;
|
||||
}
|
||||
// If the default function is enabled, store the ordinal for the user.
|
||||
if ( DLLHook->UseDefault )
|
||||
pStubs->pszNameOrOrdinal = (DWORD)pINT->u1.Ordinal;
|
||||
}
|
||||
|
||||
// If the default function is enabled, fill in the fields to the stub code.
|
||||
if ( DLLHook->UseDefault )
|
||||
{
|
||||
pStubs->data_call = (DWORD)(PDWORD)DLLHook->DefaultFn
|
||||
- (DWORD)(PDWORD)&pStubs->instr_JMP;
|
||||
pStubs->data_JMP = *(PDWORD)pIteratingIAT - (DWORD)(PDWORD)&pStubs->count;
|
||||
|
||||
// If it wasn't manually hooked, use the Stub function.
|
||||
if ( !HookFn )
|
||||
HookFn = (void*)pStubs;
|
||||
}
|
||||
|
||||
// Replace the IAT function pointer if we have a hook.
|
||||
if ( HookFn )
|
||||
{
|
||||
// Cheez-o hack to see if what we're importing is code or data.
|
||||
// If it's code, we shouldn't be able to write to it
|
||||
if ( IsBadWritePtr( (PVOID)pIteratingIAT->u1.Function, 1 ) )
|
||||
{
|
||||
pIteratingIAT->u1.Function = (DWORD)(PDWORD)HookFn;
|
||||
}
|
||||
else if ( osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
|
||||
{
|
||||
// Special hack for Win9X, which builds stubs for imported
|
||||
// functions in system DLLs (Loaded above 2GB). These stubs are
|
||||
// writeable, so we have to explicitly check for this case
|
||||
if ( pIteratingIAT->u1.Function > (DWORD)(PDWORD)0x80000000 )
|
||||
pIteratingIAT->u1.Function = (DWORD)(PDWORD)HookFn;
|
||||
}
|
||||
}
|
||||
|
||||
if ( DLLHook->UseDefault )
|
||||
pStubs++; // Advance to next stub
|
||||
|
||||
pIteratingIAT++; // Advance to next IAT entry
|
||||
pINT++; // Advance to next INT entry
|
||||
}
|
||||
|
||||
if ( DLLHook->UseDefault )
|
||||
pStubs->pszNameOrOrdinal = 0; // Final stub is a sentinel
|
||||
|
||||
// Put the page attributes back the way they were.
|
||||
VirtualProtect( pIAT, sizeof(PVOID) * cFuncs, flOldProtect, &flDontCare);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Top level routine to find the EXE's imports, and redirect them
|
||||
bool HookAPICalls( SDLLHook* hook )
|
||||
{
|
||||
if ( !hook )
|
||||
{
|
||||
LOG("no hook");
|
||||
return false;
|
||||
}
|
||||
|
||||
HMODULE hModEXE = GetModuleHandle( 0 );
|
||||
|
||||
PIMAGE_NT_HEADERS pExeNTHdr = PEHeaderFromHModule( hModEXE );
|
||||
|
||||
if ( !pExeNTHdr )
|
||||
{
|
||||
LOG("no PE header");
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD importRVA = pExeNTHdr->OptionalHeader.DataDirectory
|
||||
[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
|
||||
if ( !importRVA )
|
||||
{
|
||||
LOG("no virtual address for image directory entry import");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert imports RVA to a usable pointer
|
||||
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = MakePtr( PIMAGE_IMPORT_DESCRIPTOR,
|
||||
hModEXE, importRVA );
|
||||
|
||||
// Save off imports address in a global for later use
|
||||
g_pFirstImportDesc = pImportDesc;
|
||||
|
||||
// Iterate through each import descriptor, and redirect if appropriate
|
||||
while ( pImportDesc->FirstThunk )
|
||||
{
|
||||
PSTR pszImportModuleName = MakePtr( PSTR, hModEXE, pImportDesc->Name);
|
||||
|
||||
if ( lstrcmpi( pszImportModuleName, hook->Name ) == 0 )
|
||||
{
|
||||
LOG( "found " << hook->Name << " in process" );
|
||||
|
||||
if ( RedirectIAT( hook, pImportDesc, (PVOID)hModEXE ) )
|
||||
{
|
||||
LOG( "redirected IAT ok" );
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG( "failed to redirect IAT" );
|
||||
}
|
||||
}
|
||||
|
||||
pImportDesc++; // Advance to next import descriptor
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,68 +14,68 @@
|
|||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*--------------------------------------------------------------------------------------------------------
|
||||
Original comment:
|
||||
|
||||
APIHIJACK.H - Based on DelayLoadProfileDLL.CPP, by Matt Pietrek for MSJ February 2000.
|
||||
http://msdn.microsoft.com/library/periodic/period00/hood0200.htm
|
||||
Adapted by Wade Brainerd, wadeb@wadeb.com
|
||||
--------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#pragma warning(disable:4200)
|
||||
|
||||
// Macro for convenient pointer addition.
|
||||
// Essentially treats the last two parameters as DWORDs. The first
|
||||
// parameter is used to typecast the result to the appropriate pointer type.
|
||||
#define MakePtr(cast, ptr, addValue ) (cast)( (DWORD)(ptr)+(DWORD)(addValue))
|
||||
|
||||
// Default Hook Stub Structure: Contains data about the original function, Name/Ordinal, Address
|
||||
// and a Count field. This is actually a block of assembly code.
|
||||
#pragma pack( push, 1 )
|
||||
struct DLPD_IAT_STUB
|
||||
{
|
||||
BYTE instr_CALL;
|
||||
DWORD data_call;
|
||||
BYTE instr_JMP;
|
||||
DWORD data_JMP;
|
||||
DWORD count;
|
||||
DWORD pszNameOrOrdinal;
|
||||
|
||||
DLPD_IAT_STUB() : instr_CALL( 0xE8 ), instr_JMP( 0xE9 ), count( 0 ) {}
|
||||
};
|
||||
#pragma pack( pop )
|
||||
|
||||
// Example DefaultHook procedure, called from the DLPD_IAT_STUB stubs.
|
||||
// Increments "count" field of the stub.
|
||||
// See the implementation for more information.
|
||||
void __cdecl DefaultHook( PVOID dummy );
|
||||
|
||||
struct SFunctionHook
|
||||
{
|
||||
char* Name; // Function name, e.g. "DirectDrawCreateEx".
|
||||
void* HookFn; // Address of your function.
|
||||
void* OrigFn; // Stored by HookAPICalls, the address of the original function.
|
||||
};
|
||||
|
||||
struct SDLLHook
|
||||
{
|
||||
// Name of the DLL, e.g. "DDRAW.DLL"
|
||||
char* Name;
|
||||
|
||||
// Set true to call the default for all non-hooked functions before they are executed.
|
||||
bool UseDefault;
|
||||
void* DefaultFn;
|
||||
|
||||
// Function hook array. Terminated with a NULL Name field.
|
||||
SFunctionHook Functions[];
|
||||
};
|
||||
|
||||
// Hook functions one or more DLLs.
|
||||
bool HookAPICalls( SDLLHook* hook );
|
||||
*/
|
||||
|
||||
/*--------------------------------------------------------------------------------------------------------
|
||||
Original comment:
|
||||
|
||||
APIHIJACK.H - Based on DelayLoadProfileDLL.CPP, by Matt Pietrek for MSJ February 2000.
|
||||
http://msdn.microsoft.com/library/periodic/period00/hood0200.htm
|
||||
Adapted by Wade Brainerd, wadeb@wadeb.com
|
||||
--------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#pragma warning(disable:4200)
|
||||
|
||||
// Macro for convenient pointer addition.
|
||||
// Essentially treats the last two parameters as DWORDs. The first
|
||||
// parameter is used to typecast the result to the appropriate pointer type.
|
||||
#define MakePtr(cast, ptr, addValue ) (cast)( (DWORD)(ptr)+(DWORD)(addValue))
|
||||
|
||||
// Default Hook Stub Structure: Contains data about the original function, Name/Ordinal, Address
|
||||
// and a Count field. This is actually a block of assembly code.
|
||||
#pragma pack( push, 1 )
|
||||
struct DLPD_IAT_STUB
|
||||
{
|
||||
BYTE instr_CALL;
|
||||
DWORD data_call;
|
||||
BYTE instr_JMP;
|
||||
DWORD data_JMP;
|
||||
DWORD count;
|
||||
DWORD pszNameOrOrdinal;
|
||||
|
||||
DLPD_IAT_STUB() : instr_CALL( 0xE8 ), instr_JMP( 0xE9 ), count( 0 ) {}
|
||||
};
|
||||
#pragma pack( pop )
|
||||
|
||||
// Example DefaultHook procedure, called from the DLPD_IAT_STUB stubs.
|
||||
// Increments "count" field of the stub.
|
||||
// See the implementation for more information.
|
||||
void __cdecl DefaultHook( PVOID dummy );
|
||||
|
||||
struct SFunctionHook
|
||||
{
|
||||
char* Name; // Function name, e.g. "DirectDrawCreateEx".
|
||||
void* HookFn; // Address of your function.
|
||||
void* OrigFn; // Stored by HookAPICalls, the address of the original function.
|
||||
};
|
||||
|
||||
struct SDLLHook
|
||||
{
|
||||
// Name of the DLL, e.g. "DDRAW.DLL"
|
||||
char* Name;
|
||||
|
||||
// Set true to call the default for all non-hooked functions before they are executed.
|
||||
bool UseDefault;
|
||||
void* DefaultFn;
|
||||
|
||||
// Function hook array. Terminated with a NULL Name field.
|
||||
SFunctionHook Functions[];
|
||||
};
|
||||
|
||||
// Hook functions one or more DLLs.
|
||||
bool HookAPICalls( SDLLHook* hook );
|
||||
|
|
|
@ -1,229 +1,229 @@
|
|||
/***************************************************************************
|
||||
* *
|
||||
* XInput.h -- This module defines XBOX controller APIs *
|
||||
* and constansts for the Windows platform. *
|
||||
* *
|
||||
/***************************************************************************
|
||||
* *
|
||||
* XInput.h -- This module defines XBOX controller APIs *
|
||||
* and constansts for the Windows platform. *
|
||||
* *
|
||||
* Copyright (C) 2012 Bolton Software Ltd.
|
||||
* Copyright (c) Microsoft Corp. All rights reserved. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
#ifndef _XINPUT_H_
|
||||
#define _XINPUT_H_
|
||||
|
||||
#include <windef.h>
|
||||
|
||||
// Current name of the DLL shipped in the same SDK as this header.
|
||||
// The name reflects the current version
|
||||
#ifndef XINPUT_USE_9_1_0
|
||||
#define XINPUT_DLL_A "xinput1_3.dll"
|
||||
#define XINPUT_DLL_W L"xinput1_3.dll"
|
||||
#else
|
||||
#define XINPUT_DLL_A "xinput9_1_0.dll"
|
||||
#define XINPUT_DLL_W L"xinput9_1_0.dll"
|
||||
#endif
|
||||
#ifdef UNICODE
|
||||
#define XINPUT_DLL XINPUT_DLL_W
|
||||
#else
|
||||
#define XINPUT_DLL XINPUT_DLL_A
|
||||
#endif
|
||||
|
||||
//
|
||||
// Device types available in XINPUT_CAPABILITIES
|
||||
//
|
||||
#define XINPUT_DEVTYPE_GAMEPAD 0x01
|
||||
|
||||
//
|
||||
// Device subtypes available in XINPUT_CAPABILITIES
|
||||
//
|
||||
#define XINPUT_DEVSUBTYPE_GAMEPAD 0x01
|
||||
|
||||
#ifndef XINPUT_USE_9_1_0
|
||||
|
||||
#define XINPUT_DEVSUBTYPE_WHEEL 0x02
|
||||
#define XINPUT_DEVSUBTYPE_ARCADE_STICK 0x03
|
||||
#define XINPUT_DEVSUBTYPE_FLIGHT_SICK 0x04
|
||||
#define XINPUT_DEVSUBTYPE_DANCE_PAD 0x05
|
||||
#define XINPUT_DEVSUBTYPE_GUITAR 0x06
|
||||
#define XINPUT_DEVSUBTYPE_DRUM_KIT 0x08
|
||||
|
||||
#endif // !XINPUT_USE_9_1_0
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Flags for XINPUT_CAPABILITIES
|
||||
//
|
||||
#define XINPUT_CAPS_VOICE_SUPPORTED 0x0004
|
||||
|
||||
//
|
||||
// Constants for gamepad buttons
|
||||
//
|
||||
#define XINPUT_GAMEPAD_DPAD_UP 0x0001
|
||||
#define XINPUT_GAMEPAD_DPAD_DOWN 0x0002
|
||||
#define XINPUT_GAMEPAD_DPAD_LEFT 0x0004
|
||||
#define XINPUT_GAMEPAD_DPAD_RIGHT 0x0008
|
||||
#define XINPUT_GAMEPAD_START 0x0010
|
||||
#define XINPUT_GAMEPAD_BACK 0x0020
|
||||
#define XINPUT_GAMEPAD_LEFT_THUMB 0x0040
|
||||
#define XINPUT_GAMEPAD_RIGHT_THUMB 0x0080
|
||||
#define XINPUT_GAMEPAD_LEFT_SHOULDER 0x0100
|
||||
#define XINPUT_GAMEPAD_RIGHT_SHOULDER 0x0200
|
||||
#define XINPUT_GAMEPAD_A 0x1000
|
||||
#define XINPUT_GAMEPAD_B 0x2000
|
||||
#define XINPUT_GAMEPAD_X 0x4000
|
||||
#define XINPUT_GAMEPAD_Y 0x8000
|
||||
|
||||
|
||||
//
|
||||
// Gamepad thresholds
|
||||
//
|
||||
#define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE 7849
|
||||
#define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689
|
||||
#define XINPUT_GAMEPAD_TRIGGER_THRESHOLD 30
|
||||
|
||||
//
|
||||
// Flags to pass to XInputGetCapabilities
|
||||
//
|
||||
#define XINPUT_FLAG_GAMEPAD 0x00000001
|
||||
|
||||
|
||||
#ifndef XINPUT_USE_9_1_0
|
||||
|
||||
//
|
||||
// Devices that support batteries
|
||||
//
|
||||
#define BATTERY_DEVTYPE_GAMEPAD 0x00
|
||||
#define BATTERY_DEVTYPE_HEADSET 0x01
|
||||
|
||||
//
|
||||
// Flags for battery status level
|
||||
//
|
||||
#define BATTERY_TYPE_DISCONNECTED 0x00 // This device is not connected
|
||||
#define BATTERY_TYPE_WIRED 0x01 // Wired device, no battery
|
||||
#define BATTERY_TYPE_ALKALINE 0x02 // Alkaline battery source
|
||||
#define BATTERY_TYPE_NIMH 0x03 // Nickel Metal Hydride battery source
|
||||
#define BATTERY_TYPE_UNKNOWN 0xFF // Cannot determine the battery type
|
||||
|
||||
// These are only valid for wireless, connected devices, with known battery types
|
||||
// The amount of use time remaining depends on the type of device.
|
||||
#define BATTERY_LEVEL_EMPTY 0x00
|
||||
#define BATTERY_LEVEL_LOW 0x01
|
||||
#define BATTERY_LEVEL_MEDIUM 0x02
|
||||
#define BATTERY_LEVEL_FULL 0x03
|
||||
|
||||
// User index definitions
|
||||
#define XUSER_MAX_COUNT 4
|
||||
|
||||
#define XUSER_INDEX_ANY 0x000000FF
|
||||
|
||||
|
||||
//
|
||||
// Codes returned for the gamepad keystroke
|
||||
//
|
||||
|
||||
#define VK_PAD_A 0x5800
|
||||
#define VK_PAD_B 0x5801
|
||||
#define VK_PAD_X 0x5802
|
||||
#define VK_PAD_Y 0x5803
|
||||
#define VK_PAD_RSHOULDER 0x5804
|
||||
#define VK_PAD_LSHOULDER 0x5805
|
||||
#define VK_PAD_LTRIGGER 0x5806
|
||||
#define VK_PAD_RTRIGGER 0x5807
|
||||
|
||||
#define VK_PAD_DPAD_UP 0x5810
|
||||
#define VK_PAD_DPAD_DOWN 0x5811
|
||||
#define VK_PAD_DPAD_LEFT 0x5812
|
||||
#define VK_PAD_DPAD_RIGHT 0x5813
|
||||
#define VK_PAD_START 0x5814
|
||||
#define VK_PAD_BACK 0x5815
|
||||
#define VK_PAD_LTHUMB_PRESS 0x5816
|
||||
#define VK_PAD_RTHUMB_PRESS 0x5817
|
||||
|
||||
#define VK_PAD_LTHUMB_UP 0x5820
|
||||
#define VK_PAD_LTHUMB_DOWN 0x5821
|
||||
#define VK_PAD_LTHUMB_RIGHT 0x5822
|
||||
#define VK_PAD_LTHUMB_LEFT 0x5823
|
||||
#define VK_PAD_LTHUMB_UPLEFT 0x5824
|
||||
#define VK_PAD_LTHUMB_UPRIGHT 0x5825
|
||||
#define VK_PAD_LTHUMB_DOWNRIGHT 0x5826
|
||||
#define VK_PAD_LTHUMB_DOWNLEFT 0x5827
|
||||
|
||||
#define VK_PAD_RTHUMB_UP 0x5830
|
||||
#define VK_PAD_RTHUMB_DOWN 0x5831
|
||||
#define VK_PAD_RTHUMB_RIGHT 0x5832
|
||||
#define VK_PAD_RTHUMB_LEFT 0x5833
|
||||
#define VK_PAD_RTHUMB_UPLEFT 0x5834
|
||||
#define VK_PAD_RTHUMB_UPRIGHT 0x5835
|
||||
#define VK_PAD_RTHUMB_DOWNRIGHT 0x5836
|
||||
#define VK_PAD_RTHUMB_DOWNLEFT 0x5837
|
||||
|
||||
//
|
||||
// Flags used in XINPUT_KEYSTROKE
|
||||
//
|
||||
#define XINPUT_KEYSTROKE_KEYDOWN 0x0001
|
||||
#define XINPUT_KEYSTROKE_KEYUP 0x0002
|
||||
#define XINPUT_KEYSTROKE_REPEAT 0x0004
|
||||
|
||||
#endif //!XINPUT_USE_9_1_0
|
||||
|
||||
//
|
||||
// Structures used by XInput APIs
|
||||
//
|
||||
typedef struct _XINPUT_GAMEPAD
|
||||
{
|
||||
WORD wButtons;
|
||||
BYTE bLeftTrigger;
|
||||
BYTE bRightTrigger;
|
||||
SHORT sThumbLX;
|
||||
SHORT sThumbLY;
|
||||
SHORT sThumbRX;
|
||||
SHORT sThumbRY;
|
||||
} XINPUT_GAMEPAD, *PXINPUT_GAMEPAD;
|
||||
|
||||
typedef struct _XINPUT_STATE
|
||||
{
|
||||
DWORD dwPacketNumber;
|
||||
XINPUT_GAMEPAD Gamepad;
|
||||
} XINPUT_STATE, *PXINPUT_STATE;
|
||||
|
||||
typedef struct _XINPUT_VIBRATION
|
||||
{
|
||||
WORD wLeftMotorSpeed;
|
||||
WORD wRightMotorSpeed;
|
||||
} XINPUT_VIBRATION, *PXINPUT_VIBRATION;
|
||||
|
||||
typedef struct _XINPUT_CAPABILITIES
|
||||
{
|
||||
BYTE Type;
|
||||
BYTE SubType;
|
||||
WORD Flags;
|
||||
XINPUT_GAMEPAD Gamepad;
|
||||
XINPUT_VIBRATION Vibration;
|
||||
} XINPUT_CAPABILITIES, *PXINPUT_CAPABILITIES;
|
||||
|
||||
#ifndef XINPUT_USE_9_1_0
|
||||
|
||||
typedef struct _XINPUT_BATTERY_INFORMATION
|
||||
{
|
||||
BYTE BatteryType;
|
||||
BYTE BatteryLevel;
|
||||
} XINPUT_BATTERY_INFORMATION, *PXINPUT_BATTERY_INFORMATION;
|
||||
|
||||
typedef struct _XINPUT_KEYSTROKE
|
||||
{
|
||||
WORD VirtualKey;
|
||||
WCHAR Unicode;
|
||||
WORD Flags;
|
||||
BYTE UserIndex;
|
||||
BYTE HidCode;
|
||||
} XINPUT_KEYSTROKE, *PXINPUT_KEYSTROKE;
|
||||
|
||||
#endif // !XINPUT_USE_9_1_0
|
||||
|
||||
//
|
||||
// XInput APIs
|
||||
//
|
||||
|
||||
// now defined in proxy class.
|
||||
|
||||
#endif //_XINPUT_H_
|
||||
* Copyright (c) Microsoft Corp. All rights reserved. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
#ifndef _XINPUT_H_
|
||||
#define _XINPUT_H_
|
||||
|
||||
#include <windef.h>
|
||||
|
||||
// Current name of the DLL shipped in the same SDK as this header.
|
||||
// The name reflects the current version
|
||||
#ifndef XINPUT_USE_9_1_0
|
||||
#define XINPUT_DLL_A "xinput1_3.dll"
|
||||
#define XINPUT_DLL_W L"xinput1_3.dll"
|
||||
#else
|
||||
#define XINPUT_DLL_A "xinput9_1_0.dll"
|
||||
#define XINPUT_DLL_W L"xinput9_1_0.dll"
|
||||
#endif
|
||||
#ifdef UNICODE
|
||||
#define XINPUT_DLL XINPUT_DLL_W
|
||||
#else
|
||||
#define XINPUT_DLL XINPUT_DLL_A
|
||||
#endif
|
||||
|
||||
//
|
||||
// Device types available in XINPUT_CAPABILITIES
|
||||
//
|
||||
#define XINPUT_DEVTYPE_GAMEPAD 0x01
|
||||
|
||||
//
|
||||
// Device subtypes available in XINPUT_CAPABILITIES
|
||||
//
|
||||
#define XINPUT_DEVSUBTYPE_GAMEPAD 0x01
|
||||
|
||||
#ifndef XINPUT_USE_9_1_0
|
||||
|
||||
#define XINPUT_DEVSUBTYPE_WHEEL 0x02
|
||||
#define XINPUT_DEVSUBTYPE_ARCADE_STICK 0x03
|
||||
#define XINPUT_DEVSUBTYPE_FLIGHT_SICK 0x04
|
||||
#define XINPUT_DEVSUBTYPE_DANCE_PAD 0x05
|
||||
#define XINPUT_DEVSUBTYPE_GUITAR 0x06
|
||||
#define XINPUT_DEVSUBTYPE_DRUM_KIT 0x08
|
||||
|
||||
#endif // !XINPUT_USE_9_1_0
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Flags for XINPUT_CAPABILITIES
|
||||
//
|
||||
#define XINPUT_CAPS_VOICE_SUPPORTED 0x0004
|
||||
|
||||
//
|
||||
// Constants for gamepad buttons
|
||||
//
|
||||
#define XINPUT_GAMEPAD_DPAD_UP 0x0001
|
||||
#define XINPUT_GAMEPAD_DPAD_DOWN 0x0002
|
||||
#define XINPUT_GAMEPAD_DPAD_LEFT 0x0004
|
||||
#define XINPUT_GAMEPAD_DPAD_RIGHT 0x0008
|
||||
#define XINPUT_GAMEPAD_START 0x0010
|
||||
#define XINPUT_GAMEPAD_BACK 0x0020
|
||||
#define XINPUT_GAMEPAD_LEFT_THUMB 0x0040
|
||||
#define XINPUT_GAMEPAD_RIGHT_THUMB 0x0080
|
||||
#define XINPUT_GAMEPAD_LEFT_SHOULDER 0x0100
|
||||
#define XINPUT_GAMEPAD_RIGHT_SHOULDER 0x0200
|
||||
#define XINPUT_GAMEPAD_A 0x1000
|
||||
#define XINPUT_GAMEPAD_B 0x2000
|
||||
#define XINPUT_GAMEPAD_X 0x4000
|
||||
#define XINPUT_GAMEPAD_Y 0x8000
|
||||
|
||||
|
||||
//
|
||||
// Gamepad thresholds
|
||||
//
|
||||
#define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE 7849
|
||||
#define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689
|
||||
#define XINPUT_GAMEPAD_TRIGGER_THRESHOLD 30
|
||||
|
||||
//
|
||||
// Flags to pass to XInputGetCapabilities
|
||||
//
|
||||
#define XINPUT_FLAG_GAMEPAD 0x00000001
|
||||
|
||||
|
||||
#ifndef XINPUT_USE_9_1_0
|
||||
|
||||
//
|
||||
// Devices that support batteries
|
||||
//
|
||||
#define BATTERY_DEVTYPE_GAMEPAD 0x00
|
||||
#define BATTERY_DEVTYPE_HEADSET 0x01
|
||||
|
||||
//
|
||||
// Flags for battery status level
|
||||
//
|
||||
#define BATTERY_TYPE_DISCONNECTED 0x00 // This device is not connected
|
||||
#define BATTERY_TYPE_WIRED 0x01 // Wired device, no battery
|
||||
#define BATTERY_TYPE_ALKALINE 0x02 // Alkaline battery source
|
||||
#define BATTERY_TYPE_NIMH 0x03 // Nickel Metal Hydride battery source
|
||||
#define BATTERY_TYPE_UNKNOWN 0xFF // Cannot determine the battery type
|
||||
|
||||
// These are only valid for wireless, connected devices, with known battery types
|
||||
// The amount of use time remaining depends on the type of device.
|
||||
#define BATTERY_LEVEL_EMPTY 0x00
|
||||
#define BATTERY_LEVEL_LOW 0x01
|
||||
#define BATTERY_LEVEL_MEDIUM 0x02
|
||||
#define BATTERY_LEVEL_FULL 0x03
|
||||
|
||||
// User index definitions
|
||||
#define XUSER_MAX_COUNT 4
|
||||
|
||||
#define XUSER_INDEX_ANY 0x000000FF
|
||||
|
||||
|
||||
//
|
||||
// Codes returned for the gamepad keystroke
|
||||
//
|
||||
|
||||
#define VK_PAD_A 0x5800
|
||||
#define VK_PAD_B 0x5801
|
||||
#define VK_PAD_X 0x5802
|
||||
#define VK_PAD_Y 0x5803
|
||||
#define VK_PAD_RSHOULDER 0x5804
|
||||
#define VK_PAD_LSHOULDER 0x5805
|
||||
#define VK_PAD_LTRIGGER 0x5806
|
||||
#define VK_PAD_RTRIGGER 0x5807
|
||||
|
||||
#define VK_PAD_DPAD_UP 0x5810
|
||||
#define VK_PAD_DPAD_DOWN 0x5811
|
||||
#define VK_PAD_DPAD_LEFT 0x5812
|
||||
#define VK_PAD_DPAD_RIGHT 0x5813
|
||||
#define VK_PAD_START 0x5814
|
||||
#define VK_PAD_BACK 0x5815
|
||||
#define VK_PAD_LTHUMB_PRESS 0x5816
|
||||
#define VK_PAD_RTHUMB_PRESS 0x5817
|
||||
|
||||
#define VK_PAD_LTHUMB_UP 0x5820
|
||||
#define VK_PAD_LTHUMB_DOWN 0x5821
|
||||
#define VK_PAD_LTHUMB_RIGHT 0x5822
|
||||
#define VK_PAD_LTHUMB_LEFT 0x5823
|
||||
#define VK_PAD_LTHUMB_UPLEFT 0x5824
|
||||
#define VK_PAD_LTHUMB_UPRIGHT 0x5825
|
||||
#define VK_PAD_LTHUMB_DOWNRIGHT 0x5826
|
||||
#define VK_PAD_LTHUMB_DOWNLEFT 0x5827
|
||||
|
||||
#define VK_PAD_RTHUMB_UP 0x5830
|
||||
#define VK_PAD_RTHUMB_DOWN 0x5831
|
||||
#define VK_PAD_RTHUMB_RIGHT 0x5832
|
||||
#define VK_PAD_RTHUMB_LEFT 0x5833
|
||||
#define VK_PAD_RTHUMB_UPLEFT 0x5834
|
||||
#define VK_PAD_RTHUMB_UPRIGHT 0x5835
|
||||
#define VK_PAD_RTHUMB_DOWNRIGHT 0x5836
|
||||
#define VK_PAD_RTHUMB_DOWNLEFT 0x5837
|
||||
|
||||
//
|
||||
// Flags used in XINPUT_KEYSTROKE
|
||||
//
|
||||
#define XINPUT_KEYSTROKE_KEYDOWN 0x0001
|
||||
#define XINPUT_KEYSTROKE_KEYUP 0x0002
|
||||
#define XINPUT_KEYSTROKE_REPEAT 0x0004
|
||||
|
||||
#endif //!XINPUT_USE_9_1_0
|
||||
|
||||
//
|
||||
// Structures used by XInput APIs
|
||||
//
|
||||
typedef struct _XINPUT_GAMEPAD
|
||||
{
|
||||
WORD wButtons;
|
||||
BYTE bLeftTrigger;
|
||||
BYTE bRightTrigger;
|
||||
SHORT sThumbLX;
|
||||
SHORT sThumbLY;
|
||||
SHORT sThumbRX;
|
||||
SHORT sThumbRY;
|
||||
} XINPUT_GAMEPAD, *PXINPUT_GAMEPAD;
|
||||
|
||||
typedef struct _XINPUT_STATE
|
||||
{
|
||||
DWORD dwPacketNumber;
|
||||
XINPUT_GAMEPAD Gamepad;
|
||||
} XINPUT_STATE, *PXINPUT_STATE;
|
||||
|
||||
typedef struct _XINPUT_VIBRATION
|
||||
{
|
||||
WORD wLeftMotorSpeed;
|
||||
WORD wRightMotorSpeed;
|
||||
} XINPUT_VIBRATION, *PXINPUT_VIBRATION;
|
||||
|
||||
typedef struct _XINPUT_CAPABILITIES
|
||||
{
|
||||
BYTE Type;
|
||||
BYTE SubType;
|
||||
WORD Flags;
|
||||
XINPUT_GAMEPAD Gamepad;
|
||||
XINPUT_VIBRATION Vibration;
|
||||
} XINPUT_CAPABILITIES, *PXINPUT_CAPABILITIES;
|
||||
|
||||
#ifndef XINPUT_USE_9_1_0
|
||||
|
||||
typedef struct _XINPUT_BATTERY_INFORMATION
|
||||
{
|
||||
BYTE BatteryType;
|
||||
BYTE BatteryLevel;
|
||||
} XINPUT_BATTERY_INFORMATION, *PXINPUT_BATTERY_INFORMATION;
|
||||
|
||||
typedef struct _XINPUT_KEYSTROKE
|
||||
{
|
||||
WORD VirtualKey;
|
||||
WCHAR Unicode;
|
||||
WORD Flags;
|
||||
BYTE UserIndex;
|
||||
BYTE HidCode;
|
||||
} XINPUT_KEYSTROKE, *PXINPUT_KEYSTROKE;
|
||||
|
||||
#endif // !XINPUT_USE_9_1_0
|
||||
|
||||
//
|
||||
// XInput APIs
|
||||
//
|
||||
|
||||
// now defined in proxy class.
|
||||
|
||||
#endif //_XINPUT_H_
|
||||
|
|
|
@ -1,296 +1,296 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012 Bolton Software Ltd.
|
||||
* Copyright (C) 2011 Chris Schoeneman
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
* Copyright (C) 2011 Chris Schoeneman
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define SYNERGY_EXPORT_XINPUT_HOOKS
|
||||
#define REQUIRED_XINPUT_DLL "xinput1_3.dll"
|
||||
#define HOOK_TIMEOUT 10000 // 10 sec
|
||||
|
||||
#include <Windows.h>
|
||||
#include <XInput.h>
|
||||
#include "XInputHook.h"
|
||||
#include "HookDLL.h"
|
||||
#include <iostream>
|
||||
|
||||
HINSTANCE dll;
|
||||
char name[256];
|
||||
|
||||
#pragma data_seg(".SHARED")
|
||||
|
||||
HHOOK s_hook = NULL;
|
||||
|
||||
// @todo use a struct for multiple gamepad support
|
||||
WORD s_buttons = 0;
|
||||
SHORT s_leftStickX = 0;
|
||||
SHORT s_leftStickY = 0;
|
||||
SHORT s_rightStickX = 0;
|
||||
SHORT s_rightStickY = 0;
|
||||
BYTE s_leftTrigger = 0;
|
||||
BYTE s_rightTrigger = 0;
|
||||
BOOL s_timingReqQueued = FALSE;
|
||||
BOOL s_timingRespQueued = FALSE;
|
||||
DWORD s_lastFakeMillis = 0;
|
||||
WORD s_fakeFreqMillis = 0;
|
||||
DWORD s_packetNumber = 0;
|
||||
WORD s_leftMotor = 0;
|
||||
WORD s_rightMotor = 0;
|
||||
BOOL s_feedbackQueued = FALSE;
|
||||
|
||||
#pragma data_seg()
|
||||
|
||||
#pragma comment(linker, "/SECTION:.SHARED,RWS")
|
||||
|
||||
#include <sstream>
|
||||
std::stringstream _xInputHookLogStream;
|
||||
#define LOG(s) \
|
||||
_xInputHookLogStream.str(""); \
|
||||
_xInputHookLogStream << "Synergy XInputHook: " << s << endl; \
|
||||
OutputDebugString( _xInputHookLogStream.str().c_str())
|
||||
|
||||
using namespace std;
|
||||
|
||||
SDLLHook s_xInputHook =
|
||||
{
|
||||
XINPUT_DLL,
|
||||
false, NULL,
|
||||
{
|
||||
{ (char*)(0x80000002), HookXInputGetState },
|
||||
{ (char*)(0x80000003), HookXInputSetState },
|
||||
{ (char*)(0x80000004), HookXInputGetCapabilities },
|
||||
}
|
||||
};
|
||||
|
||||
BOOL APIENTRY
|
||||
DllMain(HINSTANCE module, DWORD reason, LPVOID reserved)
|
||||
{
|
||||
if (reason == DLL_PROCESS_ATTACH)
|
||||
{
|
||||
dll = module;
|
||||
|
||||
// disable unwanted thread notifications to reduce overhead
|
||||
DisableThreadLibraryCalls(dll);
|
||||
|
||||
GetModuleFileName(GetModuleHandle(NULL), name, sizeof(name));
|
||||
|
||||
// don't hook synergys (this needs to detect real input)
|
||||
if (string(name).find("synergy") == string::npos)
|
||||
{
|
||||
LOG("checking '" << name << "' for " << XINPUT_DLL);
|
||||
HookAPICalls(&s_xInputHook);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
SetXInputButtons(DWORD userIndex, WORD buttons)
|
||||
{
|
||||
s_buttons = buttons;
|
||||
|
||||
s_packetNumber++;
|
||||
|
||||
LOG("SetXInputButtons: idx=" << userIndex << ", btns=" << buttons);
|
||||
}
|
||||
|
||||
void
|
||||
SetXInputSticks(DWORD userIndex, SHORT lx, SHORT ly, SHORT rx, SHORT ry)
|
||||
{
|
||||
s_leftStickX = lx;
|
||||
s_leftStickY = ly;
|
||||
s_rightStickX = rx;
|
||||
s_rightStickY = ry;
|
||||
|
||||
s_packetNumber++;
|
||||
|
||||
LOG("SetXInputSticks:" <<
|
||||
" l=" << s_leftStickX << "," << s_leftStickY <<
|
||||
" r=" << s_rightStickX << "," << s_rightStickY);
|
||||
}
|
||||
|
||||
void
|
||||
SetXInputTriggers(DWORD userIndex, BYTE left, BYTE right)
|
||||
{
|
||||
s_leftTrigger = left;
|
||||
s_rightTrigger = right;
|
||||
|
||||
s_packetNumber++;
|
||||
|
||||
LOG("SetXInputTriggers: " <<
|
||||
"l=" << (int)left << " r=" << (int)right);
|
||||
}
|
||||
|
||||
void
|
||||
QueueXInputTimingReq()
|
||||
{
|
||||
s_timingReqQueued = TRUE;
|
||||
}
|
||||
|
||||
BOOL
|
||||
DequeueXInputTimingResp()
|
||||
{
|
||||
BOOL result = s_timingRespQueued;
|
||||
s_timingRespQueued = FALSE;
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOL
|
||||
DequeueXInputFeedback(WORD* leftMotor, WORD* rightMotor)
|
||||
{
|
||||
if (s_feedbackQueued)
|
||||
{
|
||||
*leftMotor = s_leftMotor;
|
||||
*rightMotor = s_rightMotor;
|
||||
s_feedbackQueued = FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WORD
|
||||
GetXInputFakeFreqMillis()
|
||||
{
|
||||
return s_fakeFreqMillis;
|
||||
}
|
||||
|
||||
DWORD WINAPI
|
||||
HookXInputGetState(DWORD userIndex, XINPUT_STATE* state)
|
||||
{
|
||||
// @todo multiple device support
|
||||
if (userIndex != 0)
|
||||
{
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
DWORD now = GetTickCount();
|
||||
s_fakeFreqMillis = (WORD)(now - s_lastFakeMillis);
|
||||
s_lastFakeMillis = now;
|
||||
|
||||
state->dwPacketNumber = s_packetNumber;
|
||||
state->Gamepad.wButtons = s_buttons;
|
||||
state->Gamepad.bLeftTrigger = s_leftTrigger;
|
||||
state->Gamepad.bRightTrigger = s_rightTrigger;
|
||||
state->Gamepad.sThumbLX = s_leftStickX;
|
||||
state->Gamepad.sThumbLY = s_leftStickY;
|
||||
state->Gamepad.sThumbRX = s_rightStickX;
|
||||
state->Gamepad.sThumbRY = s_rightStickY;
|
||||
|
||||
LOG("HookXInputGetState"
|
||||
<< ", idx=" << userIndex
|
||||
<< ", pkt=" << state->dwPacketNumber
|
||||
<< ", btn=" << state->Gamepad.wButtons
|
||||
<< ", t1=" << (int)state->Gamepad.bLeftTrigger
|
||||
<< ", t2=" << (int)state->Gamepad.bRightTrigger
|
||||
<< ", s1=" << state->Gamepad.sThumbLX << "," << state->Gamepad.sThumbLY
|
||||
<< ", s2=" << state->Gamepad.sThumbRX << "," << state->Gamepad.sThumbRY);
|
||||
|
||||
if (s_timingReqQueued)
|
||||
{
|
||||
s_timingRespQueued = TRUE;
|
||||
s_timingReqQueued = FALSE;
|
||||
LOG("timing response queued");
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
DWORD WINAPI
|
||||
HookXInputSetState(DWORD userIndex, XINPUT_VIBRATION* vibration)
|
||||
{
|
||||
// @todo multiple device support
|
||||
if (userIndex != 0)
|
||||
{
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
// only change values and queue feedback change if
|
||||
// feedback has actually changed.
|
||||
if ((s_leftMotor != vibration->wLeftMotorSpeed) ||
|
||||
(s_rightMotor != vibration->wRightMotorSpeed))
|
||||
{
|
||||
s_leftMotor = vibration->wLeftMotorSpeed;
|
||||
s_rightMotor = vibration->wRightMotorSpeed;
|
||||
s_feedbackQueued = TRUE;
|
||||
|
||||
LOG("HookXInputSetState"
|
||||
", idx=" << userIndex <<
|
||||
", lm=" << s_leftMotor <<
|
||||
", rm=" << s_rightMotor);
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
DWORD WINAPI
|
||||
HookXInputGetCapabilities(DWORD userIndex, DWORD flags, XINPUT_CAPABILITIES* capabilities)
|
||||
{
|
||||
// @todo multiple device support
|
||||
if (userIndex != 0)
|
||||
{
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
LOG("HookXInputGetCapabilities"
|
||||
", idx=" << userIndex <<
|
||||
", flags=" << flags);
|
||||
|
||||
capabilities->Type = 1;
|
||||
capabilities->SubType = 1;
|
||||
capabilities->Flags = 4;
|
||||
capabilities->Gamepad.bLeftTrigger = 1;
|
||||
capabilities->Gamepad.bRightTrigger = 1;
|
||||
capabilities->Gamepad.sThumbLX = 1;
|
||||
capabilities->Gamepad.sThumbLY = 1;
|
||||
capabilities->Gamepad.sThumbRX = 1;
|
||||
capabilities->Gamepad.sThumbRY = 1;
|
||||
capabilities->Gamepad.wButtons = 62463;
|
||||
capabilities->Vibration.wLeftMotorSpeed = 1;
|
||||
capabilities->Vibration.wRightMotorSpeed = 1;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
synxinhk_API LRESULT CALLBACK
|
||||
HookProc(int code, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
return CallNextHookEx(s_hook, code, wParam, lParam);
|
||||
}
|
||||
|
||||
synxinhk_API BOOL
|
||||
InstallXInputHook()
|
||||
{
|
||||
if (_stricmp(XINPUT_DLL, REQUIRED_XINPUT_DLL) != 0)
|
||||
{
|
||||
LOG("DLL not supported: " << XINPUT_DLL);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
LOG("installing hook");
|
||||
s_hook = SetWindowsHookEx(WH_CBT, HookProc, dll, 0);
|
||||
LOG("hook installed");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
synxinhk_API void
|
||||
RemoveXInputHook()
|
||||
{
|
||||
LOG("removing hook");
|
||||
UnhookWindowsHookEx(s_hook);
|
||||
LOG("hook removed");
|
||||
}
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define SYNERGY_EXPORT_XINPUT_HOOKS
|
||||
#define REQUIRED_XINPUT_DLL "xinput1_3.dll"
|
||||
#define HOOK_TIMEOUT 10000 // 10 sec
|
||||
|
||||
#include <Windows.h>
|
||||
#include <XInput.h>
|
||||
#include "XInputHook.h"
|
||||
#include "HookDLL.h"
|
||||
#include <iostream>
|
||||
|
||||
HINSTANCE dll;
|
||||
char name[256];
|
||||
|
||||
#pragma data_seg(".SHARED")
|
||||
|
||||
HHOOK s_hook = NULL;
|
||||
|
||||
// @todo use a struct for multiple gamepad support
|
||||
WORD s_buttons = 0;
|
||||
SHORT s_leftStickX = 0;
|
||||
SHORT s_leftStickY = 0;
|
||||
SHORT s_rightStickX = 0;
|
||||
SHORT s_rightStickY = 0;
|
||||
BYTE s_leftTrigger = 0;
|
||||
BYTE s_rightTrigger = 0;
|
||||
BOOL s_timingReqQueued = FALSE;
|
||||
BOOL s_timingRespQueued = FALSE;
|
||||
DWORD s_lastFakeMillis = 0;
|
||||
WORD s_fakeFreqMillis = 0;
|
||||
DWORD s_packetNumber = 0;
|
||||
WORD s_leftMotor = 0;
|
||||
WORD s_rightMotor = 0;
|
||||
BOOL s_feedbackQueued = FALSE;
|
||||
|
||||
#pragma data_seg()
|
||||
|
||||
#pragma comment(linker, "/SECTION:.SHARED,RWS")
|
||||
|
||||
#include <sstream>
|
||||
std::stringstream _xInputHookLogStream;
|
||||
#define LOG(s) \
|
||||
_xInputHookLogStream.str(""); \
|
||||
_xInputHookLogStream << "Synergy XInputHook: " << s << endl; \
|
||||
OutputDebugString( _xInputHookLogStream.str().c_str())
|
||||
|
||||
using namespace std;
|
||||
|
||||
SDLLHook s_xInputHook =
|
||||
{
|
||||
XINPUT_DLL,
|
||||
false, NULL,
|
||||
{
|
||||
{ (char*)(0x80000002), HookXInputGetState },
|
||||
{ (char*)(0x80000003), HookXInputSetState },
|
||||
{ (char*)(0x80000004), HookXInputGetCapabilities },
|
||||
}
|
||||
};
|
||||
|
||||
BOOL APIENTRY
|
||||
DllMain(HINSTANCE module, DWORD reason, LPVOID reserved)
|
||||
{
|
||||
if (reason == DLL_PROCESS_ATTACH)
|
||||
{
|
||||
dll = module;
|
||||
|
||||
// disable unwanted thread notifications to reduce overhead
|
||||
DisableThreadLibraryCalls(dll);
|
||||
|
||||
GetModuleFileName(GetModuleHandle(NULL), name, sizeof(name));
|
||||
|
||||
// don't hook synergys (this needs to detect real input)
|
||||
if (string(name).find("synergy") == string::npos)
|
||||
{
|
||||
LOG("checking '" << name << "' for " << XINPUT_DLL);
|
||||
HookAPICalls(&s_xInputHook);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
SetXInputButtons(DWORD userIndex, WORD buttons)
|
||||
{
|
||||
s_buttons = buttons;
|
||||
|
||||
s_packetNumber++;
|
||||
|
||||
LOG("SetXInputButtons: idx=" << userIndex << ", btns=" << buttons);
|
||||
}
|
||||
|
||||
void
|
||||
SetXInputSticks(DWORD userIndex, SHORT lx, SHORT ly, SHORT rx, SHORT ry)
|
||||
{
|
||||
s_leftStickX = lx;
|
||||
s_leftStickY = ly;
|
||||
s_rightStickX = rx;
|
||||
s_rightStickY = ry;
|
||||
|
||||
s_packetNumber++;
|
||||
|
||||
LOG("SetXInputSticks:" <<
|
||||
" l=" << s_leftStickX << "," << s_leftStickY <<
|
||||
" r=" << s_rightStickX << "," << s_rightStickY);
|
||||
}
|
||||
|
||||
void
|
||||
SetXInputTriggers(DWORD userIndex, BYTE left, BYTE right)
|
||||
{
|
||||
s_leftTrigger = left;
|
||||
s_rightTrigger = right;
|
||||
|
||||
s_packetNumber++;
|
||||
|
||||
LOG("SetXInputTriggers: " <<
|
||||
"l=" << (int)left << " r=" << (int)right);
|
||||
}
|
||||
|
||||
void
|
||||
QueueXInputTimingReq()
|
||||
{
|
||||
s_timingReqQueued = TRUE;
|
||||
}
|
||||
|
||||
BOOL
|
||||
DequeueXInputTimingResp()
|
||||
{
|
||||
BOOL result = s_timingRespQueued;
|
||||
s_timingRespQueued = FALSE;
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOL
|
||||
DequeueXInputFeedback(WORD* leftMotor, WORD* rightMotor)
|
||||
{
|
||||
if (s_feedbackQueued)
|
||||
{
|
||||
*leftMotor = s_leftMotor;
|
||||
*rightMotor = s_rightMotor;
|
||||
s_feedbackQueued = FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WORD
|
||||
GetXInputFakeFreqMillis()
|
||||
{
|
||||
return s_fakeFreqMillis;
|
||||
}
|
||||
|
||||
DWORD WINAPI
|
||||
HookXInputGetState(DWORD userIndex, XINPUT_STATE* state)
|
||||
{
|
||||
// @todo multiple device support
|
||||
if (userIndex != 0)
|
||||
{
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
DWORD now = GetTickCount();
|
||||
s_fakeFreqMillis = (WORD)(now - s_lastFakeMillis);
|
||||
s_lastFakeMillis = now;
|
||||
|
||||
state->dwPacketNumber = s_packetNumber;
|
||||
state->Gamepad.wButtons = s_buttons;
|
||||
state->Gamepad.bLeftTrigger = s_leftTrigger;
|
||||
state->Gamepad.bRightTrigger = s_rightTrigger;
|
||||
state->Gamepad.sThumbLX = s_leftStickX;
|
||||
state->Gamepad.sThumbLY = s_leftStickY;
|
||||
state->Gamepad.sThumbRX = s_rightStickX;
|
||||
state->Gamepad.sThumbRY = s_rightStickY;
|
||||
|
||||
LOG("HookXInputGetState"
|
||||
<< ", idx=" << userIndex
|
||||
<< ", pkt=" << state->dwPacketNumber
|
||||
<< ", btn=" << state->Gamepad.wButtons
|
||||
<< ", t1=" << (int)state->Gamepad.bLeftTrigger
|
||||
<< ", t2=" << (int)state->Gamepad.bRightTrigger
|
||||
<< ", s1=" << state->Gamepad.sThumbLX << "," << state->Gamepad.sThumbLY
|
||||
<< ", s2=" << state->Gamepad.sThumbRX << "," << state->Gamepad.sThumbRY);
|
||||
|
||||
if (s_timingReqQueued)
|
||||
{
|
||||
s_timingRespQueued = TRUE;
|
||||
s_timingReqQueued = FALSE;
|
||||
LOG("timing response queued");
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
DWORD WINAPI
|
||||
HookXInputSetState(DWORD userIndex, XINPUT_VIBRATION* vibration)
|
||||
{
|
||||
// @todo multiple device support
|
||||
if (userIndex != 0)
|
||||
{
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
// only change values and queue feedback change if
|
||||
// feedback has actually changed.
|
||||
if ((s_leftMotor != vibration->wLeftMotorSpeed) ||
|
||||
(s_rightMotor != vibration->wRightMotorSpeed))
|
||||
{
|
||||
s_leftMotor = vibration->wLeftMotorSpeed;
|
||||
s_rightMotor = vibration->wRightMotorSpeed;
|
||||
s_feedbackQueued = TRUE;
|
||||
|
||||
LOG("HookXInputSetState"
|
||||
", idx=" << userIndex <<
|
||||
", lm=" << s_leftMotor <<
|
||||
", rm=" << s_rightMotor);
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
DWORD WINAPI
|
||||
HookXInputGetCapabilities(DWORD userIndex, DWORD flags, XINPUT_CAPABILITIES* capabilities)
|
||||
{
|
||||
// @todo multiple device support
|
||||
if (userIndex != 0)
|
||||
{
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
LOG("HookXInputGetCapabilities"
|
||||
", idx=" << userIndex <<
|
||||
", flags=" << flags);
|
||||
|
||||
capabilities->Type = 1;
|
||||
capabilities->SubType = 1;
|
||||
capabilities->Flags = 4;
|
||||
capabilities->Gamepad.bLeftTrigger = 1;
|
||||
capabilities->Gamepad.bRightTrigger = 1;
|
||||
capabilities->Gamepad.sThumbLX = 1;
|
||||
capabilities->Gamepad.sThumbLY = 1;
|
||||
capabilities->Gamepad.sThumbRX = 1;
|
||||
capabilities->Gamepad.sThumbRY = 1;
|
||||
capabilities->Gamepad.wButtons = 62463;
|
||||
capabilities->Vibration.wLeftMotorSpeed = 1;
|
||||
capabilities->Vibration.wRightMotorSpeed = 1;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
synxinhk_API LRESULT CALLBACK
|
||||
HookProc(int code, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
return CallNextHookEx(s_hook, code, wParam, lParam);
|
||||
}
|
||||
|
||||
synxinhk_API BOOL
|
||||
InstallXInputHook()
|
||||
{
|
||||
if (_stricmp(XINPUT_DLL, REQUIRED_XINPUT_DLL) != 0)
|
||||
{
|
||||
LOG("DLL not supported: " << XINPUT_DLL);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
LOG("installing hook");
|
||||
s_hook = SetWindowsHookEx(WH_CBT, HookProc, dll, 0);
|
||||
LOG("hook installed");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
synxinhk_API void
|
||||
RemoveXInputHook()
|
||||
{
|
||||
LOG("removing hook");
|
||||
UnhookWindowsHookEx(s_hook);
|
||||
LOG("hook removed");
|
||||
}
|
||||
|
|
|
@ -1,44 +1,44 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012 Bolton Software Ltd.
|
||||
* Copyright (C) 2011 Chris Schoeneman
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef synxinhk_EXPORTS
|
||||
#define synxinhk_API __declspec(dllexport)
|
||||
#else
|
||||
#define synxinhk_API __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
synxinhk_API LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam);
|
||||
synxinhk_API BOOL InstallXInputHook();
|
||||
synxinhk_API void RemoveXInputHook();
|
||||
synxinhk_API void SetXInputButtons(DWORD userIndex, WORD buttons);
|
||||
synxinhk_API void SetXInputSticks(DWORD userIndex, SHORT lx, SHORT ly, SHORT rx, SHORT ry);
|
||||
synxinhk_API void SetXInputTriggers(DWORD userIndex, BYTE left, BYTE right);
|
||||
synxinhk_API void QueueXInputTimingReq();
|
||||
synxinhk_API BOOL DequeueXInputTimingResp();
|
||||
synxinhk_API WORD GetXInputFakeFreqMillis();
|
||||
synxinhk_API BOOL DequeueXInputFeedback(WORD* leftMotor, WORD* rightMotor);
|
||||
|
||||
#ifdef SYNERGY_EXPORT_XINPUT_HOOKS
|
||||
|
||||
synxinhk_API DWORD WINAPI HookXInputGetState(DWORD dwUserIndex, XINPUT_STATE* pState);
|
||||
synxinhk_API DWORD WINAPI HookXInputSetState(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration);
|
||||
synxinhk_API DWORD WINAPI HookXInputGetCapabilities(DWORD userIndex, DWORD flags, XINPUT_CAPABILITIES* capabilities);
|
||||
|
||||
#endif
|
||||
* Copyright (C) 2011 Chris Schoeneman
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef synxinhk_EXPORTS
|
||||
#define synxinhk_API __declspec(dllexport)
|
||||
#else
|
||||
#define synxinhk_API __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
synxinhk_API LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam);
|
||||
synxinhk_API BOOL InstallXInputHook();
|
||||
synxinhk_API void RemoveXInputHook();
|
||||
synxinhk_API void SetXInputButtons(DWORD userIndex, WORD buttons);
|
||||
synxinhk_API void SetXInputSticks(DWORD userIndex, SHORT lx, SHORT ly, SHORT rx, SHORT ry);
|
||||
synxinhk_API void SetXInputTriggers(DWORD userIndex, BYTE left, BYTE right);
|
||||
synxinhk_API void QueueXInputTimingReq();
|
||||
synxinhk_API BOOL DequeueXInputTimingResp();
|
||||
synxinhk_API WORD GetXInputFakeFreqMillis();
|
||||
synxinhk_API BOOL DequeueXInputFeedback(WORD* leftMotor, WORD* rightMotor);
|
||||
|
||||
#ifdef SYNERGY_EXPORT_XINPUT_HOOKS
|
||||
|
||||
synxinhk_API DWORD WINAPI HookXInputGetState(DWORD dwUserIndex, XINPUT_STATE* pState);
|
||||
synxinhk_API DWORD WINAPI HookXInputSetState(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration);
|
||||
synxinhk_API DWORD WINAPI HookXInputGetCapabilities(DWORD userIndex, DWORD flags, XINPUT_CAPABILITIES* capabilities);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
#define SYNERGY_EXPORT_XINPUT_HOOKS
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
|
||||
#include <Windows.h>
|
||||
#include "XInputProxy13.h"
|
||||
#include "XInputHook.h"
|
||||
|
@ -31,43 +31,43 @@
|
|||
#pragma comment(linker, "/EXPORT:XInputGetBatteryInformation=_XInputGetBatteryInformation@12,@7")
|
||||
#pragma comment(linker, "/EXPORT:XInputGetKeystroke=_XInputGetKeystroke@12,@8")
|
||||
|
||||
sxinpx13_API DWORD WINAPI
|
||||
XInputGetState(DWORD dwUserIndex, XINPUT_STATE* pState)
|
||||
{
|
||||
return HookXInputGetState(dwUserIndex, pState);
|
||||
}
|
||||
|
||||
sxinpx13_API DWORD WINAPI
|
||||
XInputSetState(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration)
|
||||
{
|
||||
return HookXInputSetState(dwUserIndex, pVibration);
|
||||
}
|
||||
|
||||
sxinpx13_API DWORD WINAPI
|
||||
XInputGetCapabilities(DWORD dwUserIndex, DWORD dwFlags, XINPUT_CAPABILITIES* pCapabilities)
|
||||
{
|
||||
return HookXInputGetCapabilities(dwUserIndex, dwFlags, pCapabilities);
|
||||
}
|
||||
|
||||
sxinpx13_API void WINAPI
|
||||
XInputEnable(BOOL enable)
|
||||
{
|
||||
}
|
||||
|
||||
sxinpx13_API DWORD WINAPI
|
||||
XInputGetDSoundAudioDeviceGuids(DWORD dwUserIndex, GUID* pDSoundRenderGuid, GUID* pDSoundCaptureGuid)
|
||||
{
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
sxinpx13_API DWORD WINAPI
|
||||
XInputGetBatteryInformation(DWORD dwUserIndex, BYTE devType, XINPUT_BATTERY_INFORMATION* pBatteryInformation)
|
||||
{
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
sxinpx13_API DWORD WINAPI
|
||||
XInputGetKeystroke(DWORD dwUserIndex, DWORD dwReserved, PXINPUT_KEYSTROKE pKeystroke)
|
||||
{
|
||||
XInputGetState(DWORD dwUserIndex, XINPUT_STATE* pState)
|
||||
{
|
||||
return HookXInputGetState(dwUserIndex, pState);
|
||||
}
|
||||
|
||||
sxinpx13_API DWORD WINAPI
|
||||
XInputSetState(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration)
|
||||
{
|
||||
return HookXInputSetState(dwUserIndex, pVibration);
|
||||
}
|
||||
|
||||
sxinpx13_API DWORD WINAPI
|
||||
XInputGetCapabilities(DWORD dwUserIndex, DWORD dwFlags, XINPUT_CAPABILITIES* pCapabilities)
|
||||
{
|
||||
return HookXInputGetCapabilities(dwUserIndex, dwFlags, pCapabilities);
|
||||
}
|
||||
|
||||
sxinpx13_API void WINAPI
|
||||
XInputEnable(BOOL enable)
|
||||
{
|
||||
}
|
||||
|
||||
sxinpx13_API DWORD WINAPI
|
||||
XInputGetDSoundAudioDeviceGuids(DWORD dwUserIndex, GUID* pDSoundRenderGuid, GUID* pDSoundCaptureGuid)
|
||||
{
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
sxinpx13_API DWORD WINAPI
|
||||
XInputGetBatteryInformation(DWORD dwUserIndex, BYTE devType, XINPUT_BATTERY_INFORMATION* pBatteryInformation)
|
||||
{
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
sxinpx13_API DWORD WINAPI
|
||||
XInputGetKeystroke(DWORD dwUserIndex, DWORD dwReserved, PXINPUT_KEYSTROKE pKeystroke)
|
||||
{
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
|
|
|
@ -14,67 +14,67 @@
|
|||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef sxinpx13_EXPORTS
|
||||
#define sxinpx13_API __declspec(dllexport)
|
||||
#else
|
||||
#define sxinpx13_API __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
#include "XInput13.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
sxinpx13_API DWORD WINAPI XInputGetState
|
||||
(
|
||||
__in DWORD dwUserIndex, // Index of the gamer associated with the device
|
||||
__out XINPUT_STATE* pState // Receives the current state
|
||||
);
|
||||
|
||||
sxinpx13_API DWORD WINAPI XInputSetState
|
||||
(
|
||||
__in DWORD dwUserIndex, // Index of the gamer associated with the device
|
||||
__in XINPUT_VIBRATION* pVibration // The vibration information to send to the controller
|
||||
);
|
||||
|
||||
sxinpx13_API DWORD WINAPI XInputGetCapabilities
|
||||
(
|
||||
__in DWORD dwUserIndex, // Index of the gamer associated with the device
|
||||
__in DWORD dwFlags, // Input flags that identify the device type
|
||||
__out XINPUT_CAPABILITIES* pCapabilities // Receives the capabilities
|
||||
);
|
||||
|
||||
sxinpx13_API void WINAPI XInputEnable
|
||||
(
|
||||
__in BOOL enable // [in] Indicates whether xinput is enabled or disabled.
|
||||
);
|
||||
|
||||
sxinpx13_API DWORD WINAPI XInputGetDSoundAudioDeviceGuids
|
||||
(
|
||||
__in DWORD dwUserIndex, // Index of the gamer associated with the device
|
||||
__out GUID* pDSoundRenderGuid, // DSound device ID for render
|
||||
__out GUID* pDSoundCaptureGuid // DSound device ID for capture
|
||||
);
|
||||
|
||||
sxinpx13_API DWORD WINAPI XInputGetBatteryInformation
|
||||
(
|
||||
__in DWORD dwUserIndex, // Index of the gamer associated with the device
|
||||
__in BYTE devType, // Which device on this user index
|
||||
__out XINPUT_BATTERY_INFORMATION* pBatteryInformation // Contains the level and types of batteries
|
||||
);
|
||||
|
||||
sxinpx13_API DWORD WINAPI XInputGetKeystroke
|
||||
(
|
||||
__in DWORD dwUserIndex, // Index of the gamer associated with the device
|
||||
__reserved DWORD dwReserved, // Reserved for future use
|
||||
__out PXINPUT_KEYSTROKE pKeystroke // Pointer to an XINPUT_KEYSTROKE structure that receives an input event.
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef sxinpx13_EXPORTS
|
||||
#define sxinpx13_API __declspec(dllexport)
|
||||
#else
|
||||
#define sxinpx13_API __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
#include "XInput13.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
sxinpx13_API DWORD WINAPI XInputGetState
|
||||
(
|
||||
__in DWORD dwUserIndex, // Index of the gamer associated with the device
|
||||
__out XINPUT_STATE* pState // Receives the current state
|
||||
);
|
||||
|
||||
sxinpx13_API DWORD WINAPI XInputSetState
|
||||
(
|
||||
__in DWORD dwUserIndex, // Index of the gamer associated with the device
|
||||
__in XINPUT_VIBRATION* pVibration // The vibration information to send to the controller
|
||||
);
|
||||
|
||||
sxinpx13_API DWORD WINAPI XInputGetCapabilities
|
||||
(
|
||||
__in DWORD dwUserIndex, // Index of the gamer associated with the device
|
||||
__in DWORD dwFlags, // Input flags that identify the device type
|
||||
__out XINPUT_CAPABILITIES* pCapabilities // Receives the capabilities
|
||||
);
|
||||
|
||||
sxinpx13_API void WINAPI XInputEnable
|
||||
(
|
||||
__in BOOL enable // [in] Indicates whether xinput is enabled or disabled.
|
||||
);
|
||||
|
||||
sxinpx13_API DWORD WINAPI XInputGetDSoundAudioDeviceGuids
|
||||
(
|
||||
__in DWORD dwUserIndex, // Index of the gamer associated with the device
|
||||
__out GUID* pDSoundRenderGuid, // DSound device ID for render
|
||||
__out GUID* pDSoundCaptureGuid // DSound device ID for capture
|
||||
);
|
||||
|
||||
sxinpx13_API DWORD WINAPI XInputGetBatteryInformation
|
||||
(
|
||||
__in DWORD dwUserIndex, // Index of the gamer associated with the device
|
||||
__in BYTE devType, // Which device on this user index
|
||||
__out XINPUT_BATTERY_INFORMATION* pBatteryInformation // Contains the level and types of batteries
|
||||
);
|
||||
|
||||
sxinpx13_API DWORD WINAPI XInputGetKeystroke
|
||||
(
|
||||
__in DWORD dwUserIndex, // Index of the gamer associated with the device
|
||||
__reserved DWORD dwReserved, // Reserved for future use
|
||||
__out PXINPUT_KEYSTROKE pKeystroke // Pointer to an XINPUT_KEYSTROKE structure that receives an input event.
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -42,7 +42,6 @@ protected:
|
|||
private:
|
||||
void handleKeepAlive(const CEvent&, void*);
|
||||
|
||||
|
||||
private:
|
||||
double m_keepAliveRate;
|
||||
CEventQueueTimer* m_keepAliveTimer;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -19,13 +19,15 @@
|
|||
#include "CProtocolUtil.h"
|
||||
#include "CLog.h"
|
||||
#include "IStream.h"
|
||||
#include "CServer.h"
|
||||
|
||||
//
|
||||
// CClientProxy1_5
|
||||
//
|
||||
|
||||
CClientProxy1_5::CClientProxy1_5(const CString& name, synergy::IStream* stream, CServer* server, IEventQueue* events) :
|
||||
CClientProxy1_4(name, stream, server, events)
|
||||
CClientProxy1_4(name, stream, server, events),
|
||||
m_events(events)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -34,23 +36,64 @@ CClientProxy1_5::~CClientProxy1_5()
|
|||
}
|
||||
|
||||
void
|
||||
CClientProxy1_5::fileChunkSending(UInt8 mark, const UInt8* data)
|
||||
CClientProxy1_5::fileChunkSending(UInt8 mark, char* data, size_t dataSize)
|
||||
{
|
||||
CString chunk(reinterpret_cast<const char*>(data));
|
||||
CString chunk(data, dataSize);
|
||||
|
||||
switch (mark) {
|
||||
case '0':
|
||||
LOG((CLOG_DEBUG2 "file sending start: file size = %s", data));
|
||||
case kFileStart:
|
||||
LOG((CLOG_DEBUG2 "file sending start: size=%s", data));
|
||||
break;
|
||||
|
||||
case '1':
|
||||
LOG((CLOG_DEBUG2 "file chunk sending: %s", data));
|
||||
case kFileChunk:
|
||||
LOG((CLOG_DEBUG2 "file chunk sending: size=%i", chunk.size()));
|
||||
break;
|
||||
|
||||
case '2':
|
||||
case kFileEnd:
|
||||
LOG((CLOG_DEBUG2 "file sending finished"));
|
||||
break;
|
||||
}
|
||||
|
||||
CProtocolUtil::writef(getStream(), kMsgDFileTransfer, mark, &chunk);
|
||||
}
|
||||
|
||||
bool
|
||||
CClientProxy1_5::parseMessage(const UInt8* code)
|
||||
{
|
||||
if (memcmp(code, kMsgDFileTransfer, 4) == 0) {
|
||||
fileChunkReceived();
|
||||
}
|
||||
else {
|
||||
return CClientProxy1_4::parseMessage(code);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CClientProxy1_5::fileChunkReceived()
|
||||
{
|
||||
// parse
|
||||
UInt8 mark;
|
||||
CString content;
|
||||
CProtocolUtil::readf(getStream(), kMsgDFileTransfer + 4, &mark, &content);
|
||||
|
||||
CServer* server = getServer();
|
||||
switch (mark) {
|
||||
case kFileStart:
|
||||
LOG((CLOG_DEBUG2 "recv file data from client: file size=%s", content.c_str()));
|
||||
server->clearReceivedFileData();
|
||||
server->setExpectedFileSize(content);
|
||||
break;
|
||||
|
||||
case kFileChunk:
|
||||
LOG((CLOG_DEBUG2 "recv file data from client: chunck size=%i", content.size()));
|
||||
server->fileChunkReceived(content);
|
||||
break;
|
||||
|
||||
case kFileEnd:
|
||||
LOG((CLOG_DEBUG2 "file data transfer finished"));
|
||||
m_events->addEvent(CEvent(m_events->forIScreen().fileRecieveComplete(), server));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -33,14 +33,22 @@
|
|||
#include "TMethodEventJob.h"
|
||||
#include "CArch.h"
|
||||
#include "CKeyState.h"
|
||||
#include "CScreen.h"
|
||||
#include "CThread.h"
|
||||
#include "TMethodJob.h"
|
||||
#include "CFileChunker.h"
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include "CScreen.h"
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
//
|
||||
// CServer
|
||||
//
|
||||
|
||||
const size_t CServer::m_chunkSize = 1024 * 512; // 512kb
|
||||
|
||||
CServer::CServer(CConfig& config, CPrimaryClient* primaryClient, CScreen* screen, IEventQueue* events) :
|
||||
m_events(events),
|
||||
m_mock(false),
|
||||
|
@ -177,6 +185,10 @@ CServer::CServer(CConfig& config, CPrimaryClient* primaryClient, CScreen* screen
|
|||
this,
|
||||
new TMethodEventJob<CServer>(this,
|
||||
&CServer::handleFileChunkSendingEvent));
|
||||
m_events->adoptHandler(m_events->forIScreen().fileRecieveComplete(),
|
||||
this,
|
||||
new TMethodEventJob<CServer>(this,
|
||||
&CServer::handleFileRecieveCompleteEvent));
|
||||
|
||||
// add connection
|
||||
addClient(m_primaryClient);
|
||||
|
@ -1516,8 +1528,13 @@ CServer::handleFakeInputEndEvent(const CEvent&, void*)
|
|||
void
|
||||
CServer::handleFileChunkSendingEvent(const CEvent& event, void*)
|
||||
{
|
||||
UInt8* data = reinterpret_cast<UInt8*>(event.getData());
|
||||
onFileChunkSending(data);
|
||||
onFileChunkSending(event.getData());
|
||||
}
|
||||
|
||||
void
|
||||
CServer::handleFileRecieveCompleteEvent(const CEvent& event, void*)
|
||||
{
|
||||
onFileRecieveComplete();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1981,13 +1998,32 @@ CServer::onGameDeviceTimingReq()
|
|||
}
|
||||
|
||||
void
|
||||
CServer::onFileChunkSending(const UInt8* data)
|
||||
CServer::onFileChunkSending(const void* data)
|
||||
{
|
||||
CFileChunker::CFileChunk* fileChunk = reinterpret_cast<CFileChunker::CFileChunk*>(const_cast<void*>(data));
|
||||
|
||||
LOG((CLOG_DEBUG1 "onFileChunkSending"));
|
||||
assert(m_active != NULL);
|
||||
|
||||
// relay
|
||||
m_active->fileChunkSending(data[0], &data[1]);
|
||||
m_active->fileChunkSending(fileChunk->m_chunk[0], &(fileChunk->m_chunk[1]), fileChunk->m_dataSize);
|
||||
}
|
||||
|
||||
void
|
||||
CServer::onFileRecieveComplete()
|
||||
{
|
||||
if (isReceivedFileSizeValid()) {
|
||||
if (!m_fileTransferDes.empty()) {
|
||||
std::fstream file;
|
||||
file.open(m_fileTransferDes.c_str(), std::ios::out | std::ios::binary);
|
||||
if (!file.is_open()) {
|
||||
// TODO: file open failed
|
||||
}
|
||||
|
||||
file.write(m_receivedFileData.c_str(), m_receivedFileData.size());
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -2260,3 +2296,49 @@ CServer::CKeyboardBroadcastInfo::alloc(State state, const CString& screens)
|
|||
strcpy(info->m_screens, screens.c_str());
|
||||
return info;
|
||||
}
|
||||
|
||||
void
|
||||
CServer::clearReceivedFileData()
|
||||
{
|
||||
m_receivedFileData.clear();
|
||||
}
|
||||
|
||||
void
|
||||
CServer::setExpectedFileSize(CString data)
|
||||
{
|
||||
std::istringstream iss(data);
|
||||
iss >> m_expectedFileSize;
|
||||
}
|
||||
|
||||
void
|
||||
CServer::fileChunkReceived(CString data)
|
||||
{
|
||||
m_receivedFileData += data;
|
||||
}
|
||||
|
||||
bool
|
||||
CServer::isReceivedFileSizeValid()
|
||||
{
|
||||
return m_expectedFileSize == m_receivedFileData.size();
|
||||
}
|
||||
|
||||
void
|
||||
CServer::sendFileToClient(const char* filename)
|
||||
{
|
||||
CThread* thread = new CThread(
|
||||
new TMethodJob<CServer>(
|
||||
this, &CServer::sendFileThread,
|
||||
reinterpret_cast<void*>(const_cast<char*>(filename))));
|
||||
}
|
||||
|
||||
void
|
||||
CServer::sendFileThread(void* filename)
|
||||
{
|
||||
try {
|
||||
char* name = reinterpret_cast<char*>(filename);
|
||||
CFileChunker::sendFileChunks(name, m_events, this);
|
||||
}
|
||||
catch (std::runtime_error error) {
|
||||
LOG((CLOG_ERR "failed sending file chunks: %s", error.what()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -144,6 +144,21 @@ public:
|
|||
//! Notify of game device feedback
|
||||
void gameDeviceFeedback(GameDeviceID id, UInt16 m1, UInt16 m2);
|
||||
|
||||
//! Clears the file buffer
|
||||
void clearReceivedFileData();
|
||||
|
||||
//! Set the expected size of receiving file
|
||||
void setExpectedFileSize(CString data);
|
||||
|
||||
//! Set
|
||||
void setFileTransferDes(CString& des) { m_fileTransferDes = des; }
|
||||
|
||||
//! Received a chunk of file data
|
||||
void fileChunkReceived(CString data);
|
||||
|
||||
//! Create a new thread and use it to send file to client
|
||||
void sendFileToClient(const char* filename);
|
||||
|
||||
//@}
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
@ -159,6 +174,9 @@ public:
|
|||
Set the \c list to the names of the currently connected clients.
|
||||
*/
|
||||
void getClients(std::vector<CString>& list) const;
|
||||
|
||||
//! Return true if recieved file size is valid
|
||||
bool isReceivedFileSizeValid();
|
||||
|
||||
//@}
|
||||
|
||||
|
@ -299,6 +317,7 @@ private:
|
|||
void handleFakeInputBeginEvent(const CEvent&, void*);
|
||||
void handleFakeInputEndEvent(const CEvent&, void*);
|
||||
void handleFileChunkSendingEvent(const CEvent&, void*);
|
||||
void handleFileRecieveCompleteEvent(const CEvent&, void*);
|
||||
|
||||
// event processing
|
||||
void onClipboardChanged(CBaseClientProxy* sender,
|
||||
|
@ -318,7 +337,8 @@ private:
|
|||
void onGameDeviceSticks(GameDeviceID id, SInt16 x1, SInt16 y1, SInt16 x2, SInt16 y2);
|
||||
void onGameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2);
|
||||
void onGameDeviceTimingReq();
|
||||
void onFileChunkSending(const UInt8* data);
|
||||
void onFileChunkSending(const void* data);
|
||||
void onFileRecieveComplete();
|
||||
|
||||
// add client to list and attach event handlers for client
|
||||
bool addClient(CBaseClientProxy*);
|
||||
|
@ -343,6 +363,9 @@ private:
|
|||
// force the cursor off of \p client
|
||||
void forceLeaveClient(CBaseClientProxy* client);
|
||||
|
||||
// thread funciton for sending file
|
||||
void sendFileThread(void*);
|
||||
|
||||
public:
|
||||
bool m_mock;
|
||||
|
||||
|
@ -438,6 +461,13 @@ private:
|
|||
CScreen* m_screen;
|
||||
|
||||
IEventQueue* m_events;
|
||||
|
||||
// file transfer
|
||||
size_t m_expectedFileSize;
|
||||
CString m_receivedFileData;
|
||||
static const size_t m_chunkSize;
|
||||
CString m_fileTransferSrc;
|
||||
CString m_fileTransferDes;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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."
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2013 Bolton Software Ltd.
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CFileChunker.h"
|
||||
#include "BasicTypes.h"
|
||||
#include "ProtocolTypes.h"
|
||||
#include "CEvent.h"
|
||||
#include "IEventQueue.h"
|
||||
#include "CEventTypes.h"
|
||||
#include "CLOG.h"
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
const size_t CFileChunker::m_chunkSize = 512 * 1024; // 512kb
|
||||
|
||||
void
|
||||
CFileChunker::sendFileChunks(char* filename, IEventQueue* events, void* eventTarget)
|
||||
{
|
||||
std::fstream file(reinterpret_cast<char*>(filename), std::ios::in | std::ios::binary);
|
||||
|
||||
if (!file.is_open()) {
|
||||
throw runtime_error("failed to open file");
|
||||
}
|
||||
|
||||
// check file size
|
||||
file.seekg (0, std::ios::end);
|
||||
size_t size = (size_t)file.tellg();
|
||||
|
||||
// send first message (file size)
|
||||
CString fileSize = intToString(size);
|
||||
UInt32 sizeLength = fileSize.size();
|
||||
CFileChunk* sizeMessage = new CFileChunk(sizeLength + 2);
|
||||
char* chunkData = sizeMessage->m_chunk;
|
||||
|
||||
chunkData[0] = kFileStart;
|
||||
memcpy(&chunkData[1], fileSize.c_str(), sizeLength);
|
||||
chunkData[sizeLength + 1] = '\0';
|
||||
events->addEvent(CEvent(events->forIScreen().fileChunkSending(), eventTarget, sizeMessage));
|
||||
|
||||
// send chunk messages with a fixed chunk size
|
||||
size_t sentLength = 0;
|
||||
size_t chunkSize = m_chunkSize;
|
||||
file.seekg (0, std::ios::beg);
|
||||
while (true) {
|
||||
// make sure we don't read too much from the mock data.
|
||||
if (sentLength + chunkSize > size) {
|
||||
chunkSize = size - sentLength;
|
||||
}
|
||||
|
||||
// for fileChunk->m_chunk, the first byte is the chunk mark, last is \0
|
||||
CFileChunk* fileChunk = new CFileChunk(chunkSize + 2);
|
||||
char* chunkData = fileChunk->m_chunk;
|
||||
|
||||
chunkData[0] = kFileChunk;
|
||||
file.read(&chunkData[1], chunkSize);
|
||||
chunkData[chunkSize + 1] = '\0';
|
||||
events->addEvent(CEvent(events->forIScreen().fileChunkSending(), eventTarget, fileChunk));
|
||||
|
||||
sentLength += chunkSize;
|
||||
file.seekg (sentLength, std::ios::beg);
|
||||
|
||||
if (sentLength == size) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// send last message
|
||||
CFileChunk* transferFinished = new CFileChunk(2);
|
||||
chunkData = transferFinished->m_chunk;
|
||||
|
||||
chunkData[0] = kFileEnd;
|
||||
chunkData[1] = '\0';
|
||||
events->addEvent(CEvent(events->forIScreen().fileChunkSending(), eventTarget, transferFinished));
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
||||
CString
|
||||
CFileChunker::intToString(size_t i)
|
||||
{
|
||||
stringstream ss;
|
||||
ss << i;
|
||||
return ss.str();
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2013 Bolton Software Ltd.
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CString.h"
|
||||
|
||||
class IEventQueue;
|
||||
|
||||
class CFileChunker {
|
||||
public:
|
||||
//! FileChunk data
|
||||
class CFileChunk {
|
||||
public:
|
||||
CFileChunk(size_t chunkSize) : m_dataSize(chunkSize - 2)
|
||||
{
|
||||
m_chunk = new char[chunkSize];
|
||||
}
|
||||
|
||||
~CFileChunk() { delete[] m_chunk; }
|
||||
|
||||
public:
|
||||
const size_t m_dataSize;
|
||||
char* m_chunk;
|
||||
};
|
||||
|
||||
static void sendFileChunks(char* filename, IEventQueue* events, void* eventTarget);
|
||||
static CString intToString(size_t i);
|
||||
|
||||
private:
|
||||
static const size_t m_chunkSize;
|
||||
};
|
|
@ -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()
|
||||
|
|
|
@ -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*);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,420 +1,420 @@
|
|||
/*
|
||||
uSynergy client -- Interface for the embedded Synergy client library
|
||||
version 1.0.0, July 7th, 2012
|
||||
|
||||
/*
|
||||
uSynergy client -- Interface for the embedded Synergy client library
|
||||
version 1.0.0, July 7th, 2012
|
||||
|
||||
Copyright (C) 2012 Bolton Software Ltd.
|
||||
Copyright (c) 2012 Alex Evans
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Configuration
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Determine endianness
|
||||
**/
|
||||
#if defined(USYNERGY_LITTLE_ENDIAN) && defined(USYNERGY_BIG_ENDIAN)
|
||||
/* Ambiguous: both endians specified */
|
||||
#error "Can't define both USYNERGY_LITTLE_ENDIAN and USYNERGY_BIG_ENDIAN"
|
||||
#elif !defined(USYNERGY_LITTLE_ENDIAN) && !defined(USYNERGY_BIG_ENDIAN)
|
||||
/* Attempt to auto detect */
|
||||
#if defined(__LITTLE_ENDIAN__) || defined(LITTLE_ENDIAN) || (_BYTE_ORDER == _LITTLE_ENDIAN)
|
||||
#define USYNERGY_LITTLE_ENDIAN
|
||||
#elif defined(__BIG_ENDIAN__) || defined(BIG_ENDIAN) || (_BYTE_ORDER == _BIG_ENDIAN)
|
||||
#define USYNERGY_BIG_ENDIAN
|
||||
#else
|
||||
#error "Can't detect endian-nes, please defined either USYNERGY_LITTLE_ENDIAN or USYNERGY_BIG_ENDIAN";
|
||||
#endif
|
||||
#else
|
||||
/* User-specified endian-nes, nothing to do for us */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Types and Constants
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Boolean type
|
||||
**/
|
||||
typedef int uSynergyBool;
|
||||
#define USYNERGY_FALSE 0 /* False value */
|
||||
#define USYNERGY_TRUE 1 /* True value */
|
||||
|
||||
|
||||
/**
|
||||
@brief User context type
|
||||
|
||||
The uSynergyCookie type is an opaque type that is used by uSynergy to communicate to the client. It is passed along to
|
||||
callback functions as context.
|
||||
**/
|
||||
typedef struct { int ignored; } * uSynergyCookie;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Clipboard types
|
||||
**/
|
||||
enum uSynergyClipboardFormat
|
||||
{
|
||||
USYNERGY_CLIPBOARD_FORMAT_TEXT = 0, /* Text format, UTF-8, newline is LF */
|
||||
USYNERGY_CLIPBOARD_FORMAT_BITMAP = 1, /* Bitmap format, BMP 24/32bpp, BI_RGB */
|
||||
USYNERGY_CLIPBOARD_FORMAT_HTML = 2, /* HTML format, HTML fragment, UTF-8, newline is LF */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Constants and limits
|
||||
**/
|
||||
#define USYNERGY_NUM_JOYSTICKS 4 /* Maximum number of supported joysticks */
|
||||
|
||||
#define USYNERGY_PROTOCOL_MAJOR 1 /* Major protocol version */
|
||||
#define USYNERGY_PROTOCOL_MINOR 4 /* Minor protocol version */
|
||||
|
||||
#define USYNERGY_IDLE_TIMEOUT 2000 /* Timeout in milliseconds before reconnecting */
|
||||
|
||||
#define USYNERGY_TRACE_BUFFER_SIZE 1024 /* Maximum length of traced message */
|
||||
#define USYNERGY_REPLY_BUFFER_SIZE 1024 /* Maximum size of a reply packet */
|
||||
#define USYNERGY_RECEIVE_BUFFER_SIZE 4096 /* Maximum size of an incoming packet */
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Keyboard constants
|
||||
**/
|
||||
#define USYNERGY_MODIFIER_SHIFT 0x0001 /* Shift key modifier */
|
||||
#define USYNERGY_MODIFIER_CTRL 0x0002 /* Ctrl key modifier */
|
||||
#define USYNERGY_MODIFIER_ALT 0x0004 /* Alt key modifier */
|
||||
Copyright (c) 2012 Alex Evans
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Configuration
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Determine endianness
|
||||
**/
|
||||
#if defined(USYNERGY_LITTLE_ENDIAN) && defined(USYNERGY_BIG_ENDIAN)
|
||||
/* Ambiguous: both endians specified */
|
||||
#error "Can't define both USYNERGY_LITTLE_ENDIAN and USYNERGY_BIG_ENDIAN"
|
||||
#elif !defined(USYNERGY_LITTLE_ENDIAN) && !defined(USYNERGY_BIG_ENDIAN)
|
||||
/* Attempt to auto detect */
|
||||
#if defined(__LITTLE_ENDIAN__) || defined(LITTLE_ENDIAN) || (_BYTE_ORDER == _LITTLE_ENDIAN)
|
||||
#define USYNERGY_LITTLE_ENDIAN
|
||||
#elif defined(__BIG_ENDIAN__) || defined(BIG_ENDIAN) || (_BYTE_ORDER == _BIG_ENDIAN)
|
||||
#define USYNERGY_BIG_ENDIAN
|
||||
#else
|
||||
#error "Can't detect endian-nes, please defined either USYNERGY_LITTLE_ENDIAN or USYNERGY_BIG_ENDIAN";
|
||||
#endif
|
||||
#else
|
||||
/* User-specified endian-nes, nothing to do for us */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Types and Constants
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Boolean type
|
||||
**/
|
||||
typedef int uSynergyBool;
|
||||
#define USYNERGY_FALSE 0 /* False value */
|
||||
#define USYNERGY_TRUE 1 /* True value */
|
||||
|
||||
|
||||
/**
|
||||
@brief User context type
|
||||
|
||||
The uSynergyCookie type is an opaque type that is used by uSynergy to communicate to the client. It is passed along to
|
||||
callback functions as context.
|
||||
**/
|
||||
typedef struct { int ignored; } * uSynergyCookie;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Clipboard types
|
||||
**/
|
||||
enum uSynergyClipboardFormat
|
||||
{
|
||||
USYNERGY_CLIPBOARD_FORMAT_TEXT = 0, /* Text format, UTF-8, newline is LF */
|
||||
USYNERGY_CLIPBOARD_FORMAT_BITMAP = 1, /* Bitmap format, BMP 24/32bpp, BI_RGB */
|
||||
USYNERGY_CLIPBOARD_FORMAT_HTML = 2, /* HTML format, HTML fragment, UTF-8, newline is LF */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Constants and limits
|
||||
**/
|
||||
#define USYNERGY_NUM_JOYSTICKS 4 /* Maximum number of supported joysticks */
|
||||
|
||||
#define USYNERGY_PROTOCOL_MAJOR 1 /* Major protocol version */
|
||||
#define USYNERGY_PROTOCOL_MINOR 4 /* Minor protocol version */
|
||||
|
||||
#define USYNERGY_IDLE_TIMEOUT 2000 /* Timeout in milliseconds before reconnecting */
|
||||
|
||||
#define USYNERGY_TRACE_BUFFER_SIZE 1024 /* Maximum length of traced message */
|
||||
#define USYNERGY_REPLY_BUFFER_SIZE 1024 /* Maximum size of a reply packet */
|
||||
#define USYNERGY_RECEIVE_BUFFER_SIZE 4096 /* Maximum size of an incoming packet */
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Keyboard constants
|
||||
**/
|
||||
#define USYNERGY_MODIFIER_SHIFT 0x0001 /* Shift key modifier */
|
||||
#define USYNERGY_MODIFIER_CTRL 0x0002 /* Ctrl key modifier */
|
||||
#define USYNERGY_MODIFIER_ALT 0x0004 /* Alt key modifier */
|
||||
#define USYNERGY_MODIFIER_META 0x0008 /* Meta key modifier */
|
||||
#define USYNERGY_MODIFIER_WIN 0x0010 /* Windows key modifier */
|
||||
#define USYNERGY_MODIFIER_WIN 0x0010 /* Windows key modifier */
|
||||
#define USYNERGY_MODIFIER_ALT_GR 0x0020 /* AltGr key modifier */
|
||||
#define USYNERGY_MODIFIER_LEVEL5LOCK 0x0040 /* Level5Lock key modifier */
|
||||
#define USYNERGY_MODIFIER_CAPSLOCK 0x1000 /* CapsLock key modifier */
|
||||
#define USYNERGY_MODIFIER_NUMLOCK 0x2000 /* NumLock key modifier */
|
||||
#define USYNERGY_MODIFIER_SCROLLOCK 0x4000 /* ScrollLock key modifier */
|
||||
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Functions and Callbacks
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Connect function
|
||||
|
||||
This function is called when uSynergy needs to connect to the host. It doesn't imply a network implementation or
|
||||
destination address, that must all be handled on the user side. The function should return USYNERGY_TRUE if a
|
||||
connection was established or USYNERGY_FALSE if it could not connect.
|
||||
|
||||
When network errors occur (e.g. uSynergySend or uSynergyReceive fail) then the connect call will be called again
|
||||
so the implementation of the function must close any old connections and clean up resources before retrying.
|
||||
|
||||
@param cookie Cookie supplied in the Synergy context
|
||||
**/
|
||||
typedef uSynergyBool (*uSynergyConnectFunc)(uSynergyCookie cookie);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Send function
|
||||
|
||||
This function is called when uSynergy needs to send something over the default connection. It should return
|
||||
USYNERGY_TRUE if sending succeeded and USYNERGY_FALSE otherwise. This function should block until the send
|
||||
operation is completed.
|
||||
|
||||
@param cookie Cookie supplied in the Synergy context
|
||||
@param buffer Address of buffer to send
|
||||
@param length Length of buffer to send
|
||||
**/
|
||||
typedef uSynergyBool (*uSynergySendFunc)(uSynergyCookie cookie, const uint8_t *buffer, int length);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Receive function
|
||||
|
||||
This function is called when uSynergy needs to receive data from the default connection. It should return
|
||||
USYNERGY_TRUE if receiving data succeeded and USYNERGY_FALSE otherwise. This function should block until data
|
||||
has been received and wait for data to become available. If @a outLength is set to 0 upon completion it is
|
||||
assumed that the connection is alive, but still in a connecting state and needs time to settle.
|
||||
|
||||
@param cookie Cookie supplied in the Synergy context
|
||||
@param buffer Address of buffer to receive data into
|
||||
@param maxLength Maximum amount of bytes to write into the receive buffer
|
||||
@param outLength Address of integer that receives the actual amount of bytes written into @a buffer
|
||||
**/
|
||||
typedef uSynergyBool (*uSynergyReceiveFunc)(uSynergyCookie cookie, uint8_t *buffer, int maxLength, int* outLength);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Thread sleep function
|
||||
|
||||
This function is called when uSynergy wants to suspend operation for a while before retrying an operation. It
|
||||
is mostly used when a socket times out or disconnect occurs to prevent uSynergy from continuously hammering a
|
||||
network connection in case the network is down.
|
||||
|
||||
@param cookie Cookie supplied in the Synergy context
|
||||
@param timeMs Time to sleep the current thread (in milliseconds)
|
||||
**/
|
||||
typedef void (*uSynergySleepFunc)(uSynergyCookie cookie, int timeMs);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Get time function
|
||||
|
||||
This function is called when uSynergy needs to know the current time. This is used to determine when timeouts
|
||||
have occured. The time base should be a cyclic millisecond time value.
|
||||
|
||||
@returns Time value in milliseconds
|
||||
**/
|
||||
typedef uint32_t (*uSynergyGetTimeFunc)();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Trace function
|
||||
|
||||
This function is called when uSynergy wants to trace something. It is optional to show these messages, but they
|
||||
are often useful when debugging. uSynergy only traces major events like connecting and disconnecting. Usually
|
||||
only a single trace is shown when the connection is established and no more trace are called.
|
||||
|
||||
@param cookie Cookie supplied in the Synergy context
|
||||
@param text Text to be traced
|
||||
**/
|
||||
typedef void (*uSynergyTraceFunc)(uSynergyCookie cookie, const char *text);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Screen active callback
|
||||
|
||||
This callback is called when Synergy makes the screen active or inactive. This
|
||||
callback is usually sent when the mouse enters or leaves the screen.
|
||||
|
||||
@param cookie Cookie supplied in the Synergy context
|
||||
@param active Activation flag, 1 if the screen has become active, 0 if the screen has become inactive
|
||||
**/
|
||||
typedef void (*uSynergyScreenActiveCallback)(uSynergyCookie cookie, uSynergyBool active);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Mouse callback
|
||||
|
||||
This callback is called when a mouse events happens. The mouse X and Y position,
|
||||
wheel and button state is communicated in the message. It's up to the user to
|
||||
interpret if this is a mouse up, down, double-click or other message.
|
||||
|
||||
@param cookie Cookie supplied in the Synergy context
|
||||
@param x Mouse X position
|
||||
@param y Mouse Y position
|
||||
@param wheelX Mouse wheel X position
|
||||
@param wheelY Mouse wheel Y position
|
||||
@param buttonLeft Left button pressed status, 0 for released, 1 for pressed
|
||||
@param buttonMiddle Middle button pressed status, 0 for released, 1 for pressed
|
||||
@param buttonRight Right button pressed status, 0 for released, 1 for pressed
|
||||
**/
|
||||
typedef void (*uSynergyMouseCallback)(uSynergyCookie cookie, uint16_t x, uint16_t y, int16_t wheelX, int16_t wheelY, uSynergyBool buttonLeft, uSynergyBool buttonRight, uSynergyBool buttonMiddle);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Key event callback
|
||||
|
||||
This callback is called when a key is pressed or released.
|
||||
|
||||
@param cookie Cookie supplied in the Synergy context
|
||||
@param key Key code of key that was pressed or released
|
||||
@param modifiers Status of modifier keys (alt, shift, etc.)
|
||||
@param down Down or up status, 1 is key is pressed down, 0 if key is released (up)
|
||||
@param repeat Repeat flag, 1 if the key is down because the key is repeating, 0 if the key is initially pressed by the user
|
||||
**/
|
||||
typedef void (*uSynergyKeyboardCallback)(uSynergyCookie cookie, uint16_t key, uint16_t modifiers, uSynergyBool down, uSynergyBool repeat);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Joystick event callback
|
||||
|
||||
This callback is called when a joystick stick or button changes. It is possible that multiple callbacks are
|
||||
fired when different sticks or buttons change as these are individual messages in the packet stream. Each
|
||||
callback will contain all the valid state for the different axes and buttons. The last callback received will
|
||||
represent the most current joystick state.
|
||||
|
||||
@param cookie Cookie supplied in the Synergy context
|
||||
@param joyNum Joystick number, always in the range [0 ... USYNERGY_NUM_JOYSTICKS>
|
||||
@param buttons Button pressed mask
|
||||
@param leftStickX Left stick X position, in range [-127 ... 127]
|
||||
@param leftStickY Left stick Y position, in range [-127 ... 127]
|
||||
@param rightStickX Right stick X position, in range [-127 ... 127]
|
||||
@param rightStickY Right stick Y position, in range [-127 ... 127]
|
||||
**/
|
||||
typedef void (*uSynergyJoystickCallback)(uSynergyCookie cookie, uint8_t joyNum, uint16_t buttons, int8_t leftStickX, int8_t leftStickY, int8_t rightStickX, int8_t rightStickY);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Clipboard event callback
|
||||
|
||||
This callback is called when something is placed on the clipboard. Multiple callbacks may be fired for
|
||||
multiple clipboard formats if they are supported. The data provided is read-only and may not be modified
|
||||
by the application.
|
||||
|
||||
@param cookie Cookie supplied in the Synergy context
|
||||
@param format Clipboard format
|
||||
@param data Memory area containing the clipboard raw data
|
||||
@param size Size of clipboard data
|
||||
**/
|
||||
typedef void (*uSynergyClipboardCallback)(uSynergyCookie cookie, enum uSynergyClipboardFormat format, const uint8_t *data, uint32_t size);
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Context
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief uSynergy context
|
||||
**/
|
||||
typedef struct
|
||||
{
|
||||
/* Mandatory configuration data, filled in by client */
|
||||
uSynergyConnectFunc m_connectFunc; /* Connect function */
|
||||
uSynergySendFunc m_sendFunc; /* Send data function */
|
||||
uSynergyReceiveFunc m_receiveFunc; /* Receive data function */
|
||||
uSynergySleepFunc m_sleepFunc; /* Thread sleep function */
|
||||
uSynergyGetTimeFunc m_getTimeFunc; /* Get current time function */
|
||||
const char* m_clientName; /* Name of Synergy Screen / Client */
|
||||
uint16_t m_clientWidth; /* Width of screen */
|
||||
uint16_t m_clientHeight; /* Height of screen */
|
||||
|
||||
/* Optional configuration data, filled in by client */
|
||||
uSynergyCookie m_cookie; /* Cookie pointer passed to callback functions (can be NULL) */
|
||||
uSynergyTraceFunc m_traceFunc; /* Function for tracing status (can be NULL) */
|
||||
uSynergyScreenActiveCallback m_screenActiveCallback; /* Callback for entering and leaving screen */
|
||||
uSynergyMouseCallback m_mouseCallback; /* Callback for mouse events */
|
||||
uSynergyKeyboardCallback m_keyboardCallback; /* Callback for keyboard events */
|
||||
uSynergyJoystickCallback m_joystickCallback; /* Callback for joystick events */
|
||||
uSynergyClipboardCallback m_clipboardCallback; /* Callback for clipboard events */
|
||||
|
||||
/* State data, used internall by client, initialized by uSynergyInit() */
|
||||
uSynergyBool m_connected; /* Is our socket connected? */
|
||||
uSynergyBool m_hasReceivedHello; /* Have we received a 'Hello' from the server? */
|
||||
uSynergyBool m_isCaptured; /* Is Synergy active (i.e. this client is receiving input messages?) */
|
||||
uint32_t m_lastMessageTime; /* Time at which last message was received */
|
||||
uint32_t m_sequenceNumber; /* Packet sequence number */
|
||||
uint8_t m_receiveBuffer[USYNERGY_RECEIVE_BUFFER_SIZE]; /* Receive buffer */
|
||||
int m_receiveOfs; /* Receive buffer offset */
|
||||
uint8_t m_replyBuffer[USYNERGY_REPLY_BUFFER_SIZE]; /* Reply buffer */
|
||||
uint8_t* m_replyCur; /* Write offset into reply buffer */
|
||||
uint16_t m_mouseX; /* Mouse X position */
|
||||
uint16_t m_mouseY; /* Mouse Y position */
|
||||
int16_t m_mouseWheelX; /* Mouse wheel X position */
|
||||
int16_t m_mouseWheelY; /* Mouse wheel Y position */
|
||||
uSynergyBool m_mouseButtonLeft; /* Mouse left button */
|
||||
uSynergyBool m_mouseButtonRight; /* Mouse right button */
|
||||
uSynergyBool m_mouseButtonMiddle; /* Mouse middle button */
|
||||
int8_t m_joystickSticks[USYNERGY_NUM_JOYSTICKS][4]; /* Joystick stick position in 2 axes for 2 sticks */
|
||||
uint16_t m_joystickButtons[USYNERGY_NUM_JOYSTICKS]; /* Joystick button state */
|
||||
} uSynergyContext;
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Interface
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Initialize uSynergy context
|
||||
|
||||
This function initializes @a context for use. Call this function directly after
|
||||
creating the context, before filling in any configuration data in it. Not calling
|
||||
this function will cause undefined behavior.
|
||||
|
||||
@param context Context to be initialized
|
||||
**/
|
||||
extern void uSynergyInit(uSynergyContext *context);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Update uSynergy
|
||||
|
||||
This function updates uSynergy and does the bulk of the work. It does connection management,
|
||||
receiving data, reconnecting after errors or timeouts and so on. It assumes that networking
|
||||
operations are blocking and it can suspend the current thread if it needs to wait. It is
|
||||
best practice to call uSynergyUpdate from a background thread so it is responsive.
|
||||
|
||||
Because uSynergy relies mostly on blocking calls it will mostly stay in thread sleep state
|
||||
waiting for system mutexes and won't eat much memory.
|
||||
|
||||
uSynergyUpdate doesn't do any memory allocations or have any side effects beyond those of
|
||||
the callbacks it calls.
|
||||
|
||||
@param context Context to be updated
|
||||
**/
|
||||
extern void uSynergyUpdate(uSynergyContext *context);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Send clipboard data
|
||||
|
||||
This function sets new clipboard data and sends it to the server. Use this function if
|
||||
your client cuts or copies data onto the clipboard that it needs to share with the
|
||||
server.
|
||||
|
||||
Currently there is only support for plaintext, but HTML and image data could be
|
||||
supported with some effort.
|
||||
|
||||
@param context Context to send clipboard data to
|
||||
@param text Text to set to the clipboard
|
||||
**/
|
||||
extern void uSynergySendClipboard(uSynergyContext *context, const char *text);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Functions and Callbacks
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Connect function
|
||||
|
||||
This function is called when uSynergy needs to connect to the host. It doesn't imply a network implementation or
|
||||
destination address, that must all be handled on the user side. The function should return USYNERGY_TRUE if a
|
||||
connection was established or USYNERGY_FALSE if it could not connect.
|
||||
|
||||
When network errors occur (e.g. uSynergySend or uSynergyReceive fail) then the connect call will be called again
|
||||
so the implementation of the function must close any old connections and clean up resources before retrying.
|
||||
|
||||
@param cookie Cookie supplied in the Synergy context
|
||||
**/
|
||||
typedef uSynergyBool (*uSynergyConnectFunc)(uSynergyCookie cookie);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Send function
|
||||
|
||||
This function is called when uSynergy needs to send something over the default connection. It should return
|
||||
USYNERGY_TRUE if sending succeeded and USYNERGY_FALSE otherwise. This function should block until the send
|
||||
operation is completed.
|
||||
|
||||
@param cookie Cookie supplied in the Synergy context
|
||||
@param buffer Address of buffer to send
|
||||
@param length Length of buffer to send
|
||||
**/
|
||||
typedef uSynergyBool (*uSynergySendFunc)(uSynergyCookie cookie, const uint8_t *buffer, int length);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Receive function
|
||||
|
||||
This function is called when uSynergy needs to receive data from the default connection. It should return
|
||||
USYNERGY_TRUE if receiving data succeeded and USYNERGY_FALSE otherwise. This function should block until data
|
||||
has been received and wait for data to become available. If @a outLength is set to 0 upon completion it is
|
||||
assumed that the connection is alive, but still in a connecting state and needs time to settle.
|
||||
|
||||
@param cookie Cookie supplied in the Synergy context
|
||||
@param buffer Address of buffer to receive data into
|
||||
@param maxLength Maximum amount of bytes to write into the receive buffer
|
||||
@param outLength Address of integer that receives the actual amount of bytes written into @a buffer
|
||||
**/
|
||||
typedef uSynergyBool (*uSynergyReceiveFunc)(uSynergyCookie cookie, uint8_t *buffer, int maxLength, int* outLength);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Thread sleep function
|
||||
|
||||
This function is called when uSynergy wants to suspend operation for a while before retrying an operation. It
|
||||
is mostly used when a socket times out or disconnect occurs to prevent uSynergy from continuously hammering a
|
||||
network connection in case the network is down.
|
||||
|
||||
@param cookie Cookie supplied in the Synergy context
|
||||
@param timeMs Time to sleep the current thread (in milliseconds)
|
||||
**/
|
||||
typedef void (*uSynergySleepFunc)(uSynergyCookie cookie, int timeMs);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Get time function
|
||||
|
||||
This function is called when uSynergy needs to know the current time. This is used to determine when timeouts
|
||||
have occured. The time base should be a cyclic millisecond time value.
|
||||
|
||||
@returns Time value in milliseconds
|
||||
**/
|
||||
typedef uint32_t (*uSynergyGetTimeFunc)();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Trace function
|
||||
|
||||
This function is called when uSynergy wants to trace something. It is optional to show these messages, but they
|
||||
are often useful when debugging. uSynergy only traces major events like connecting and disconnecting. Usually
|
||||
only a single trace is shown when the connection is established and no more trace are called.
|
||||
|
||||
@param cookie Cookie supplied in the Synergy context
|
||||
@param text Text to be traced
|
||||
**/
|
||||
typedef void (*uSynergyTraceFunc)(uSynergyCookie cookie, const char *text);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Screen active callback
|
||||
|
||||
This callback is called when Synergy makes the screen active or inactive. This
|
||||
callback is usually sent when the mouse enters or leaves the screen.
|
||||
|
||||
@param cookie Cookie supplied in the Synergy context
|
||||
@param active Activation flag, 1 if the screen has become active, 0 if the screen has become inactive
|
||||
**/
|
||||
typedef void (*uSynergyScreenActiveCallback)(uSynergyCookie cookie, uSynergyBool active);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Mouse callback
|
||||
|
||||
This callback is called when a mouse events happens. The mouse X and Y position,
|
||||
wheel and button state is communicated in the message. It's up to the user to
|
||||
interpret if this is a mouse up, down, double-click or other message.
|
||||
|
||||
@param cookie Cookie supplied in the Synergy context
|
||||
@param x Mouse X position
|
||||
@param y Mouse Y position
|
||||
@param wheelX Mouse wheel X position
|
||||
@param wheelY Mouse wheel Y position
|
||||
@param buttonLeft Left button pressed status, 0 for released, 1 for pressed
|
||||
@param buttonMiddle Middle button pressed status, 0 for released, 1 for pressed
|
||||
@param buttonRight Right button pressed status, 0 for released, 1 for pressed
|
||||
**/
|
||||
typedef void (*uSynergyMouseCallback)(uSynergyCookie cookie, uint16_t x, uint16_t y, int16_t wheelX, int16_t wheelY, uSynergyBool buttonLeft, uSynergyBool buttonRight, uSynergyBool buttonMiddle);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Key event callback
|
||||
|
||||
This callback is called when a key is pressed or released.
|
||||
|
||||
@param cookie Cookie supplied in the Synergy context
|
||||
@param key Key code of key that was pressed or released
|
||||
@param modifiers Status of modifier keys (alt, shift, etc.)
|
||||
@param down Down or up status, 1 is key is pressed down, 0 if key is released (up)
|
||||
@param repeat Repeat flag, 1 if the key is down because the key is repeating, 0 if the key is initially pressed by the user
|
||||
**/
|
||||
typedef void (*uSynergyKeyboardCallback)(uSynergyCookie cookie, uint16_t key, uint16_t modifiers, uSynergyBool down, uSynergyBool repeat);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Joystick event callback
|
||||
|
||||
This callback is called when a joystick stick or button changes. It is possible that multiple callbacks are
|
||||
fired when different sticks or buttons change as these are individual messages in the packet stream. Each
|
||||
callback will contain all the valid state for the different axes and buttons. The last callback received will
|
||||
represent the most current joystick state.
|
||||
|
||||
@param cookie Cookie supplied in the Synergy context
|
||||
@param joyNum Joystick number, always in the range [0 ... USYNERGY_NUM_JOYSTICKS>
|
||||
@param buttons Button pressed mask
|
||||
@param leftStickX Left stick X position, in range [-127 ... 127]
|
||||
@param leftStickY Left stick Y position, in range [-127 ... 127]
|
||||
@param rightStickX Right stick X position, in range [-127 ... 127]
|
||||
@param rightStickY Right stick Y position, in range [-127 ... 127]
|
||||
**/
|
||||
typedef void (*uSynergyJoystickCallback)(uSynergyCookie cookie, uint8_t joyNum, uint16_t buttons, int8_t leftStickX, int8_t leftStickY, int8_t rightStickX, int8_t rightStickY);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Clipboard event callback
|
||||
|
||||
This callback is called when something is placed on the clipboard. Multiple callbacks may be fired for
|
||||
multiple clipboard formats if they are supported. The data provided is read-only and may not be modified
|
||||
by the application.
|
||||
|
||||
@param cookie Cookie supplied in the Synergy context
|
||||
@param format Clipboard format
|
||||
@param data Memory area containing the clipboard raw data
|
||||
@param size Size of clipboard data
|
||||
**/
|
||||
typedef void (*uSynergyClipboardCallback)(uSynergyCookie cookie, enum uSynergyClipboardFormat format, const uint8_t *data, uint32_t size);
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Context
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief uSynergy context
|
||||
**/
|
||||
typedef struct
|
||||
{
|
||||
/* Mandatory configuration data, filled in by client */
|
||||
uSynergyConnectFunc m_connectFunc; /* Connect function */
|
||||
uSynergySendFunc m_sendFunc; /* Send data function */
|
||||
uSynergyReceiveFunc m_receiveFunc; /* Receive data function */
|
||||
uSynergySleepFunc m_sleepFunc; /* Thread sleep function */
|
||||
uSynergyGetTimeFunc m_getTimeFunc; /* Get current time function */
|
||||
const char* m_clientName; /* Name of Synergy Screen / Client */
|
||||
uint16_t m_clientWidth; /* Width of screen */
|
||||
uint16_t m_clientHeight; /* Height of screen */
|
||||
|
||||
/* Optional configuration data, filled in by client */
|
||||
uSynergyCookie m_cookie; /* Cookie pointer passed to callback functions (can be NULL) */
|
||||
uSynergyTraceFunc m_traceFunc; /* Function for tracing status (can be NULL) */
|
||||
uSynergyScreenActiveCallback m_screenActiveCallback; /* Callback for entering and leaving screen */
|
||||
uSynergyMouseCallback m_mouseCallback; /* Callback for mouse events */
|
||||
uSynergyKeyboardCallback m_keyboardCallback; /* Callback for keyboard events */
|
||||
uSynergyJoystickCallback m_joystickCallback; /* Callback for joystick events */
|
||||
uSynergyClipboardCallback m_clipboardCallback; /* Callback for clipboard events */
|
||||
|
||||
/* State data, used internall by client, initialized by uSynergyInit() */
|
||||
uSynergyBool m_connected; /* Is our socket connected? */
|
||||
uSynergyBool m_hasReceivedHello; /* Have we received a 'Hello' from the server? */
|
||||
uSynergyBool m_isCaptured; /* Is Synergy active (i.e. this client is receiving input messages?) */
|
||||
uint32_t m_lastMessageTime; /* Time at which last message was received */
|
||||
uint32_t m_sequenceNumber; /* Packet sequence number */
|
||||
uint8_t m_receiveBuffer[USYNERGY_RECEIVE_BUFFER_SIZE]; /* Receive buffer */
|
||||
int m_receiveOfs; /* Receive buffer offset */
|
||||
uint8_t m_replyBuffer[USYNERGY_REPLY_BUFFER_SIZE]; /* Reply buffer */
|
||||
uint8_t* m_replyCur; /* Write offset into reply buffer */
|
||||
uint16_t m_mouseX; /* Mouse X position */
|
||||
uint16_t m_mouseY; /* Mouse Y position */
|
||||
int16_t m_mouseWheelX; /* Mouse wheel X position */
|
||||
int16_t m_mouseWheelY; /* Mouse wheel Y position */
|
||||
uSynergyBool m_mouseButtonLeft; /* Mouse left button */
|
||||
uSynergyBool m_mouseButtonRight; /* Mouse right button */
|
||||
uSynergyBool m_mouseButtonMiddle; /* Mouse middle button */
|
||||
int8_t m_joystickSticks[USYNERGY_NUM_JOYSTICKS][4]; /* Joystick stick position in 2 axes for 2 sticks */
|
||||
uint16_t m_joystickButtons[USYNERGY_NUM_JOYSTICKS]; /* Joystick button state */
|
||||
} uSynergyContext;
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Interface
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Initialize uSynergy context
|
||||
|
||||
This function initializes @a context for use. Call this function directly after
|
||||
creating the context, before filling in any configuration data in it. Not calling
|
||||
this function will cause undefined behavior.
|
||||
|
||||
@param context Context to be initialized
|
||||
**/
|
||||
extern void uSynergyInit(uSynergyContext *context);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Update uSynergy
|
||||
|
||||
This function updates uSynergy and does the bulk of the work. It does connection management,
|
||||
receiving data, reconnecting after errors or timeouts and so on. It assumes that networking
|
||||
operations are blocking and it can suspend the current thread if it needs to wait. It is
|
||||
best practice to call uSynergyUpdate from a background thread so it is responsive.
|
||||
|
||||
Because uSynergy relies mostly on blocking calls it will mostly stay in thread sleep state
|
||||
waiting for system mutexes and won't eat much memory.
|
||||
|
||||
uSynergyUpdate doesn't do any memory allocations or have any side effects beyond those of
|
||||
the callbacks it calls.
|
||||
|
||||
@param context Context to be updated
|
||||
**/
|
||||
extern void uSynergyUpdate(uSynergyContext *context);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@brief Send clipboard data
|
||||
|
||||
This function sets new clipboard data and sends it to the server. Use this function if
|
||||
your client cuts or copies data onto the clipboard that it needs to share with the
|
||||
server.
|
||||
|
||||
Currently there is only support for plaintext, but HTML and image data could be
|
||||
supported with some effort.
|
||||
|
||||
@param context Context to send clipboard data to
|
||||
@param text Text to set to the clipboard
|
||||
**/
|
||||
extern void uSynergySendClipboard(uSynergyContext *context, const char *text);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -19,15 +19,15 @@
|
|||
#include "winmmjoy.h"
|
||||
|
||||
#include <MMSystem.h>
|
||||
#include <iostream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#pragma comment(lib, "winmm.lib")
|
||||
|
||||
std::stringstream _logStream;
|
||||
#define LOG(s) \
|
||||
_logStream.str(""); \
|
||||
_logStream << "winmmjoy: " << s << std::endl; \
|
||||
|
||||
std::stringstream _logStream;
|
||||
#define LOG(s) \
|
||||
_logStream.str(""); \
|
||||
_logStream << "winmmjoy: " << s << std::endl; \
|
||||
s_log( _logStream.str().c_str())
|
||||
|
||||
static bool s_running = true;
|
||||
|
@ -64,7 +64,7 @@ mainLoop(void* data)
|
|||
const char* triggersEvent = "IPrimaryScreen::getGameDeviceTriggersEvent";
|
||||
|
||||
JOYINFOEX joyInfo;
|
||||
ZeroMemory(&joyInfo, sizeof(joyInfo));
|
||||
ZeroMemory(&joyInfo, sizeof(joyInfo));
|
||||
joyInfo.dwSize = sizeof(joyInfo);
|
||||
joyInfo.dwFlags = JOY_RETURNALL;
|
||||
|
||||
|
|
|
@ -1,47 +1,47 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012 Bolton Software Ltd.
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "VersionCheckerTests.h"
|
||||
#include "VersionChecker.cpp"
|
||||
#include "../../gui/tmp/debug/moc_VersionChecker.cpp"
|
||||
|
||||
#include <QtTest/QTest>
|
||||
|
||||
void VersionCheckerTests::compareVersions()
|
||||
{
|
||||
VersionChecker versionChecker;
|
||||
|
||||
// compare majors
|
||||
QCOMPARE(versionChecker.compareVersions("1.0.0", "2.0.0"), 1);
|
||||
QCOMPARE(versionChecker.compareVersions("2.0.0", "1.0.0"), -1);
|
||||
QCOMPARE(versionChecker.compareVersions("1.0.0", "1.0.0"), 0);
|
||||
QCOMPARE(versionChecker.compareVersions("1.4.8", "2.4.7"), 1);
|
||||
QCOMPARE(versionChecker.compareVersions("2.4.7", "1.4.8"), -1);
|
||||
|
||||
// compare minors
|
||||
QCOMPARE(versionChecker.compareVersions("1.3.0", "1.4.0"), 1);
|
||||
QCOMPARE(versionChecker.compareVersions("1.4.0", "1.3.0"), -1);
|
||||
QCOMPARE(versionChecker.compareVersions("1.4.0", "1.4.0"), 0);
|
||||
QCOMPARE(versionChecker.compareVersions("1.3.8", "1.4.7"), 1);
|
||||
QCOMPARE(versionChecker.compareVersions("1.4.7", "1.3.8"), -1);
|
||||
|
||||
// compare revs
|
||||
QCOMPARE(versionChecker.compareVersions("1.4.7", "1.4.8"), 1);
|
||||
QCOMPARE(versionChecker.compareVersions("1.4.8", "1.4.7"), -1);
|
||||
QCOMPARE(versionChecker.compareVersions("1.4.7", "1.4.7"), 0);
|
||||
}
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "VersionCheckerTests.h"
|
||||
#include "VersionChecker.cpp"
|
||||
#include "../../gui/tmp/debug/moc_VersionChecker.cpp"
|
||||
|
||||
#include <QtTest/QTest>
|
||||
|
||||
void VersionCheckerTests::compareVersions()
|
||||
{
|
||||
VersionChecker versionChecker;
|
||||
|
||||
// compare majors
|
||||
QCOMPARE(versionChecker.compareVersions("1.0.0", "2.0.0"), 1);
|
||||
QCOMPARE(versionChecker.compareVersions("2.0.0", "1.0.0"), -1);
|
||||
QCOMPARE(versionChecker.compareVersions("1.0.0", "1.0.0"), 0);
|
||||
QCOMPARE(versionChecker.compareVersions("1.4.8", "2.4.7"), 1);
|
||||
QCOMPARE(versionChecker.compareVersions("2.4.7", "1.4.8"), -1);
|
||||
|
||||
// compare minors
|
||||
QCOMPARE(versionChecker.compareVersions("1.3.0", "1.4.0"), 1);
|
||||
QCOMPARE(versionChecker.compareVersions("1.4.0", "1.3.0"), -1);
|
||||
QCOMPARE(versionChecker.compareVersions("1.4.0", "1.4.0"), 0);
|
||||
QCOMPARE(versionChecker.compareVersions("1.3.8", "1.4.7"), 1);
|
||||
QCOMPARE(versionChecker.compareVersions("1.4.7", "1.3.8"), -1);
|
||||
|
||||
// compare revs
|
||||
QCOMPARE(versionChecker.compareVersions("1.4.7", "1.4.8"), 1);
|
||||
QCOMPARE(versionChecker.compareVersions("1.4.8", "1.4.7"), -1);
|
||||
QCOMPARE(versionChecker.compareVersions("1.4.7", "1.4.7"), 0);
|
||||
}
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012 Bolton Software Ltd.
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "QObject.h"
|
||||
|
||||
class VersionCheckerTests : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void compareVersions();
|
||||
};
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "QObject.h"
|
||||
|
||||
class VersionCheckerTests : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void compareVersions();
|
||||
};
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012 Bolton Software Ltd.
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <QtTest/QTest>
|
||||
#include "VersionCheckerTests.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
VersionCheckerTests versionCheckerTests;
|
||||
QTest::qExec(&versionCheckerTests, argc, argv);
|
||||
}
|
||||
* Copyright (C) 2012 Nick Bolton
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <QtTest/QTest>
|
||||
#include "VersionCheckerTests.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
VersionCheckerTests versionCheckerTests;
|
||||
QTest::qExec(&versionCheckerTests, argc, argv);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "CLog.h"
|
||||
#include "TMethodEventJob.h"
|
||||
#include "CSimpleEventQueueBuffer.h"
|
||||
#include <stdexcept>
|
||||
|
||||
void
|
||||
CTestEventQueue::raiseQuitEvent()
|
||||
|
@ -47,6 +48,5 @@ CTestEventQueue::cleanupQuitTimeout()
|
|||
void
|
||||
CTestEventQueue::handleQuitTimeout(const CEvent&, void* vclient)
|
||||
{
|
||||
LOG((CLOG_ERR "timeout"));
|
||||
raiseQuitEvent();
|
||||
throw std::runtime_error("test event queue timeout");
|
||||
}
|
||||
|
|
|
@ -16,8 +16,11 @@
|
|||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
|
||||
#define TEST_ENV
|
||||
|
||||
|
@ -33,42 +36,74 @@
|
|||
#include "CTCPSocketFactory.h"
|
||||
#include "CCryptoOptions.h"
|
||||
#include "CSocketMultiplexer.h"
|
||||
#include "CMSWindowsScreen.h"
|
||||
#include "CGameDevice.h"
|
||||
#include "CThread.h"
|
||||
#include "TMethodJob.h"
|
||||
#include "CTestEventQueue.h"
|
||||
#include "server/CMockInputFilter.h"
|
||||
#include "TMethodJob.h"
|
||||
#include "CThread.h"
|
||||
#include "CFileChunker.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
using ::testing::_;
|
||||
using ::testing::NiceMock;
|
||||
using ::testing::NiceMock;
|
||||
using ::testing::Return;
|
||||
using ::testing::Invoke;
|
||||
|
||||
#define TEST_PORT 24803
|
||||
#define TEST_HOST "localhost"
|
||||
|
||||
const int klargeDataSize = 512;
|
||||
char g_largeData[klargeDataSize] = "large data:head.1221412312341244213123fdsfasdawdwadwadacwdd.12321412312341244213123fdsfasdawdwadwadacwdawddawdwacawdawd232141231awddawdwacawdawd2321412312341244213123fdsfasdawdwadacwdawddawdwacawdtrtetawdawdwaewe1213412321412312341244213123fdsfasdawdwadacwdawddawdwacawdawdawdwaewe121341awdwaewedacwdawddawdwacawdawd2321412312341244213123fdsfasdawdwadacwdawddawdwacawdtrtetawdawdwaewe1213412321412312341244213123fdsfasdawdwadacwdawddawdwacawdawdawdwaewe121341awdwaewe12134123njk1u31i2nm3e123hu23oi132213njk.tail";
|
||||
const size_t kMockDataSize = 1024 * 1024 * 10; // 10MB
|
||||
const UInt16 kMockDataChunkIncrement = 1024; // 1KB
|
||||
const char* kMockFilename = "NetworkTests.mock";
|
||||
const size_t kMockFileSize = 1024 * 1024 * 10; // 10MB
|
||||
|
||||
void sendFileToClient_getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h);
|
||||
void sendFileToClient_getCursorPos(SInt32& x, SInt32& y);
|
||||
void getScreenShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h);
|
||||
void getCursorPos(SInt32& x, SInt32& y);
|
||||
CString intToString(size_t i);
|
||||
UInt8* newMockData(size_t size);
|
||||
void createFile(fstream& file, const char* filename, size_t size);
|
||||
|
||||
class NetworkTests : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
NetworkTests() { }
|
||||
NetworkTests() :
|
||||
m_mockData(NULL),
|
||||
m_mockDataSize(0),
|
||||
m_mockFileSize(0)
|
||||
{
|
||||
m_mockData = newMockData(kMockDataSize);
|
||||
createFile(m_mockFile, kMockFilename, kMockFileSize);
|
||||
}
|
||||
|
||||
void sendData(CServer* server);
|
||||
~NetworkTests()
|
||||
{
|
||||
remove(kMockFilename);
|
||||
delete[] m_mockData;
|
||||
}
|
||||
|
||||
void sendMockData(void* eventTarget);
|
||||
|
||||
void sendFileToClient_handleClientConnected(const CEvent&, void* vlistener);
|
||||
void sendFileToClient_fileRecieveComplete(const CEvent&, void*);
|
||||
void sendToClient_mockData_handleClientConnected(const CEvent&, void* vlistener);
|
||||
void sendToClient_mockData_fileRecieveComplete(const CEvent&, void*);
|
||||
|
||||
void sendToClient_mockFile_handleClientConnected(const CEvent&, void* vlistener);
|
||||
void sendToClient_mockFile_fileRecieveComplete(const CEvent& event, void*);
|
||||
|
||||
void sendToServer_mockData_handleClientConnected(const CEvent&, void* vlistener);
|
||||
void sendToServer_mockData_fileRecieveComplete(const CEvent& event, void*);
|
||||
|
||||
void sendToServer_mockFile_handleClientConnected(const CEvent&, void* vlistener);
|
||||
void sendToServer_mockFile_fileRecieveComplete(const CEvent& event, void*);
|
||||
|
||||
public:
|
||||
CTestEventQueue m_events;
|
||||
UInt8* m_mockData;
|
||||
size_t m_mockDataSize;
|
||||
fstream m_mockFile;
|
||||
size_t m_mockFileSize;
|
||||
};
|
||||
|
||||
TEST_F(NetworkTests, sendFileToClient)
|
||||
TEST_F(NetworkTests, sendToClient_mockData)
|
||||
{
|
||||
// server and client
|
||||
CNetworkAddress serverAddress(TEST_HOST, TEST_PORT);
|
||||
|
@ -88,7 +123,7 @@ TEST_F(NetworkTests, sendFileToClient)
|
|||
m_events.adoptHandler(
|
||||
m_events.forCClientListener().connected(), &listener,
|
||||
new TMethodEventJob<NetworkTests>(
|
||||
this, &NetworkTests::sendFileToClient_handleClientConnected, &listener));
|
||||
this, &NetworkTests::sendToClient_mockData_handleClientConnected, &listener));
|
||||
|
||||
ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true));
|
||||
ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter));
|
||||
|
@ -102,43 +137,196 @@ TEST_F(NetworkTests, sendFileToClient)
|
|||
CSocketMultiplexer clientSocketMultiplexer;
|
||||
CTCPSocketFactory* clientSocketFactory = new CTCPSocketFactory(&m_events, &clientSocketMultiplexer);
|
||||
|
||||
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(sendFileToClient_getShape));
|
||||
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(sendFileToClient_getCursorPos));
|
||||
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape));
|
||||
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
|
||||
|
||||
CClient client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions);
|
||||
|
||||
m_events.adoptHandler(
|
||||
m_events.forIScreen().fileRecieveComplete(), &client,
|
||||
new TMethodEventJob<NetworkTests>(
|
||||
this, &NetworkTests::sendFileToClient_fileRecieveComplete));
|
||||
this, &NetworkTests::sendToClient_mockData_fileRecieveComplete));
|
||||
|
||||
client.connect();
|
||||
|
||||
m_events.initQuitTimeout(10);
|
||||
m_events.initQuitTimeout(5);
|
||||
m_events.loop();
|
||||
m_events.cleanupQuitTimeout();
|
||||
}
|
||||
|
||||
TEST_F(NetworkTests, sendToClient_mockFile)
|
||||
{
|
||||
// server and client
|
||||
CNetworkAddress serverAddress(TEST_HOST, TEST_PORT);
|
||||
CCryptoOptions cryptoOptions;
|
||||
|
||||
serverAddress.resolve();
|
||||
|
||||
// server
|
||||
CSocketMultiplexer serverSocketMultiplexer;
|
||||
CTCPSocketFactory* serverSocketFactory = new CTCPSocketFactory(&m_events, &serverSocketMultiplexer);
|
||||
CClientListener listener(serverAddress, serverSocketFactory, NULL, cryptoOptions, &m_events);
|
||||
NiceMock<CMockScreen> serverScreen;
|
||||
NiceMock<CMockPrimaryClient> primaryClient;
|
||||
NiceMock<CMockConfig> serverConfig;
|
||||
NiceMock<CMockInputFilter> serverInputFilter;
|
||||
|
||||
m_events.adoptHandler(
|
||||
m_events.forCClientListener().connected(), &listener,
|
||||
new TMethodEventJob<NetworkTests>(
|
||||
this, &NetworkTests::sendToClient_mockFile_handleClientConnected, &listener));
|
||||
|
||||
ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true));
|
||||
ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter));
|
||||
|
||||
CServer server(serverConfig, &primaryClient, &serverScreen, &m_events);
|
||||
server.m_mock = true;
|
||||
listener.setServer(&server);
|
||||
|
||||
// client
|
||||
NiceMock<CMockScreen> clientScreen;
|
||||
CSocketMultiplexer clientSocketMultiplexer;
|
||||
CTCPSocketFactory* clientSocketFactory = new CTCPSocketFactory(&m_events, &clientSocketMultiplexer);
|
||||
|
||||
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape));
|
||||
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
|
||||
|
||||
CClient client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions);
|
||||
|
||||
m_events.adoptHandler(
|
||||
m_events.forIScreen().fileRecieveComplete(), &client,
|
||||
new TMethodEventJob<NetworkTests>(
|
||||
this, &NetworkTests::sendToClient_mockFile_fileRecieveComplete));
|
||||
|
||||
client.connect();
|
||||
|
||||
m_events.initQuitTimeout(5);
|
||||
m_events.loop();
|
||||
m_events.cleanupQuitTimeout();
|
||||
}
|
||||
|
||||
TEST_F(NetworkTests, sendToServer_mockData)
|
||||
{
|
||||
// server and client
|
||||
CNetworkAddress serverAddress(TEST_HOST, TEST_PORT);
|
||||
CCryptoOptions cryptoOptions;
|
||||
|
||||
serverAddress.resolve();
|
||||
|
||||
// server
|
||||
CSocketMultiplexer serverSocketMultiplexer;
|
||||
CTCPSocketFactory* serverSocketFactory = new CTCPSocketFactory(&m_events, &serverSocketMultiplexer);
|
||||
CClientListener listener(serverAddress, serverSocketFactory, NULL, cryptoOptions, &m_events);
|
||||
NiceMock<CMockScreen> serverScreen;
|
||||
NiceMock<CMockPrimaryClient> primaryClient;
|
||||
NiceMock<CMockConfig> serverConfig;
|
||||
NiceMock<CMockInputFilter> serverInputFilter;
|
||||
|
||||
ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true));
|
||||
ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter));
|
||||
|
||||
CServer server(serverConfig, &primaryClient, &serverScreen, &m_events);
|
||||
server.m_mock = true;
|
||||
listener.setServer(&server);
|
||||
|
||||
// client
|
||||
NiceMock<CMockScreen> clientScreen;
|
||||
CSocketMultiplexer clientSocketMultiplexer;
|
||||
CTCPSocketFactory* clientSocketFactory = new CTCPSocketFactory(&m_events, &clientSocketMultiplexer);
|
||||
|
||||
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape));
|
||||
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
|
||||
|
||||
CClient client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions);
|
||||
|
||||
m_events.adoptHandler(
|
||||
m_events.forCClientListener().connected(), &listener,
|
||||
new TMethodEventJob<NetworkTests>(
|
||||
this, &NetworkTests::sendToServer_mockData_handleClientConnected, &client));
|
||||
|
||||
m_events.adoptHandler(
|
||||
m_events.forIScreen().fileRecieveComplete(), &server,
|
||||
new TMethodEventJob<NetworkTests>(
|
||||
this, &NetworkTests::sendToServer_mockData_fileRecieveComplete));
|
||||
|
||||
client.connect();
|
||||
|
||||
m_events.initQuitTimeout(5);
|
||||
m_events.loop();
|
||||
m_events.cleanupQuitTimeout();
|
||||
}
|
||||
|
||||
TEST_F(NetworkTests, sendToServer_mockFile)
|
||||
{
|
||||
// server and client
|
||||
CNetworkAddress serverAddress(TEST_HOST, TEST_PORT);
|
||||
CCryptoOptions cryptoOptions;
|
||||
|
||||
serverAddress.resolve();
|
||||
|
||||
// server
|
||||
CSocketMultiplexer serverSocketMultiplexer;
|
||||
CTCPSocketFactory* serverSocketFactory = new CTCPSocketFactory(&m_events, &serverSocketMultiplexer);
|
||||
CClientListener listener(serverAddress, serverSocketFactory, NULL, cryptoOptions, &m_events);
|
||||
NiceMock<CMockScreen> serverScreen;
|
||||
NiceMock<CMockPrimaryClient> primaryClient;
|
||||
NiceMock<CMockConfig> serverConfig;
|
||||
NiceMock<CMockInputFilter> serverInputFilter;
|
||||
|
||||
ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true));
|
||||
ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter));
|
||||
|
||||
CServer server(serverConfig, &primaryClient, &serverScreen, &m_events);
|
||||
server.m_mock = true;
|
||||
listener.setServer(&server);
|
||||
|
||||
// client
|
||||
NiceMock<CMockScreen> clientScreen;
|
||||
CSocketMultiplexer clientSocketMultiplexer;
|
||||
CTCPSocketFactory* clientSocketFactory = new CTCPSocketFactory(&m_events, &clientSocketMultiplexer);
|
||||
|
||||
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape));
|
||||
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
|
||||
|
||||
CClient client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions);
|
||||
|
||||
m_events.adoptHandler(
|
||||
m_events.forCClientListener().connected(), &listener,
|
||||
new TMethodEventJob<NetworkTests>(
|
||||
this, &NetworkTests::sendToServer_mockFile_handleClientConnected, &client));
|
||||
|
||||
m_events.adoptHandler(
|
||||
m_events.forIScreen().fileRecieveComplete(), &server,
|
||||
new TMethodEventJob<NetworkTests>(
|
||||
this, &NetworkTests::sendToServer_mockFile_fileRecieveComplete));
|
||||
|
||||
client.connect();
|
||||
|
||||
m_events.initQuitTimeout(5);
|
||||
m_events.loop();
|
||||
m_events.cleanupQuitTimeout();
|
||||
}
|
||||
|
||||
void
|
||||
NetworkTests::sendFileToClient_handleClientConnected(const CEvent&, void* vlistener)
|
||||
NetworkTests::sendToClient_mockData_handleClientConnected(const CEvent&, void* vlistener)
|
||||
{
|
||||
CClientListener* listener = reinterpret_cast<CClientListener*>(vlistener);
|
||||
CServer* server = listener->getServer();
|
||||
|
||||
CClientProxy* client = listener->getNextClient();
|
||||
if (client == NULL) {
|
||||
throw std::exception("client is null");
|
||||
throw runtime_error("client is null");
|
||||
}
|
||||
|
||||
CBaseClientProxy* bcp = reinterpret_cast<CBaseClientProxy*>(client);
|
||||
server->adoptClient(bcp);
|
||||
server->setActive(bcp);
|
||||
|
||||
sendData(server);
|
||||
sendMockData(server);
|
||||
}
|
||||
|
||||
void
|
||||
NetworkTests::sendFileToClient_fileRecieveComplete(const CEvent& event, void*)
|
||||
NetworkTests::sendToClient_mockData_fileRecieveComplete(const CEvent& event, void*)
|
||||
{
|
||||
CClient* client = reinterpret_cast<CClient*>(event.getTarget());
|
||||
EXPECT_TRUE(client->isReceivedFileSizeValid());
|
||||
|
@ -147,32 +335,166 @@ NetworkTests::sendFileToClient_fileRecieveComplete(const CEvent& event, void*)
|
|||
}
|
||||
|
||||
void
|
||||
NetworkTests::sendData(CServer* server)
|
||||
NetworkTests::sendToClient_mockFile_handleClientConnected(const CEvent&, void* vlistener)
|
||||
{
|
||||
UInt8* largeDataSize = new UInt8[5];
|
||||
largeDataSize[0] = '0';
|
||||
largeDataSize[1] = '5';
|
||||
largeDataSize[2] = '1';
|
||||
largeDataSize[3] = '1';
|
||||
largeDataSize[4] = '\0';
|
||||
|
||||
// transfer data from server -> client
|
||||
m_events.addEvent(CEvent(m_events.forIScreen().fileChunkSending(), server, largeDataSize));
|
||||
|
||||
UInt8* largeData = new UInt8[klargeDataSize + 1];
|
||||
largeData[0] = '1';
|
||||
memcpy(&largeData[1], g_largeData, klargeDataSize);
|
||||
m_events.addEvent(CEvent(m_events.forIScreen().fileChunkSending(), server, (UInt8*)largeData));
|
||||
CClientListener* listener = reinterpret_cast<CClientListener*>(vlistener);
|
||||
CServer* server = listener->getServer();
|
||||
|
||||
UInt8* transferFinished = new UInt8[2];
|
||||
transferFinished[0] = '2';
|
||||
transferFinished[1] = '\0';
|
||||
CClientProxy* client = listener->getNextClient();
|
||||
if (client == NULL) {
|
||||
throw runtime_error("client is null");
|
||||
}
|
||||
|
||||
m_events.addEvent(CEvent(m_events.forIScreen().fileChunkSending(), server, transferFinished));
|
||||
CBaseClientProxy* bcp = reinterpret_cast<CBaseClientProxy*>(client);
|
||||
server->adoptClient(bcp);
|
||||
server->setActive(bcp);
|
||||
|
||||
server->sendFileToClient(kMockFilename);
|
||||
}
|
||||
|
||||
void
|
||||
NetworkTests::sendToClient_mockFile_fileRecieveComplete(const CEvent& event, void*)
|
||||
{
|
||||
CClient* client = reinterpret_cast<CClient*>(event.getTarget());
|
||||
EXPECT_TRUE(client->isReceivedFileSizeValid());
|
||||
|
||||
m_events.raiseQuitEvent();
|
||||
}
|
||||
|
||||
void
|
||||
NetworkTests::sendToServer_mockData_handleClientConnected(const CEvent&, void* vclient)
|
||||
{
|
||||
CClient* client = reinterpret_cast<CClient*>(vclient);
|
||||
sendMockData(client);
|
||||
}
|
||||
|
||||
void
|
||||
NetworkTests::sendToServer_mockData_fileRecieveComplete(const CEvent& event, void*)
|
||||
{
|
||||
CServer* server = reinterpret_cast<CServer*>(event.getTarget());
|
||||
EXPECT_TRUE(server->isReceivedFileSizeValid());
|
||||
|
||||
m_events.raiseQuitEvent();
|
||||
}
|
||||
|
||||
void
|
||||
NetworkTests::sendToServer_mockFile_handleClientConnected(const CEvent&, void* vclient)
|
||||
{
|
||||
CClient* client = reinterpret_cast<CClient*>(vclient);
|
||||
client->sendFileToServer(kMockFilename);
|
||||
}
|
||||
|
||||
void
|
||||
NetworkTests::sendToServer_mockFile_fileRecieveComplete(const CEvent& event, void*)
|
||||
{
|
||||
CServer* server = reinterpret_cast<CServer*>(event.getTarget());
|
||||
EXPECT_TRUE(server->isReceivedFileSizeValid());
|
||||
|
||||
m_events.raiseQuitEvent();
|
||||
}
|
||||
|
||||
void
|
||||
NetworkTests::sendMockData(void* eventTarget)
|
||||
{
|
||||
// send first message (file size)
|
||||
CString size = intToString(kMockDataSize);
|
||||
UInt32 sizeLength = size.size();
|
||||
CFileChunker::CFileChunk* sizeMessage = new CFileChunker::CFileChunk(sizeLength + 2);
|
||||
char* chunkData = sizeMessage->m_chunk;
|
||||
|
||||
chunkData[0] = kFileStart;
|
||||
memcpy(&chunkData[1], size.c_str(), sizeLength);
|
||||
chunkData[sizeLength + 1] = '\0';
|
||||
m_events.addEvent(CEvent(m_events.forIScreen().fileChunkSending(), eventTarget, sizeMessage));
|
||||
|
||||
// send chunk messages with incrementing chunk size
|
||||
size_t lastSize = 0;
|
||||
size_t sentLength = 0;
|
||||
while (true) {
|
||||
size_t chunkSize = lastSize + kMockDataChunkIncrement;
|
||||
|
||||
// make sure we don't read too much from the mock data.
|
||||
if (sentLength + chunkSize > kMockDataSize) {
|
||||
chunkSize = kMockDataSize - sentLength;
|
||||
}
|
||||
|
||||
// first byte is the chunk mark, last is \0
|
||||
CFileChunker::CFileChunk* fileChunk = new CFileChunker::CFileChunk(chunkSize + 2);
|
||||
char* chunkData = fileChunk->m_chunk;
|
||||
|
||||
chunkData[0] = kFileChunk;
|
||||
memcpy(&chunkData[1], &m_mockData[sentLength], chunkSize);
|
||||
chunkData[chunkSize + 1] = '\0';
|
||||
m_events.addEvent(CEvent(m_events.forIScreen().fileChunkSending(), eventTarget, fileChunk));
|
||||
|
||||
sentLength += chunkSize;
|
||||
lastSize = chunkSize;
|
||||
|
||||
if (sentLength == kMockDataSize) {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// send last message
|
||||
CFileChunker::CFileChunk* transferFinished = new CFileChunker::CFileChunk(2);
|
||||
chunkData = transferFinished->m_chunk;
|
||||
|
||||
chunkData[0] = kFileEnd;
|
||||
chunkData[1] = '\0';
|
||||
m_events.addEvent(CEvent(m_events.forIScreen().fileChunkSending(), eventTarget, transferFinished));
|
||||
}
|
||||
|
||||
UInt8*
|
||||
newMockData(size_t size)
|
||||
{
|
||||
UInt8* buffer = new UInt8[size];
|
||||
|
||||
UInt8* data = buffer;
|
||||
const UInt8 head[] = "mock head... ";
|
||||
size_t headSize = sizeof(head) - 1;
|
||||
const UInt8 tail[] = "... mock tail";
|
||||
size_t tailSize = sizeof(tail) - 1;
|
||||
const UInt8 synergyRocks[] = "synergy\0 rocks! ";
|
||||
size_t synergyRocksSize = sizeof(synergyRocks) - 1;
|
||||
|
||||
memcpy(data, head, headSize);
|
||||
data += headSize;
|
||||
|
||||
SInt32 times = (size - headSize - tailSize) / synergyRocksSize;
|
||||
for (SInt32 i = 0; i < times; ++i) {
|
||||
memcpy(data, synergyRocks, synergyRocksSize);
|
||||
data += synergyRocksSize;
|
||||
}
|
||||
|
||||
SInt32 remainder = (size - headSize - tailSize) % synergyRocksSize;
|
||||
if (remainder != 0) {
|
||||
memset(data, '.', remainder);
|
||||
data += remainder;
|
||||
}
|
||||
|
||||
memcpy(data, tail, tailSize);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void
|
||||
sendFileToClient_getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h)
|
||||
createFile(fstream& file, const char* filename, size_t size)
|
||||
{
|
||||
UInt8* buffer = newMockData(size);
|
||||
|
||||
file.open(filename, ios::out | ios::binary);
|
||||
if (!file.is_open()) {
|
||||
throw runtime_error("file not open");
|
||||
}
|
||||
|
||||
file.write(reinterpret_cast<char*>(buffer), size);
|
||||
file.close();
|
||||
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
void
|
||||
getScreenShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h)
|
||||
{
|
||||
x = 0;
|
||||
y = 0;
|
||||
|
@ -181,8 +503,16 @@ sendFileToClient_getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h)
|
|||
}
|
||||
|
||||
void
|
||||
sendFileToClient_getCursorPos(SInt32& x, SInt32& y)
|
||||
getCursorPos(SInt32& x, SInt32& y)
|
||||
{
|
||||
x = 0;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
CString
|
||||
intToString(size_t i)
|
||||
{
|
||||
stringstream ss;
|
||||
ss << i;
|
||||
return ss.str();
|
||||
}
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
#include <gmock/gmock.h>
|
||||
|
||||
#include "COSXKeyState.h"
|
||||
#include "CMockKeyMap.h"
|
||||
#include "CMockEventQueue.h"
|
||||
#include "synergy/CMockKeyMap.h"
|
||||
#include "synergy/CMockEventQueue.h"
|
||||
|
||||
#include "CLog.h"
|
||||
|
||||
|
|
|
@ -22,8 +22,8 @@
|
|||
#define TEST_ENV
|
||||
#include "Global.h"
|
||||
|
||||
#include "CMockKeyMap.h"
|
||||
#include "CMockEventQueue.h"
|
||||
#include "synergy/CMockKeyMap.h"
|
||||
#include "synergy/CMockEventQueue.h"
|
||||
#include "CXWindowsKeyState.h"
|
||||
#include "CLog.h"
|
||||
#include <errno.h>
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
#include <gtest/gtest.h>
|
||||
#include "CXWindowsScreen.h"
|
||||
#include "CMockEventQueue.h"
|
||||
#include "synergy/CMockEventQueue.h"
|
||||
|
||||
using ::testing::_;
|
||||
|
||||
|
|
|
@ -48,8 +48,8 @@ TEST(CServerProxyTests, mouseMove)
|
|||
g_mouseMove_bufferIndex = 0;
|
||||
|
||||
NiceMock<CMockEventQueue> eventQueue;
|
||||
NiceMock<CMockClient> client;
|
||||
NiceMock<CMockStream> stream;
|
||||
NiceMock<CMockClient> client;
|
||||
IStreamEvents streamEvents;
|
||||
streamEvents.setEvents(&eventQueue);
|
||||
|
||||
|
|
Loading…
Reference in New Issue