@@ -30,6 +30,39 @@ Q_LOGGING_CATEGORY(configTool, "fcitx5.configtool.main")
3030namespace deepin {
3131namespace fcitx5configtool {
3232
33+ static QString dccLayoutToFcitxIMKey (const QString &key) {
34+ // DCC: "fr;" or "fr;bepo" -> fcitx5: "keyboard-fr" or "keyboard-fr-bepo"
35+ QString stripped = key;
36+ stripped.replace (' ;' , ' -' );
37+ while (stripped.endsWith (' -' )) stripped.chop (1 );
38+ return QStringLiteral (" keyboard-" ) + stripped;
39+ }
40+ static QString fcitxIMKeyToDccLayout (const QString &imKey) {
41+ const QString prefix = QStringLiteral (" keyboard-" );
42+ if (!imKey.startsWith (prefix)) return QString ();
43+ // fcitx5: "keyboard-fr-bepo" -> DCC: "fr;bepo"
44+ QString stripped = imKey.mid (prefix.length ());
45+ int dashPos = stripped.indexOf (' -' );
46+ if (dashPos < 0 ) {
47+ return stripped + ' ;' ;
48+ }
49+ return stripped.left (dashPos) + ' ;' + stripped.mid (dashPos + 1 );
50+ }
51+
52+ static int indexOfEntry (const fcitx::FcitxQtStringKeyValueList &entries, const QString &key) {
53+ for (int i = 0 ; i < entries.size (); ++i)
54+ if (entries[i].key () == key) return i;
55+ return -1 ;
56+ }
57+
58+ struct SyncGuard {
59+ bool &flag;
60+ SyncGuard (bool &f) : flag(f) { flag = true ; }
61+ ~SyncGuard () { flag = false ; }
62+ SyncGuard (const SyncGuard &) = delete ;
63+ SyncGuard &operator =(const SyncGuard &) = delete ;
64+ };
65+
3366static QString kFcitxConfigGlobalPath = " fcitx://config/global" ;
3467#ifdef BUILD_UOS
3568static const QString kSogouAddonUniqueName = " com.sogou.ime.ng.fcitx5.uos-addon" ;
@@ -70,6 +103,10 @@ void Fcitx5ConfigToolWorkerPrivate::initConnect()
70103 if (avail) {
71104 configProxy->requestConfig (false );
72105 addonsProxy->load ();
106+ connect (dbusProvider->controller (), &fcitx::FcitxQtControllerProxy::InputMethodGroupsChanged,
107+ this , [this ]() {
108+ if (!m_syncInProgress) imConfig->load ();
109+ }, Qt::UniqueConnection);
73110 } else {
74111 configProxy->clear ();
75112 addonsProxy->clear ();
@@ -94,6 +131,25 @@ void Fcitx5ConfigToolWorkerPrivate::initConnect()
94131
95132 connect (configProxy, &Fcitx5ConfigProxy::requestConfigFinished, q, &Fcitx5ConfigToolWorker::requestConfigFinished);
96133 connect (addonsProxy, &Fcitx5AddonsProxy::requestAddonsFinished, q, &Fcitx5ConfigToolWorker::requestAddonsFinished);
134+
135+ connect (keyboardController, &dccV25::KeyboardController::currentLayoutSet, this ,
136+ [this ](const QString &key) {
137+ if (!m_syncInProgress) syncCurrentLayoutToFcitx5 (key);
138+ });
139+
140+ connect (keyboardController, &dccV25::KeyboardController::layoutDeleted, this ,
141+ [this ](const QString &key, bool isCurrent) {
142+ if (!m_syncInProgress && isCurrent) syncLayoutDeletedFromFcitx5 (key);
143+ });
144+
145+ connect (imConfig, &fcitx::kcm::IMConfig::imListChanged, this , [this ]() {
146+ if (!m_syncInProgress) syncFcitx5FirstKeyboardToDCC ();
147+ if (!m_pendingLayoutKey.isEmpty ()) {
148+ QString key = m_pendingLayoutKey;
149+ syncCurrentLayoutToFcitx5 (key);
150+ }
151+ });
152+
97153 configProxy->requestConfig (false );
98154 addonsProxy->load ();
99155 qCDebug (configTool) << " Exiting Fcitx5ConfigToolWorkerPrivate::initConnect" ;
@@ -244,6 +300,94 @@ fcitx::kcm::IMProxyModel *Fcitx5ConfigToolWorker::imProxyModel() const
244300 return d->imConfig ->availIMModel ();
245301}
246302
303+ void Fcitx5ConfigToolWorkerPrivate::syncCurrentLayoutToFcitx5 (const QString &layoutKey)
304+ {
305+ if (!dbusProvider || !dbusProvider->controller ()) {
306+ qCDebug (configTool) << " syncCurrentLayoutToFcitx5: controller not available, pending:" << layoutKey;
307+ m_pendingLayoutKey = layoutKey;
308+ return ;
309+ }
310+
311+ QString fcitxKey = dccLayoutToFcitxIMKey (layoutKey);
312+
313+ const auto &entries = imConfig->imEntries ();
314+ int existIndex = indexOfEntry (entries, fcitxKey);
315+
316+ SyncGuard guard (m_syncInProgress);
317+ m_pendingLayoutKey.clear ();
318+
319+ if (existIndex > 0 ) {
320+ qCDebug (configTool) << " syncCurrentLayoutToFcitx5: move to front:" << fcitxKey;
321+ auto updatedEntries = entries;
322+ updatedEntries.move (existIndex, 0 );
323+ imConfig->setIMEntries (updatedEntries);
324+ imConfig->emitChanged ();
325+ imConfig->save ();
326+ } else if (existIndex < 0 ) {
327+ qCDebug (configTool) << " syncCurrentLayoutToFcitx5: prepend:" << fcitxKey;
328+ auto updatedEntries = entries;
329+ fcitx::FcitxQtStringKeyValue newEntry;
330+ newEntry.setKey (fcitxKey);
331+ updatedEntries.prepend (newEntry);
332+ imConfig->setIMEntries (updatedEntries);
333+ imConfig->emitChanged ();
334+ imConfig->save ();
335+ }
336+
337+ dbusProvider->controller ()->SetCurrentIM (fcitxKey);
338+ }
339+
340+ void Fcitx5ConfigToolWorkerPrivate::syncLayoutDeletedFromFcitx5 (const QString &layoutKey)
341+ {
342+ if (!dbusProvider || !dbusProvider->controller ()) return ;
343+
344+ QString fcitxKey = dccLayoutToFcitxIMKey (layoutKey);
345+ const auto &entries = imConfig->imEntries ();
346+ int removedIndex = indexOfEntry (entries, fcitxKey);
347+ if (removedIndex < 0 ) return ;
348+
349+ qCDebug (configTool) << " syncLayoutDeletedFromFcitx5:" << fcitxKey;
350+ SyncGuard guard (m_syncInProgress);
351+ auto updatedEntries = entries;
352+ updatedEntries.removeAt (removedIndex);
353+ imConfig->setIMEntries (updatedEntries);
354+ imConfig->emitChanged ();
355+ imConfig->save ();
356+
357+ if (!updatedEntries.isEmpty ()) {
358+ dbusProvider->controller ()->SetCurrentIM (updatedEntries.first ().key ());
359+ }
360+ }
361+
362+ void Fcitx5ConfigToolWorkerPrivate::syncFcitx5FirstKeyboardToDCC ()
363+ {
364+ if (!keyboardController || !imConfig) return ;
365+
366+ const auto &entries = imConfig->imEntries ();
367+ QString firstKeyboardLayout;
368+ for (const auto &entry : entries) {
369+ QString dccKey = fcitxIMKeyToDccLayout (entry.key ());
370+ if (!dccKey.isEmpty ()) {
371+ firstKeyboardLayout = dccKey;
372+ break ;
373+ }
374+ }
375+
376+ if (firstKeyboardLayout.isEmpty ()) return ;
377+
378+ if (!keyboardController->allLayoutsContains (firstKeyboardLayout)) {
379+ qCDebug (configTool) << " syncFcitx5FirstKeyboardToDCC: layout not in DCC:" << firstKeyboardLayout;
380+ return ;
381+ }
382+
383+ qCDebug (configTool) << " syncFcitx5FirstKeyboardToDCC:" << firstKeyboardLayout;
384+ SyncGuard guard (m_syncInProgress);
385+ if (!keyboardController->userLayoutsContains (firstKeyboardLayout)) {
386+ keyboardController->addUserLayout (firstKeyboardLayout);
387+ }
388+ keyboardController->setCurrentLayout (firstKeyboardLayout);
389+ }
390+
247391DCC_FACTORY_CLASS (Fcitx5ConfigToolWorker)
248392} // namespace fcitx5configtool
249393} // namespace deepin
0 commit comments