diff --git a/src/plugin-keyboard/operation/keyboardcontroller.cpp b/src/plugin-keyboard/operation/keyboardcontroller.cpp index 1db54bf4e1..1ba7ac8ff7 100644 --- a/src/plugin-keyboard/operation/keyboardcontroller.cpp +++ b/src/plugin-keyboard/operation/keyboardcontroller.cpp @@ -45,6 +45,8 @@ KeyboardController::KeyboardController(QObject *parent) connect(m_model, &KeyboardModel::userLayoutChanged, this, &KeyboardController::layoutCountChanged); connect(m_model, &KeyboardModel::curLayoutChanged, this, &KeyboardController::currentLayoutChanged); connect(m_model, &KeyboardModel::keyboardEnabledChanged, this, &KeyboardController::keyboardEnabledChanged); + connect(m_worker, &KeyboardWorker::shortcutCommandReady, + this, &KeyboardController::shortcutCommandReady); connect(m_shortcutModel, &ShortcutModel::keyEvent, this, [this](bool press, const QString &shortcut){ ShortcutInfo *current = m_shortcutModel->currentInfo(); @@ -282,12 +284,7 @@ QString KeyboardController::checkDesktopCmd(const QString &cmd) void KeyboardController::addCustomShortcut(const QString &name, const QString &cmd, const QString &accels) { if (m_worker->isWayland()) { - // dde-services' Keybinding1 has no AddCustomShortcut yet (the service's - // own CONTROL_CENTER_INTEGRATION.md marks custom-shortcut CRUD as 服务侧需补齐). - // Bail out before any side effect (the conflict Disable below, the - // optimistic model insert in the worker) so the row doesn't flicker. - // TODO: wire up once AddCustomShortcut/ModifyCustomShortcut/DeleteCustomShortcut land. - qWarning() << "[Wayland] addCustomShortcut not yet supported by dde-services; ignoring"; + m_worker->addCustomShortcut(name, checkDesktopCmd(cmd), accels); return; } @@ -303,21 +300,21 @@ void KeyboardController::addCustomShortcut(const QString &name, const QString &c void KeyboardController::modifyCustomShortcut(const QString &id, const QString &name, const QString &cmd, const QString &accels) { - if (m_worker->isWayland()) { - // No ModifyCustomShortcut on the Wayland service yet — return before - // mutating the local model or triggering the conflict Disable below, - // so the UI is unchanged rather than showing an edit that won't persist. - // TODO: wire up once dde-services implements custom-shortcut CRUD. - qWarning() << "[Wayland] modifyCustomShortcut not yet supported by dde-services; ignoring"; - return; - } - ShortcutInfo *shortcut = m_shortcutModel->findInfoIf([id](ShortcutInfo *info){ return id == info->id; }); if (!shortcut) { qWarning() << "shortcut not found..." << id << name; return; } + if (m_worker->isWayland()) { + ShortcutInfo updated = *shortcut; + updated.name = name; + updated.command = checkDesktopCmd(cmd); + updated.accels = accels; + m_worker->modifyCustomShortcut(&updated); + return; + } + // Clear conflicting shortcuts when modifying if (auto conflict = m_shortcutModel->getInfo(accels)) { m_worker->onDisableShortcut(conflict); @@ -330,17 +327,14 @@ void KeyboardController::modifyCustomShortcut(const QString &id, const QString & m_worker->modifyCustomShortcut(shortcut); } -void KeyboardController::deleteCustomShortcut(const QString &id) +void KeyboardController::requestShortcutCommand(const QString &id) { - if (m_worker->isWayland()) { - // No DeleteCustomShortcut on the Wayland service yet. Return before - // delShortcut's optimistic delInfo() (which removes + deletes the row); - // otherwise the row would vanish then reappear on the next refresh. - // TODO: wire up once dde-services implements custom-shortcut CRUD. - qWarning() << "[Wayland] deleteCustomShortcut not yet supported by dde-services; ignoring"; - return; - } + if (m_worker) + m_worker->requestShortcutCommand(id); +} +void KeyboardController::deleteCustomShortcut(const QString &id) +{ ShortcutInfo *shortcut = m_shortcutModel->findInfoIf([id](ShortcutInfo *info){ return id == info->id; }); if (!shortcut) { qWarning() << "shortcut not found..." << id; diff --git a/src/plugin-keyboard/operation/keyboardcontroller.h b/src/plugin-keyboard/operation/keyboardcontroller.h index 446ddafa3b..113dfa1519 100644 --- a/src/plugin-keyboard/operation/keyboardcontroller.h +++ b/src/plugin-keyboard/operation/keyboardcontroller.h @@ -96,6 +96,7 @@ public Q_SLOTS: void addCustomShortcut(const QString &name, const QString &cmd, const QString &accels); void modifyCustomShortcut(const QString &id, const QString &name, const QString &cmd, const QString &accels); + Q_INVOKABLE void requestShortcutCommand(const QString &id); void modifyShortcut(const QString &id, const QString &accels, const int &type); void deleteCustomShortcut(const QString &id); void clearShortcut(const QString &id, const int &type); @@ -130,6 +131,7 @@ public Q_SLOTS: void waylandKeyCaptureFinished(const QString &id, int type, const QString &accels); void waylandKeyCaptureFailed(const QString &id, int type, int reason); + void shortcutCommandReady(const QString &id, const QString &command, bool available); void conflictTextChanged(); void keyboardEnabledChanged(); diff --git a/src/plugin-keyboard/operation/keyboarddbusproxy.cpp b/src/plugin-keyboard/operation/keyboarddbusproxy.cpp index a734240a3c..2264053a4c 100644 --- a/src/plugin-keyboard/operation/keyboarddbusproxy.cpp +++ b/src/plugin-keyboard/operation/keyboarddbusproxy.cpp @@ -293,7 +293,8 @@ void KeyboardDBusProxy::onListAllShortcutsNewFinished(QDBusPendingCallWatcher *w { QDBusPendingReply> reply = *w; if (!reply.isError()) { - QString json = convertShortcutListToJson(reply.value()); + const QList shortcuts = reply.value(); + QString json = convertShortcutListToJson(shortcuts); Q_EMIT AllShortcutsReady(json); } else { qWarning() << "Wayland ListAllShortcuts failed:" << reply.error(); @@ -354,7 +355,8 @@ void KeyboardDBusProxy::onGetShortcutNewFinished(QDBusPendingCallWatcher *w) { QDBusPendingReply reply = *w; if (!reply.isError()) { - QString json = convertShortcutToJson(reply.value()); + const ShortcutInfoNew info = reply.value(); + QString json = convertShortcutToJson(info); Q_EMIT shortcutQueried(json); } w->deleteLater(); @@ -462,27 +464,34 @@ QDBusPendingReply<> KeyboardDBusProxy::AddShortcutKeystroke(const QString &in0, return m_dBusKeybingdingInter->asyncCallWithArgumentList(QStringLiteral("AddShortcutKeystroke"), argumentList); } -QDBusPendingReply<> KeyboardDBusProxy::AddCustomShortcut(const QString &in0, const QString &in1, const QString &in2) +QDBusPendingReply KeyboardDBusProxy::AddCustomShortcut(const QString &in0, const QString &in1, const QString &in2) { QList argumentList; argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1) << QVariant::fromValue(in2); return m_dBusKeybingdingInter->asyncCallWithArgumentList(QStringLiteral("AddCustomShortcut"), argumentList); } -QDBusPendingReply<> KeyboardDBusProxy::ModifyCustomShortcut(const QString &in0, const QString &in1, const QString &in2, const QString &in3) +QDBusPendingReply KeyboardDBusProxy::ModifyCustomShortcut(const QString &in0, const QString &in1, const QString &in2, const QString &in3) { QList argumentList; argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1) << QVariant::fromValue(in2) << QVariant::fromValue(in3); return m_dBusKeybingdingInter->asyncCallWithArgumentList(QStringLiteral("ModifyCustomShortcut"), argumentList); } -QDBusPendingReply<> KeyboardDBusProxy::DeleteCustomShortcut(const QString &in0) +QDBusPendingReply KeyboardDBusProxy::DeleteCustomShortcut(const QString &in0) { QList argumentList; argumentList << QVariant::fromValue(in0); return m_dBusKeybingdingInter->asyncCallWithArgumentList(QStringLiteral("DeleteCustomShortcut"), argumentList); } +QDBusPendingReply KeyboardDBusProxy::GetShortcutCommand(const QString &in0) +{ + QList argumentList; + argumentList << QVariant::fromValue(in0); + return m_dBusKeybingdingInter->asyncCallWithArgumentList(QStringLiteral("GetShortcutCommand"), argumentList); +} + QDBusPendingReply<> KeyboardDBusProxy::GrabScreen() { QList argumentList; @@ -505,7 +514,8 @@ void KeyboardDBusProxy::onSearchShortcutsNewFinished(QDBusPendingCallWatcher *w) { QDBusPendingReply> reply = *w; if (!reply.isError()) { - QString json = convertShortcutListToJson(reply.value()); + const QList shortcuts = reply.value(); + QString json = convertShortcutListToJson(shortcuts); Q_EMIT searchShortcutsReady(json); } w->deleteLater(); diff --git a/src/plugin-keyboard/operation/keyboarddbusproxy.h b/src/plugin-keyboard/operation/keyboarddbusproxy.h index 49e70112c5..1cae53b774 100644 --- a/src/plugin-keyboard/operation/keyboarddbusproxy.h +++ b/src/plugin-keyboard/operation/keyboarddbusproxy.h @@ -248,9 +248,10 @@ public slots: QDBusPendingReply callModifyHotkeys(const QString &id, const QStringList &hotkeys); // Wayland: replace hotkey — remove newHotkey from conflictId, add to targetId. QDBusPendingReply callReplaceHotkey(const QString &targetId, const QString &newHotkey, const QString &conflictId); - QDBusPendingReply<> AddCustomShortcut(const QString &in0, const QString &in1, const QString &in2); - QDBusPendingReply<> ModifyCustomShortcut(const QString &in0, const QString &in1, const QString &in2, const QString &in3); - QDBusPendingReply<> DeleteCustomShortcut(const QString &in0); + QDBusPendingReply AddCustomShortcut(const QString &in0, const QString &in1, const QString &in2); + QDBusPendingReply ModifyCustomShortcut(const QString &in0, const QString &in1, const QString &in2, const QString &in3); + QDBusPendingReply DeleteCustomShortcut(const QString &in0); + QDBusPendingReply GetShortcutCommand(const QString &in0); QDBusPendingReply<> GrabScreen(); void SetNumLockState(int in0); QDBusPendingReply GetShortcut(const QString &in0, int in1); diff --git a/src/plugin-keyboard/operation/keyboardwork.cpp b/src/plugin-keyboard/operation/keyboardwork.cpp index cf93944185..480e0fb714 100644 --- a/src/plugin-keyboard/operation/keyboardwork.cpp +++ b/src/plugin-keyboard/operation/keyboardwork.cpp @@ -350,11 +350,56 @@ void KeyboardWorker::modifyShortcutEdit(ShortcutInfo *info) { void KeyboardWorker::addCustomShortcut(const QString &name, const QString &command, const QString &accels) { - m_keyboardDBusProxy->AddCustomShortcut(name, command, accels); + if (!m_keyboardDBusProxy->isWayland()) { + m_keyboardDBusProxy->AddCustomShortcut(name, command, accels); + return; + } + + QDBusPendingReply reply = m_keyboardDBusProxy->AddCustomShortcut(name, command, accels); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); + connect(watcher, &QDBusPendingCallWatcher::finished, + this, &KeyboardWorker::onAddCustomShortcutFinished); +} + +void KeyboardWorker::callModifyCustomShortcut(const QString &id, const QString &name, + const QString &command, const QString &accels, + int type) +{ + QDBusPendingReply reply = m_keyboardDBusProxy->ModifyCustomShortcut(id, name, command, accels); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); + watcher->setProperty("id", id); + watcher->setProperty("type", type); + connect(watcher, &QDBusPendingCallWatcher::finished, + this, &KeyboardWorker::onModifyCustomShortcutFinished); +} + +void KeyboardWorker::requestShortcutCommand(const QString &id) +{ + ShortcutInfo *shortcut = m_shortcutModel ? m_shortcutModel->findInfoIf([&id](ShortcutInfo *info) { + return info->id == id; + }) : nullptr; + const QString fallbackCommand = shortcut ? shortcut->command : QString(); + + if (id.isEmpty() || !m_keyboardDBusProxy->isWayland()) { + Q_EMIT shortcutCommandReady(id, fallbackCommand, !id.isEmpty()); + return; + } + + QDBusPendingReply reply = m_keyboardDBusProxy->GetShortcutCommand(id); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); + watcher->setProperty("id", id); + watcher->setProperty("fallbackCommand", fallbackCommand); + connect(watcher, &QDBusPendingCallWatcher::finished, + this, &KeyboardWorker::onGetShortcutCommandFinished); } void KeyboardWorker::modifyCustomShortcut(ShortcutInfo *info) { + if (m_keyboardDBusProxy->isWayland()) { + callModifyCustomShortcut(info->id, info->name, info->command, info->accels, info->type); + return; + } + if (info->replace) { onDisableShortcut(info->replace); } @@ -362,9 +407,6 @@ void KeyboardWorker::modifyCustomShortcut(ShortcutInfo *info) // reset replace shortcut info->replace = nullptr; - // Wayland custom-shortcut CRUD is stubbed at the controller layer - // (KeyboardController::modifyCustomShortcut early-returns) until - // dde-services implements ModifyCustomShortcut, so this body is X11-only. const QString &result = m_keyboardDBusProxy->LookupConflictingShortcut(info->accels); if (!result.isEmpty()) { @@ -408,9 +450,19 @@ QString KeyboardWorker::lookupConflictingShortcut(const QString &key) void KeyboardWorker::delShortcut(ShortcutInfo* info) { - m_keyboardDBusProxy->DeleteCustomShortcut(info->id); - if (m_shortcutModel) - m_shortcutModel->delInfo(info); + if (!m_keyboardDBusProxy->isWayland()) { + m_keyboardDBusProxy->DeleteCustomShortcut(info->id); + if (m_shortcutModel) + m_shortcutModel->delInfo(info); + return; + } + + QDBusPendingReply reply = m_keyboardDBusProxy->DeleteCustomShortcut(info->id); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); + watcher->setProperty("id", info->id); + watcher->setProperty("type", info->type); + connect(watcher, &QDBusPendingCallWatcher::finished, + this, &KeyboardWorker::onDeleteCustomShortcutFinished); } void KeyboardWorker::setRepeatDelay(uint value) @@ -931,6 +983,11 @@ void KeyboardWorker::cleanShortcutSlef(const QString &id, const int type, const void KeyboardWorker::setNewCustomShortcut(const QString &id, const QString &name, const QString &command, const QString &accles) { + if (m_keyboardDBusProxy->isWayland()) { + callModifyCustomShortcut(id, name, command, accles, ShortcutModel::Custom); + return; + } + m_keyboardDBusProxy->ModifyCustomShortcut(id, name, command, accles); } @@ -1092,6 +1149,67 @@ void KeyboardWorker::onCustomConflictCleanFinished(QDBusPendingCallWatcher *w) w->deleteLater(); } +void KeyboardWorker::onAddCustomShortcutFinished(QDBusPendingCallWatcher *watch) +{ + QDBusPendingReply reply = *watch; + if (reply.isError() || reply.value().isEmpty()) { + qWarning() << "AddCustomShortcut failed:" + << (reply.isError() ? reply.error().message() : QStringLiteral("server returned empty id")); + refreshShortcut(); + } else { + onAdded(reply.value(), ShortcutModel::Custom); + } + + watch->deleteLater(); +} + +void KeyboardWorker::onModifyCustomShortcutFinished(QDBusPendingCallWatcher *watch) +{ + QDBusPendingReply reply = *watch; + const QString id = watch->property("id").toString(); + const int type = watch->property("type").toInt(); + const bool success = (!reply.isError() && reply.value()); + if (!success) { + qWarning() << "ModifyCustomShortcut failed for" << id + << (reply.isError() ? reply.error().message() : QStringLiteral("server returned false")); + refreshShortcut(); + } else if (!id.isEmpty()) { + onShortcutChanged(id, type); + } + + watch->deleteLater(); +} + +void KeyboardWorker::onDeleteCustomShortcutFinished(QDBusPendingCallWatcher *watch) +{ + QDBusPendingReply reply = *watch; + const QString id = watch->property("id").toString(); + const bool success = (!reply.isError() && reply.value()); + if (!success) { + qWarning() << "DeleteCustomShortcut failed for" << id + << (reply.isError() ? reply.error().message() : QStringLiteral("server returned false")); + } + refreshShortcut(); + + watch->deleteLater(); +} + +void KeyboardWorker::onGetShortcutCommandFinished(QDBusPendingCallWatcher *watch) +{ + QDBusPendingReply reply = *watch; + const QString id = watch->property("id").toString(); + QString command = watch->property("fallbackCommand").toString(); + + if (reply.isError()) { + qWarning() << "GetShortcutCommand failed for" << id << reply.error().message(); + } else { + command = reply.value(); + } + + Q_EMIT shortcutCommandReady(id, command, !reply.isError() || !command.isEmpty()); + watch->deleteLater(); +} + QString KeyboardWorker::makeShortcutKey(const QString &id, int type) { return id + "_" + QString::number(type); diff --git a/src/plugin-keyboard/operation/keyboardwork.h b/src/plugin-keyboard/operation/keyboardwork.h index f585abfe22..670800b918 100644 --- a/src/plugin-keyboard/operation/keyboardwork.h +++ b/src/plugin-keyboard/operation/keyboardwork.h @@ -49,6 +49,14 @@ class KeyboardWorker : public QObject void modifyShortcutEdit(ShortcutInfo* info); void addCustomShortcut(const QString& name, const QString& command, const QString& accels); void modifyCustomShortcut(ShortcutInfo *info); + void requestShortcutCommand(const QString &id); + // Fire ModifyCustomShortcut on the Wayland service and wire the reply to + // onModifyCustomShortcutFinished. Shared by modifyCustomShortcut (Wayland + // branch) and setNewCustomShortcut so the watcher/id/type setup stays in + // one place. + void callModifyCustomShortcut(const QString &id, const QString &name, + const QString &command, const QString &accels, + int type); void grabScreen(); bool checkAvaliable(const QString& key); @@ -85,6 +93,7 @@ class KeyboardWorker : public QObject void onLettersChanged(QList letters); // 快捷键恢复默认完成 void onResetFinished(); + void shortcutCommandReady(const QString &id, const QString &command, bool available); public Q_SLOTS: void setLang(const QString &value); @@ -122,6 +131,10 @@ public Q_SLOTS: void onLookupConflictForShortcutFinished(QDBusPendingCallWatcher *watch); void onShortcutCleanFinished(QDBusPendingCallWatcher *watch); void onCustomConflictCleanFinished(QDBusPendingCallWatcher *w); + void onAddCustomShortcutFinished(QDBusPendingCallWatcher *watch); + void onModifyCustomShortcutFinished(QDBusPendingCallWatcher *watch); + void onDeleteCustomShortcutFinished(QDBusPendingCallWatcher *watch); + void onGetShortcutCommandFinished(QDBusPendingCallWatcher *watch); private: static QString makeShortcutKey(const QString &id, int type); diff --git a/src/plugin-keyboard/operation/shortcutmodel.cpp b/src/plugin-keyboard/operation/shortcutmodel.cpp index e5e5a4d583..a96d684f2d 100644 --- a/src/plugin-keyboard/operation/shortcutmodel.cpp +++ b/src/plugin-keyboard/operation/shortcutmodel.cpp @@ -95,6 +95,28 @@ static QString toPinyin(const QString &name) return pinyin(name, TS_NoneTone).join(FieldSeparator) + FieldSeparator + firstLetters(name).join(FieldSeparator); } +static void fillShortcutInfoFromJson(dccV25::ShortcutInfo *info, const QJsonObject &obj) +{ + if (!info) + return; + + info->type = obj["Type"].toInt(); + const QJsonArray accels = obj["Accels"].toArray(); + info->accels = accels.isEmpty() ? QString() : accels.first().toString(); + info->name = obj["Name"].toString(); + info->pinyin = toPinyin(info->name); + info->id = obj["Id"].toString(); + info->command = obj["Exec"].toString(); + + const QString sectionKey = obj["Section"].toString(); + if (!sectionKey.isEmpty()) { + info->sectionKey = sectionKey; + info->sectionName = obj["SectionName"].toString(); + if (info->sectionName.isEmpty()) + info->sectionName = sectionKey; + } +} + using namespace dccV25; DCORE_USE_NAMESPACE ShortcutModel::ShortcutModel(QObject *parent) @@ -455,25 +477,71 @@ void ShortcutModel::onKeyBindingChanged(const QString &value) const QJsonObject &obj = QJsonDocument::fromJson(value.toStdString().c_str()).object(); const QString &update_id = obj["Id"].toString(); const int &update_type = obj["Type"].toInt(); + const bool hasSectionField = obj.contains("Section"); + const bool useDynamicGrouping = hasSectionField || !m_groupInfos.isEmpty() || !m_categoryMeta.isEmpty(); + if (update_id.isEmpty()) + return; + auto res = std::find_if(m_infos.begin(), m_infos.end(), [ = ] (const ShortcutInfo *info)->bool{ return info->id == update_id && info->type == update_type; }); if (res != m_infos.end()) { - (*res)->type = obj["Type"].toInt(); - (*res)->accels = obj["Accels"].toArray().first().toString(); - (*res)->name = obj["Name"].toString(); - (*res)->command = obj["Exec"].toString(); + const QString oldSectionKey = (*res)->sectionKey; + fillShortcutInfoFromJson(*res, obj); + const bool sectionChanged = oldSectionKey != (*res)->sectionKey; + if (useDynamicGrouping) { + if (!oldSectionKey.isEmpty() && oldSectionKey != (*res)->sectionKey) + m_groupInfos[oldSectionKey].removeOne(*res); + if (!(*res)->sectionKey.isEmpty() && !m_groupInfos[(*res)->sectionKey].contains(*res)) + m_groupInfos[(*res)->sectionKey].append(*res); + } + + bool searchUpdated = false; + for (ShortcutInfo *searchInfo : m_searchList) { + if (searchInfo && searchInfo->id == update_id && searchInfo->type == update_type) { + fillShortcutInfoFromJson(searchInfo, obj); + searchUpdated = true; + } + } Q_EMIT shortcutChanged((*res)); + if (searchUpdated) + Q_EMIT searchFinished(m_searchList); + if (!m_groupInfos.isEmpty() && sectionChanged) + Q_EMIT categoryMetaChanged(); + return; + } + + ShortcutInfo *info = new ShortcutInfo(); + fillShortcutInfoFromJson(info, obj); + + if (!info->sectionKey.isEmpty()) { + m_infos.append(info); + m_groupInfos[info->sectionKey].append(info); + if (info->type == Custom) + m_customInfos.append(info); + invalidateSystemShortcutNamesCache(); + Q_EMIT addCustomInfo(info); + Q_EMIT categoryMetaChanged(); + return; + } + + if (info->type != Custom) { + delete info; + return; } - // NOTE: update-in-place only — no insert branch. A change signal for an id - // not yet in m_infos is dropped. On X11 new shortcuts arrive via Added → - // onCustomInfo (the insert path); on Wayland that path is unused (custom - // CRUD is stubbed) and a brand-new id would only appear through the next - // full ListAllShortcuts refresh. Tolerated because no realistic Wayland flow - // surfaces an unknown id via ShortcutChanged alone; revisit if dde-services - // grows dynamic shortcut registration. + + info->sectionName = tr("Custom"); + const QString customKey = useDynamicGrouping ? customCategoryKey() : QString(); + info->sectionKey = customKey.isEmpty() ? info->sectionName : customKey; + m_infos.append(info); + if (!customKey.isEmpty()) + m_groupInfos[info->sectionKey].append(info); + m_customInfos.append(info); + Q_EMIT addCustomInfo(info); + if (!customKey.isEmpty()) + Q_EMIT categoryMetaChanged(); } void ShortcutModel::onWindowSwitchChanged(bool value) @@ -578,6 +646,17 @@ void ShortcutModel::setCategoryMeta(const QList &meta) if (m.isCustom) m_customCategoryKey = m.key; } + if (!m_customCategoryKey.isEmpty()) { + auto &customGroup = m_groupInfos[m_customCategoryKey]; + for (ShortcutInfo *info : std::as_const(m_customInfos)) { + if (!info || customGroup.contains(info)) + continue; + info->sectionKey = m_customCategoryKey; + if (info->sectionName.isEmpty()) + info->sectionName = m_categoryMeta.value(m_customCategoryKey).displayName; + customGroup.append(info); + } + } invalidateSystemShortcutNamesCache(); Q_EMIT categoryMetaChanged(); } @@ -682,6 +761,13 @@ void ShortcutModel::setSearchResult(const QString &searchResult) QJsonArray array = QJsonDocument::fromJson(searchResult.toStdString().c_str()).array(); for (auto value : array) { QJsonObject obj = value.toObject(); + if (!obj["Section"].toString().isEmpty()) { + ShortcutInfo *info = new ShortcutInfo(); + fillShortcutInfoFromJson(info, obj); + m_searchList << info; + continue; + } + int type = obj["Type"].toInt(); ShortcutInfo *info = new ShortcutInfo(); info->type = type; @@ -847,7 +933,15 @@ void ShortcutListModel::onUpdateShortcut(ShortcutInfo *info) if (row >= 0) { QModelIndex modelIndex = index(row); - Q_EMIT dataChanged(modelIndex, modelIndex, {Qt::DisplayRole, KeySequenceRole, AccelsRole}); + Q_EMIT dataChanged(modelIndex, modelIndex, { + Qt::DisplayRole, + SearchedTextRole, + KeySequenceRole, + CommandRole, + AccelsRole, + SectionNameRole, + SectionKeyRole + }); } } diff --git a/src/plugin-keyboard/qml/ShortcutSettingDialog.qml b/src/plugin-keyboard/qml/ShortcutSettingDialog.qml index b4fc857de2..69ae007476 100644 --- a/src/plugin-keyboard/qml/ShortcutSettingDialog.qml +++ b/src/plugin-keyboard/qml/ShortcutSettingDialog.qml @@ -167,7 +167,10 @@ D.DialogWindow { Layout.leftMargin: 4 text: qsTr("Cancel") onClicked: { - if (ddialog.keyId.length > 0) { + if (ddialog.keyId.length > 0 + && (nameEdit.text !== ddialog.saveKeyName + || commandEdit.text !== ddialog.saveCmdName + || edit.accels !== ddialog.saveAccels)) { dccData.modifyCustomShortcut(ddialog.keyId, ddialog.saveKeyName, ddialog.saveCmdName, ddialog.saveAccels); } ddialog.close(); diff --git a/src/plugin-keyboard/qml/Shortcuts.qml b/src/plugin-keyboard/qml/Shortcuts.qml index 3aa1ecc567..a81162cd30 100644 --- a/src/plugin-keyboard/qml/Shortcuts.qml +++ b/src/plugin-keyboard/qml/Shortcuts.qml @@ -83,6 +83,7 @@ DccObject { id: shortcutView property Item editItem property Item conflictText + property string pendingCommandId clip: true interactive: false // 外层有滚动了,listview 就别滚了 implicitHeight: contentHeight @@ -127,6 +128,7 @@ DccObject { } onCheckedChanged: { shortcutSettingsBody.isEditing = button.checked + shortcutView.pendingCommandId = "" if (!shortcutView.editItem) return @@ -158,6 +160,7 @@ DccObject { contentItem: ColumnLayout { KeySequenceDisplay { id: edit + property string dialogCommand: model.command text: model.display keys: model.keySequence placeholderText: qsTr("please enter a new shortcut key") @@ -197,10 +200,15 @@ DccObject { dccData.beginWaylandKeyCapture(edit, model.id, model.type) } onRequestEditKeys: { - dialogloader.active = true + if (dialogloader.active) + return + + shortcutView.pendingCommandId = model.id + dccData.requestShortcutCommand(model.id) } onRequestDeleteKeys: { console.log("onRequestDeleteKeys", model.id) + shortcutView.pendingCommandId = "" dccData.deleteCustomShortcut(model.id) } @@ -239,6 +247,7 @@ DccObject { onClosing: { dccData.endWaylandKeyCapture() dialogloader.active = false + shortcutView.pendingCommandId = "" conflictText.visible = false shortcutSettingsBody.conflictAccels = "" @@ -251,7 +260,7 @@ DccObject { item.keyId = model.id item.keyName = model.display - item.cmdName = model.command + item.cmdName = edit.dialogCommand item.keySequence = model.keySequence if (model.keySequence.length > 0) { item.saveKeys = model.keySequence @@ -264,6 +273,20 @@ DccObject { item.show() } } + Connections { + target: dccData + function onShortcutCommandReady(id, command, available) { + if (shortcutView.pendingCommandId !== id || model.id !== id) + return + + shortcutView.pendingCommandId = "" + if (!available) + return + + edit.dialogCommand = command + dialogloader.active = true + } + } } Item { @@ -343,6 +366,8 @@ DccObject { } function restoreShortcutView() { + shortcutView.pendingCommandId = "" + if (!shortcutView.editItem) return