Skip to content

feat: add shortcut manager plugin#55

Merged
deepin-bot[bot] merged 1 commit into
linuxdeepin:masterfrom
yixinshark:feat-shortcut
Jun 1, 2026
Merged

feat: add shortcut manager plugin#55
deepin-bot[bot] merged 1 commit into
linuxdeepin:masterfrom
yixinshark:feat-shortcut

Conversation

@yixinshark
Copy link
Copy Markdown
Contributor

-Keyboard shortcut management in X11;
-Keyboard shortcut and gesture management in Treeland -develop-guide document

Log: add shortcut manager plugin

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Sorry @yixinshark, your pull request is larger than the review limit of 150000 diff characters

@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

1 similar comment
@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

@yixinshark
Copy link
Copy Markdown
Contributor Author

TODO:
1.进一步测试triggers触发重新加载快捷键配置
2.treeland的联调,已初步测试。关注协议的变化。

Comment thread debian/control Outdated
Comment thread src/plugin-qt/shortcut/src/backend/wayland/treelandshortcutwrapper.cpp Outdated
Comment thread src/plugin-qt/shortcut/src/backend/wayland/treelandshortcutwrapper.cpp Outdated
Comment thread src/plugin-qt/shortcut/src/config/configloader.cpp Outdated
Comment thread src/plugin-qt/shortcut/src/config/configloader.h
Comment thread src/plugin-qt/shortcut/src/core/gesturemanager.cpp Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a new shortcut manager plugin for Deepin, including a core daemon/service with X11 and Wayland backends, a helper CLI (dde-shortcut-tool), DConfig-based shortcut/gesture definitions, translations, and Debian packaging hooks to reload shortcuts when configs change.

Changes:

  • Add a full-featured dde-shortcut Qt plugin and optional standalone debug binary that manage global keyboard shortcuts and gestures across X11 and Treeland/Wayland, with X11/Wayland-specific handlers and DBus APIs (org.deepin.dde.Keybinding1 / org.deepin.dde.Gesture1).
  • Introduce dde-shortcut-tool CLI with multiple controllers (audio, display, power, touchpad, network, keyboard backlight, lock keys, app launcher) to execute system actions used by the shortcut configs.
  • Define a large set of DConfig-based shortcut/gesture metadata under org.deepin.dde.keybinding, translation infrastructure (TS files, i18n extraction tool and CMake helpers), and Debian integration (extra build/runtime deps, triggers, and postinst logic to call ReloadConfigs on running sessions).

Notable Issue

  • Bug – ConfigLoader cannot persist updated values to DConfig
    In src/plugin-qt/shortcut/src/config/configloader.cpp, loadConfig() calls DConfig::create(APP_ID, CONFIG_NAME, "/" + subPath, ...) and later sets keyConfig.subPath = config->subpath();, so keyConfig.getId() is based on config->subpath() (which includes the leading /).
    However, m_configs is keyed by the unprefixed subPath (m_configs.insert(subPath, config); around lines 140–221), while updateValue() checks if (m_configs.contains(id)) and uses m_configs[id] (lines ~85–92), where id is passed from KeybindingManager as config.getId() (the prefixed form).
    This mismatch means updateValue() will never find the entry and thus will not call setValue, so DBus methods like ModifyHotkeys and Disable update the in-memory maps and grabs but will not persist changes back into DConfig. A concrete fix would be to key m_configs by the same string used for getId() (e.g. config->subpath()) or to translate from id back to subPath via m_subPathToId before indexing m_configs.

Reviewed changes

Copilot reviewed 176 out of 176 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/plugin-qt/CMakeLists.txt Adds the shortcut plugin subdirectory to the Qt plugin build, wiring the new module into the overall project.
src/plugin-qt/shortcut/CMakeLists.txt Defines build of the plugin-dde-shortcut library and optional dde-shortcut-debug binary, sets up Wayland protocol codegen, installs configs, i18n tooling, and integrates translation generation.
src/plugin-qt/shortcut/src/main.cpp Standalone debug entry point that initializes ShortcutManager in a QGuiApplication, supports --list to dump configs.
src/plugin-qt/shortcut/src/core/shortcutmanager.h/.cpp Coordinates config loading, backend selection (X11 vs Wayland), and creation of KeybindingManager/GestureManager; handles Wayland protocol lifecycle and registration.
src/plugin-qt/shortcut/src/core/keybindingmanager.h/.cpp Implements DBus interface org.deepin.dde.Keybinding1, manages key shortcut registration, conflict checking, lock-key properties, and delegates execution to ActionExecutor; affected by the ConfigLoader::updateValue bug described above.
src/plugin-qt/shortcut/src/core/gesturemanager.h/.cpp Implements DBus interface org.deepin.dde.Gesture1, manages gesture registration, config updates, and activation signals for Wayland sessions.
src/plugin-qt/shortcut/src/core/shortcutconfig.h Defines shared configuration structs/enums for shortcuts and gestures (trigger types, categories, key event flags, gesture types/directions).
src/plugin-qt/shortcut/src/core/qkeysequenceconverter.h/.cpp Provides conversions between Qt key sequence names, XKB-style strings, and Qt key combinations; used by X11 backend and Wayland binding names.
src/plugin-qt/shortcut/src/core/actionexecutor.h/.cpp Executes configured actions based on TriggerType (command/app/action), invoking /usr/bin/dde-am or launching app IDs.
src/plugin-qt/shortcut/src/core/translationmanager.h/.cpp Manages per-app-id QTranslator instances loaded from /usr/share/deepin/org.deepin.dde.keybinding/translations, and provides translation lookup used in DBus structs.
src/plugin-qt/shortcut/src/config/configloader.h/.cpp Loads DConfig-based shortcut and gesture definitions from .ini + org.deepin.shortcut.json files, exposes lists and change signals, and attempts to update DConfig on changes; contains the id/subPath key mismatch bug for updateValue().
src/plugin-qt/shortcut/src/backend/abstractkeyhandler.h Abstract interface for key backends (register/unregister, commit, lock-key operations, and activation signal).
src/plugin-qt/shortcut/src/backend/abstractgesturehandler.h Abstract interface for gesture backends (register/unregister, commit, and activation signal).
src/plugin-qt/shortcut/src/backend/specialkeyhandler.h/.cpp Handles “special” keys that come via org.deepin.dde.KeyEvent1 (libinput), mapping numeric keycodes to shortcut IDs with support for press/release/repeat semantics.
src/plugin-qt/shortcut/src/backend/x11/x11keyhandler.h/.cpp Implements AbstractKeyHandler for X11 using XCB/XTest, including key grabbing, repeat detection, standalone modifier handling, and Caps/Num Lock state get/set.
src/plugin-qt/shortcut/src/backend/x11/modifierkeymonitor.h/.cpp Polling-based helper that tracks standalone modifier presses/releases and emits modifierKeyReleased for use by X11KeyHandler.
src/plugin-qt/shortcut/src/backend/x11/x11helper.cpp Wraps XStringToKeysym in a C-accessible function used by the X11 backend.
src/plugin-qt/shortcut/src/backend/wayland/treelandshortcutwrapper.h/.cpp Wraps the Treeland shortcut manager Wayland protocol (treeland_shortcut_manager_v2), handling bind/unbind, commit semantics, and activation callbacks.
src/plugin-qt/shortcut/src/backend/wayland/waylandkeyhandler.h/.cpp Implements AbstractKeyHandler on Wayland via TreelandShortcutWrapper and KDE keystate protocol, managing bindings and Caps/Num Lock state where compositor support is available.
src/plugin-qt/shortcut/src/backend/wayland/waylandgesturehandler.h/.cpp Implements AbstractGestureHandler on Wayland, binding swipe/hold gestures via Treeland, tracking active bindings, and forwarding activations.
src/plugin-qt/shortcut/src/3rdparty/kde-keystate.xml Bundles the KDE keystate Wayland protocol description used to generate client stubs.
src/plugin-qt/shortcut/pluginshortcutmanager.h/.cpp Adapter that owns a ShortcutManager in plugin mode and uses a provided QDBusConnection to register/unregister Keybinding and Gesture DBus objects and org.deepin.dde.Keybinding1 service.
src/plugin-qt/shortcut/plugin.cpp Defines DSM plugin entry points DSMRegister / DSMUnRegister, creating and cleaning up PluginShortcutManager.
src/plugin-qt/shortcut/plugin-dde-shortcut.json Deepin service-manager plugin metadata for the shortcut plugin (name, library path, exposed DBus paths, residency policy).
src/plugin-qt/shortcut/tools/extract_shortcuts_i18n.py Helper script that scans org.deepin.shortcut.json configs for modifiable shortcuts and generates a C++ file with QT_TRANSLATE_NOOP entries for lupdate.
src/plugin-qt/shortcut/tools/CMakeLists.txt Adds the dde-shortcut-tool subdirectory to the tools build.
src/plugin-qt/shortcut/tools/dde-shortcut-tool/CMakeLists.txt Builds the dde-shortcut-tool CLI, links Qt6, Dtk6, XCB, and installs the binary.
src/plugin-qt/shortcut/tools/dde-shortcut-tool/main.cpp Entry point for dde-shortcut-tool, setting up CommandParser and registering all controllers.
src/plugin-qt/shortcut/tools/dde-shortcut-tool/commandparser.h/.cpp CLI parser that dispatches subcommands like audio, display, network, etc., to their respective controllers and prints usage/help.
src/plugin-qt/shortcut/tools/dde-shortcut-tool/basecontroller.h Abstract base class for individual CLI controllers (name, supported actions, execute, help).
src/plugin-qt/shortcut/tools/dde-shortcut-tool/audiocontroller.h/.cpp Controls system audio via DBus (mute/unmute, volume up/down) and optional OSD signalling.
src/plugin-qt/shortcut/tools/dde-shortcut-tool/displaycontroller.h/.cpp Controls display brightness and mode via Deepin display DBus APIs and DConfig, and can turn off the screen.
src/plugin-qt/shortcut/tools/dde-shortcut-tool/powercontroller.h/.cpp Exposes power-related actions (shutdown/suspend/hibernate/turn-off-screen/away/etc.) via DBus integrations and DConfig.
src/plugin-qt/shortcut/tools/dde-shortcut-tool/touchpadcontroller.h/.cpp Toggles and controls touchpad enabled state via DBus, with OSD signalling.
src/plugin-qt/shortcut/tools/dde-shortcut-tool/networkcontroller.h/.cpp Toggles WiFi and airplane mode via org.deepin.dde.AirplaneMode1 on the system bus.
src/plugin-qt/shortcut/tools/dde-shortcut-tool/mediaplayercontroller.h/.cpp Controls media players (play/pause/next/prev/seek/rewind/forward) via MPRIS DBus interfaces.
src/plugin-qt/shortcut/tools/dde-shortcut-tool/kbdlightcontroller.h/.cpp Manages keyboard backlight toggling and brightness via DBus and backlight interfaces.
src/plugin-qt/shortcut/tools/dde-shortcut-tool/lockkeycontroller.h/.cpp Shows OSD for CapsLock/NumLock state changes and queries/sets lock states across X11 and Wayland sessions.
src/plugin-qt/shortcut/tools/dde-shortcut-tool/launchcontroller.h/.cpp Launches default applications for given MIME types or URL scheme handlers using xdg-mime and dde-am.
src/plugin-qt/shortcut/tools/dde-shortcut-tool/networkcontroller.h/.cpp See above; used by WLAN shortcut config to toggle WiFi.
src/plugin-qt/shortcut/tools/dde-shortcut-tool/constant.h Defines enums for audio/media/display/touchpad actions and DConfig key constants used across controllers.
src/plugin-qt/shortcut/tools/dde-shortcut-tool/test_shortcut_tool.sh Shell script to exercise and validate dde-shortcut-tool actions, serving as an integration test harness.
src/plugin-qt/shortcut/translations/org.deepin.dde.keybinding*.ts New TS stubs (per-locale) containing Display switch and terminal sources, marked as unfinished translations for future localization.
src/plugin-qt/shortcut/configs/org.deepin.dde.keybinding.ini Registers all shortcut and gesture DConfig subpaths so ConfigLoader can discover them at runtime.
src/plugin-qt/shortcut/configs/org.deepin.dde.keybinding.shortcut.*/org.deepin.shortcut.json Define a comprehensive set of system keyboard shortcuts (volume, brightness, media, power, WLAN, touchpad, lock keys, default terminal, apps, etc.) with metadata (appId, displayName, hotkeys, triggerType/value, category, enabled, modifiable).
src/plugin-qt/shortcut/configs/org.deepin.dde.keybinding.gesture.*/org.deepin.shortcut.json Define touchpad gesture shortcuts (3/4-finger swipes and taps) for Wayland, mapping to compositor action IDs used in Treeland protocol.
src/plugin-qt/shortcut/src/3rdparty/kde-keystate.xml (Already noted above) Wayland protocol spec for key states, used by KeyStateManager.
debian/control Extends build-deps (Qt Wayland, tools, XCB keysyms/xtest, Wayland, treeland-protocols, Python) and runtime deps (Qt6, Dtk6, Wayland/XCB libs) to support the new plugin and tools; updates package description to mention the shortcut manager.
debian/dde-services.triggers Adds a trigger on /usr/share/deepin/org.deepin.dde.keybinding so DConfig metadata changes will cause postinst to run with triggered.
debian/dde-services.postinst On trigger, iterates active user DBus session buses and calls org.deepin.dde.Keybinding1.ReloadConfigs for each, so running sessions pick up updated shortcut configs without restart.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@deepin-bot
Copy link
Copy Markdown

deepin-bot Bot commented Jan 29, 2026

TAG Bot

New tag: 1.0.20
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #56

@deepin-bot
Copy link
Copy Markdown

deepin-bot Bot commented Feb 27, 2026

TAG Bot

New tag: 1.0.21
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #58

@deepin-bot
Copy link
Copy Markdown

deepin-bot Bot commented Apr 24, 2026

TAG Bot

New tag: 1.0.22
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #62

@deepin-bot
Copy link
Copy Markdown

deepin-bot Bot commented Apr 24, 2026

TAG Bot

New tag: 1.0.23
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #64

@deepin-bot
Copy link
Copy Markdown

deepin-bot Bot commented May 8, 2026

TAG Bot

New tag: 1.0.24
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #66

@deepin-bot
Copy link
Copy Markdown

deepin-bot Bot commented May 15, 2026

TAG Bot

New tag: 1.0.25
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #68

- Add dde-app-shortcuts config module for built-in app shortcuts and translations.
- Route logout shortcut through dde-shortcut-tool power show-ui.
- Lazily create dde-shortcut-tool controllers and expose static command metadata.
- Keep power shortcut actions stateless and initialize dependencies per action.
- Skip Display1 initialization on Wayland to avoid shortcut command DBus timeout.
- Print Treeland bind error names on commit failure.

Log: add shortcut manager plugin
Pms: TASK-390447
Change-Id: I4c8ad94a31d4703d78bafb756e5c6b81c36375fd
@deepin-ci-robot
Copy link
Copy Markdown

deepin pr auto review

这是一个非常庞大且功能完整的代码变更,为 Deepin Desktop Environment 添加了全新的快捷键服务插件。代码整体架构清晰,模块划分合理,文档极其详尽。但在仔细审查后,我发现了一些在语法逻辑、代码质量、性能和安全性方面值得改进的问题。

以下是详细的审查意见:

一、 语法与逻辑问题

  1. INI 文件解析逻辑存在潜在 Bug

    • 文件: src/plugin-qt/shortcut/src/config/configloader.cpp (第 107-118 行)
    • 问题: QSettings 在解析 INI 文件时,如果值中包含分号 ;,可能会被误认为是注释符而导致解析截断。此外,代码中同时兼容了 SubPathsSubPath,但文档中只提到了 SubPaths,这种隐式兼容容易造成混乱。
    • 建议: 明确废弃 SubPath 并打印 deprecation 警告;确保 INI 文件中的分号不会被误解析,必要时在写入端进行转义,或在读取时使用更严格的解析策略。
  2. Wayland 协议文件重复生成与冗余依赖

    • 文件: src/plugin-qt/shortcut/CMakeLists.txt (第 54-64 行)
    • 问题: qt6_generate_wayland_protocol_client_sources 已经会生成对应的 C 协议文件,但紧接着又使用 target_sources 手动添加了 ${CMAKE_CURRENT_BINARY_DIR}/wayland-treeland-shortcut-manager-v2-protocol.c。这可能导致编译单元重复包含,引发 ODR (One Definition Rule) 违规或链接错误。
    • 建议: 移除手动的 target_sources 添加,qt6_generate_wayland_protocol_client_sources 会自动处理生成文件的引入。
  3. DConfig 指针内存泄漏风险

    • 文件: src/plugin-qt/shortcut/src/config/configloader.cpp (第 133 行)
    • 问题: DConfig::create 返回的是裸指针,如果后续的 isValid() 检查失败,虽然调用了 delete config,但在后续的复杂逻辑中(如 configCanNotChanged 分支),如果发生异常或提前返回,极易造成内存泄漏。
    • 建议: 使用智能指针管理 DConfig 生命周期,例如 QScopedPointer<DConfig> config(DConfig::create(...)),在确认需要保留时再通过 take() 交由原始指针管理,或直接在类成员中使用智能指针。

二、 代码质量与可维护性

  1. X11 轮询性能隐患

    • 文件: src/plugin-qt/shortcut/src/backend/x11/modifierkeymonitor.cpp
    • 问题: PollingModifierKeyMonitor 使用 10ms 间隔的 QTimer 不断轮询 X11 键盘状态(XQueryKeymap)和抓取状态(xcb_grab_keyboard)。这不仅带来持续的 CPU 唤醒,而且 isKeyboardGrabbed() 每次都会向 X Server 发送同步的 Grab/Ungrab 请求,在高频轮询下极易引发 X Server 竞态条件或性能瓶颈。
    • 建议:
      • 增大轮询间隔(如 50-100ms),对于修饰键释放检测,10ms 的延迟人类几乎无法感知。
      • isKeyboardGrabbed() 的实现非常危险(Grab 后立即 Ungrab),建议改用 X Input Extension 监听设备变更,或缓存 Grab 状态来减少 X Server 交互。
  2. Magic Number 过多

    • 文件: 多个 JSON 配置文件及 shortcutconfig.h
    • 问题: 诸如 triggerType: 1/2/3category: 1/2/3direction: 0-4 等在 JSON 和代码中大量使用纯数字。虽然文档中有解释,但在代码审查和维护时极不直观。
    • 建议: 在 JSON 的 description 字段中明确写出枚举含义(部分已做,建议全部统一),并在 C++ 代码中为 triggerTypecategory 等定义强类型枚举(enum class),在解析层做好映射,避免业务逻辑层直接操作 int
  3. 废弃的 Go 版本逻辑注释

    • 文件: src/plugin-qt/shortcut/tools/dde-shortcut-tool/ 下多个文件
    • 问题: 代码中大量存在 // Go version logic// Following Go version 的注释。虽然这有助于理解迁移历史,但长期保留会降低代码整洁度,让维护者困惑于当前实现是否只是为了兼容 Go 版本的某种缺陷。
    • 建议: 清理这些注释,保留必要的业务逻辑说明即可。如果是修复 Go 版本 Bug 的逻辑,应明确注释 Bug 编号和现象。

三、 代码性能

  1. 配置重载时的低效遍历

    • 文件: src/plugin-qt/shortcut/src/config/configloader.cpp (reload 方法)
    • 问题: 在 reload 时,使用 std::remove_if 配合 eraseQList 中移除元素。QList 在移除中间元素时会导致后续元素的大规模内存拷贝。如果快捷键配置较多,频繁重载(如 dpkg 触发)会导致性能抖动。
    • 建议: 考虑使用 QHashQMap 替代 QList 来存储 KeyConfigGestureConfig,以 SubPath 为 Key,这样删除和新增都是 O(1) 操作。
  2. TranslationManager 的低效加载

    • 文件: src/plugin-qt/shortcut/src/core/translationmanager.cpp
    • 问题: reload() 方法会遍历文件系统寻找 .qm 文件,并使用 QTranslator::load 加载。这在每次 ReloadConfigs 时都会触发(m_translationManager->reload())。
    • 建议: 翻译文件通常只在语言环境变化时更新,不应在每次配置重载时重新加载文件系统。应增加语言环境变化的监听,或实现增量更新机制。

四、 代码安全

  1. 命令执行注入风险

    • 文件: src/plugin-qt/shortcut/src/core/actionexecutor.cpp
    • 问题: runCommand 直接将 DConfig 中的 triggerValue 拼接后通过 QProcess::startDetached 执行。如果 DConfig 配置被恶意篡改(例如通过其他漏洞修改了 JSON 文件),攻击者可以以当前用户权限执行任意命令。
    • 建议:
      • 对从 DConfig 读取的 triggerValue 进行严格的白名单校验或路径校验(如必须是 /usr/bin//usr/lib/deepin-daemon/ 下的合法程序)。
      • 避免使用 shell 启动,确保参数是以数组形式传递(QProcess 的字符串列表形式),防止参数注入。
  2. DBus 接口权限控制缺失

    • 文件: src/plugin-qt/shortcut/src/core/keybindingmanager.h
    • 问题: ModifyHotkeys, Disable, Reset 等高权限方法直接暴露在 Session DBus 上,没有任何权限校验。任何同 Session 的应用都可以调用这些方法禁用或修改系统快捷键。
    • 建议: 在 DBus 方法实现中加入调用者检查,或配置 DBus Policy 限制只有特定用户/组(如 dde-daemon 自身或控制中心)可以调用修改类接口。
  3. postinst 脚本中的 runuser 风险

    • 文件: debian/dde-services.postinst
    • 问题: 脚本遍历 /run/user/*/bus 并使用 runuser -u <name> 执行 DBus 调用。如果存在恶意的用户名(虽然 getent passwd 通常能过滤掉畸形条目),或者 /run/user/ 下存在伪造的 socket,可能导致意外行为。
    • 建议: 确保 user_id 是纯数字,且在调用 runuser 前验证用户的有效性(不仅检查 user_name 非空,还可检查 UID >= 1000 等常规用户条件)。

总结

该 PR 完成度极高,文档和测试脚本的补充令人印象深刻。但在合并前,建议优先修复以下问题:

  1. 移除 CMakeLists 中重复的 Wayland 协议文件引入(语法错误风险)。
  2. 优化 X11 轮询逻辑,特别是 isKeyboardGrabbed 的实现(性能与稳定性风险)。
  3. 加强 ActionExecutor 中的命令执行校验(安全风险)。
  4. 修复 ConfigLoader 中 DConfig 指针的内存管理问题(内存泄漏风险)。

其他关于代码整洁度和微优化的建议,可在后续迭代中逐步完善。

@yixinshark
Copy link
Copy Markdown
Contributor Author

/forcemerge

@deepin-bot
Copy link
Copy Markdown

deepin-bot Bot commented Jun 1, 2026

This pr force merged! (status: blocked)

@deepin-bot deepin-bot Bot merged commit a6001dc into linuxdeepin:master Jun 1, 2026
8 of 10 checks passed
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.

4 participants