* SYNERGY-854 Compiling with MSVC 2014 causes error C2280 *Fix compilation error * SYNERGY-854 Compiling with MSVC 2014 causes error C2280 *Update ChangeLog * SYNERGY-854 Compiling with MSVC 2014 causes error C2280 *Fix Utils compilation * SYNERGY-854 Fix code smell Co-authored-by: Andrii Batyiev <andrii-external@symless.com> Co-authored-by: SerhiiGadzhilov <71632867+SerhiiGadzhilov@users.noreply.github.com> Co-authored-by: Serhii Hadzhilov <serhii-external@symless.com>
283 lines
7.8 KiB
C++
283 lines
7.8 KiB
C++
/*
|
|
* synergy -- mouse and keyboard sharing utility
|
|
* Copyright (C) 2012-2016 Symless Ltd.
|
|
* Copyright (C) 2002 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 LICENSE 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 "synergy/win32/AppUtilWindows.h"
|
|
#include "synergy/Screen.h"
|
|
#include "synergy/ArgsBase.h"
|
|
#include "synergy/App.h"
|
|
#include "synergy/XSynergy.h"
|
|
#include "platform/MSWindowsScreen.h"
|
|
#include "arch/win32/XArchWindows.h"
|
|
#include "arch/win32/ArchMiscWindows.h"
|
|
#include "arch/IArchTaskBarReceiver.h"
|
|
#include "base/Log.h"
|
|
#include "base/log_outputters.h"
|
|
#include "base/IEventQueue.h"
|
|
#include "base/Event.h"
|
|
#include "base/EventQueue.h"
|
|
#include "common/Version.h"
|
|
#include "wintoastlib.h"
|
|
|
|
#include <memory>
|
|
#include <sstream>
|
|
#include <iostream>
|
|
#include <conio.h>
|
|
#include <VersionHelpers.h>
|
|
|
|
#include <Windows.h>
|
|
|
|
AppUtilWindows::AppUtilWindows(IEventQueue* events) :
|
|
m_events(events),
|
|
m_exitMode(kExitModeNormal)
|
|
{
|
|
if (SetConsoleCtrlHandler((PHANDLER_ROUTINE)consoleHandler, TRUE) == FALSE)
|
|
{
|
|
throw XArch(new XArchEvalWindows());
|
|
}
|
|
}
|
|
|
|
AppUtilWindows::~AppUtilWindows()
|
|
{
|
|
}
|
|
|
|
BOOL WINAPI AppUtilWindows::consoleHandler(DWORD)
|
|
{
|
|
LOG((CLOG_INFO "got shutdown signal"));
|
|
IEventQueue* events = AppUtil::instance().app().getEvents();
|
|
events->addEvent(Event(Event::kQuit));
|
|
return TRUE;
|
|
}
|
|
|
|
static
|
|
int
|
|
mainLoopStatic()
|
|
{
|
|
return AppUtil::instance().app().mainLoop();
|
|
}
|
|
|
|
int
|
|
AppUtilWindows::daemonNTMainLoop(int argc, const char** argv)
|
|
{
|
|
app().initApp(argc, argv);
|
|
debugServiceWait();
|
|
|
|
return ArchMiscWindows::runDaemon(mainLoopStatic);
|
|
}
|
|
|
|
void
|
|
AppUtilWindows::exitApp(int code)
|
|
{
|
|
switch (m_exitMode) {
|
|
|
|
case kExitModeDaemon:
|
|
ArchMiscWindows::daemonFailed(code);
|
|
break;
|
|
|
|
default:
|
|
throw XExitApp(code);
|
|
}
|
|
}
|
|
|
|
int daemonNTMainLoopStatic(int argc, const char** argv)
|
|
{
|
|
return AppUtilWindows::instance().daemonNTMainLoop(argc, argv);
|
|
}
|
|
|
|
int
|
|
AppUtilWindows::daemonNTStartup(int, char**)
|
|
{
|
|
SystemLogger sysLogger(app().daemonName(), false);
|
|
m_exitMode = kExitModeDaemon;
|
|
return ARCH->daemonize(app().daemonName(), daemonNTMainLoopStatic);
|
|
}
|
|
|
|
static
|
|
int
|
|
daemonNTStartupStatic(int argc, char** argv)
|
|
{
|
|
return AppUtilWindows::instance().daemonNTStartup(argc, argv);
|
|
}
|
|
|
|
static
|
|
int
|
|
foregroundStartupStatic(int argc, char** argv)
|
|
{
|
|
return AppUtil::instance().app().foregroundStartup(argc, argv);
|
|
}
|
|
|
|
void
|
|
AppUtilWindows::beforeAppExit()
|
|
{
|
|
// this can be handy for debugging, since the application is launched in
|
|
// a new console window, and will normally close on exit (making it so
|
|
// that we can't see error messages).
|
|
if (app().argsBase().m_pauseOnExit) {
|
|
std::cout << std::endl << "press any key to exit..." << std::endl;
|
|
int c = _getch();
|
|
}
|
|
}
|
|
|
|
int
|
|
AppUtilWindows::run(int argc, char** argv)
|
|
{
|
|
if (!IsWindowsXPSP3OrGreater()) {
|
|
throw std::runtime_error("Synergy only supports Windows XP SP3 and above.");
|
|
}
|
|
|
|
// record window instance for tray icon, etc
|
|
ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL));
|
|
|
|
MSWindowsScreen::init(ArchMiscWindows::instanceWin32());
|
|
Thread::getCurrentThread().setPriority(-14);
|
|
|
|
StartupFunc startup;
|
|
if (ArchMiscWindows::wasLaunchedAsService()) {
|
|
startup = &daemonNTStartupStatic;
|
|
} else {
|
|
startup = &foregroundStartupStatic;
|
|
app().argsBase().m_daemon = false;
|
|
}
|
|
|
|
return app().runInner(argc, argv, NULL, startup);
|
|
}
|
|
|
|
AppUtilWindows&
|
|
AppUtilWindows::instance()
|
|
{
|
|
return (AppUtilWindows&)AppUtil::instance();
|
|
}
|
|
|
|
void
|
|
AppUtilWindows::debugServiceWait()
|
|
{
|
|
if (app().argsBase().m_debugServiceWait)
|
|
{
|
|
while(true)
|
|
{
|
|
// this code is only executed when the process is launched via the
|
|
// windows service controller (and --debug-service-wait arg is
|
|
// used). to debug, set a breakpoint on this line so that
|
|
// execution is delayed until the debugger is attached.
|
|
ARCH->sleep(1);
|
|
LOG((CLOG_INFO "waiting for debugger to attach"));
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
AppUtilWindows::startNode()
|
|
{
|
|
app().startNode();
|
|
}
|
|
|
|
std::vector<String>
|
|
AppUtilWindows::getKeyboardLayoutList()
|
|
{
|
|
std::vector<String> layoutLangCodes;
|
|
{
|
|
auto uLayouts = GetKeyboardLayoutList(0, NULL);
|
|
auto lpList = (HKL*)LocalAlloc(LPTR, (uLayouts * sizeof(HKL)));
|
|
uLayouts = GetKeyboardLayoutList(uLayouts, lpList);
|
|
|
|
for (int i = 0; i < uLayouts; ++i){
|
|
String code("", 2);
|
|
GetLocaleInfoA(MAKELCID(((UINT)lpList[i] & 0xffffffff), SORT_DEFAULT), LOCALE_SISO639LANGNAME, &code[0], code.size());
|
|
layoutLangCodes.push_back(code);
|
|
}
|
|
|
|
if (lpList) {
|
|
LocalFree(lpList);
|
|
}
|
|
}
|
|
return layoutLangCodes;
|
|
}
|
|
|
|
String
|
|
AppUtilWindows::getCurrentLanguageCode()
|
|
{
|
|
String code("", 2);
|
|
|
|
auto hklLayout = getCurrentKeyboardLayout();
|
|
if (hklLayout) {
|
|
auto localLayoutID = MAKELCID(LOWORD(hklLayout), SORT_DEFAULT);
|
|
GetLocaleInfoA(localLayoutID, LOCALE_SISO639LANGNAME, &code[0], code.size());
|
|
}
|
|
|
|
return code;
|
|
}
|
|
|
|
HKL AppUtilWindows::getCurrentKeyboardLayout() const
|
|
{
|
|
HKL layout = nullptr;
|
|
|
|
GUITHREADINFO gti = {sizeof(GUITHREADINFO)};
|
|
if (GetGUIThreadInfo(0, >i) && gti.hwndActive) {
|
|
layout = GetKeyboardLayout(GetWindowThreadProcessId(gti.hwndActive, NULL));
|
|
}
|
|
else {
|
|
LOG((CLOG_WARN "Failed to determine current keyboard layout"));
|
|
}
|
|
|
|
return layout;
|
|
}
|
|
|
|
class WinToastHandler : public WinToastLib::IWinToastHandler {
|
|
public:
|
|
WinToastHandler() {}
|
|
// Public interfaces
|
|
void toastActivated() const override {}
|
|
void toastActivated(int actionIndex) const override {}
|
|
void toastDismissed(WinToastDismissalReason state) const override {}
|
|
void toastFailed() const override {}
|
|
};
|
|
|
|
void
|
|
AppUtilWindows::showNotification(const String & title, const String & text) const
|
|
{
|
|
LOG((CLOG_DEBUG "Showing notification. Title: \"%s\". Text: \"%s\"", title.c_str(), text.c_str()));
|
|
if (!WinToastLib::WinToast::isCompatible()) {
|
|
LOG((CLOG_INFO "This system does not support toast notifications"));
|
|
return;
|
|
}
|
|
if (!WinToastLib::WinToast::instance()->isInitialized())
|
|
{
|
|
WinToastLib::WinToast::instance()->setAppName(L"Synergy");
|
|
const auto aumi = WinToastLib::WinToast::configureAUMI(L"Symless", L"Synergy", L"Synergy App", L"1.14.1+");
|
|
WinToastLib::WinToast::instance()->setAppUserModelId(aumi);
|
|
|
|
if (!WinToastLib::WinToast::instance()->initialize())
|
|
{
|
|
LOG((CLOG_DEBUG "Failed to initialize toast notifications"));
|
|
return;
|
|
}
|
|
}
|
|
|
|
WinToastLib::WinToast::WinToastError error;
|
|
auto handler = std::make_unique<WinToastHandler>();
|
|
WinToastLib::WinToastTemplate templ = WinToastLib::WinToastTemplate(WinToastLib::WinToastTemplate::Text02);
|
|
templ.setTextField(std::wstring(title.begin(), title.end()), WinToastLib::WinToastTemplate::FirstLine);
|
|
templ.setTextField(std::wstring(text.begin(), text.end()), WinToastLib::WinToastTemplate::SecondLine);
|
|
|
|
const bool launched = WinToastLib::WinToast::instance()->showToast(templ, handler.get(), &error);
|
|
if (!launched) {
|
|
LOG((CLOG_DEBUG "Failed to show toast notification. Error code: %d", error));
|
|
return;
|
|
}
|
|
}
|
|
|