Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
//SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd.
//
//SPDX-License-Identifier: GPL-3.0-or-later

Expand Down Expand Up @@ -161,6 +161,11 @@ bool KeyboardController::userLayoutsContains(const QString &key)
return userLayouts().contains(key);
}

bool KeyboardController::allLayoutsContains(const QString &key) const
{
return m_model->allLayout().contains(key);
}

QSortFilterProxyModel *KeyboardController::layoutSearchModel()
{
if (m_layoutSearchModel)
Expand Down Expand Up @@ -311,7 +316,11 @@ void KeyboardController::addUserLayout(const QString &layout)

void KeyboardController::deleteUserLayout(const QString &layout)
{
const auto &userLayout = m_model->userLayout();
QString key = userLayout.key(layout, layout);
bool isCur = (key == currentLayout());
m_worker->delUserLayout(layout);
Q_EMIT layoutDeleted(key, isCur);
Comment thread
wyu71 marked this conversation as resolved.
}

int KeyboardController::layoutCount() const
Expand All @@ -330,6 +339,7 @@ void KeyboardController::setCurrentLayout(const QString &key)
return;

m_worker->setLayout(key);
Q_EMIT currentLayoutSet(key);
}

QString KeyboardController::conflictText() const
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
//SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd.
//
//SPDX-License-Identifier: GPL-3.0-or-later

Expand Down Expand Up @@ -58,6 +58,7 @@ public Q_SLOTS:
QMap<QString, QString> userLayouts() const;
QString userLayoutAt(int index, bool isValue = true) const;
bool userLayoutsContains(const QString &key);
bool allLayoutsContains(const QString &key) const;
QSortFilterProxyModel *layoutSearchModel();
QSortFilterProxyModel *shortcutSearchModel();

Expand Down Expand Up @@ -95,6 +96,9 @@ public Q_SLOTS:
void keyDone(const QString &accels);
void keyEvent(const QString &accels);

void layoutDeleted(const QString &key, bool isCurrentLayout);
void currentLayoutSet(const QString &key);
Comment thread
wyu71 marked this conversation as resolved.

void conflictTextChanged();
void keyboardEnabledChanged();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
//SPDX-FileCopyrightText: 2018 - 2026 UnionTech Software Technology Co., Ltd.
//
//SPDX-License-Identifier: GPL-3.0-or-later

Expand Down Expand Up @@ -202,7 +202,7 @@ QString KeyboardModel::curLang() const
return langByKey(m_currentLangKey);
}

QMap<QString, QString> KeyboardModel::userLayout() const
const QMap<QString, QString> &KeyboardModel::userLayout() const
{
return m_userLayout;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
//SPDX-FileCopyrightText: 2018 - 2026 UnionTech Software Technology Co., Ltd.
//
//SPDX-License-Identifier: GPL-3.0-or-later

Expand Down Expand Up @@ -32,9 +32,9 @@ class KeyboardModel : public QObject

QString curLayout() const;
QString curLang() const;
QMap<QString, QString> userLayout() const;
const QMap<QString, QString> &userLayout() const;
QMap<QString, QString> kbLayout() const;
QMap<QString, QString> allLayout() const { return m_allLayouts; }
const QMap<QString, QString> &allLayout() const { return m_allLayouts; }
QStringList localLang() const;
QList<MetaData> langLists() const;
bool capsLock() const;
Expand Down
144 changes: 144 additions & 0 deletions src/dcc-fcitx5configtool/operation/fcitx5configtool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,39 @@ Q_LOGGING_CATEGORY(configTool, "fcitx5.configtool.main")
namespace deepin {
namespace fcitx5configtool {

static QString dccLayoutToFcitxIMKey(const QString &key) {
// DCC: "fr;" or "fr;bepo" -> fcitx5: "keyboard-fr" or "keyboard-fr-bepo"
QString stripped = key;
stripped.replace(';', '-');
while (stripped.endsWith('-')) stripped.chop(1);
return QStringLiteral("keyboard-") + stripped;
}
static QString fcitxIMKeyToDccLayout(const QString &imKey) {
const QString prefix = QStringLiteral("keyboard-");
if (!imKey.startsWith(prefix)) return QString();
// fcitx5: "keyboard-fr-bepo" -> DCC: "fr;bepo"
QString stripped = imKey.mid(prefix.length());
int dashPos = stripped.indexOf('-');
if (dashPos < 0) {
return stripped + ';';
}
return stripped.left(dashPos) + ';' + stripped.mid(dashPos + 1);
}

static int indexOfEntry(const fcitx::FcitxQtStringKeyValueList &entries, const QString &key) {
for (int i = 0; i < entries.size(); ++i)
if (entries[i].key() == key) return i;
return -1;
}

struct SyncGuard {
bool &flag;
SyncGuard(bool &f) : flag(f) { flag = true; }
~SyncGuard() { flag = false; }
SyncGuard(const SyncGuard &) = delete;
SyncGuard &operator=(const SyncGuard &) = delete;
};

static QString kFcitxConfigGlobalPath = "fcitx://config/global";
#ifdef BUILD_UOS
static const QString kSogouAddonUniqueName = "com.sogou.ime.ng.fcitx5.uos-addon";
Expand Down Expand Up @@ -70,6 +103,10 @@ void Fcitx5ConfigToolWorkerPrivate::initConnect()
if (avail) {
configProxy->requestConfig(false);
addonsProxy->load();
connect(dbusProvider->controller(), &fcitx::FcitxQtControllerProxy::InputMethodGroupsChanged,
this, [this]() {
if (!m_syncInProgress) imConfig->load();
}, Qt::UniqueConnection);
} else {
configProxy->clear();
addonsProxy->clear();
Expand All @@ -94,6 +131,25 @@ void Fcitx5ConfigToolWorkerPrivate::initConnect()

connect(configProxy, &Fcitx5ConfigProxy::requestConfigFinished, q, &Fcitx5ConfigToolWorker::requestConfigFinished);
connect(addonsProxy, &Fcitx5AddonsProxy::requestAddonsFinished, q, &Fcitx5ConfigToolWorker::requestAddonsFinished);

connect(keyboardController, &dccV25::KeyboardController::currentLayoutSet, this,
[this](const QString &key) {
if (!m_syncInProgress) syncCurrentLayoutToFcitx5(key);
});

connect(keyboardController, &dccV25::KeyboardController::layoutDeleted, this,
[this](const QString &key, bool isCurrent) {
if (!m_syncInProgress && isCurrent) syncLayoutDeletedFromFcitx5(key);
});

connect(imConfig, &fcitx::kcm::IMConfig::imListChanged, this, [this]() {
if (!m_syncInProgress) syncFcitx5FirstKeyboardToDCC();
if (!m_pendingLayoutKey.isEmpty()) {
QString key = m_pendingLayoutKey;
syncCurrentLayoutToFcitx5(key);
}
});

configProxy->requestConfig(false);
addonsProxy->load();
qCDebug(configTool) << "Exiting Fcitx5ConfigToolWorkerPrivate::initConnect";
Expand Down Expand Up @@ -244,6 +300,94 @@ fcitx::kcm::IMProxyModel *Fcitx5ConfigToolWorker::imProxyModel() const
return d->imConfig->availIMModel();
}

void Fcitx5ConfigToolWorkerPrivate::syncCurrentLayoutToFcitx5(const QString &layoutKey)
{
if (!dbusProvider || !dbusProvider->controller()) {
qCDebug(configTool) << "syncCurrentLayoutToFcitx5: controller not available, pending:" << layoutKey;
m_pendingLayoutKey = layoutKey;
return;
}

QString fcitxKey = dccLayoutToFcitxIMKey(layoutKey);

const auto &entries = imConfig->imEntries();
int existIndex = indexOfEntry(entries, fcitxKey);

SyncGuard guard(m_syncInProgress);
m_pendingLayoutKey.clear();

if (existIndex > 0) {
qCDebug(configTool) << "syncCurrentLayoutToFcitx5: move to front:" << fcitxKey;
auto updatedEntries = entries;
updatedEntries.move(existIndex, 0);
imConfig->setIMEntries(updatedEntries);
imConfig->emitChanged();
imConfig->save();
} else if (existIndex < 0) {
qCDebug(configTool) << "syncCurrentLayoutToFcitx5: prepend:" << fcitxKey;
auto updatedEntries = entries;
fcitx::FcitxQtStringKeyValue newEntry;
newEntry.setKey(fcitxKey);
updatedEntries.prepend(newEntry);
imConfig->setIMEntries(updatedEntries);
imConfig->emitChanged();
imConfig->save();
}

dbusProvider->controller()->SetCurrentIM(fcitxKey);
}

void Fcitx5ConfigToolWorkerPrivate::syncLayoutDeletedFromFcitx5(const QString &layoutKey)
{
if (!dbusProvider || !dbusProvider->controller()) return;

QString fcitxKey = dccLayoutToFcitxIMKey(layoutKey);
const auto &entries = imConfig->imEntries();
int removedIndex = indexOfEntry(entries, fcitxKey);
if (removedIndex < 0) return;

qCDebug(configTool) << "syncLayoutDeletedFromFcitx5:" << fcitxKey;
SyncGuard guard(m_syncInProgress);
auto updatedEntries = entries;
updatedEntries.removeAt(removedIndex);
imConfig->setIMEntries(updatedEntries);
imConfig->emitChanged();
imConfig->save();

if (!updatedEntries.isEmpty()) {
dbusProvider->controller()->SetCurrentIM(updatedEntries.first().key());
}
}

void Fcitx5ConfigToolWorkerPrivate::syncFcitx5FirstKeyboardToDCC()
{
if (!keyboardController || !imConfig) return;

const auto &entries = imConfig->imEntries();
QString firstKeyboardLayout;
for (const auto &entry : entries) {
QString dccKey = fcitxIMKeyToDccLayout(entry.key());
if (!dccKey.isEmpty()) {
firstKeyboardLayout = dccKey;
break;
}
}

if (firstKeyboardLayout.isEmpty()) return;

if (!keyboardController->allLayoutsContains(firstKeyboardLayout)) {
qCDebug(configTool) << "syncFcitx5FirstKeyboardToDCC: layout not in DCC:" << firstKeyboardLayout;
return;
}

qCDebug(configTool) << "syncFcitx5FirstKeyboardToDCC:" << firstKeyboardLayout;
SyncGuard guard(m_syncInProgress);
if (!keyboardController->userLayoutsContains(firstKeyboardLayout)) {
keyboardController->addUserLayout(firstKeyboardLayout);
}
keyboardController->setCurrentLayout(firstKeyboardLayout);
}

DCC_FACTORY_CLASS(Fcitx5ConfigToolWorker)
} // namespace fcitx5configtool
} // namespace deepin
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2024 - 2027 UnionTech Software Technology Co., Ltd.
// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef FCITX5CONFIGTOOL_P_H
Expand Down Expand Up @@ -36,7 +36,13 @@ class Fcitx5ConfigToolWorkerPrivate : public QObject
IMListModel *imListModel { nullptr };
dccV25::KeyboardController *keyboardController { nullptr };

bool m_syncInProgress { false };
QString m_pendingLayoutKey;

private:
void syncCurrentLayoutToFcitx5(const QString &layoutKey);
void syncLayoutDeletedFromFcitx5(const QString &layoutKey);
void syncFcitx5FirstKeyboardToDCC();
void init();
void initConnect();

Expand Down
Loading