Skip to content

Commit a756767

Browse files
yixinsharkdeepin-bot[bot]
authored andcommitted
feat(keyboard): consume shortcut category metadata
Read shortcut category metadata from dde-services on Wayland and use it to group, order, and label shortcut sections dynamically. Replace hardcoded category mapping with section keys and localized category names from D-Bus, while keeping the legacy X11 grouping fallback intact. 在 Wayland 下从 dde-services 读取快捷键分类元数据,并用它动态分组、排序和显示快捷键分区。移除硬编码分类映射,改为使用 D-Bus 返回的 section key 和本地化分类名,同时保留 X11 旧分组逻辑作为回退。 Log: consume shortcut category metadata Pms: BUG-367657 Change-Id: I5a27eb227275e373aa3943b804c4128bbb6b7394
1 parent 5dfcf11 commit a756767

9 files changed

Lines changed: 337 additions & 54 deletions

File tree

src/plugin-keyboard/operation/keyboardcontroller.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,8 @@ QSortFilterProxyModel *KeyboardController::shortcutSearchModel()
221221
connect(m_shortcutModel, &ShortcutModel::addCustomInfo, sourceModel, &ShortcutListModel::reset);
222222
connect(m_shortcutModel, &ShortcutModel::shortcutChanged, sourceModel, &ShortcutListModel::onUpdateShortcut);
223223
connect(m_shortcutModel, &ShortcutModel::windowSwitchChanged, sourceModel, &ShortcutListModel::reset);
224+
// Wayland: re-layout rows when category ordering metadata arrives.
225+
connect(m_shortcutModel, &ShortcutModel::categoryMetaChanged, sourceModel, &ShortcutListModel::reset);
224226

225227
m_shortcutSearchModel->setSourceModel(sourceModel);
226228
m_shortcutSearchModel->setFilterRole(ShortcutListModel::SearchedTextRole);
@@ -229,6 +231,16 @@ QSortFilterProxyModel *KeyboardController::shortcutSearchModel()
229231
return m_shortcutSearchModel;
230232
}
231233

234+
QString KeyboardController::sectionDisplayName(const QString &key) const
235+
{
236+
return m_shortcutModel ? m_shortcutModel->sectionDisplayName(key) : key;
237+
}
238+
239+
QString KeyboardController::customCategoryKey() const
240+
{
241+
return m_shortcutModel ? m_shortcutModel->customCategoryKey() : QString();
242+
}
243+
232244
void KeyboardController::updateKey(const QString &id, const int &type)
233245
{
234246
ShortcutInfo *shortcut = nullptr;

src/plugin-keyboard/operation/keyboardcontroller.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,13 @@ public Q_SLOTS:
6767
QSortFilterProxyModel *layoutSearchModel();
6868
QSortFilterProxyModel *shortcutSearchModel();
6969

70+
// Wayland: category metadata is supplied by the service (ListCategories).
71+
// Exposed to QML so the section delegate can render the display name for
72+
// a section key and detect the user-editable (Custom) group without any
73+
// hardcoded category strings.
74+
Q_INVOKABLE QString sectionDisplayName(const QString &key) const;
75+
Q_INVOKABLE QString customCategoryKey() const;
76+
7077
void updateKey(const QString &id, const int &type);
7178
QStringList formatKeys(const QString &shortcuts);
7279
Q_INVOKABLE QString keyEventToAccels(int key, int modifiers);

src/plugin-keyboard/operation/keyboarddbusproxy.cpp

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ KeyboardDBusProxy::KeyboardDBusProxy(QObject *parent)
5151
qRegisterMetaType<QList<ShortcutInfoNew>>("QList<ShortcutInfoNew>");
5252
qDBusRegisterMetaType<QList<ShortcutInfoNew>>();
5353

54+
qRegisterMetaType<CategoryInfoNew>("CategoryInfoNew");
55+
qDBusRegisterMetaType<CategoryInfoNew>();
56+
qRegisterMetaType<QList<CategoryInfoNew>>("QList<CategoryInfoNew>");
57+
qDBusRegisterMetaType<QList<CategoryInfoNew>>();
58+
5459
init();
5560
}
5661

@@ -59,17 +64,6 @@ bool KeyboardDBusProxy::isWayland() const
5964
return m_isWayland;
6065
}
6166

62-
// Map new API category to section name (Wayland 3-category: System/App/Custom)
63-
static QString categoryToSection(int category)
64-
{
65-
switch (category) {
66-
case 1: return QStringLiteral("System");
67-
case 2: return QStringLiteral("App");
68-
case 3: return QStringLiteral("Custom");
69-
default: return QString();
70-
}
71-
}
72-
7367
// Convert a single ShortcutInfo to old-API JSON object
7468
static QJsonObject shortcutInfoToJsonObject(const ShortcutInfoNew &info)
7569
{
@@ -80,12 +74,15 @@ static QJsonObject shortcutInfoToJsonObject(const ShortcutInfoNew &info)
8074
// dde-services already emits hotkeys in X11/XKB form ("<Control><Alt>T",
8175
// "XF86AudioMute"), so we just forward the first one to Accels.
8276
obj["Accels"] = QJsonArray{info.hotkeys.isEmpty() ? QString() : info.hotkeys.first()};
83-
// Type: 0=System, 1=Custom (old API). App(category==2) must map to 0,
84-
// otherwise IsCustomRole would mark App shortcuts as editable.
85-
obj["Type"] = (info.category == 3) ? 1 : 0;
77+
// Type is now driven by the explicit isCustom flag from dde-services
78+
// (was derived from category==3). 0=System, 1=Custom.
79+
obj["Type"] = info.isCustom ? 1 : 0;
8680
obj["Exec"] = QString();
87-
// New API section: overrides old hardcoded ID-based categorization
88-
obj["Section"] = categoryToSection(info.category);
81+
// Section carries the stable logical category key (for grouping/ordering
82+
// and Custom detection); SectionName carries the already-resolved display
83+
// text for direct rendering — dcc no longer translates categories.
84+
obj["Section"] = info.category;
85+
obj["SectionName"] = info.localLanguageCategory;
8986
return obj;
9087
}
9188

@@ -323,6 +320,33 @@ QDBusPendingReply<QString> KeyboardDBusProxy::ListAllShortcuts()
323320
m_dBusKeybingdingInter->asyncCallWithArgumentList(QStringLiteral("ListAllShortcuts"), argumentList));
324321
}
325322

323+
// Wayland: fetch category metadata (key/displayName/order/isCustom) so the
324+
// model can group, order, and identify the Custom group without hardcoding
325+
// any category strings.
326+
QDBusPendingReply<> KeyboardDBusProxy::ListCategories()
327+
{
328+
QList<QVariant> argumentList;
329+
if (isWayland()) {
330+
QDBusPendingCall call = m_dBusKeybingdingInter->asyncCallWithArgumentList(
331+
QStringLiteral("ListCategories"), argumentList);
332+
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
333+
connect(watcher, &QDBusPendingCallWatcher::finished,
334+
this, &KeyboardDBusProxy::onListCategoriesFinished);
335+
}
336+
return QDBusPendingReply<>();
337+
}
338+
339+
void KeyboardDBusProxy::onListCategoriesFinished(QDBusPendingCallWatcher *w)
340+
{
341+
QDBusPendingReply<QList<CategoryInfoNew>> reply = *w;
342+
if (!reply.isError()) {
343+
Q_EMIT categoriesReady(reply.value());
344+
} else {
345+
qWarning() << "Wayland ListCategories failed:" << reply.error();
346+
}
347+
w->deleteLater();
348+
}
349+
326350
// Wayland: called when new API GetShortcut() async reply arrives.
327351
// The result is delivered via shortcutQueried so the downstream
328352
// model-update path never re-enters onShortcutChanged → Query → ...

src/plugin-keyboard/operation/keyboarddbusproxy.h

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,25 +71,55 @@ class DCCDBusInterface;
7171
struct ShortcutInfoNew {
7272
QString id;
7373
QString displayName;
74-
int category;
74+
QString category; // Logical category key (e.g. "System", app-defined)
7575
QStringList hotkeys;
7676
QString localLanguageName;
77+
QString localLanguageCategory; // Resolved display text for the category
78+
bool isCustom = false; // True for runtime-added (service API) shortcuts
7779
};
7880
Q_DECLARE_METATYPE(ShortcutInfoNew)
7981
Q_DECLARE_METATYPE(QList<ShortcutInfoNew>)
8082

8183
inline QDBusArgument &operator<<(QDBusArgument &argument, const ShortcutInfoNew &info) {
8284
argument.beginStructure();
8385
argument << info.id << info.displayName << info.category
84-
<< info.hotkeys << info.localLanguageName;
86+
<< info.hotkeys << info.localLanguageName
87+
<< info.localLanguageCategory << info.isCustom;
8588
argument.endStructure();
8689
return argument;
8790
}
8891

8992
inline const QDBusArgument &operator>>(const QDBusArgument &argument, ShortcutInfoNew &info) {
9093
argument.beginStructure();
9194
argument >> info.id >> info.displayName >> info.category
92-
>> info.hotkeys >> info.localLanguageName;
95+
>> info.hotkeys >> info.localLanguageName
96+
>> info.localLanguageCategory >> info.isCustom;
97+
argument.endStructure();
98+
return argument;
99+
}
100+
101+
// New API category metadata (dde-services ListCategories()). The control
102+
// center treats this as the single source of truth for grouping/ordering/
103+
// display/custom-detection — it never hardcodes category strings.
104+
struct CategoryInfoNew {
105+
QString key;
106+
QString displayName;
107+
int order = 0;
108+
bool isCustom = false;
109+
};
110+
Q_DECLARE_METATYPE(CategoryInfoNew)
111+
Q_DECLARE_METATYPE(QList<CategoryInfoNew>)
112+
113+
inline QDBusArgument &operator<<(QDBusArgument &argument, const CategoryInfoNew &info) {
114+
argument.beginStructure();
115+
argument << info.key << info.displayName << info.order << info.isCustom;
116+
argument.endStructure();
117+
return argument;
118+
}
119+
120+
inline const QDBusArgument &operator>>(const QDBusArgument &argument, CategoryInfoNew &info) {
121+
argument.beginStructure();
122+
argument >> info.key >> info.displayName >> info.order >> info.isCustom;
93123
argument.endStructure();
94124
return argument;
95125
}
@@ -194,6 +224,9 @@ class KeyboardDBusProxy : public QObject, public DCC_NAMESPACE::IKeyboardDeviceP
194224
// never reuse Deleted, whose X11 auto-wiring → KeyboardWorker::removed is a
195225
// dead-end relay. Carries only the id (the new-API signal has no type).
196226
void shortcutRemovedById(const QString &id);
227+
// Wayland: category metadata from ListCategories() — drives grouping,
228+
// ordering, display names, and custom-group identity in the model.
229+
void categoriesReady(const QList<CategoryInfoNew> &categories);
197230

198231
//wm
199232
void compositingEnabledChanged(bool enabled);
@@ -204,6 +237,8 @@ public slots:
204237
// Keybinding
205238
QDBusPendingReply<> KeybindingReset();
206239
QDBusPendingReply<QString> ListAllShortcuts();
240+
// Wayland: fetch category metadata (ordering/display/custom flag).
241+
QDBusPendingReply<> ListCategories();
207242
QString LookupConflictingShortcut(const QString &in0);
208243
QDBusPendingReply<ShortcutInfoNew> LookupConflictShortcut(const QString &in0);
209244
QDBusPendingReply<> ClearShortcutKeystrokes(const QString &in0, int in1);
@@ -239,6 +274,7 @@ private slots:
239274
void onLangSelectorStartServiceProcessFinished(QDBusPendingCallWatcher *w);
240275
// New API -> Old API adapters (Wayland)
241276
void onListAllShortcutsNewFinished(QDBusPendingCallWatcher *w);
277+
void onListCategoriesFinished(QDBusPendingCallWatcher *w);
242278
void onGetShortcutNewFinished(QDBusPendingCallWatcher *w);
243279
void onSearchShortcutsNewFinished(QDBusPendingCallWatcher *w);
244280
// Bridge: new dde-services D-Bus signals (ShortcutChanged/ShortcutRemoved)

src/plugin-keyboard/operation/keyboardwork.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,24 @@ KeyboardWorker::KeyboardWorker(KeyboardModel *model, QObject *parent)
7373
connect(m_keyboardDBusProxy, &KeyboardDBusProxy::compositingEnabledChanged, this, &KeyboardWorker::onGetWindowWM);
7474
connect(m_keyboardDBusProxy, &KeyboardDBusProxy::Added, this, &KeyboardWorker::onAdded);
7575
connect(m_keyboardDBusProxy, &KeyboardDBusProxy::AllShortcutsReady, this, &KeyboardWorker::onAllShortcutsReady);
76+
// Wayland: category metadata (ordering/display/custom flag) from the
77+
// service's ListCategories(). Feeds the model so it never hardcodes
78+
// category strings for grouping or Custom detection.
79+
connect(m_keyboardDBusProxy, &KeyboardDBusProxy::categoriesReady, this, [this](const QList<CategoryInfoNew> &cats) {
80+
if (!m_shortcutModel)
81+
return;
82+
QList<ShortcutModel::CategoryMeta> meta;
83+
meta.reserve(cats.size());
84+
for (const auto &c : cats) {
85+
ShortcutModel::CategoryMeta m;
86+
m.key = c.key;
87+
m.displayName = c.displayName;
88+
m.order = c.order;
89+
m.isCustom = c.isCustom;
90+
meta.append(m);
91+
}
92+
m_shortcutModel->setCategoryMeta(meta);
93+
});
7694
connect(m_keyboardDBusProxy, &KeyboardDBusProxy::searchShortcutsReady, this, [this](const QString &json) {
7795
if (m_shortcutModel)
7896
m_shortcutModel->setSearchResult(json);
@@ -146,6 +164,8 @@ void KeyboardWorker::refreshShortcut()
146164
if (m_keyboardDBusProxy->isWayland()) {
147165
// Wayland: result is delivered asynchronously via AllShortcutsReady signal.
148166
m_keyboardDBusProxy->ListAllShortcuts();
167+
// Also refresh category metadata (ordering/display/custom flag).
168+
m_keyboardDBusProxy->ListCategories();
149169
return;
150170
}
151171
QDBusPendingCallWatcher *result = new QDBusPendingCallWatcher(m_keyboardDBusProxy->ListAllShortcuts(), this);

0 commit comments

Comments
 (0)