Skip to content

feat(shortcut): support unassigned hotkeys#91

Open
yixinshark wants to merge 1 commit into
linuxdeepin:masterfrom
yixinshark:feat/shortcut-unassigned-hotkeys
Open

feat(shortcut): support unassigned hotkeys#91
yixinshark wants to merge 1 commit into
linuxdeepin:masterfrom
yixinshark:feat/shortcut-unassigned-hotkeys

Conversation

@yixinshark

Copy link
Copy Markdown
Contributor

Summary

  • Allow a shortcut to be left without any hotkey: it stays visible in the list (shown as "None") without being registered with the compositor, so ReplaceHotkey can intentionally unassign a binding and Reset can restore the default later.
  • Reset: unregister reset targets up front and only mutate local state after the compositor confirms the commit; on commit failure leave the map and dconfig untouched so state stays consistent (matching the rollback contract of ModifyHotkeys/Disable).
  • Reset: drop reset targets from the map so the async valueChanged restore takes the new-entry path and always emits ShortcutChanged, even when the restored default is unassigned.
  • Add KeyConfig operator==/!= and skip onKeyConfigChanged work (and the spurious ShortcutChanged) when the incoming config is unchanged.

Test plan

  • Assign a custom hotkey, then Reset: the shortcut returns to its default (or to unassigned when the default is empty) and the control center reflects the change.
  • Reset a set where defaults would swap/collide: no async registration conflict; each restores correctly.
  • Confirm an unchanged DConfig write no longer emits a redundant ShortcutChanged.

Pms: BUG-365989

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @yixinshark, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: yixinshark

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Allow a shortcut to be left without any hotkey: it stays visible in the
list (shown as "None") without being registered with the compositor, so
ReplaceHotkey can intentionally unassign a binding and Reset can restore
the default later.

- Keep empty-hotkey configs valid and visible without registration
- Reset: collect resettable ids, unregister them up front and only mutate
  local state after the compositor confirms the commit; on commit failure
  leave the map and dconfig untouched so state stays consistent
- Reset: drop reset targets from the map so the async valueChanged restore
  takes the new-entry path and always emits ShortcutChanged, even when the
  restored default is unassigned
- Add KeyConfig operator==/!= and skip onKeyConfigChanged work (and the
  spurious ShortcutChanged) when the incoming config is unchanged

支持快捷键不分配任何热键:该项仍显示在列表中(显示为 "None"),
但不向合成器注册,从而 ReplaceHotkey 可以主动取消绑定,Reset 之后
可恢复默认值。

- 空热键配置保持有效并可见,但不注册
- Reset:先收集可重置项并提前注销,仅在合成器确认提交后才修改本地
  状态;提交失败时不动 map 与 dconfig,保持状态一致
- Reset:从 map 中移除重置目标,使异步 valueChanged 恢复走新增分支,
  即使恢复后的默认值为未分配也能正确发出 ShortcutChanged
- 新增 KeyConfig operator==/!=,当传入配置无变化时跳过
  onKeyConfigChanged 处理并避免冗余的 ShortcutChanged 信号

Log: support unassigned hotkeys
Pms: BUG-365989
Change-Id: I655ae653366dfd6b554002c55e2444a3ee731fa3
@yixinshark yixinshark force-pushed the feat/shortcut-unassigned-hotkeys branch from a814bce to 6ed6f9d Compare June 25, 2026 07:03
@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

★ 总体评分:95分

■ 【总体评价】

代码重构了快捷键重置与冲突处理逻辑,解决了空快捷键状态下的UI丢失与重置冲突问题
逻辑严密、注释充分且无任何安全漏洞,符合优秀标准

■ 【详细分析】

  • 1.语法逻辑(完全正确)✓

重构后的 KeybindingManager::Reset() 采用“先收集注销->同步提交->清空本地缓存->触发DConfig重置”的严格顺序,彻底杜绝了异步重置过程中旧绑定未释放引发的快捷键冲突。KeyConfig::isValid() 放宽校验与 registerShortcut() 中对空 hotkeys 的提前返回逻辑完美配合,保证了空快捷键可见但不绑定的状态一致性。onKeyConfigChanged() 中引入的 operator== 判断有效避免了无状态变更时的冗余信号发射
建议:无

  • 2.代码质量(良好)✓

ConfigLoader::resetConfig() 拆分为 resettableHotkeyIds()resetHotkeys() 两个职责单一的函数,提升了可读性和可测试性。使用匿名命名空间管理 kDefaultShortcutAppId 等常量,符合 C++ 最佳实践。新增的 containsEmptyHotkey 采用 std::any_of 算法,代码简洁现代。注释详尽,准确解释了“为何需要先 commitSync 再重置 DConfig”等关键设计决策
建议:无

  • 3.代码性能(高效)✓

containsEmptyHotkey 使用短路求值的 std::any_of,在遇到首个空串时立即返回,避免了不必要的全量遍历。Reset() 中虽然对目标列表进行了两次遍历(注销与清理),但由于中间存在 commitSync 的 IPC 阻塞调用,两次 O(N) 遍历的开销完全可忽略。operator== 逐字段比较对于轻量级结构体 KeyConfig 而言是最优解
建议:无

  • 4.代码安全(存在0个安全漏洞)✓

漏洞对比统计:新增漏洞 0 个,减少漏洞 0 个,持平 0 个
代码未引入任何安全风险。ModifyHotkeysReplaceHotkey 入口处均增加了严格的空值拦截,防止非法空快捷键注入。resetHotkeys 通过 m_configs.value(id) 获取指针并做空指针保护,杜绝了悬空指针解引用。常量字符串统一使用 QString::fromLatin1 处理,避免了潜在的编码注入风险
建议:无

■ 【改进建议代码示例】

// 当前代码已非常完善,无需强制修改。以下仅展示一种可选的微优化:
// 在 Reset() 中合并遍历逻辑(仅为演示风格,当前分离逻辑因 commitSync 阻塞更清晰)
void KeybindingManager::Reset()
{
    const QStringList resetIds = m_loader->resettableHotkeyIds();
    if (resetIds.isEmpty()) {
        return;
    }

    QStringList toRestore;
    for (const QString &id : resetIds) {
        if (!m_keyConfigsMap.contains(id)) {
            continue;
        }
        m_keyHandler->unregisterKey(id);
        m_specialKeyHandler->unregisterKey(id);
        toRestore.append(id);
    }

    if (!m_keyHandler->commitSync()) {
        qWarning() << "Reset: failed to commit unregistering existing hotkeys";
        return;
    }

    for (const QString &id : toRestore) {
        m_keyConfigsMap.remove(id);
    }

    m_loader->resetHotkeys(resetIds);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants