diff --git a/src/lib/client/ServerProxy.cpp b/src/lib/client/ServerProxy.cpp index c23cd6a0d..a04aa35e2 100644 --- a/src/lib/client/ServerProxy.cpp +++ b/src/lib/client/ServerProxy.cpp @@ -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(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"); } } diff --git a/src/lib/client/ServerProxy.h b/src/lib/client/ServerProxy.h index 595356640..149d7b972 100644 --- a/src/lib/client/ServerProxy.h +++ b/src/lib/client/ServerProxy.h @@ -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; }; diff --git a/src/lib/deskflow/CMakeLists.txt b/src/lib/deskflow/CMakeLists.txt index 2d8ab2a0b..a0bc4c236 100644 --- a/src/lib/deskflow/CMakeLists.txt +++ b/src/lib/deskflow/CMakeLists.txt @@ -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 diff --git a/src/lib/deskflow/KeyboardLayoutManager.cpp b/src/lib/deskflow/KeyboardLayoutManager.cpp new file mode 100644 index 000000000..b571b8fe3 --- /dev/null +++ b/src/lib/deskflow/KeyboardLayoutManager.cpp @@ -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 + +namespace { + +std::string vectorToString(const std::vector &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 &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 &KeyboardLayoutManager::getRemoteLayouts() const +{ + return m_remoteLayouts; +} + +const std::vector &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 diff --git a/src/lib/deskflow/KeyboardLayoutManager.h b/src/lib/deskflow/KeyboardLayoutManager.h new file mode 100644 index 000000000..2e4094e60 --- /dev/null +++ b/src/lib/deskflow/KeyboardLayoutManager.h @@ -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 + +namespace deskflow { + +class KeyboardLayoutManager +{ + std::vector m_remoteLayouts; + std::vector m_localLayouts; + +public: + explicit KeyboardLayoutManager( + const std::vector &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 &getRemoteLayouts() const; + + /** + * @brief getLocalLayouts getter for local layouts + * @return vector of local layouts + */ + const std::vector &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 diff --git a/src/lib/deskflow/languages/LanguageManager.cpp b/src/lib/deskflow/languages/LanguageManager.cpp deleted file mode 100644 index 6df5339f7..000000000 --- a/src/lib/deskflow/languages/LanguageManager.cpp +++ /dev/null @@ -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 - -namespace { - -std::string vectorToString(const std::vector &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 &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 &LanguageManager::getRemoteLanguages() const -{ - return m_remoteLanguages; -} - -const std::vector &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 diff --git a/src/lib/deskflow/languages/LanguageManager.h b/src/lib/deskflow/languages/LanguageManager.h deleted file mode 100644 index 4aef2db60..000000000 --- a/src/lib/deskflow/languages/LanguageManager.h +++ /dev/null @@ -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 - -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 m_remoteLanguages; - std::vector m_localLanguages; - -public: - explicit LanguageManager( - const std::vector &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 &getRemoteLanguages() const; - - /** - * @brief getLocalLanguages getter for local languages - * @return vector of local languages - */ - const std::vector &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 diff --git a/src/lib/server/ClientProxy1_8.cpp b/src/lib/server/ClientProxy1_8.cpp index 7a86073c2..fcdb63352 100644 --- a/src/lib/server/ClientProxy1_8.cpp +++ b/src/lib/server/ClientProxy1_8.cpp @@ -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); } diff --git a/src/unittests/deskflow/CMakeLists.txt b/src/unittests/deskflow/CMakeLists.txt index f4beb8abe..937a3573f 100644 --- a/src/unittests/deskflow/CMakeLists.txt +++ b/src/unittests/deskflow/CMakeLists.txt @@ -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" ) diff --git a/src/unittests/deskflow/KeyboardLayoutManagerTests.cpp b/src/unittests/deskflow/KeyboardLayoutManagerTests.cpp new file mode 100644 index 000000000..0d602a8d0 --- /dev/null +++ b/src/unittests/deskflow/KeyboardLayoutManagerTests.cpp @@ -0,0 +1,63 @@ +/* + * Deskflow -- mouse and keyboard sharing utility + * SPDX-FileCopyrightText: (C) 2025 Chris Rizzitello + * 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{"ru", "en", "uk"})); + + manager.setRemoteLayouts(std::string()); + QVERIFY(manager.getRemoteLayouts().empty()); +} + +void KeyboardLayoutManagerTests::localLayout() +{ + std::vector localLayouts = {"ru", "en", "uk"}; + deskflow::KeyboardLayoutManager manager(localLayouts); + QCOMPARE(manager.getLocalLayouts(), (std::vector{"ru", "en", "uk"})); +} + +void KeyboardLayoutManagerTests::missedLayout() +{ + std::string remoteLayouts = "ruenuk"; + std::vector localLayouts = {"en"}; + deskflow::KeyboardLayoutManager manager(localLayouts); + + manager.setRemoteLayouts(remoteLayouts); + QCOMPARE(manager.getMissedLayouts(), "ru, uk"); +} + +void KeyboardLayoutManagerTests::layoutInstall() +{ + std::vector localLayouts = {"ru", "en", "uk"}; + deskflow::KeyboardLayoutManager manager(localLayouts); + + QVERIFY(!manager.isLayoutInstalled("us")); + QVERIFY(manager.isLayoutInstalled("en")); +} + +void KeyboardLayoutManagerTests::serializeLocalLayouts() +{ + std::vector localLayouts = {"ru", "en", "uk"}; + deskflow::KeyboardLayoutManager manager(localLayouts); + + QCOMPARE(manager.getSerializedLocalLayouts(), "ruenuk"); +} + +QTEST_MAIN(KeyboardLayoutManagerTests) diff --git a/src/unittests/deskflow/LanguageManagerTests.h b/src/unittests/deskflow/KeyboardLayoutManagerTests.h similarity index 67% rename from src/unittests/deskflow/LanguageManagerTests.h rename to src/unittests/deskflow/KeyboardLayoutManagerTests.h index 9816c8b6a..14ba6ffd7 100644 --- a/src/unittests/deskflow/LanguageManagerTests.h +++ b/src/unittests/deskflow/KeyboardLayoutManagerTests.h @@ -8,17 +8,17 @@ #include -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; diff --git a/src/unittests/deskflow/LanguageManagerTests.cpp b/src/unittests/deskflow/LanguageManagerTests.cpp deleted file mode 100644 index 4f1464f1e..000000000 --- a/src/unittests/deskflow/LanguageManagerTests.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Deskflow -- mouse and keyboard sharing utility - * SPDX-FileCopyrightText: (C) 2025 Chris Rizzitello - * 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{"ru", "en", "uk"})); - - manager.setRemoteLanguages(std::string()); - QVERIFY(manager.getRemoteLanguages().empty()); -} - -void LanguageManagerTests::localLanguage() -{ - std::vector localLanguages = {"ru", "en", "uk"}; - deskflow::languages::LanguageManager manager(localLanguages); - QCOMPARE(manager.getLocalLanguages(), (std::vector{"ru", "en", "uk"})); -} - -void LanguageManagerTests::missedLanguage() -{ - std::string remoteLanguages = "ruenuk"; - std::vector localLanguages = {"en"}; - deskflow::languages::LanguageManager manager(localLanguages); - - manager.setRemoteLanguages(remoteLanguages); - QCOMPARE(manager.getMissedLanguages(), "ru, uk"); -} - -void LanguageManagerTests::languageInstall() -{ - std::vector localLanguages = {"ru", "en", "uk"}; - deskflow::languages::LanguageManager manager(localLanguages); - - QVERIFY(!manager.isLanguageInstalled("us")); - QVERIFY(manager.isLanguageInstalled("en")); -} - -void LanguageManagerTests::serializeLocalLanguages() -{ - std::vector localLanguages = {"ru", "en", "uk"}; - deskflow::languages::LanguageManager manager(localLanguages); - - QCOMPARE(manager.getSerializedLocalLanguages(), "ruenuk"); -} - -QTEST_MAIN(LanguageManagerTests)