fix: sync keyboard layout between DCC and fcitx5#147
fix: sync keyboard layout between DCC and fcitx5#147wyu71 merged 1 commit intolinuxdeepin:masterfrom
Conversation
Reviewer's GuideImplements bidirectional synchronization between DCC keyboard layouts and fcitx5 input methods by mapping layout keys, wiring KeyboardController signals to Fcitx5ConfigToolWorker, and updating fcitx5 IM lists and DCC layouts while guarding against feedback loops. Sequence diagram for DCC layout change syncing to fcitx5sequenceDiagram
actor User
participant DCC_UI
participant KeyboardController
participant Fcitx5ConfigToolWorkerPrivate
participant IMConfig
participant DbusController
User->>DCC_UI: Select keyboard layout
DCC_UI->>KeyboardController: setCurrentLayout(layoutKey)
KeyboardController->>KeyboardController: m_worker->setLayout(layoutKey)
KeyboardController-->>Fcitx5ConfigToolWorkerPrivate: currentLayoutSet(layoutKey)
alt Controller not available
Fcitx5ConfigToolWorkerPrivate->>Fcitx5ConfigToolWorkerPrivate: syncCurrentLayoutToFcitx5(layoutKey)
Fcitx5ConfigToolWorkerPrivate->>Fcitx5ConfigToolWorkerPrivate: m_pendingLayoutKey = layoutKey
else Controller available
Fcitx5ConfigToolWorkerPrivate->>Fcitx5ConfigToolWorkerPrivate: syncCurrentLayoutToFcitx5(layoutKey)
Fcitx5ConfigToolWorkerPrivate->>Fcitx5ConfigToolWorkerPrivate: SyncGuard sets m_syncInProgress = true
Fcitx5ConfigToolWorkerPrivate->>Fcitx5ConfigToolWorkerPrivate: fcitxKey = dccLayoutToFcitxIMKey(layoutKey)
Fcitx5ConfigToolWorkerPrivate->>IMConfig: imEntries()
IMConfig-->>Fcitx5ConfigToolWorkerPrivate: entries
alt Entry exists and not first
Fcitx5ConfigToolWorkerPrivate->>Fcitx5ConfigToolWorkerPrivate: move entry to front
else Entry missing
Fcitx5ConfigToolWorkerPrivate->>Fcitx5ConfigToolWorkerPrivate: prepend new keyboard entry
end
Fcitx5ConfigToolWorkerPrivate->>IMConfig: setIMEntries(updatedEntries)
Fcitx5ConfigToolWorkerPrivate->>IMConfig: emitChanged()
Fcitx5ConfigToolWorkerPrivate->>IMConfig: save()
Fcitx5ConfigToolWorkerPrivate->>DbusController: SetCurrentIM(fcitxKey)
Fcitx5ConfigToolWorkerPrivate->>Fcitx5ConfigToolWorkerPrivate: SyncGuard resets m_syncInProgress = false
end
DbusController-->>IMConfig: InputMethodGroupsChanged
IMConfig-->>Fcitx5ConfigToolWorkerPrivate: imListChanged()
Fcitx5ConfigToolWorkerPrivate->>Fcitx5ConfigToolWorkerPrivate: m_syncInProgress prevents resync loop
Sequence diagram for fcitx5 IM list change syncing first keyboard to DCCsequenceDiagram
participant DbusController
participant IMConfig
participant Fcitx5ConfigToolWorkerPrivate
participant KeyboardController
DbusController-->>IMConfig: InputMethodGroupsChanged
IMConfig-->>Fcitx5ConfigToolWorkerPrivate: imListChanged()
alt Sync not in progress
Fcitx5ConfigToolWorkerPrivate->>Fcitx5ConfigToolWorkerPrivate: syncFcitx5FirstKeyboardToDCC()
Fcitx5ConfigToolWorkerPrivate->>IMConfig: imEntries()
IMConfig-->>Fcitx5ConfigToolWorkerPrivate: entries
Fcitx5ConfigToolWorkerPrivate->>Fcitx5ConfigToolWorkerPrivate: find first keyboard-* entry
Fcitx5ConfigToolWorkerPrivate->>Fcitx5ConfigToolWorkerPrivate: firstKeyboardLayout = fcitxIMKeyToDccLayout(entry.key)
Fcitx5ConfigToolWorkerPrivate->>KeyboardController: allLayoutsContains(firstKeyboardLayout)
alt Layout not supported by DCC
Fcitx5ConfigToolWorkerPrivate->>Fcitx5ConfigToolWorkerPrivate: return
else Layout supported
Fcitx5ConfigToolWorkerPrivate->>Fcitx5ConfigToolWorkerPrivate: SyncGuard sets m_syncInProgress = true
Fcitx5ConfigToolWorkerPrivate->>KeyboardController: userLayoutsContains(firstKeyboardLayout)
alt Not in user layouts
Fcitx5ConfigToolWorkerPrivate->>KeyboardController: addUserLayout(firstKeyboardLayout)
end
Fcitx5ConfigToolWorkerPrivate->>KeyboardController: setCurrentLayout(firstKeyboardLayout)
KeyboardController-->>Fcitx5ConfigToolWorkerPrivate: currentLayoutSet(firstKeyboardLayout)
Fcitx5ConfigToolWorkerPrivate->>Fcitx5ConfigToolWorkerPrivate: syncCurrentLayoutToFcitx5(firstKeyboardLayout) guarded by SyncGuard
Fcitx5ConfigToolWorkerPrivate->>Fcitx5ConfigToolWorkerPrivate: SyncGuard resets m_syncInProgress = false
end
alt Pending layout key exists
Fcitx5ConfigToolWorkerPrivate->>Fcitx5ConfigToolWorkerPrivate: syncCurrentLayoutToFcitx5(m_pendingLayoutKey)
end
else Sync already in progress
Fcitx5ConfigToolWorkerPrivate->>Fcitx5ConfigToolWorkerPrivate: Ignore imListChanged
end
Class diagram for keyboard layout and fcitx5 sync structuresclassDiagram
class Fcitx5ConfigToolWorkerPrivate {
-fcitx::kcm::Fcitx5ConfigProxy *configProxy
-fcitx::kcm::Fcitx5AddonsProxy *addonsProxy
-IMListModel *imListModel
-dccV25::KeyboardController *keyboardController
-bool m_syncInProgress
-QString m_pendingLayoutKey
+init()
+initConnect()
-syncCurrentLayoutToFcitx5(QString layoutKey)
-syncLayoutDeletedFromFcitx5(QString layoutKey)
-syncFcitx5FirstKeyboardToDCC()
}
class SyncGuard {
-bool &flag
+SyncGuard(bool &flag)
+~SyncGuard()
-SyncGuard(SyncGuard &other)
-operator=(SyncGuard &other)
}
class KeyboardController {
-KeyboardModel *m_model
-KeyboardWorker *m_worker
+QMap~QString,QString~ userLayouts() const
+QString userLayoutAt(int index, bool isValue) const
+bool userLayoutsContains(QString key)
+bool allLayoutsContains(QString key) const
+QSortFilterProxyModel *layoutSearchModel()
+void addUserLayout(QString layout)
+void deleteUserLayout(QString layout)
+int layoutCount() const
+void setCurrentLayout(QString key)
+void layoutDeleted(QString key, bool isCurrentLayout)
+void currentLayoutSet(QString key)
}
class KeyboardModel {
-QMap~QString,QString~ m_userLayout
-QMap~QString,QString~ m_allLayouts
+QString curLayout() const
+QString curLang() const
+const QMap~QString,QString~ &userLayout() const
+QMap~QString,QString~ kbLayout() const
+const QMap~QString,QString~ &allLayout() const
}
class IMConfig {
+fcitx::FcitxQtStringKeyValueList imEntries() const
+void setIMEntries(fcitx::FcitxQtStringKeyValueList entries)
+void emitChanged()
+void save()
+signal imListChanged()
}
class DbusController {
+void SetCurrentIM(QString imKey)
+signal InputMethodGroupsChanged()
}
Fcitx5ConfigToolWorkerPrivate --> KeyboardController : keyboardController
Fcitx5ConfigToolWorkerPrivate --> IMConfig : imConfig
Fcitx5ConfigToolWorkerPrivate --> DbusController : controller()
Fcitx5ConfigToolWorkerPrivate ..> SyncGuard : uses
KeyboardController --> KeyboardModel : m_model
KeyboardController ..> Fcitx5ConfigToolWorkerPrivate : signals currentLayoutSet, layoutDeleted
IMConfig ..> Fcitx5ConfigToolWorkerPrivate : signal imListChanged
DbusController ..> IMConfig : signal InputMethodGroupsChanged
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 2 issues, and left some high level feedback:
- The newly introduced
layoutDeletedandcurrentLayoutSetinKeyboardControllerare declared as slots but are used as signals (Q_EMITandconnectexpecting signals); they should be moved to thesignalssection rather thanpublic Q_SLOTSto match their intended usage. - In
syncCurrentLayoutToFcitx5and related sync functions, consider adding a brief comment nearm_syncInProgress/SyncGuardexplaining the reentrancy/dead-loop prevention strategy, as the interaction between DCC and fcitx5 callbacks is non-trivial and easy to regress in future changes.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The newly introduced `layoutDeleted` and `currentLayoutSet` in `KeyboardController` are declared as slots but are used as signals (`Q_EMIT` and `connect` expecting signals); they should be moved to the `signals` section rather than `public Q_SLOTS` to match their intended usage.
- In `syncCurrentLayoutToFcitx5` and related sync functions, consider adding a brief comment near `m_syncInProgress`/`SyncGuard` explaining the reentrancy/dead-loop prevention strategy, as the interaction between DCC and fcitx5 callbacks is non-trivial and easy to regress in future changes.
## Individual Comments
### Comment 1
<location path="src/dcc-fcitx5configtool/keyboard-layout/operation/keyboardcontroller.h" line_range="99-100" />
<code_context>
void keyDone(const QString &accels);
void keyEvent(const QString &accels);
+ void layoutDeleted(const QString &key, bool isCurrentLayout);
+ void currentLayoutSet(const QString &key);
+
void conflictTextChanged();
</code_context>
<issue_to_address>
**issue (bug_risk):** These should be declared as signals, not slots, to work with the new connect syntax.
`layoutDeleted` and `currentLayoutSet` are currently under `public Q_SLOTS:`, but they’re used with the function-pointer `connect` syntax and emitted via `Q_EMIT`. For this usage, Qt requires them to be declared as `signals`. Please move these to a `Q_SIGNALS:` section so moc treats them correctly and the code compiles with the new connect syntax.
</issue_to_address>
### Comment 2
<location path="src/dcc-fcitx5configtool/keyboard-layout/operation/keyboardcontroller.cpp" line_range="317-324" />
<code_context>
void KeyboardController::deleteUserLayout(const QString &layout)
{
+ const auto &userLayout = m_model->userLayout();
+ QString key = userLayout.key(layout, layout);
+ QString currentKey = userLayout.key(currentLayout());
+ bool isCur = (key == currentKey);
m_worker->delUserLayout(layout);
+ Q_EMIT layoutDeleted(key, isCur);
}
</code_context>
<issue_to_address>
**issue (bug_risk):** The use of QMap::key() suggests `layout` is treated as a value, which may conflict with other methods that treat it as a key.
`QMap::key(value, defaultKey)` looks up a key by value, but other APIs (e.g. `userLayoutsContains(const QString &key)`) treat the external `key` as the actual map key. If `layout` here is already the map key, using `userLayout.key(layout, layout)` is unnecessary and can even return a different key if a value matches another key. It also means `delUserLayout` still receives `layout`, not the derived `key`, which is inconsistent. Please verify whether `layout` at call sites is meant to be the map key or the value, and then align both `delUserLayout(...)` and the `layoutDeleted(...)` emission with that same notion of key.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
7d15ad6 to
3c21cc0
Compare
Add bidirectional synchronization between DCC keyboard layout settings and fcitx5 input method configuration. 添加DCC键盘布局与fcitx5输入法的双向同步功能。 DCC切换布局时自动同步到fcitx5(添加/排序/设置当前), fcitx5输入法列表变化时同步第一个键盘布局到DCC。 Log: 添加DCC键盘布局与fcitx5输入法双向同步 PMS: BUG-357551 Influence: DCC键盘布局设置与fcitx5输入法配置保持一致, 切换/添加/删除键盘布局时自动同步,支持带变体的键盘布局。
deepin pr auto review这份代码主要实现了 DCC (Deepin Control Center) 的键盘布局与 Fcitx5 输入法框架之间的双向同步功能。下面是对代码的详细审查和改进建议: 1. 语法与逻辑审查优点:
潜在逻辑问题:
2. 代码质量优点:
改进意见:
3. 代码性能
4. 代码安全
5. 详细改进建议
总结这份代码整体质量很高,逻辑清晰,使用了 RAII 模式来处理同步问题,并且对性能敏感的部分(如返回值)进行了优化。主要的改进点在于增强边界条件的处理和增加必要的注释以提高代码的可维护性。 |
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: lzwind, wyu71 The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
Add bidirectional synchronization between DCC keyboard layout settings and fcitx5 input method configuration.
添加DCC键盘布局与fcitx5输入法的双向同步功能。
DCC切换布局时自动同步到fcitx5(添加/排序/设置当前),
fcitx5输入法列表变化时同步第一个键盘布局到DCC。
Log: 添加DCC键盘布局与fcitx5输入法双向同步
PMS: BUG-357551
Influence: DCC键盘布局设置与fcitx5输入法配置保持一致,
切换/添加/删除键盘布局时自动同步,支持带变体的键盘布局。
Summary by Sourcery
Synchronize keyboard layouts between DCC and fcitx5 so that changes in either system are reflected in the other while avoiding sync loops.
New Features:
Enhancements: