refactor: Move -> deskflow/languages/LanguageManager -> deskflow/KeyboardLayoutManager

rename methods to relfect its use for keyboard layouts not languages
This commit is contained in:
sithlord48 2026-04-08 01:42:19 -04:00 committed by Nick Bolton
parent e293d4eb8c
commit 1922f916af
12 changed files with 253 additions and 254 deletions

View file

@ -141,7 +141,7 @@ ServerProxy::ConnectionResult ServerProxy::parseHandshakeMessage(const uint8_t *
// handshake is complete
m_parser = &ServerProxy::parseMessage;
if (const auto missedKeyboardLayouts = m_languageManager.getMissedLanguages(); !missedKeyboardLayouts.empty()) {
if (const auto missedKeyboardLayouts = m_layoutManager.getMissedLayouts(); !missedKeyboardLayouts.empty()) {
LOG_WARN("server layouts missing on this computer: %s", missedKeyboardLayouts.c_str());
ipcSendToClient("missingKeyboardLayouts", QString::fromStdString(missedKeyboardLayouts));
}
@ -505,8 +505,8 @@ void ServerProxy::enter()
m_dxMouse = 0;
m_dyMouse = 0;
m_seqNum = seqNum;
m_serverLanguage = "";
m_isUserNotifiedAboutLanguageSyncError = false;
m_serverLayout = "";
m_isUserNotifiedAboutLayoutSyncError = false;
// forward
m_client->enter(x, y, seqNum, static_cast<KeyModifierMask>(mask), false);
@ -825,28 +825,28 @@ void ServerProxy::secureInputNotification()
void ServerProxy::setServerLanguages()
{
std::string serverLanguages;
ProtocolUtil::readf(m_stream, kMsgDLanguageSynchronisation + 4, &serverLanguages);
m_languageManager.setRemoteLanguages(serverLanguages);
std::string serverLayout;
ProtocolUtil::readf(m_stream, kMsgDLanguageSynchronisation + 4, &serverLayout);
m_layoutManager.setRemoteLayouts(serverLayout);
}
void ServerProxy::setActiveServerLanguage(const std::string_view &language)
{
if (!language.empty() && (language.size() > 0)) {
if (m_serverLanguage != language) {
m_isUserNotifiedAboutLanguageSyncError = false;
m_serverLanguage = language;
if (m_serverLayout != language) {
m_isUserNotifiedAboutLayoutSyncError = false;
m_serverLayout = language;
}
if (!m_languageManager.isLanguageInstalled(m_serverLanguage)) {
if (!m_isUserNotifiedAboutLanguageSyncError) {
LOG_WARN("current server language is not installed on client");
m_isUserNotifiedAboutLanguageSyncError = true;
if (!m_layoutManager.isLayoutInstalled(m_serverLayout)) {
if (!m_isUserNotifiedAboutLayoutSyncError) {
LOG_WARN("current server layout is not installed on client");
m_isUserNotifiedAboutLayoutSyncError = true;
}
} else {
m_isUserNotifiedAboutLanguageSyncError = false;
m_isUserNotifiedAboutLayoutSyncError = false;
}
} else {
LOG_DEBUG1("active server language is empty");
LOG_DEBUG1("active server layout is empty");
}
}

View file

@ -10,7 +10,7 @@
#include "deskflow/ClipboardTypes.h"
#include "deskflow/KeyTypes.h"
#include "deskflow/languages/LanguageManager.h"
#include "deskflow/KeyboardLayoutManager.h"
class Client;
class ClientInfo;
@ -123,7 +123,7 @@ private:
MessageParser m_parser = &ServerProxy::parseHandshakeMessage;
IEventQueue *m_events = nullptr;
std::string m_serverLanguage = "";
bool m_isUserNotifiedAboutLanguageSyncError = false;
deskflow::languages::LanguageManager m_languageManager;
std::string m_serverLayout = "";
bool m_isUserNotifiedAboutLayoutSyncError = false;
deskflow::KeyboardLayoutManager m_layoutManager;
};

View file

@ -77,8 +77,8 @@ add_library(${lib_name} STATIC ${PLATFORM_CODE}
ServerApp.h
StreamChunker.cpp
StreamChunker.h
languages/LanguageManager.cpp
languages/LanguageManager.h
KeyboardLayoutManager.cpp
KeyboardLayoutManager.h
ipc/IpcServer.cpp
ipc/IpcServer.h
ipc/DaemonIpcServer.cpp

View file

@ -0,0 +1,90 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2014 - 2021 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include "KeyboardLayoutManager.h"
#include "base/Log.h"
#include <algorithm>
namespace {
std::string vectorToString(const std::vector<std::string> &vector, const std::string_view &delimiter = "")
{
std::string string;
for (const auto &item : vector) {
if (&item != &vector[0]) {
string += delimiter;
}
string += item;
}
return string;
}
} // anonymous namespace
namespace deskflow {
KeyboardLayoutManager::KeyboardLayoutManager(const std::vector<std::string> &localLayouts)
: m_localLayouts(localLayouts)
{
LOG_INFO("local layouts: %s", vectorToString(m_localLayouts, ", ").c_str());
}
void KeyboardLayoutManager::setRemoteLayouts(const std::string_view &remoteLayouts)
{
m_remoteLayouts.clear();
if (!remoteLayouts.empty()) {
for (size_t i = 0; i <= remoteLayouts.size() - 2; i += 2) {
auto rLangs = remoteLayouts.substr(i, 2);
m_remoteLayouts.emplace_back(rLangs);
}
}
LOG_INFO("remote layouts: %s", vectorToString(m_remoteLayouts, ", ").c_str());
}
const std::vector<std::string> &KeyboardLayoutManager::getRemoteLayouts() const
{
return m_remoteLayouts;
}
const std::vector<std::string> &KeyboardLayoutManager::getLocalLayouts() const
{
return m_localLayouts;
}
std::string KeyboardLayoutManager::getMissedLayouts() const
{
std::string missedLayouts;
for (const auto &layout : m_remoteLayouts) {
if (!isLayoutInstalled(layout)) {
if (!missedLayouts.empty()) {
missedLayouts += ", ";
}
missedLayouts += layout;
}
}
return missedLayouts;
}
std::string KeyboardLayoutManager::getSerializedLocalLayouts() const
{
return vectorToString(m_localLayouts);
}
bool KeyboardLayoutManager::isLayoutInstalled(const std::string &layout) const
{
bool isInstalled = true;
if (!m_localLayouts.empty()) {
isInstalled = (std::find(m_localLayouts.begin(), m_localLayouts.end(), layout) != m_localLayouts.end());
}
return isInstalled;
}
} // namespace deskflow

View file

@ -0,0 +1,63 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2014 - 2021 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#pragma once
#include "deskflow/AppUtil.h"
#include <vector>
namespace deskflow {
class KeyboardLayoutManager
{
std::vector<std::string> m_remoteLayouts;
std::vector<std::string> m_localLayouts;
public:
explicit KeyboardLayoutManager(
const std::vector<std::string> &localLayouts = AppUtil::instance().getKeyboardLayoutList()
);
/**
* @brief setRemoteLayouts sets remote layouts
* @param remoteLayouts is a string with sericalized layouts
*/
void setRemoteLayouts(const std::string_view &remoteLayouts);
/**
* @brief getRemoteLayouts getter for remote layouts
* @return vector of remote layouts
*/
const std::vector<std::string> &getRemoteLayouts() const;
/**
* @brief getLocalLayouts getter for local layouts
* @return vector of local layouts
*/
const std::vector<std::string> &getLocalLayouts() const;
/**
* @brief getMissedLayouts getter for missed layouts on local machine
* @return difference between remote and local layouts as a coma separated
* string
*/
std::string getMissedLayouts() const;
/**
* @brief getSerializedLocalLayouts getter for local serialized layouts
* @return serialized local layouts as a string
*/
std::string getSerializedLocalLayouts() const;
/**
* @brief isLayoutInstalled checks if layout is installed
* @param layout which should be checked
* @return true if the specified layout is installed
*/
bool isLayoutInstalled(const std::string &layout) const;
};
} // namespace deskflow

View file

@ -1,89 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2014 - 2021 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include "LanguageManager.h"
#include "base/Log.h"
#include <algorithm>
namespace {
std::string vectorToString(const std::vector<std::string> &vector, const std::string_view &delimiter = "")
{
std::string string;
for (const auto &item : vector) {
if (&item != &vector[0]) {
string += delimiter;
}
string += item;
}
return string;
}
} // anonymous namespace
namespace deskflow::languages {
LanguageManager::LanguageManager(const std::vector<std::string> &localLanguages) : m_localLanguages(localLanguages)
{
LOG_INFO("local languages: %s", vectorToString(m_localLanguages, ", ").c_str());
}
void LanguageManager::setRemoteLanguages(const std::string_view &remoteLanguages)
{
m_remoteLanguages.clear();
if (!remoteLanguages.empty()) {
for (size_t i = 0; i <= remoteLanguages.size() - 2; i += 2) {
auto rLangs = remoteLanguages.substr(i, 2);
m_remoteLanguages.emplace_back(rLangs);
}
}
LOG_INFO("remote languages: %s", vectorToString(m_remoteLanguages, ", ").c_str());
}
const std::vector<std::string> &LanguageManager::getRemoteLanguages() const
{
return m_remoteLanguages;
}
const std::vector<std::string> &LanguageManager::getLocalLanguages() const
{
return m_localLanguages;
}
std::string LanguageManager::getMissedLanguages() const
{
std::string missedLanguages;
for (const auto &language : m_remoteLanguages) {
if (!isLanguageInstalled(language)) {
if (!missedLanguages.empty()) {
missedLanguages += ", ";
}
missedLanguages += language;
}
}
return missedLanguages;
}
std::string LanguageManager::getSerializedLocalLanguages() const
{
return vectorToString(m_localLanguages);
}
bool LanguageManager::isLanguageInstalled(const std::string &language) const
{
bool isInstalled = true;
if (!m_localLanguages.empty()) {
isInstalled = (std::find(m_localLanguages.begin(), m_localLanguages.end(), language) != m_localLanguages.end());
}
return isInstalled;
}
} // namespace deskflow::languages

View file

@ -1,65 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2014 - 2021 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#pragma once
#include "deskflow/AppUtil.h"
#include <vector>
namespace deskflow::languages {
// TODO: rename class and namespace; "languages" is a misnomer. These are keyboard
// _layouts_ (Windows/X11) or input sources (macOS), not spoken "languages".
class LanguageManager
{
std::vector<std::string> m_remoteLanguages;
std::vector<std::string> m_localLanguages;
public:
explicit LanguageManager(
const std::vector<std::string> &localLanguages = AppUtil::instance().getKeyboardLayoutList()
);
/**
* @brief setRemoteLanguages sets remote languages
* @param remoteLanguages is a string with sericalized languages
*/
void setRemoteLanguages(const std::string_view &remoteLanguages);
/**
* @brief getRemoteLanguages getter for remote languages
* @return vector of remote languages
*/
const std::vector<std::string> &getRemoteLanguages() const;
/**
* @brief getLocalLanguages getter for local languages
* @return vector of local languages
*/
const std::vector<std::string> &getLocalLanguages() const;
/**
* @brief getMissedLanguages getter for missed languages on local machine
* @return difference between remote and local languages as a coma separated
* string
*/
std::string getMissedLanguages() const;
/**
* @brief getSerializedLocalLanguages getter for local serialized languages
* @return serialized local languages as a string
*/
std::string getSerializedLocalLanguages() const;
/**
* @brief isLanguageInstalled checks if language is installed
* @param language which should be checked
* @return true if the specified language is installed
*/
bool isLanguageInstalled(const std::string &language) const;
};
} // namespace deskflow::languages

View file

@ -5,8 +5,8 @@
*/
#include "base/Log.h"
#include "deskflow/KeyboardLayoutManager.h"
#include "deskflow/ProtocolUtil.h"
#include "deskflow/languages/LanguageManager.h"
#include "ClientProxy1_8.h"
@ -20,11 +20,11 @@ ClientProxy1_8::ClientProxy1_8(
void ClientProxy1_8::synchronizeLanguages() const
{
deskflow::languages::LanguageManager languageManager;
auto localLanguages = languageManager.getSerializedLocalLanguages();
if (!localLanguages.empty()) {
LOG_DEBUG1("send server languages to the client: %s", localLanguages.c_str());
ProtocolUtil::writef(getStream(), kMsgDLanguageSynchronisation, &localLanguages);
deskflow::KeyboardLayoutManager layoutManager;
auto localLayouts = layoutManager.getSerializedLocalLayouts();
if (!localLayouts.empty()) {
LOG_DEBUG1("send server languages to the client: %s", localLayouts.c_str());
ProtocolUtil::writef(getStream(), kMsgDLanguageSynchronisation, &localLayouts);
} else {
LOG_ERR("failed to read server languages");
}
@ -33,8 +33,8 @@ void ClientProxy1_8::synchronizeLanguages() const
void ClientProxy1_8::keyDown(KeyID key, KeyModifierMask mask, KeyButton button, const std::string &language)
{
LOG(
(CLOG_DEBUG1 "send key down to \"%s\" id=%d, mask=0x%04x, button=0x%04x, language=%s", getName().c_str(), key,
mask, button, language.c_str())
(CLOG_DEBUG1 "send key down to \"%s\" id=%d, mask=0x%04x, button=0x%04x, layout=%s", getName().c_str(), key, mask,
button, language.c_str())
);
ProtocolUtil::writef(getStream(), kMsgDKeyDownLang, key, mask, button, &language);
}

View file

@ -46,10 +46,10 @@ create_test(
)
create_test(
NAME LanguageManagerTests
NAME KeyboardLayoutManagerTests
DEPENDS app
LIBS arch base ${extra_libs}
SOURCE LanguageManagerTests.cpp
SOURCE KeyboardLayoutManagerTests.cpp
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/src/lib/deskflow"
)

View file

@ -0,0 +1,63 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2025 Chris Rizzitello <sithlord48@gmail.com>
* SPDX-FileCopyrightText: (C) 2014 - 2024 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include "KeyboardLayoutManagerTests.h"
#include "deskflow/KeyboardLayoutManager.h"
void KeyboardLayoutManagerTests::initTestCase()
{
m_log.setFilter(LogLevel::Debug2);
}
void KeyboardLayoutManagerTests::remoteLayouts()
{
std::string remoteLayouts = "ruenuk";
deskflow::KeyboardLayoutManager manager({"ru", "en", "uk"});
manager.setRemoteLayouts(remoteLayouts);
QCOMPARE(manager.getRemoteLayouts(), (std::vector<std::string>{"ru", "en", "uk"}));
manager.setRemoteLayouts(std::string());
QVERIFY(manager.getRemoteLayouts().empty());
}
void KeyboardLayoutManagerTests::localLayout()
{
std::vector<std::string> localLayouts = {"ru", "en", "uk"};
deskflow::KeyboardLayoutManager manager(localLayouts);
QCOMPARE(manager.getLocalLayouts(), (std::vector<std::string>{"ru", "en", "uk"}));
}
void KeyboardLayoutManagerTests::missedLayout()
{
std::string remoteLayouts = "ruenuk";
std::vector<std::string> localLayouts = {"en"};
deskflow::KeyboardLayoutManager manager(localLayouts);
manager.setRemoteLayouts(remoteLayouts);
QCOMPARE(manager.getMissedLayouts(), "ru, uk");
}
void KeyboardLayoutManagerTests::layoutInstall()
{
std::vector<std::string> localLayouts = {"ru", "en", "uk"};
deskflow::KeyboardLayoutManager manager(localLayouts);
QVERIFY(!manager.isLayoutInstalled("us"));
QVERIFY(manager.isLayoutInstalled("en"));
}
void KeyboardLayoutManagerTests::serializeLocalLayouts()
{
std::vector<std::string> localLayouts = {"ru", "en", "uk"};
deskflow::KeyboardLayoutManager manager(localLayouts);
QCOMPARE(manager.getSerializedLocalLayouts(), "ruenuk");
}
QTEST_MAIN(KeyboardLayoutManagerTests)

View file

@ -8,17 +8,17 @@
#include <QTest>
class LanguageManagerTests : public QObject
class KeyboardLayoutManagerTests : public QObject
{
Q_OBJECT
private Q_SLOTS:
void initTestCase();
// Test are run in order top to bottom
void remoteLanguages();
void localLanguage();
void missedLanguage();
void serializeLocalLanguages();
void languageInstall();
void remoteLayouts();
void localLayout();
void missedLayout();
void serializeLocalLayouts();
void layoutInstall();
private:
Log m_log;

View file

@ -1,63 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2025 Chris Rizzitello <sithlord48@gmail.com>
* SPDX-FileCopyrightText: (C) 2014 - 2024 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include "LanguageManagerTests.h"
#include "deskflow/languages/LanguageManager.h"
void LanguageManagerTests::initTestCase()
{
m_log.setFilter(LogLevel::Debug2);
}
void LanguageManagerTests::remoteLanguages()
{
std::string remoteLanguages = "ruenuk";
deskflow::languages::LanguageManager manager({"ru", "en", "uk"});
manager.setRemoteLanguages(remoteLanguages);
QCOMPARE(manager.getRemoteLanguages(), (std::vector<std::string>{"ru", "en", "uk"}));
manager.setRemoteLanguages(std::string());
QVERIFY(manager.getRemoteLanguages().empty());
}
void LanguageManagerTests::localLanguage()
{
std::vector<std::string> localLanguages = {"ru", "en", "uk"};
deskflow::languages::LanguageManager manager(localLanguages);
QCOMPARE(manager.getLocalLanguages(), (std::vector<std::string>{"ru", "en", "uk"}));
}
void LanguageManagerTests::missedLanguage()
{
std::string remoteLanguages = "ruenuk";
std::vector<std::string> localLanguages = {"en"};
deskflow::languages::LanguageManager manager(localLanguages);
manager.setRemoteLanguages(remoteLanguages);
QCOMPARE(manager.getMissedLanguages(), "ru, uk");
}
void LanguageManagerTests::languageInstall()
{
std::vector<std::string> localLanguages = {"ru", "en", "uk"};
deskflow::languages::LanguageManager manager(localLanguages);
QVERIFY(!manager.isLanguageInstalled("us"));
QVERIFY(manager.isLanguageInstalled("en"));
}
void LanguageManagerTests::serializeLocalLanguages()
{
std::vector<std::string> localLanguages = {"ru", "en", "uk"};
deskflow::languages::LanguageManager manager(localLanguages);
QCOMPARE(manager.getSerializedLocalLanguages(), "ruenuk");
}
QTEST_MAIN(LanguageManagerTests)