feat: begin to use QStrings for strings

feat: get windows building with the UNICODE forced by using Qt
refactor: remove ARCHString use QString to convert to / from utf8
build: (arch) link to common
build: (base) link to arch
build: (io) Link to common
build: (client) link to common
build: (server) link to common
fix: Append to log file instead of creating a new one each log line
refactor: Trim cipher description for neater log output
fix: Update log messages to use wide string format for Unicode support
fix: Correct event creation to use wide string for Unicode compatibility
refactor: Use QStringDecoder for UTF-8 handling on Windows Daemon child process
fix: Use correct wide type for Win32 consts
This commit is contained in:
sithlord48
2025-05-30 18:26:02 -04:00
committed by Nick Bolton
parent 66a022a012
commit c4c2f7f37f
63 changed files with 290 additions and 781 deletions

View File

@ -46,6 +46,7 @@
"logonui",
"Lysytsia",
"macdeployqt",
"mojibake",
"msvc",
"noquote",
"NOSONAR",

View File

@ -25,7 +25,6 @@
#pragma once
#include "arch/ArchString.h"
#include "common/Common.h"
#if SYSAPI_WIN32
@ -60,7 +59,7 @@ to each method to those implementations. Clients should use the
exactly one of these objects before attempting to call any method,
typically at the beginning of \c main().
*/
class Arch : public ARCH_DAEMON, public ARCH_LOG, public ARCH_MULTITHREAD, public ARCH_NETWORK, public ArchString
class Arch : public ARCH_DAEMON, public ARCH_LOG, public ARCH_MULTITHREAD, public ARCH_NETWORK
{
public:
Arch();

View File

@ -6,19 +6,22 @@
*/
#include "arch/ArchDaemonNone.h"
#include <QString>
//
// ArchDaemonNone
//
int ArchDaemonNone::daemonize(const char *name, DaemonFunc const &func)
int ArchDaemonNone::daemonize(const QString &name, DaemonFunc const &func)
{
// simply forward the call to func. obviously, this doesn't
// do any daemonizing.
return func(1, &name);
auto t = name.toStdString();
const char *n = t.c_str();
return func(1, &n);
}
std::string ArchDaemonNone::commandLine() const
QString ArchDaemonNone::commandLine() const
{
return "";
return {};
}

View File

@ -24,6 +24,6 @@ public:
~ArchDaemonNone() override = default;
// IArchDaemon overrides
int daemonize(const char *name, DaemonFunc const &func) override;
std::string commandLine() const override;
int daemonize(const QString &name, DaemonFunc const &func) override;
QString commandLine() const override;
};

View File

@ -1,163 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include "arch/ArchString.h"
#include "common/Common.h"
#include <climits>
#include <cstring>
#include <mutex>
static std::mutex s_mutex;
//
// use C library non-reentrant multibyte conversion with mutex
//
int ArchString::convStringWCToMB(char *dst, const wchar_t *src, uint32_t n, bool *errors) const
{
std::scoped_lock lock{s_mutex};
ptrdiff_t len = 0;
bool dummyErrors;
if (errors == nullptr) {
errors = &dummyErrors;
}
*errors = false;
if (dst == nullptr) {
char dummy[MB_LEN_MAX];
const wchar_t *scan = src;
for (; n > 0; --n) {
ptrdiff_t mblen = wctomb(dummy, *scan);
if (mblen == -1) {
*errors = true;
mblen = 1;
}
len += mblen;
++scan;
}
if (ptrdiff_t mblen = wctomb(dummy, L'\0'); mblen != -1) {
len += mblen - 1;
}
} else {
const char *dst0 = dst;
const wchar_t *scan = src;
for (; n > 0; --n) {
if (ptrdiff_t mblen = wctomb(dst, *scan); mblen == -1) {
*errors = true;
*dst++ = '?';
} else {
dst += mblen;
}
++scan;
}
if (ptrdiff_t mblen = wctomb(dst, L'\0'); mblen != -1) {
// don't include nul terminator
dst += mblen - 1;
}
len = dst - dst0;
}
return static_cast<int>(len);
}
ArchString::EWideCharEncoding ArchString::getWideCharEncoding() const
{
#ifdef SYSAPI_WIN32
return EWideCharEncoding::kUTF16;
#else
return EWideCharEncoding::kUCS4;
#endif
}
int ArchString::convStringMBToWC(wchar_t *dst, const char *src, uint32_t n, bool *errors) const
{
std::scoped_lock lock{s_mutex};
ptrdiff_t len = 0;
wchar_t dummy;
bool dummyErrors;
if (errors == nullptr) {
errors = &dummyErrors;
}
*errors = false;
if (dst == nullptr) {
const char *scan = src;
while (n > 0) {
switch (ptrdiff_t mblen = mbtowc(&dummy, scan, n); mblen) {
case -2:
// incomplete last character. convert to unknown character.
*errors = true;
len += 1;
n = 0;
break;
case -1:
// invalid character. count one unknown character and
// start at the next byte.
*errors = true;
len += 1;
scan += 1;
n -= 1;
break;
case 0:
len += 1;
scan += 1;
n -= 1;
break;
default:
// normal character
len += 1;
scan += static_cast<int>(mblen);
n -= static_cast<int>(mblen);
break;
}
}
} else {
const wchar_t *dst0 = dst;
const char *scan = src;
while (n > 0) {
switch (ptrdiff_t mblen = mbtowc(dst, scan, n); mblen) {
case -2:
// incomplete character. convert to unknown character.
*errors = true;
*dst = (wchar_t)0xfffd;
n = 0;
break;
case -1:
// invalid character. count one unknown character and
// start at the next byte.
*errors = true;
*dst = (wchar_t)0xfffd;
scan += 1;
n -= 1;
break;
case 0:
*dst = (wchar_t)0x0000;
scan += 1;
n -= 1;
break;
default:
// normal character
scan += static_cast<int>(mblen);
n -= static_cast<int>(mblen);
break;
}
++dst;
}
len = dst - dst0;
}
return static_cast<int>(len);
}

View File

@ -1,56 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2025 Deskflow Developers
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#pragma once
#include <stdarg.h>
#include <stdint.h>
//! Interface for architecture dependent string operations
/*!
This interface defines the string operations required by
deskflow. Each architecture must implement this interface.
*/
class ArchString
{
public:
ArchString() = default;
ArchString(const ArchString &) = delete;
ArchString(ArchString &&) = delete;
virtual ~ArchString() = default;
ArchString &operator=(const ArchString &) = delete;
ArchString &operator=(ArchString &&) = delete;
//! Wide character encodings
/*!
The known wide character encodings
*/
enum class EWideCharEncoding : uint8_t
{
kUCS2, //!< The UCS-2 encoding
kUCS4, //!< The UCS-4 encoding
kUTF16, //!< The UTF-16 encoding
kUTF32, //!< The UTF-32 encoding
kPlatformDetermined
};
//! @name manipulators
//@{
//! Convert multibyte string to wide character string
int convStringMBToWC(wchar_t *, const char *, uint32_t n, bool *errors) const;
//! Convert wide character string to multibyte string
int convStringWCToMB(char *, const wchar_t *, uint32_t n, bool *errors) const;
//! Return the architecture's native wide character encoding
EWideCharEncoding getWideCharEncoding() const;
//@}
};

View File

@ -45,10 +45,10 @@ add_library(arch STATIC ${PLATFORM_CODE}
IArchLog.h
IArchMultithread.h
IArchNetwork.h
ArchString.cpp
ArchString.h
)
target_link_libraries (arch PUBLIC common)
if(UNIX)
target_link_libraries(arch ${libs})
target_link_libraries(arch PUBLIC ${libs})
endif()

View File

@ -8,8 +8,8 @@
#pragma once
#include <QString>
#include <functional>
#include <string>
//! Interface for architecture dependent daemonizing
/*!
@ -53,7 +53,7 @@ public:
\c ArchMiscWindows::daemonFailed() to indicate startup failure.
</ul>
*/
virtual int daemonize(const char *name, DaemonFunc const &func) = 0;
virtual int daemonize(const QString &name, DaemonFunc const &func) = 0;
//@}
@ -61,7 +61,7 @@ public:
/*!
Gets the command line with which the application was started.
*/
virtual std::string commandLine() const = 0;
virtual QString commandLine() const = 0;
//@}
};

View File

@ -8,6 +8,8 @@
#pragma once
#include <QString>
#include "base/LogLevel.h"
//! Interface for architecture dependent logging
@ -27,7 +29,7 @@ public:
Opens the log for writing. The log must be opened before being
written to.
*/
virtual void openLog(const char *name) = 0;
virtual void openLog(const QString &name) = 0;
//! Close the log
/*!
@ -48,7 +50,6 @@ public:
/*!
Writes the given string to the log with the given level.
*/
virtual void writeLog(LogLevel, const char *) = 0;
virtual void writeLog(LogLevel, const QString &) = 0;
//@}
};

View File

@ -19,6 +19,7 @@
#include <sys/types.h>
#include <unistd.h>
#include <QString>
//
// ArchDaemonUnix
//
@ -46,11 +47,14 @@ bool alreadyDaemonized()
#endif
int ArchDaemonUnix::daemonize(const char *name, DaemonFunc const &func)
int ArchDaemonUnix::daemonize(const QString &name, DaemonFunc const &func)
{
#ifdef __APPLE__
if (alreadyDaemonized())
return func(1, &name);
if (alreadyDaemonized()) {
auto t = name.toStdString();
const char *n = t.c_str();
return func(1, &n);
}
#endif
// fork so shell thinks we're done and so we're not a process
@ -104,5 +108,8 @@ int ArchDaemonUnix::daemonize(const char *name, DaemonFunc const &func)
#endif
// invoke function
return func(1, &name);
auto t = name.toStdString();
const char *n = t.c_str();
return func(1, &n);
}

View File

@ -20,5 +20,5 @@ public:
~ArchDaemonUnix() override = default;
// IArchDaemon overrides
int daemonize(const char *name, DaemonFunc const &func) override;
int daemonize(const QString &name, DaemonFunc const &func) override;
};

View File

@ -7,15 +7,15 @@
#include "arch/unix/ArchLogUnix.h"
#include <QString>
#include <syslog.h>
//
// ArchLogUnix
//
void ArchLogUnix::openLog(const char *name)
void ArchLogUnix::openLog(const QString &name)
{
openlog(name, 0, LOG_DAEMON);
openlog(qPrintable(name), 0, LOG_DAEMON);
}
void ArchLogUnix::closeLog()
@ -28,7 +28,7 @@ void ArchLogUnix::showLog(bool)
// do nothing
}
void ArchLogUnix::writeLog(LogLevel level, const char *msg)
void ArchLogUnix::writeLog(LogLevel level, const QString &msg)
{
// convert level
int priority;
@ -56,5 +56,5 @@ void ArchLogUnix::writeLog(LogLevel level, const char *msg)
}
// log it
syslog(priority, "%s", msg);
syslog(priority, "%s", qPrintable(msg));
}

View File

@ -19,8 +19,8 @@ public:
~ArchLogUnix() override = default;
// IArchLog overrides
void openLog(const char *name) override;
void openLog(const QString &name) override;
void closeLog() override;
void showLog(bool) override;
void writeLog(LogLevel, const char *) override;
void writeLog(LogLevel, const QString &) override;
};

View File

@ -21,7 +21,7 @@ ArchDaemonWindows *ArchDaemonWindows::s_daemon = nullptr;
ArchDaemonWindows::ArchDaemonWindows() : m_daemonThreadID(0)
{
m_quitMessage = RegisterWindowMessage("DeskflowDaemonExit");
m_quitMessage = RegisterWindowMessage(L"DeskflowDaemonExit");
}
int ArchDaemonWindows::runDaemon(RunFunc runFunc)
@ -52,7 +52,7 @@ void ArchDaemonWindows::daemonFailed(int result)
throw ArchDaemonRunException(result);
}
int ArchDaemonWindows::daemonize(const char *name, DaemonFunc const &func)
int ArchDaemonWindows::daemonize(const QString &name, DaemonFunc const &func)
{
assert(name != nullptr);
assert(func != nullptr);
@ -62,7 +62,7 @@ int ArchDaemonWindows::daemonize(const char *name, DaemonFunc const &func)
// construct the service entry
SERVICE_TABLE_ENTRY entry[2];
entry[0].lpServiceName = const_cast<char *>(name);
entry[0].lpServiceName = const_cast<wchar_t *>(name.toStdWString().c_str());
entry[0].lpServiceProc = &ArchDaemonWindows::serviceMainEntry;
entry[1].lpServiceName = nullptr;
entry[1].lpServiceProc = nullptr;
@ -82,7 +82,7 @@ int ArchDaemonWindows::daemonize(const char *name, DaemonFunc const &func)
HKEY ArchDaemonWindows::openNTServicesKey()
{
static const char *s_keyNames[] = {_T("SYSTEM"), _T("CurrentControlSet"), _T("Services"), nullptr};
static const wchar_t *s_keyNames[] = {_T("SYSTEM"), _T("CurrentControlSet"), _T("Services"), nullptr};
return ArchMiscWindows::addKey(HKEY_LOCAL_MACHINE, s_keyNames);
}
@ -204,9 +204,9 @@ void ArchDaemonWindows::setStatusError(DWORD error)
void ArchDaemonWindows::serviceMain(DWORD argc, LPTSTR *argvIn)
{
using ArgList = std::vector<LPCTSTR>;
using Arguments = std::vector<std::string>;
const char **argv = const_cast<const char **>(argvIn);
using ArgList = std::vector<LPWSTR>;
using Arguments = std::vector<std::wstring>;
const wchar_t **argv = const_cast<const wchar_t **>(argvIn);
// create synchronization objects
m_serviceMutex = ARCH->newMutex();
@ -226,7 +226,7 @@ void ArchDaemonWindows::serviceMain(DWORD argc, LPTSTR *argvIn)
m_serviceState = SERVICE_START_PENDING;
setStatus(m_serviceState, 0, 10000);
std::string commandLine;
std::wstring commandLine;
// if no arguments supplied then try getting them from the registry.
// the first argument doesn't count because it's the service name.
@ -244,17 +244,17 @@ void ArchDaemonWindows::serviceMain(DWORD argc, LPTSTR *argvIn)
// if the command line isn't empty then parse and use it
if (!commandLine.empty()) {
// parse, honoring double quoted substrings
std::string::size_type i = commandLine.find_first_not_of(" \t");
std::wstring::size_type i = commandLine.find_first_not_of(_T(" \t"));
while (i != std::string::npos && i != commandLine.size()) {
// find end of string
std::string::size_type e;
std::wstring::size_type e;
if (commandLine[i] == '\"') {
// quoted. find closing quote.
++i;
e = commandLine.find("\"", i);
e = commandLine.find(_T("\""), i);
// whitespace must follow closing quote
if (e == std::string::npos ||
if (e == std::wstring::npos ||
(e + 1 != commandLine.size() && commandLine[e + 1] != ' ' && commandLine[e + 1] != '\t')) {
args.clear();
break;
@ -265,8 +265,8 @@ void ArchDaemonWindows::serviceMain(DWORD argc, LPTSTR *argvIn)
i = e + 1;
} else {
// unquoted. find next whitespace.
e = commandLine.find_first_of(" \t", i);
if (e == std::string::npos) {
e = commandLine.find_first_of(_T(" \t"), i);
if (e == std::wstring::npos) {
e = commandLine.size();
}
@ -276,28 +276,28 @@ void ArchDaemonWindows::serviceMain(DWORD argc, LPTSTR *argvIn)
}
// next argument
i = commandLine.find_first_not_of(" \t", i);
i = commandLine.find_first_not_of(_T(" \t"), i);
}
// service name goes first
myArgv.push_back(argv[0]);
myArgv.push_back(LPWSTR(argv[0]));
// get pointers
for (size_t j = 0; j < args.size(); ++j) {
myArgv.push_back(args[j].c_str());
myArgv.push_back(LPWSTR(args[j].c_str()));
}
// adjust argc/argv
argc = (DWORD)myArgv.size();
argv = &myArgv[0];
argv = const_cast<const wchar_t **>(&myArgv[0]);
}
}
m_commandLine = commandLine;
m_commandLine = QString::fromStdWString(commandLine);
try {
// invoke daemon function
m_daemonResult = m_daemonFunc(static_cast<int>(argc), argv);
m_daemonResult = m_daemonFunc(static_cast<int>(argc), reinterpret_cast<const char **>(argv));
} catch (ArchDaemonRunException &e) {
setStatusError(e.m_result);
m_daemonResult = -1;
@ -381,7 +381,7 @@ void WINAPI ArchDaemonWindows::serviceHandlerEntry(DWORD ctrl)
s_daemon->serviceHandler(ctrl);
}
void ArchDaemonWindows::start(const char *name)
void ArchDaemonWindows::start(const QString &name)
{
// open service manager
SC_HANDLE mgr = OpenSCManager(nullptr, nullptr, GENERIC_READ);
@ -390,7 +390,7 @@ void ArchDaemonWindows::start(const char *name)
}
// open the service
SC_HANDLE service = OpenService(mgr, name, SERVICE_START);
SC_HANDLE service = OpenService(mgr, name.toStdWString().c_str(), SERVICE_START);
if (service == nullptr) {
CloseServiceHandle(mgr);
@ -403,7 +403,7 @@ void ArchDaemonWindows::start(const char *name)
}
}
void ArchDaemonWindows::stop(const char *name)
void ArchDaemonWindows::stop(const QString &name)
{
// open service manager
SC_HANDLE mgr = OpenSCManager(nullptr, nullptr, GENERIC_READ);
@ -412,7 +412,7 @@ void ArchDaemonWindows::stop(const char *name)
}
// open the service
SC_HANDLE service = OpenService(mgr, name, SERVICE_STOP | SERVICE_QUERY_STATUS);
SC_HANDLE service = OpenService(mgr, name.toStdWString().c_str(), SERVICE_STOP | SERVICE_QUERY_STATUS);
if (service == nullptr) {
CloseServiceHandle(mgr);

View File

@ -15,7 +15,8 @@
#include <tchar.h>
#include <functional>
#include <string>
#include <QString>
#define ARCH_DAEMON ArchDaemonWindows
@ -67,8 +68,8 @@ public:
static UINT getDaemonQuitMessage();
// IArchDaemon overrides
int daemonize(const char *name, DaemonFunc const &func) override;
std::string commandLine() const override
int daemonize(const QString &name, DaemonFunc const &func) override;
QString commandLine() const override
{
return m_commandLine;
}
@ -92,8 +93,8 @@ private:
void serviceHandler(DWORD ctrl);
static void WINAPI serviceHandlerEntry(DWORD ctrl);
void start(const char *name);
void stop(const char *name);
void start(const QString &name);
void stop(const QString &name);
private:
class ArchDaemonRunException
@ -124,5 +125,5 @@ private:
UINT m_quitMessage;
std::string m_commandLine;
QString m_commandLine;
};

View File

@ -7,7 +7,7 @@
#include "arch/win32/ArchLogWindows.h"
#include <string.h>
#include <QString>
//
// ArchLogWindows
@ -18,10 +18,10 @@ ArchLogWindows::ArchLogWindows() : m_eventLog(nullptr)
// do nothing
}
void ArchLogWindows::openLog(const char *name)
void ArchLogWindows::openLog(const QString &name)
{
if (m_eventLog == nullptr) {
m_eventLog = RegisterEventSource(nullptr, name);
m_eventLog = RegisterEventSource(nullptr, name.toStdWString().c_str());
}
}
@ -38,7 +38,7 @@ void ArchLogWindows::showLog(bool)
// do nothing
}
void ArchLogWindows::writeLog(LogLevel level, const char *msg)
void ArchLogWindows::writeLog(LogLevel level, const QString &msg)
{
if (m_eventLog != nullptr) {
// convert priority
@ -67,9 +67,9 @@ void ArchLogWindows::writeLog(LogLevel level, const char *msg)
m_eventLog, type, static_cast<WORD>(level),
0, // event ID
nullptr, 0,
(DWORD)strlen(msg) + 1, // raw data size
(DWORD)(msg.length()) + 1, // raw data size
nullptr,
const_cast<char *>(msg)
const_cast<char *>(qPrintable(msg))
); // raw data
}
}

View File

@ -22,10 +22,10 @@ public:
~ArchLogWindows() override = default;
// IArchLog overrides
void openLog(const char *name) override;
void openLog(const QString &name) override;
void closeLog() override;
void showLog(bool showIfEmpty) override;
void writeLog(LogLevel, const char *) override;
void writeLog(LogLevel, const QString &) override;
private:
HANDLE m_eventLog;

View File

@ -196,29 +196,29 @@ void ArchMiscWindows::setValue(HKEY key, const TCHAR *name, DWORD value)
RegSetValueEx(key, name, 0, REG_DWORD, reinterpret_cast<CONST BYTE *>(&value), sizeof(DWORD));
}
std::string ArchMiscWindows::readBinaryOrString(HKEY key, const TCHAR *name, DWORD type)
std::wstring ArchMiscWindows::readBinaryOrString(HKEY key, const TCHAR *name, DWORD type)
{
// get the size of the string
DWORD actualType;
DWORD size = 0;
LONG result = RegQueryValueEx(key, name, 0, &actualType, nullptr, &size);
if (result != ERROR_SUCCESS || actualType != type) {
return std::string();
return std::wstring();
}
// if zero size then return empty string
if (size == 0) {
return std::string();
return std::wstring();
}
// allocate space
char *buffer = new char[size];
wchar_t *buffer = new wchar_t[size];
// read it
result = RegQueryValueEx(key, name, 0, &actualType, reinterpret_cast<BYTE *>(buffer), &size);
if (result != ERROR_SUCCESS || actualType != type) {
delete[] buffer;
return std::string();
return std::wstring();
}
// clean up and return value
@ -226,12 +226,12 @@ std::string ArchMiscWindows::readBinaryOrString(HKEY key, const TCHAR *name, DWO
// don't include terminating nul; std::string will add one.
--size;
}
std::string value(buffer, size);
std::wstring value(buffer, size);
delete[] buffer;
return value;
}
std::string ArchMiscWindows::readValueString(HKEY key, const TCHAR *name)
std::wstring ArchMiscWindows::readValueString(HKEY key, const TCHAR *name)
{
return readBinaryOrString(key, name, REG_SZ);
}
@ -265,7 +265,7 @@ void ArchMiscWindows::setThreadExecutionState(DWORD busyModes)
{
// look up function dynamically so we work on older systems
if (s_stes == nullptr) {
HINSTANCE kernel = LoadLibrary("kernel32.dll");
HINSTANCE kernel = LoadLibrary(L"kernel32.dll");
if (kernel != nullptr) {
s_stes = reinterpret_cast<STES_t>(GetProcAddress(kernel, "SetThreadExecutionState"));
}
@ -303,7 +303,7 @@ void ArchMiscWindows::wakeupDisplay()
// ES_CONTINUOUS, which we don't want.
if (s_stes == nullptr) {
HINSTANCE kernel = LoadLibrary("kernel32.dll");
HINSTANCE kernel = LoadLibrary(L"kernel32.dll");
if (kernel != nullptr) {
s_stes = reinterpret_cast<STES_t>(GetProcAddress(kernel, "SetThreadExecutionState"));
}
@ -320,16 +320,16 @@ void ArchMiscWindows::wakeupDisplay()
bool ArchMiscWindows::wasLaunchedAsService()
{
std::string name;
std::wstring name;
if (!getParentProcessName(name)) {
LOG_ERR("cannot determine if process was launched as service");
return false;
}
return (name == "services.exe");
return (name == L"services.exe");
}
bool ArchMiscWindows::getParentProcessName(std::string &name)
bool ArchMiscWindows::getParentProcessName(std::wstring &name)
{
PROCESSENTRY32 parentEntry;
if (!getParentProcessEntry(parentEntry)) {
@ -405,7 +405,7 @@ void ArchMiscWindows::setInstanceWin32(HINSTANCE instance)
s_instanceWin32 = instance;
}
std::string ArchMiscWindows::getActiveDesktopName()
std::wstring ArchMiscWindows::getActiveDesktopName()
{
HDESK desk = OpenInputDesktop(0, TRUE, GENERIC_READ);
if (desk == nullptr) {
@ -440,7 +440,7 @@ HMODULE ArchMiscWindows::findLoadedModule(std::array<const char *, 2> moduleName
}
for (const auto &moduleName : moduleNames) {
if (_stricmp(loadedModuleName.data(), moduleName) == 0) {
if (_stricmp((loadedModuleName.data()), moduleName) == 0) {
return hModules[i];
}
}

View File

@ -92,7 +92,7 @@ public:
static void setValue(HKEY key, const TCHAR *name, DWORD value);
//! Read a string value from the registry
static std::string readValueString(HKEY, const TCHAR *name);
static std::wstring readValueString(HKEY, const TCHAR *name);
//! Read a DWORD value from the registry
static DWORD readValueInt(HKEY, const TCHAR *name);
@ -110,7 +110,7 @@ public:
static bool wasLaunchedAsService();
//! Returns true if we got the parent process name.
static bool getParentProcessName(std::string &name);
static bool getParentProcessName(std::wstring &name);
//! Prevent hard to troubleshoot errors, e.g. access violations.
static void guardRuntimeVersion();
@ -125,7 +125,7 @@ public:
static void setInstanceWin32(HINSTANCE instance);
//! Get the name of the active input desktop.
static std::string getActiveDesktopName();
static std::wstring getActiveDesktopName();
//! Returns true if the process is running with elevated privileges (i.e. as admin).
static bool isProcessElevated();
@ -138,7 +138,7 @@ private:
static HKEY openKey(HKEY parent, const TCHAR *const *keyPath, bool create);
//! Read a string value from the registry
static std::string readBinaryOrString(HKEY, const TCHAR *name, DWORD type);
static std::wstring readBinaryOrString(HKEY, const TCHAR *name, DWORD type);
//! Set thread busy state
static void setThreadExecutionState(DWORD);

View File

@ -100,7 +100,7 @@ ArchNetworkWinsock::~ArchNetworkWinsock()
void ArchNetworkWinsock::init()
{
static const char *s_library[] = {"ws2_32.dll"};
static const wchar_t *s_library[] = {L"ws2_32.dll"};
assert(WSACleanup_winsock == nullptr);
assert(s_networkModule == nullptr);

View File

@ -41,7 +41,7 @@ add_library(base STATIC
Unicode.h
)
target_link_libraries(base PRIVATE arch)
target_link_libraries(base PUBLIC arch)
if (CMAKE_CXX_BYTE_ORDER STREQUAL "BIG_ENDIAN")
target_compile_definitions(base PUBLIC WORDS_BIGENDIAN=1)
endif()

View File

@ -30,7 +30,7 @@ public:
Opens the outputter for writing. Calling this method on an
already open outputter must have no effect.
*/
virtual void open(const char *title) = 0;
virtual void open(const QString &title) = 0;
//! Close the outputter
/*!
@ -55,7 +55,7 @@ public:
message to all outputters in the outputter chain, otherwise
it continues. Most implementations should return true.
*/
virtual bool write(LogLevel level, const char *message) = 0;
virtual bool write(LogLevel level, const QString &message) = 0;
//@}
};

View File

@ -8,19 +8,20 @@
#include "base/LogOutputters.h"
#include "arch/Arch.h"
#include "base/Path.h"
#include "base/String.h"
#include <fstream>
#include <iostream>
#include <QFile>
#include <QString>
#include <QTextStream>
constexpr auto s_logFileSizeLimit = 1024 * 1024; //!< Max Log size before rotating (1Mb)
//
// StopLogOutputter
//
void StopLogOutputter::open(const char *)
void StopLogOutputter::open(const QString &)
{
// do nothing
}
@ -35,7 +36,7 @@ void StopLogOutputter::show(bool)
// do nothing
}
bool StopLogOutputter::write(LogLevel, const char *)
bool StopLogOutputter::write(LogLevel, const QString &)
{
return false;
}
@ -44,7 +45,7 @@ bool StopLogOutputter::write(LogLevel, const char *)
// ConsoleLogOutputter
//
void ConsoleLogOutputter::open(const char *title)
void ConsoleLogOutputter::open(const QString &title)
{
// do nothing
}
@ -59,12 +60,12 @@ void ConsoleLogOutputter::show(bool showIfEmpty)
// do nothing
}
bool ConsoleLogOutputter::write(LogLevel level, const char *msg)
bool ConsoleLogOutputter::write(LogLevel level, const QString &msg)
{
if ((level >= LogLevel::Fatal) && (level <= LogLevel::Warning))
std::cerr << msg << std::endl;
std::cerr << qPrintable(msg) << std::endl;
else
std::cout << msg << std::endl;
std::cout << qPrintable(msg) << std::endl;
std::cout.flush();
return true;
}
@ -78,7 +79,7 @@ void ConsoleLogOutputter::flush() const
// SystemLogOutputter
//
void SystemLogOutputter::open(const char *title)
void SystemLogOutputter::open(const QString &title)
{
ARCH->openLog(title);
}
@ -93,7 +94,7 @@ void SystemLogOutputter::show(bool showIfEmpty)
ARCH->showLog(showIfEmpty);
}
bool SystemLogOutputter::write(LogLevel level, const char *msg)
bool SystemLogOutputter::write(LogLevel level, const QString &msg)
{
ARCH->writeLog(level, msg);
return true;
@ -103,7 +104,7 @@ bool SystemLogOutputter::write(LogLevel level, const char *msg)
// SystemLogger
//
SystemLogger::SystemLogger(const char *title, bool blockConsole)
SystemLogger::SystemLogger(const QString &title, bool blockConsole)
{
// redirect log messages
if (blockConsole) {
@ -129,44 +130,36 @@ SystemLogger::~SystemLogger()
// FileLogOutputter
//
FileLogOutputter::FileLogOutputter(const char *logFile)
FileLogOutputter::FileLogOutputter(const QString &logFile)
{
setLogFilename(logFile);
}
void FileLogOutputter::setLogFilename(const char *logFile)
void FileLogOutputter::setLogFilename(const QString &logFile)
{
assert(logFile != nullptr);
m_fileName = logFile;
}
bool FileLogOutputter::write(LogLevel level, const char *message)
bool FileLogOutputter::write(LogLevel level, const QString &message)
{
bool moveFile = false;
QFile file(m_fileName);
if (!file.open(QFile::WriteOnly | QFile::Append))
return false;
std::ofstream m_handle;
m_handle.open(deskflow::filesystem::path(m_fileName), std::fstream::app);
if (m_handle.is_open() && m_handle.fail() != true) {
m_handle << message << std::endl;
QTextStream(&file) << message << Qt::endl;
file.close();
// when file size exceeds limits, move to 'old log' filename.
size_t p = m_handle.tellp();
if (p > s_logFileSizeLimit) {
moveFile = true;
}
}
m_handle.close();
if (moveFile) {
std::string oldLogFilename = deskflow::string::sprintf("%s.1", m_fileName.c_str());
remove(oldLogFilename.c_str());
rename(m_fileName.c_str(), oldLogFilename.c_str());
if (file.size() > s_logFileSizeLimit) {
const auto oldFile = QStringLiteral("%1.1").arg(m_fileName);
QFile::remove(m_fileName);
file.rename(m_fileName, oldFile);
}
return true;
}
void FileLogOutputter::open(const char *title)
void FileLogOutputter::open(const QString &title)
{
// do nothing
}

View File

@ -11,6 +11,7 @@
#include "base/ILogOutputter.h"
#include "mt/Thread.h"
#include <QString>
//! Stop traversing log chain outputter
/*!
This outputter performs no output and returns false from \c write(),
@ -24,10 +25,10 @@ public:
~StopLogOutputter() override = default;
// ILogOutputter overrides
void open(const char *title) override;
void open(const QString &title) override;
void close() override;
void show(bool showIfEmpty) override;
bool write(LogLevel level, const char *message) override;
bool write(LogLevel level, const QString &message) override;
};
//! Write log to console
@ -42,10 +43,10 @@ public:
~ConsoleLogOutputter() override = default;
// ILogOutputter overrides
void open(const char *title) override;
void open(const QString &title) override;
void close() override;
void show(bool showIfEmpty) override;
bool write(LogLevel level, const char *message) override;
bool write(LogLevel level, const QString &message) override;
void flush() const;
};
@ -58,19 +59,19 @@ message is ignored.
class FileLogOutputter : public ILogOutputter
{
public:
explicit FileLogOutputter(const char *logFile);
explicit FileLogOutputter(const QString &logFile);
~FileLogOutputter() override = default;
// ILogOutputter overrides
void open(const char *title) override;
void open(const QString &title) override;
void close() override;
void show(bool showIfEmpty) override;
bool write(LogLevel level, const char *message) override;
bool write(LogLevel level, const QString &message) override;
void setLogFilename(const char *title);
void setLogFilename(const QString &title);
private:
std::string m_fileName;
QString m_fileName;
};
//! Write log to system log
@ -84,10 +85,10 @@ public:
~SystemLogOutputter() override = default;
// ILogOutputter overrides
void open(const char *title) override;
void open(const QString &title) override;
void close() override;
void show(bool showIfEmpty) override;
bool write(LogLevel level, const char *message) override;
bool write(LogLevel level, const QString &message) override;
};
//! Write log to system log only
@ -101,7 +102,7 @@ the scope.
class SystemLogger
{
public:
SystemLogger(const char *title, bool blockConsole);
SystemLogger(const QString &title, bool blockConsole);
SystemLogger(SystemLogger const &) = delete;
SystemLogger(SystemLogger &&) = delete;
~SystemLogger();

View File

@ -6,9 +6,7 @@
*/
#include "base/Unicode.h"
#include "arch/Arch.h"
using enum ArchString::EWideCharEncoding;
//
// local utility functions
//
@ -197,28 +195,6 @@ std::string Unicode::UTF8ToUTF32(const std::string &src, bool *errors)
return dst;
}
std::string Unicode::UTF8ToText(const std::string &src, bool *errors)
{
// default to success
resetError(errors);
// convert to wide char
uint32_t size;
wchar_t *tmp = UTF8ToWideChar(src, size, errors);
// convert string to multibyte
int len = ARCH->convStringWCToMB(nullptr, tmp, size, errors);
auto *mbs = new char[len + 1];
ARCH->convStringWCToMB(mbs, tmp, size, errors);
std::string text(mbs, len);
// clean up
delete[] mbs;
delete[] tmp;
return text;
}
std::string Unicode::UCS2ToUTF8(const std::string_view &src, bool *errors)
{
// default to success
@ -259,89 +235,6 @@ std::string Unicode::UTF32ToUTF8(const std::string_view &src, bool *errors)
return doUTF32ToUTF8(reinterpret_cast<const uint8_t *>(src.data()), n, errors);
}
std::string Unicode::textToUTF8(const std::string &src, bool *errors, ArchString::EWideCharEncoding encoding)
{
// default to success
resetError(errors);
// convert string to wide characters
auto n = (uint32_t)src.size();
int len = ARCH->convStringMBToWC(nullptr, src.c_str(), n, errors);
auto *wcs = new wchar_t[len + 1];
ARCH->convStringMBToWC(wcs, src.c_str(), n, errors);
// convert to UTF8
std::string utf8 = wideCharToUTF8(wcs, len, errors, encoding);
// clean up
delete[] wcs;
return utf8;
}
wchar_t *Unicode::UTF8ToWideChar(const std::string &src, uint32_t &size, bool *errors)
{
// convert to platform's wide character encoding
std::string tmp;
switch (ARCH->getWideCharEncoding()) {
case kUCS2:
tmp = UTF8ToUCS2(src, errors);
size = (uint32_t)tmp.size() >> 1;
break;
case kUCS4:
tmp = UTF8ToUCS4(src, errors);
size = (uint32_t)tmp.size() >> 2;
break;
case kUTF16:
tmp = UTF8ToUTF16(src, errors);
size = (uint32_t)tmp.size() >> 1;
break;
case kUTF32:
tmp = UTF8ToUTF32(src, errors);
size = (uint32_t)tmp.size() >> 2;
break;
default:
assert(0 && "unknown wide character encoding");
}
// copy to a wchar_t array
auto *dst = new wchar_t[size];
::memcpy(dst, tmp.data(), sizeof(wchar_t) * size);
return dst;
}
std::string
Unicode::wideCharToUTF8(const wchar_t *src, uint32_t size, bool *errors, ArchString::EWideCharEncoding encoding)
{
if (encoding == kPlatformDetermined) {
encoding = ARCH->getWideCharEncoding();
}
// convert from platform's wide character encoding.
// note -- this must include a wide nul character (independent of
// the String's nul character).
switch (encoding) {
case kUCS2:
return doUCS2ToUTF8(reinterpret_cast<const uint8_t *>(src), size, errors);
case kUCS4:
return doUCS4ToUTF8(reinterpret_cast<const uint8_t *>(src), size, errors);
case kUTF16:
return doUTF16ToUTF8(reinterpret_cast<const uint8_t *>(src), size, errors);
case kUTF32:
return doUTF32ToUTF8(reinterpret_cast<const uint8_t *>(src), size, errors);
default:
assert(0 && "unknown wide character encoding");
return std::string();
}
}
std::string Unicode::doUCS2ToUTF8(const uint8_t *data, uint32_t n, bool *errors)
{
// make some space

View File

@ -7,7 +7,7 @@
#pragma once
#include "arch/ArchString.h"
#include "common/Common.h"
#include <string>
@ -61,14 +61,6 @@ public:
*/
static std::string UTF8ToUTF32(const std::string &, bool *errors = nullptr);
//! Convert from UTF-8 to the current locale encoding
/*!
Convert from UTF-8 to the current locale encoding. If errors is not
nullptr then *errors is set to true iff any character could not be encoded.
Decoding errors do not set *errors.
*/
static std::string UTF8ToText(const std::string &, bool *errors = nullptr);
//! Convert from UCS-2 to UTF-8
/*!
Convert from UCS-2 to UTF-8. If errors is not nullptr then *errors is
@ -97,32 +89,9 @@ public:
*/
static std::string UTF32ToUTF8(const std::string_view &, bool *errors = nullptr);
//! Convert from the current locale encoding to UTF-8
/*!
Convert from the current locale encoding to UTF-8. If errors is not
nullptr then *errors is set to true iff any character could not be decoded.
*/
static std::string textToUTF8(
const std::string &, bool *errors = nullptr,
ArchString::EWideCharEncoding encoding = ArchString::EWideCharEncoding::kPlatformDetermined
);
//@}
private:
// convert UTF8 to wchar_t string (using whatever encoding is native
// to the platform). caller must delete[] the returned string. the
// string is *not* nul terminated; the length (in characters) is
// returned in size.
static wchar_t *UTF8ToWideChar(const std::string &, uint32_t &size, bool *errors);
// convert nul terminated wchar_t string (in platform's native
// encoding) to UTF8.
static std::string wideCharToUTF8(
const wchar_t *, uint32_t size, bool *errors,
ArchString::EWideCharEncoding encoding = ArchString::EWideCharEncoding::kPlatformDetermined
);
// internal conversion to UTF8
static std::string doUCS2ToUTF8(const uint8_t *src, uint32_t n, bool *errors);
static std::string doUCS4ToUTF8(const uint8_t *src, uint32_t n, bool *errors);

View File

@ -13,6 +13,8 @@ add_library(client STATIC
ServerProxy.h
)
target_link_libraries(client PUBLIC common)
if(UNIX)
target_link_libraries(client app io)
target_link_libraries(client PUBLIC app io)
endif()

View File

@ -21,7 +21,6 @@ const auto kCopyright = //
"Copyright (C) 2009-2012 Nick Bolton\n"
"Copyright (C) 2002-2009 Chris Schoeneman";
const auto kCoreBinName = "@CORE_BINARY@";
#ifndef NDEBUG
@ -43,11 +42,8 @@ const auto kWindowsRuntimeMajor = @REQUIRED_MSVC_RUNTIME_MAJOR@;
const auto kWindowsRuntimeMinor = @REQUIRED_MSVC_RUNTIME_MINOR@;
// clang-format on
const auto kWindowsRegistryKey = "SOFTWARE\\@CMAKE_PROJECT_PROPER_NAME@";
const auto kCloseEventName = "Global\\@CMAKE_PROJECT_PROPER_NAME@Close";
const auto kSendSasEventName = "Global\\@CMAKE_PROJECT_PROPER_NAME@SendSAS";
constexpr auto kWindowsRegistryKey = L"SOFTWARE\\@CMAKE_PROJECT_PROPER_NAME@";
constexpr auto kCloseEventName = L"Global\\@CMAKE_PROJECT_PROPER_NAME@Close";
constexpr auto kSendSasEventName = L"Global\\@CMAKE_PROJECT_PROPER_NAME@SendSAS";
#endif

View File

@ -6,10 +6,10 @@
*/
#if WINAPI_XWINDOWS
#include "base/Log.h"
#include <memory>
#include "DeskflowXkbKeyboard.h"
#include "base/Log.h"
#include "DeskflowXkbKeyboard.h" // Include last due to X11 use
namespace deskflow::linux {

View File

@ -189,7 +189,7 @@ HKL AppUtilWindows::getCurrentKeyboardLayout() const
void AppUtilWindows::eventLoop()
{
HANDLE hCloseEvent = CreateEventA(nullptr, TRUE, FALSE, kCloseEventName);
HANDLE hCloseEvent = CreateEvent(nullptr, TRUE, FALSE, kCloseEventName);
if (!hCloseEvent) {
LOG_CRIT("failed to create event for windows event loop");
throw std::runtime_error(windowsErrorToString(GetLastError()));

View File

@ -27,7 +27,7 @@ QString CommandProcess::run()
QString error;
if (success) {
if (!m_Input.isEmpty()) {
process.write(m_Input.toStdString().c_str());
process.write(qPrintable(m_Input));
}
if (process.waitForFinished()) {

View File

@ -14,3 +14,5 @@ add_library(io STATIC
StreamFilter.cpp
StreamFilter.h
)
target_link_libraries(io PUBLIC common)

View File

@ -90,7 +90,7 @@ void SslLogger::logSecureConnectInfo(const SSL *ssl)
if (cipher) {
char msg[128] = {0};
SSL_CIPHER_description(cipher, msg, sizeof(msg));
LOG_DEBUG("openssl cipher: %s", msg);
LOG_DEBUG("openssl cipher: %s", QString(msg).trimmed().toStdString().c_str());
// For some reason SSL_get_version is return mismatching information to
// SSL_CIPHER_description

View File

@ -15,7 +15,7 @@
MSWindowsClipboardHTMLConverter::MSWindowsClipboardHTMLConverter()
{
m_format = RegisterClipboardFormat("HTML Format");
m_format = RegisterClipboardFormat(L"HTML Format");
}
IClipboard::Format MSWindowsClipboardHTMLConverter::getFormat() const

View File

@ -9,6 +9,8 @@
#include "base/Unicode.h"
#include <QString>
//
// MSWindowsClipboardTextConverter
//
@ -20,17 +22,12 @@ UINT MSWindowsClipboardTextConverter::getWin32Format() const
std::string MSWindowsClipboardTextConverter::doFromIClipboard(const std::string &data) const
{
// convert and add nul terminator
return Unicode::UTF8ToText(data) += '\0';
return QString::fromStdString(data).toLatin1().toStdString() + '\0';
}
std::string MSWindowsClipboardTextConverter::doToIClipboard(const std::string &data) const
{
// convert and truncate at first nul terminator
std::string dst = Unicode::textToUTF8(data);
std::string::size_type n = dst.find('\0');
if (n != std::string::npos) {
dst.erase(n);
}
return dst;
auto q = QString::fromStdString(data);
q.truncate(q.indexOf('\0'));
return q.toStdString();
}

View File

@ -9,9 +9,10 @@
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <string>
void MSWindowsDebugOutputter::open(const char *title)
#include <QString>
void MSWindowsDebugOutputter::open(const QString &title)
{
// do nothing
}
@ -26,9 +27,10 @@ void MSWindowsDebugOutputter::show(bool showIfEmpty)
// do nothing
}
bool MSWindowsDebugOutputter::write(LogLevel level, const char *msg)
bool MSWindowsDebugOutputter::write(LogLevel level, const QString &msg)
{
OutputDebugString((std::string(msg) + "\n").c_str());
std::wstring out = msg.toStdWString() + L"\n";
OutputDebugString(out.c_str());
return true;
}

View File

@ -21,9 +21,9 @@ public:
~MSWindowsDebugOutputter() override = default;
// ILogOutputter overrides
void open(const char *title) override;
void open(const QString &title) override;
void close() override;
void show(bool showIfEmpty) override;
bool write(LogLevel level, const char *message) override;
bool write(LogLevel level, const QString &message) override;
void flush();
};

View File

@ -348,7 +348,7 @@ ATOM MSWindowsDesks::createDeskWindowClass(bool isPrimary) const
classInfo.hCursor = m_cursor;
classInfo.hbrBackground = nullptr;
classInfo.lpszMenuName = nullptr;
classInfo.lpszClassName = "DeskflowDesk";
classInfo.lpszClassName = L"DeskflowDesk";
classInfo.hIconSm = nullptr;
return RegisterClassEx(&classInfo);
}
@ -360,7 +360,7 @@ void MSWindowsDesks::destroyClass(ATOM windowClass) const
}
}
HWND MSWindowsDesks::createWindow(ATOM windowClass, const char *name) const
HWND MSWindowsDesks::createWindow(ATOM windowClass, const wchar_t *name) const
{
HWND window = CreateWindowEx(
WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW, MAKEINTATOM(windowClass), name, WS_POPUP, 0, 0, 1, 1, nullptr, nullptr,
@ -610,11 +610,11 @@ void MSWindowsDesks::deskThread(void *vdesk)
// create a window. we use this window to hide the cursor.
try {
desk->m_window = createWindow(m_deskClass, "DeskflowDesk");
LOG_DEBUG("desk %s window is 0x%08x", desk->m_name.c_str(), desk->m_window);
desk->m_window = createWindow(m_deskClass, L"DeskflowDesk");
LOG_DEBUG("desk %ls window is 0x%08x", desk->m_name.c_str(), desk->m_window);
} catch (...) {
// ignore
LOG_DEBUG("can't create desk window for %s", desk->m_name.c_str());
LOG_DEBUG("can't create desk window for %ls", desk->m_name.c_str());
}
}
@ -744,7 +744,7 @@ void MSWindowsDesks::deskThread(void *vdesk)
}
}
MSWindowsDesks::Desk *MSWindowsDesks::addDesk(const std::string &name, HDESK hdesk)
MSWindowsDesks::Desk *MSWindowsDesks::addDesk(const std::wstring &name, HDESK hdesk)
{
Desk *desk = new Desk;
desk->m_name = name;
@ -767,7 +767,7 @@ void MSWindowsDesks::removeDesks()
}
m_desks.clear();
m_activeDesk = nullptr;
m_activeDeskName = "";
m_activeDeskName = L"";
}
void MSWindowsDesks::checkDesk()
@ -775,7 +775,7 @@ void MSWindowsDesks::checkDesk()
// get current desktop. if we already know about it then return.
Desk *desk;
HDESK hdesk = openInputDesktop();
std::string name = getDesktopName(hdesk);
std::wstring name = getDesktopName(hdesk);
Desks::const_iterator index = m_desks.find(name);
if (index == m_desks.end()) {
desk = addDesk(name, hdesk);
@ -802,7 +802,7 @@ void MSWindowsDesks::checkDesk()
// from an inaccessible desktop so when we switch from an
// inaccessible desktop to an accessible one we have to
// update the keyboard state.
LOG_DEBUG("switched to desk \"%s\"", name.c_str());
LOG_DEBUG("switched to desk \"%ls\"", name.c_str());
bool syncKeys = false;
bool isAccessible = isDeskAccessible(desk);
if (isDeskAccessible(m_activeDesk) != isAccessible) {
@ -876,16 +876,16 @@ void MSWindowsDesks::closeDesktop(HDESK desk)
}
}
std::string MSWindowsDesks::getDesktopName(HDESK desk)
std::wstring MSWindowsDesks::getDesktopName(HDESK desk)
{
if (desk == nullptr) {
return std::string();
return std::wstring();
} else {
DWORD size;
GetUserObjectInformation(desk, UOI_NAME, nullptr, 0, &size);
TCHAR *name = (TCHAR *)alloca(size + sizeof(TCHAR));
GetUserObjectInformation(desk, UOI_NAME, name, size, &size);
std::string result(name);
std::wstring result(name);
return result;
}
}

View File

@ -179,7 +179,7 @@ private:
class Desk
{
public:
std::string m_name;
std::wstring m_name;
Thread *m_thread;
DWORD m_threadID;
DWORD m_targetID;
@ -188,14 +188,14 @@ private:
HWND m_foregroundWindow;
bool m_lowLevel;
};
using Desks = std::map<std::string, Desk *>;
using Desks = std::map<std::wstring, Desk *>;
// initialization and shutdown operations
HCURSOR createBlankCursor() const;
void destroyCursor(HCURSOR cursor) const;
ATOM createDeskWindowClass(bool isPrimary) const;
void destroyClass(ATOM windowClass) const;
HWND createWindow(ATOM windowClass, const char *name) const;
HWND createWindow(ATOM windowClass, const wchar_t *name) const;
void destroyWindow(HWND) const;
// message handlers
@ -206,7 +206,7 @@ private:
void deskThread(void *vdesk);
// desk switch checking and handling
Desk *addDesk(const std::string &name, HDESK hdesk);
Desk *addDesk(const std::wstring &name, HDESK hdesk);
void removeDesks();
void checkDesk();
bool isDeskAccessible(const Desk *desk) const;
@ -222,7 +222,7 @@ private:
// desk API wrappers
HDESK openInputDesktop();
void closeDesktop(HDESK);
std::string getDesktopName(HDESK);
std::wstring getDesktopName(HDESK);
// our desk window procs
static LRESULT CALLBACK primaryDeskProc(HWND, UINT, WPARAM, LPARAM);
@ -263,7 +263,7 @@ private:
// the current desk and it's name
Desk *m_activeDesk = nullptr;
std::string m_activeDeskName;
std::wstring m_activeDeskName;
// one desk per desktop and a cond var to communicate with it
Mutex m_mutex;

View File

@ -29,7 +29,7 @@ MSWindowsEventQueueBuffer::MSWindowsEventQueueBuffer(IEventQueue *events) : m_ev
m_thread = GetCurrentThreadId();
// create a message type for custom events
m_userEvent = RegisterWindowMessage("DESKFLOW_USER_EVENT");
m_userEvent = RegisterWindowMessage(L"DESKFLOW_USER_EVENT");
// get message type for daemon quit
m_daemonQuit = ArchMiscWindows::getDaemonQuitMessage();

View File

@ -599,7 +599,7 @@ MSWindowsKeyState::~MSWindowsKeyState()
void MSWindowsKeyState::init()
{
// look up symbol that's available on winNT family but not win95
HMODULE userModule = GetModuleHandle("user32.dll");
HMODULE userModule = GetModuleHandle(L"user32.dll");
m_ToUnicodeEx = (ToUnicodeEx_t)GetProcAddress(userModule, "ToUnicodeEx");
}
@ -766,7 +766,7 @@ bool MSWindowsKeyState::fakeCtrlAltDel()
{
// The daemon creates this event with default permissions, which means this process must be
// elevated to be able to open it. If not elevated, an access denied error will be returned.
MSWindowsHandle sendSasEvent(OpenEvent(EVENT_MODIFY_STATE, FALSE, kSendSasEventName));
MSWindowsHandle sendSasEvent(OpenEvent(EVENT_MODIFY_STATE, FALSE, LPCWSTR(kSendSasEventName)));
if (!sendSasEvent.get()) {
LOG_ERR(
"couldn't open SAS event, unable to simulate ctrl+alt+del, error: %s",

View File

@ -23,7 +23,7 @@
namespace deskflow::platform {
MSWindowsProcess::MSWindowsProcess(const std::string &command, HANDLE stdOutput, HANDLE stdError)
MSWindowsProcess::MSWindowsProcess(const std::wstring &command, HANDLE stdOutput, HANDLE stdError)
: m_command(command),
m_stdOutput(stdOutput),
m_stdError(stdError)
@ -52,7 +52,7 @@ BOOL MSWindowsProcess::startInForeground()
si.wShowWindow = SW_MINIMIZE;
m_createProcessResult =
CreateProcess(nullptr, LPSTR(m_command.c_str()), nullptr, nullptr, TRUE, 0, nullptr, nullptr, &si, &m_info);
CreateProcess(nullptr, LPWSTR(m_command.c_str()), nullptr, nullptr, TRUE, 0, nullptr, nullptr, &si, &m_info);
return m_createProcessResult;
}
@ -70,7 +70,8 @@ BOOL MSWindowsProcess::startAsUser(HANDLE userToken, LPSECURITY_ATTRIBUTES sa)
ZeroMemory(&m_info, sizeof(PROCESS_INFORMATION));
const DWORD creationFlags = NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT;
m_createProcessResult = CreateProcessAsUser(
userToken, nullptr, LPSTR(m_command.c_str()), sa, nullptr, TRUE, creationFlags, environment, nullptr, &si, &m_info
userToken, nullptr, LPWSTR(m_command.c_str()), sa, nullptr, TRUE, creationFlags, environment, nullptr, &si,
&m_info
);
DestroyEnvironmentBlock(environment);
@ -81,7 +82,7 @@ BOOL MSWindowsProcess::startAsUser(HANDLE userToken, LPSECURITY_ATTRIBUTES sa)
void MSWindowsProcess::setStartupInfo(STARTUPINFO &si)
{
static char g_desktopName[] = "winsta0\\Default"; // NOSONAR -- Idiomatic Win32
static wchar_t g_desktopName[] = L"winsta0\\Default"; // NOSONAR -- Idiomatic Win32
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
@ -217,20 +218,20 @@ void MSWindowsProcess::createPipes()
}
}
std::string MSWindowsProcess::readStdOutput()
std::wstring MSWindowsProcess::readStdOutput()
{
return readOutput(m_outputPipe);
}
std::string MSWindowsProcess::readStdError()
std::wstring MSWindowsProcess::readStdError()
{
return readOutput(m_errorPipe);
}
std::string MSWindowsProcess::readOutput(HANDLE handle)
std::wstring MSWindowsProcess::readOutput(HANDLE handle)
{
const auto kOutputBufferSize = 4096;
char buffer[kOutputBufferSize]; // NOSONAR -- Idiomatic Win32
wchar_t buffer[kOutputBufferSize]; // NOSONAR -- Idiomatic Win32
DWORD bytesRead;
DWORD totalBytesAvail;
@ -243,7 +244,7 @@ std::string MSWindowsProcess::readOutput(HANDLE handle)
}
if (totalBytesAvail == 0) {
return "";
return {};
}
if (!ReadFile(handle, buffer, kOutputBufferSize, &bytesRead, nullptr)) {
@ -251,7 +252,7 @@ std::string MSWindowsProcess::readOutput(HANDLE handle)
throw std::runtime_error(windowsErrorToString(GetLastError()));
}
return std::string(buffer, bytesRead);
return std::wstring(buffer, bytesRead);
}
} // namespace deskflow::platform

View File

@ -20,7 +20,7 @@ const auto kDefaultShutdownTimeout = 10;
class MSWindowsProcess
{
public:
explicit MSWindowsProcess(const std::string &command, HANDLE stdOutput = nullptr, HANDLE stdError = nullptr);
explicit MSWindowsProcess(const std::wstring &command, HANDLE stdOutput = nullptr, HANDLE stdError = nullptr);
~MSWindowsProcess();
BOOL startInForeground();
@ -28,8 +28,8 @@ public:
void shutdown(int timeout = kDefaultShutdownTimeout);
DWORD waitForExit();
void createPipes();
std::string readStdOutput();
std::string readStdError();
std::wstring readStdOutput();
std::wstring readStdError();
PROCESS_INFORMATION info() const
{
@ -41,9 +41,9 @@ public:
private:
void setStartupInfo(STARTUPINFO &si);
static std::string readOutput(HANDLE handle);
static std::wstring readOutput(HANDLE handle);
std::string m_command;
std::wstring m_command;
HANDLE m_stdOutput;
HANDLE m_stdError;
HANDLE m_outputPipe = nullptr;

View File

@ -112,7 +112,7 @@ MSWindowsScreen::MSWindowsScreen(
updateScreenShape();
m_class = createWindowClass();
m_window = createWindow(m_class, kAppName);
m_window = createWindow(m_class, LPCWSTR(kAppName));
setupMouseKeys();
LOG_DEBUG("screen shape: %d,%d %dx%d %s", m_x, m_y, m_w, m_h, m_multimon ? "(multi-monitor)" : "");
LOG_DEBUG("window is 0x%08x", m_window);
@ -786,7 +786,7 @@ ATOM MSWindowsScreen::createWindowClass() const
classInfo.hCursor = nullptr;
classInfo.hbrBackground = nullptr;
classInfo.lpszMenuName = nullptr;
classInfo.lpszClassName = kAppName;
classInfo.lpszClassName = LPCWSTR(kAppName);
classInfo.hIconSm = nullptr;
return RegisterClassEx(&classInfo);
}
@ -798,7 +798,7 @@ void MSWindowsScreen::destroyClass(ATOM windowClass) const
}
}
HWND MSWindowsScreen::createWindow(ATOM windowClass, const char *name) const
HWND MSWindowsScreen::createWindow(ATOM windowClass, const wchar_t *name) const
{
HWND window = CreateWindowEx(
WS_EX_TOPMOST | WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW, MAKEINTATOM(windowClass), name, WS_POPUP, 0, 0, 1, 1,

View File

@ -142,7 +142,7 @@ private:
ATOM createWindowClass() const;
ATOM createDeskWindowClass(bool isPrimary) const;
void destroyClass(ATOM windowClass) const;
HWND createWindow(ATOM windowClass, const char *name) const;
HWND createWindow(ATOM windowClass, const wchar_t *name) const;
void destroyWindow(HWND) const;
// convenience function to send events

View File

@ -21,9 +21,9 @@
#define SPI_GETSCREENSAVERRUNNING 114
#endif
static const TCHAR *g_isSecureNT = "ScreenSaverIsSecure";
static const TCHAR *g_isSecure9x = "ScreenSaveUsePassword";
static const TCHAR *const g_pathScreenSaverIsSecure[] = {"Control Panel", "Desktop", nullptr};
static const TCHAR *g_isSecureNT = L"ScreenSaverIsSecure";
static const TCHAR *g_isSecure9x = L"ScreenSaveUsePassword";
static const TCHAR *const g_pathScreenSaverIsSecure[] = {L"Control Panel", L"Desktop", nullptr};
//
// MSWindowsScreenSaver
@ -121,7 +121,7 @@ void MSWindowsScreenSaver::deactivate()
bool killed = false;
// NT runs screen saver in another desktop
HDESK desktop = OpenDesktop("Screen-saver", 0, FALSE, DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS);
HDESK desktop = OpenDesktop(L"Screen-saver", 0, FALSE, DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS);
if (desktop != nullptr) {
EnumDesktopWindows(desktop, &MSWindowsScreenSaver::killScreenSaverFunc, reinterpret_cast<LPARAM>(&killed));
CloseDesktop(desktop);
@ -130,10 +130,10 @@ void MSWindowsScreenSaver::deactivate()
// if above failed or wasn't tried, try the windows 95 way
if (!killed) {
// find screen saver window and close it
HWND hwnd = FindWindow("WindowsScreenSaverClass", nullptr);
HWND hwnd = FindWindow(L"WindowsScreenSaverClass", nullptr);
if (hwnd == nullptr) {
// win2k may use a different class
hwnd = FindWindow("Default Screen Saver", nullptr);
hwnd = FindWindow(L"Default Screen Saver", nullptr);
}
if (hwnd != nullptr) {
PostMessage(hwnd, WM_CLOSE, 0, 0);
@ -284,9 +284,9 @@ bool MSWindowsScreenSaver::isSecure(bool *wasSecureFlagAnInt) const
}
case ArchMiscWindows::kSTRING: {
std::string value = ArchMiscWindows::readValueString(hkey, g_isSecureNT);
std::wstring value = ArchMiscWindows::readValueString(hkey, g_isSecureNT);
*wasSecureFlagAnInt = false;
result = (value != "0");
result = (value != L"0");
break;
}
}

View File

@ -16,7 +16,7 @@ MSWindowsSession::MSWindowsSession() : m_activeSessionId(-1)
{
}
bool MSWindowsSession::isProcessInSession(const char *name, PHANDLE process = nullptr)
bool MSWindowsSession::isProcessInSession(const wchar_t *name, PHANDLE process = nullptr)
{
// first we need to take a snapshot of the running processes
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
@ -37,7 +37,7 @@ bool MSWindowsSession::isProcessInSession(const char *name, PHANDLE process = nu
}
// used to record process names for debug info
std::list<std::string> nameList;
std::list<std::wstring> nameList;
// now just iterate until we can find winlogon.exe pid
DWORD pid = 0;
@ -64,7 +64,7 @@ bool MSWindowsSession::isProcessInSession(const char *name, PHANDLE process = nu
// store the names so we can record them for debug
nameList.push_back(entry.szExeFile);
if (_stricmp(entry.szExeFile, name) == 0) {
if (_wcsicmp(entry.szExeFile, name) == 0) {
pid = entry.th32ProcessID;
}
}
@ -75,10 +75,10 @@ bool MSWindowsSession::isProcessInSession(const char *name, PHANDLE process = nu
gotEntry = nextProcessEntry(snapshot, &entry);
}
std::string nameListJoin;
for (std::list<std::string>::iterator it = nameList.begin(); it != nameList.end(); it++) {
std::wstring nameListJoin;
for (std::list<std::wstring>::iterator it = nameList.begin(); it != nameList.end(); it++) {
nameListJoin.append(*it);
nameListJoin.append(", ");
nameListJoin.append(L", ");
}
LOG_DEBUG2("processes in session %d: %s", m_activeSessionId, nameListJoin.c_str());

View File

@ -6,8 +6,6 @@
#pragma once
#include <string>
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
@ -25,7 +23,7 @@ public:
*/
BOOL hasChanged();
bool isProcessInSession(const char *name, PHANDLE process);
bool isProcessInSession(const wchar_t *name, PHANDLE process);
HANDLE getUserToken(LPSECURITY_ATTRIBUTES security);
void updateActiveSession();

View File

@ -23,44 +23,23 @@
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <shlobj.h>
#include <string.h>
#include <tchar.h>
#include <QStringDecoder>
//
// Free functions
//
std::string trimOutputBuffer(const CHAR *buffer)
{
// strip out windows \r chars to prevent extra lines in log file.
std::string output(buffer);
if (output.empty()) {
LOG_DEBUG1("output buffer is empty");
return output;
}
size_t pos = 0;
while ((pos = output.find("\r", pos)) != std::string::npos) {
output.replace(pos, 1, "");
}
// trip ending newline, as file writer will add it's own newline.
if (output[output.length() - 1] == '\n') {
output = output.substr(0, output.length() - 1);
}
return output;
}
HANDLE openProcessForKill(const PROCESSENTRY32 &entry)
{
// pid 0 is 'system idle process'
if (entry.th32ProcessID == 0)
return nullptr;
if (_stricmp(entry.szExeFile, "deskflow-client.exe") != 0 && //
_stricmp(entry.szExeFile, "deskflow-server.exe") != 0 && //
_stricmp(entry.szExeFile, "deskflow-core.exe") != 0) {
if (_wcsicmp(entry.szExeFile, L"deskflow-client.exe") != 0 && //
_wcsicmp(entry.szExeFile, L"deskflow-server.exe") != 0 && //
_wcsicmp(entry.szExeFile, L"deskflow-core.exe") != 0) {
return nullptr;
}
@ -155,7 +134,7 @@ MSWindowsWatchdog::getUserToken(LPSECURITY_ATTRIBUTES security, bool elevatedTok
LOG_DEBUG("getting elevated token");
HANDLE process;
if (!m_session.isProcessInSession("winlogon.exe", &process)) {
if (!m_session.isProcessInSession(L"winlogon.exe", &process)) {
throw std::runtime_error("cannot get user token without winlogon.exe");
}
@ -330,7 +309,7 @@ void MSWindowsWatchdog::setProcessConfig(const std::string_view &command, bool e
std::scoped_lock lock{m_processStateMutex};
LOG_DEBUG("setting watchdog process config");
m_command = command;
m_command = std::wstring(command.begin(), command.end());
m_elevateProcess = elevate;
if (m_command.empty()) {
@ -345,35 +324,49 @@ void MSWindowsWatchdog::setProcessConfig(const std::string_view &command, bool e
void MSWindowsWatchdog::outputLoop(void *)
{
const auto kOutputBufferSize = 4096;
static constexpr DWORD kBufSize = 4096;
// +1 char for \0
CHAR buffer[kOutputBufferSize + 1];
BYTE raw[kBufSize];
DWORD bytesRead = 0;
// Warning: Manual decoding while we still use Win32 APIs for process launching and output reading.
// Using a byte decoder should help to prevent mojibake when we get a partial UTF-8 sequence in a read chunk.
// In future when we move to Qt process APIs, this can all be simplified.
QStringDecoder decoder(QStringDecoder::Utf8);
while (m_running) {
const BOOL ok = ::ReadFile(m_outputReadPipe, raw, kBufSize, &bytesRead, nullptr);
DWORD bytesRead;
BOOL success = ReadFile(m_outputReadPipe, buffer, kOutputBufferSize, &bytesRead, nullptr);
if (!success || bytesRead == 0) {
// Sleep for only 100ms rather than 1 second so that the service can shut down faster.
Arch::sleep(0.1);
} else {
buffer[bytesRead] = '\0';
// strip out windows \r chars to prevent extra lines in log file.
std::string output = trimOutputBuffer(buffer);
m_fileLogOutputter.write(LogLevel::Print, output.c_str());
#if SYSAPI_WIN32
if (m_foreground) {
// when in foreground mode (useful for debugging), send the core
// process output to the VS debug output window.
// we could use the MSWindowsDebugOutputter, but it's really fiddly to
// so, and there doesn't seem to be an advantage of doing that.
OutputDebugString(buffer);
if (!ok) {
const DWORD err = ::GetLastError();
if (err == ERROR_BROKEN_PIPE) {
// It doesn't make sense to keep reading the pipe if the process has exited and closed its end of the pipe.
LOG_DEBUG("output pipe closed, exiting output loop");
break;
}
#endif
// Retry immediately when we get a transient error like ERROR_NO_DATA (pipe is non-blocking).
continue;
}
if (bytesRead == 0) {
// Sleep for short moment so we're not busy looping while the Core is quiet (which is the case most of the time).
// Important: Keep the sleep short so the service can shut down fast.
Arch::sleep(0.1);
LOG_DEBUG("no more data to read from output pipe");
break;
}
const QString decoded =
decoder.decode(QByteArray::fromRawData(reinterpret_cast<const char *>(raw), int(bytesRead)));
// The file log outputter adds its own newlines, so trim the decoded string to avoid double newlines.
const auto trimmed = decoded.trimmed();
m_fileLogOutputter.write(LogLevel::Print, trimmed);
if (m_foreground) {
// Doesn't add it's own newlines, so use the original ones from the process output.
::OutputDebugString(decoded.toStdWString().c_str());
}
}
}
@ -497,7 +490,7 @@ void MSWindowsWatchdog::initSasFunc()
{
// the SendSAS function is used to send a sas (secure attention sequence) to the
// winlogon process. this is used to switch to the login screen.
HINSTANCE sasLib = LoadLibrary("sas.dll");
HINSTANCE sasLib = LoadLibrary(L"sas.dll");
if (!sasLib) {
LOG_ERR("could not load sas.dll");
throw std::runtime_error(windowsErrorToString(GetLastError()));
@ -529,7 +522,7 @@ void MSWindowsWatchdog::sasLoop(void *) // NOSONAR - Thread entry point signatur
}
// Create a an event so that other processes can tell the daemon to call the `SendSAS` function.
MSWindowsHandle sendSasEvent(CreateEvent(nullptr, FALSE, FALSE, kSendSasEventName));
MSWindowsHandle sendSasEvent(CreateEvent(nullptr, FALSE, FALSE, LPCWSTR(kSendSasEventName)));
if (sendSasEvent.get() == nullptr) {
LOG_ERR("could not create SAS event, error: %s", windowsErrorToString(GetLastError()).c_str());
Arch::sleep(1);

View File

@ -140,11 +140,11 @@ private:
int m_startFailures = 0;
FileLogOutputter &m_fileLogOutputter;
bool m_foreground = false;
std::string m_activeDesktop = "";
std::wstring m_activeDesktop = {};
std::unique_ptr<deskflow::platform::MSWindowsProcess> m_process;
std::optional<double> m_nextStartTime = std::nullopt;
ProcessState m_processState = ProcessState::Idle;
std::string m_command = "";
std::wstring m_command = {};
SendSas m_sendSasFunc = nullptr;
std::mutex m_processStateMutex;
};

View File

@ -11,6 +11,8 @@
#include "deskflow/ClipboardTypes.h"
#include "deskflow/IClipboard.h"
#include <QString>
#include <list>
#include <map>
#include <vector>

View File

@ -7,7 +7,7 @@
#include "platform/XWindowsClipboardTextConverter.h"
#include "base/Unicode.h"
#include <QString>
//
// XWindowsClipboardTextConverter
@ -36,22 +36,10 @@ int XWindowsClipboardTextConverter::getDataSize() const
std::string XWindowsClipboardTextConverter::fromIClipboard(const std::string &data) const
{
return Unicode::UTF8ToText(data);
return QString::fromStdString(data).toLatin1().toStdString();
}
std::string XWindowsClipboardTextConverter::toIClipboard(const std::string &data) const
{
// convert to UTF-8
bool errors;
std::string utf8 = Unicode::textToUTF8(data, &errors);
// if there were decoding errors then, to support old applications
// that don't understand UTF-8 but can report the exact binary
// UTF-8 representation, see if the data appears to be UTF-8. if
// so then use it as is.
if (errors && Unicode::isUTF8(data)) {
return data;
}
return utf8;
return QString::fromLatin1(data).toUtf8().toStdString();
}

View File

@ -17,6 +17,8 @@
#include <set>
#include <vector>
#include <QString>
#include <X11/Xlib.h>
class XWindowsClipboard;

View File

@ -6,11 +6,12 @@
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include "base/Log.h" // include first Qt...
#include "platform/XWindowsScreenSaver.h"
#include "base/Event.h"
#include "base/IEventQueue.h"
#include "base/Log.h"
#include "deskflow/IPlatformScreen.h"
#include "platform/XWindowsUtil.h"

View File

@ -5,12 +5,12 @@
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include "platform/XWindowsUtil.h"
#include "base/Log.h" //Include First
#include "base/Log.h"
#include "base/String.h"
#include "deskflow/KeyTypes.h"
#include "mt/Thread.h"
#include "platform/XWindowsUtil.h"
#include <X11/Xatom.h>
#define XK_APL

View File

@ -40,6 +40,8 @@ add_library(server STATIC
Server.h
)
target_link_libraries(server PUBLIC common)
if(UNIX)
target_link_libraries(server app)
target_link_libraries(server PUBLIC app)
endif()

View File

@ -56,7 +56,6 @@ endfunction()
enable_testing()
find_package(Qt6 ${REQUIRED_QT_VERSION} REQUIRED COMPONENTS Test)
add_subdirectory(arch)
add_subdirectory(base)
add_subdirectory(common)
add_subdirectory(deskflow)

View File

@ -1,58 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2025 Chris Rizzitello <sithlord48@gmail.com>
* SPDX-FileCopyrightText: (C) 2014 - 2016 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include "ArchStringTests.h"
#include "arch/ArchString.h"
void ArchStringTests::initTestCase()
{
m_arch.init();
m_log.setFilter(LogLevel::Debug2);
}
void ArchStringTests::convertStringWCToMB_buffer()
{
ArchString as;
char buff[20];
bool errors;
auto converted = as.convStringWCToMB(buff, L"Hello", 6, &errors);
QCOMPARE(converted, 6);
QCOMPARE(buff, "Hello");
QVERIFY(!errors);
}
void ArchStringTests::convertStringWCToMB_noBuffer()
{
ArchString as;
bool errors;
auto converted = as.convStringWCToMB(nullptr, L"Hello", 6, &errors);
QCOMPARE(converted, 6);
QVERIFY(!errors);
}
void ArchStringTests::convertStringMBToWC()
{
ArchString as;
wchar_t buff[20];
bool errors;
auto converted = as.convStringMBToWC(buff, "Hello", 6, &errors);
QCOMPARE(converted, 6);
auto actual = QString::fromStdWString(buff);
auto expected = QString::fromStdWString(L"Hello");
QCOMPARE(actual, expected);
QVERIFY(!errors);
}
QTEST_MAIN(ArchStringTests)

View File

@ -1,24 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2025 Chris Rizzitello <sithlord48@gmail.com>
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include "base/Log.h"
#include <QTest>
class ArchStringTests : public QObject
{
Q_OBJECT
private Q_SLOTS:
void initTestCase();
// Test are run in order top to bottom
void convertStringWCToMB_buffer();
void convertStringWCToMB_noBuffer();
void convertStringMBToWC();
private:
Arch m_arch;
Log m_log;
};

View File

@ -1,14 +0,0 @@
# SPDX-FileCopyrightText: 2025 Deskflow Developers
# SPDX-License-Identifier: MIT
if(WIN32)
set(extra_libs version)
endif()
create_test(
NAME ArchStringTests
DEPENDS arch
LIBS base ${extra_libs}
SOURCE ArchStringTests.cpp
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/src/lib/arch"
)

View File

@ -4,10 +4,10 @@
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include <QTest>
#include "base/Log.h"
#include <QTest>
class LogTests : public QObject
{
Q_OBJECT

View File

@ -7,7 +7,6 @@
#include "UnicodeTests.h"
#include "arch/ArchString.h"
#include "base/Unicode.h"
void UnicodeTests::initTestCase()
@ -34,30 +33,4 @@ void UnicodeTests::UTF16ToUTF8()
QCOMPARE(result.c_str(), "hello");
}
void UnicodeTests::UCS2ToUTF8_kUCS2()
{
bool errors;
auto result = Unicode::textToUTF8("hello", &errors, ArchString::EWideCharEncoding::kUCS2);
QVERIFY(!errors);
#ifdef _WIN32
QCOMPARE(result, std::string("hello", 5)); // mixed-platform expected result
#else
#ifdef WORDS_BIGENDIAN
QCOMPARE(result, std::string("\0h\0e\0", 5)); // mixed-platform expected result
#else
QCOMPARE(result, std::string("h\0e\0l", 5)); // mixed-platform expected result
#endif // WORDS_BIGENDIAN
#endif // _WIN32
}
void UnicodeTests::UCS2ToUTF8()
{
bool errors;
auto result = Unicode::textToUTF8("hello", &errors);
QVERIFY(!errors);
QCOMPARE(result, std::string("hello", 5)); // mixed-platform expected result
}
QTEST_MAIN(UnicodeTests)

View File

@ -15,8 +15,6 @@ private Q_SLOTS:
void initTestCase();
void UTF32ToUTF8();
void UTF16ToUTF8();
void UCS2ToUTF8_kUCS2();
void UCS2ToUTF8();
private:
Arch m_arch;