Visitar URL original
fix(debug): inject evdev keycodes from a fixed key table by deepin-wm · Pull Request #1595 · linuxdeepin/treeland · GitHub
Skip to content

fix(debug): inject evdev keycodes from a fixed key table - #1595

Draft
deepin-wm wants to merge 3 commits into
linuxdeepin:masterfrom
deepin-wm:agent/bot/74eaae9f95f5
Draft

deepin-wm wants to merge 3 commits into
linuxdeepin:masterfrom
deepin-wm:agent/bot/74eaae9f95f5

Conversation

@deepin-wm

@deepin-wm deepin-wm commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

解决的问题

treeland-debug event key <key> 注入的按键到复合器后变成别的键,或者干脆无效(2026-11-06 在多键盘布局的测试机上实测):

请求 实际到达的 Qt key
event key a 76(Qt::Key_L)
event key Space 16777270
event key Return / event key Right 0(无效键,注入静默失败)
event key VolumeMute 46(Qt::Key_Period)

根因是服务端 qtKeyToEvdev() 的做法:扫 live xkb keymap 的每个 keycode,取 level-0 的第一个 keysym 反查 Qt::Key。

  • 多布局 keymap 上多个 keycode 在 level-0 共享同一符号(或映射到同一 Qt::Key),遍历顺序上第一个胜出,于是 a 命中 Key_L 的键码;
  • Return、方向键这类 Qt::Key 在 level-0 根本没有符号,返回 0,注入静默失败;
  • 找不到映射时也只是静默注入失败,CLI 一样打印 ok。

改了什么

1. 名字 → 固定 evdev 表(不再反扫 keymap) — tools/treeland-debug/debughelpers.cpp

keyCode() 先按 Qt::Key 枚举名(带不带 Key_ 前缀、不区分大小写)查名字,再用固定的 Qt::Key → evdev 表(linux/input-event-codes.h)换成 evdev keycode,客户端把 keycode 通过调试协议发出去。表覆盖字母/数字/标点、空白与编辑键、方向键、修饰键、F1–F12 和常用媒体/系统键。名字查不到时 *ok=false,CLI/listen/MCP 三处都输出 unknown key '<name>',不再静默成功。

2. 服务端直接收 evdev keycode — src/modules/resource/treelandremotesource.cpp

删掉 43 行反向扫 keymap 的 qtKeyToEvdev(),sendKey() 把收到的 keycode 直接交给 wlr_seat_keyboard_notify_key()(它本来就吃 evdev code,与 waylib 的 WSeat::doNotifyKey() 一致)。顺带去掉不再需要的 private/qxkbcommon_p.h 与 xkbcommon/xkbcommon.h。treelandwindowtree.rep/.h 的参数相应更名 evdevKey(wire 签名 sendKey(int,bool) 不变)。

3. 参数语义与文档口径统一

  • 名字 = Qt 键名(Escape/escape/Key_Escape 均可,不区分大小写);Enter 是小键盘回车(KEY_KPENTER),主回车用 Return;esc/del 这类 Qt 从来不认的写法已从文档删除。
  • 注入的是 US 参考布局上的物理键位,最终产出什么字符取决于当前布局(例如德语布局下 event key Z 打出 y)。
  • --help、tools/treeland-debug/README.md、根 README.md / README.zh_CN.md、listen 的 MCP/JSON schema、.agents/skills/treeland-debug/SKILL.md 统一成同一套说法。

需要注意:数字参数是 breaking change

event key 的数字参数语义由 Qt::Key 值 改为 evdev keycode(evtest/ydotool 的约定):

  • 57 = KEY_SPACE,30 = KEY_A;
  • 单数字按 Qt::Key 名字解析 —— 5 就是 5 键(KEY_5=6),不是 evdev 5;要传 1–9 的原始码请用前导零,057 = 57;
  • 名字优先于数字,0–9 都走名字;
  • 旧脚本里传 Qt::Key 数值(如 16777216)需要换算。

协议没有版本协商,但槽签名未变,所以旧客户端 + 新服务端不会连不上,只是会把旧语义的数字当 evdev 码注入。

验证情况

  • 新增/更新回归断言:a → KEY_A(30)、VolumeMute → KEY_MUTE(113)、Space → 57、Return → 28、Right → 106、"5" → KEY_5(6)、"0" → KEY_0(11)、" 5 " 带空白同样 → KEY_5(6)、057 → 57、300/-5/非数字串被拒。
  • 最小 CMake 只编 tests/test_treeland_debug 的三个源文件(Debug 口径,TREELAND_DEBUG_DEV_BUILD + TREELAND_DEBUG_SOCKET=...debug-dev):109 passed, 0 failed。
  • 未在真机复合器上做注入验证:整仓编译在本机卡在缺 /usr/share/treeland-protocols/treeland-foreign-toplevel-manager-unstable-v3.xml(本机只有 v1/v2),与本次改动无关。合入前建议在测试机上补一次 event key Space / event key Return / event key 5 的实机注入。

影响面

只影响 treeland-debug event key 这条调试注入路径与调试协议这一个 slot;快捷键监控(shortcuts / events 的 type 6/7/8)不变。

后续(本 PR 不含)

  • 无键盘焦点 surface 时 sendKey() 仍返回 ok(事件被 wlroots 丢弃)—— 建议单独处理;
  • 名字覆盖缺口:Key_F13–F35、亮度、触控板开关等 evdev 有码但表中未收录,需要时补表。

Related issue: WM-953

Summary by Sourcery

Make debug keyboard injection use deterministic evdev keycodes and provide consistent validation and documentation for key names and numeric codes.

Bug Fixes:

  • Fix debug keyboard injection so named keys consistently map to their intended Linux evdev keycodes across keyboard layouts, including keys that previously failed or resolved incorrectly.
  • Report unknown or unsupported key names as errors instead of silently acknowledging failed injections.

Enhancements:

  • Define keyboard names using Qt key names mapped through a fixed evdev table, with physical US-layout semantics and distinct handling for keypad Enter.
  • Support raw multi-digit evdev keycodes while preserving numeric key names such as 5 and 0, and pass evdev codes directly through the debug protocol to wlroots.

Documentation:

  • Synchronize CLI help, README files, MCP schemas, and debugging guidance with the updated key-name, evdev-code, and keyboard-layout semantics.

Tests:

  • Expand debug key parsing regression coverage for named keys, media keys, numeric precedence, whitespace, invalid ranges, and raw evdev codes.

@sourcery-ai

sourcery-ai Bot commented Nov 6, 2026

Copy link
Copy Markdown

Reviewer's Guide

The PR fixes debug keyboard injection by resolving names on the client through a fixed Qt-to-evdev table and passing evdev codes directly to wlroots, eliminating ambiguous live-keymap reverse lookup. It also introduces explicit invalid-key handling, updates the protocol-facing terminology and documentation for the breaking numeric behavior, and adds regression coverage for representative mappings and parsing edge cases.

Sequence diagram for fixed evdev keyboard injection

sequenceDiagram
    participant CLI as treeland-debug
    participant Client as DebugClient
    participant Server as TreelandRemoteSource
    participant Seat as wlr_seat
    participant Surface as KeyboardFocusedSurface
    CLI->>Client: event key <key> press|release|tap
    Client->>Client: keyCode(name)
    alt Qt key name
        Client->>Client: Resolve Qt::Key and fixed Qt-to-evdev table
    else Numeric evdev code
        Client->>Client: Parse evdev keycode
    end
    alt Invalid or unmapped key
        Client-->>CLI: unknown key '<name>'
    else Valid evdev key
        Client->>Server: sendKey(evdevKey, pressed)
        Server->>Seat: wlr_seat_keyboard_notify_key(evdevKey, pressed)
        Seat->>Surface: Deliver physical key event
        Server-->>CLI: ok
    end
Loading

Flow diagram for key name and numeric parsing

flowchart LR
    Input[event key input] --> Trim[Trim input]
    Trim --> Name{Qt::Key name matches?}
    Name -->|Yes| Table[Fixed Qt::Key to evdev table]
    Table -->|Mapped| Send[Send evdev keycode]
    Table -->|Unmapped| Error[unknown key]
    Name -->|No| Number{Valid evdev code 1..255?}
    Number -->|Yes| Send
    Number -->|No| Error
Loading

File-Level Changes

Change Details Files
Replaced live xkb keymap reverse lookup with a fixed Qt-key-to-evdev mapping and clarified numeric parsing semantics.
  • Resolve Qt key names case-insensitively, with optional Key_ prefix, to Linux evdev codes.
  • Prioritize named digit keys over numeric parsing; accept bounded raw evdev codes and reject invalid or unmapped keys.
  • Return explicit unknown-key failures instead of allowing silent injection success.
tools/treeland-debug/debughelpers.cpp
tools/treeland-debug/debughelpers.h
tools/treeland-debug/main.cpp
tools/treeland-debug/debugserver.cpp
Changed the remote injection path to pass evdev keycodes directly to wlroots.
  • Removed server-side xkb keymap scanning and obsolete xkbprivate dependencies.
  • Renamed the implementation parameter to evdevKey while preserving the wire slot signature.
  • Reject non-positive codes before notifying the wlroots keyboard seat.
src/modules/resource/treelandremotesource.cpp
src/modules/resource/treelandremotesource.h
src/modules/resource/treelandwindowtree.rep
Expanded regression coverage for key translation and parsing behavior.
  • Verify representative letters, navigation, editing, function, media, keypad, and main Return mappings.
  • Cover whitespace trimming, digit-name precedence, raw multi-digit codes, invalid ranges, and unknown names.
tests/test_treeland_debug/main.cpp
Aligned user-facing documentation and examples with physical US-layout key injection and the breaking numeric semantics.
  • Document Qt names, evdev raw-code rules, Return versus keypad Enter, layout-dependent output, and explicit errors.
  • Update CLI, MCP schema, skill guidance, and English/Chinese README examples.
.agents/skills/treeland-debug/SKILL.md
README.md
README.zh_CN.md
tools/treeland-debug/README.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

1. Resolve `treeland-debug event key` names through a fixed Qt::Key ->
   evdev table (linux/input-event-codes.h) on the client, instead of
   reverse-scanning the live xkb keymap. On a multi-layout keymap that
   scan returned the first keycode with the same level-0 symbol ("a"
   landed on Key_L) and 0 for keys with no level-0 symbol at all
   (Return, the arrow keys), so those keys were dropped silently.
2. Send the evdev keycode over the debug protocol and drop the 43-line
   qtKeyToEvdev() on the server: wlr_seat_keyboard_notify_key() takes
   evdev codes anyway. Also drop the now unused private/qxkbcommon_p.h
   and xkbcommon/xkbcommon.h includes, and rename the slot parameter to
   evdevKey (the wire signature sendKey(int,bool) is unchanged).
3. Fail an unmappable name on the client with "unknown key '<name>'",
   reported by the CLI, listen and MCP entries, instead of injecting
   nothing while printing ok.
4. Read a numeric argument as a raw evdev keycode (the evtest/ydotool
   convention) and say the same in README, --help, the listen JSON
   schema and the treeland-debug skill; assert the evdev values in the
   tests.

Log: `treeland-debug event key` now injects the key that was asked for
on multi-layout keymaps; Return, the arrow keys and media keys work, and
an unknown name is an error instead of a silent no-op. Numeric
arguments changed meaning: they are raw evdev keycodes now (57=space,
30=A) rather than Qt::Key values, so old scripts need converting.

Influence:
1. On a us+cn multi-layout machine, `event key a`, `Space`, `Return`,
   `Right` and `VolumeMute` each inject the requested key.
2. `event key NoSuchKey` prints "unknown key 'NoSuchKey'" instead of ok.
3. `event key 57` presses space and `event key 30` presses A; a Qt::Key
   value such as 16777216 is no longer accepted.
4. Shortcut monitoring (`shortcuts`, `events` type 6/7/8) is unchanged.

fix(debug): 按键名改为查固定 evdev 映射表

1. `treeland-debug event key` 的名字解析改在客户端走固定的
   Qt::Key -> evdev 表(linux/input-event-codes.h),不再反扫 live
   xkb keymap:多布局 keymap 上反扫会命中遍历顺序第一个同符号的键码
   (`a` 落到 Key_L),而 Return、方向键这类在 level-0 没有符号的键
   直接得到 0,注入静默失败。
2. 调试协议直接传 evdev keycode,服务端删掉 43 行 qtKeyToEvdev();
   wlr_seat_keyboard_notify_key() 本来就吃 evdev code。顺带删掉不再
   需要的 private/qxkbcommon_p.h 与 xkbcommon/xkbcommon.h,槽参数
   更名为 evdevKey(wire 签名 sendKey(int,bool) 不变)。
3. 名字查不到时客户端直接失败,CLI / listen / MCP 三处都输出
   "unknown key '<name>'",不再注入空却打印 ok。
4. 数字参数按原始 evdev keycode 解释(evtest/ydotool 的约定),
   README、--help、listen 的 JSON schema 与 treeland-debug skill
   口径统一,测试里改为按 evdev 值断言。

Log: `treeland-debug event key` 在多布局 keymap 上现在能注入请求的键,
Return、方向键与媒体键也能用,未知键名会报错而不是静默注入空。数字
参数语义变了:现在按原始 evdev keycode 解释(57=空格、30=A),不再
是 Qt::Key 值,旧脚本需要换算。

Influence:
1. us+cn 多布局机器上,`event key a`、`Space`、`Return`、`Right`、
   `VolumeMute` 均注入对应的键。
2. `event key NoSuchKey` 输出 "unknown key 'NoSuchKey'",不再打印 ok。
3. `event key 57` 按下空格、`event key 30` 按下 A;`16777216` 这类
   Qt::Key 值不再被接受。
4. 快捷键监控(`shortcuts`、`events` 的 type 6/7/8)行为不变。

Multica Issue: WM-953
1. Look the key name up first and only then fall back to a numeric evdev
   keycode, so a single digit resolves as a Qt::Key name: `event key 5`
   injects KEY_5(6) instead of evdev 5 (KEY_4), and `event key 1` no
   longer injects Escape. Only multi-digit numbers are raw evdev codes
   (`057` = 57).
2. State the exact semantics in the docs: the injected code is a
   physical key position on the US reference layout, and the character
   it produces depends on the active layout (on a German layout
   `event key Z` types `y`); `Enter` is the keypad Enter.
3. Replace the dead `esc`/`del` names in the root READMEs with the Qt
   key names that actually resolve, using the same wording as the tools
   README.
4. Switch the `event key enter tap` examples to `Return tap`.
5. Assert the digit cases in the tests and fix the include order that
   clang-format expects.

Log: `event key 5` (and any single digit) presses the digit key now
instead of the evdev code of that number, which could be Escape or
another character. The root READMEs, the tools README, --help and the
treeland-debug skill describe one and the same key semantics.

Influence:
1. `event key 1`..`event key 9` press 1..9, and `event key 0` presses 0.
2. Raw codes 1-9 need a leading zero (`057` for space); multi-digit
   codes such as `30` and `57` are unchanged.
3. `event key Z` on a German layout types `y` (physical key position).
4. `esc` / `del` still report "unknown key"; the docs say `Escape` /
   `Delete` now.

fix(debug): 名字优先于数字解析

1. 先查键名,未命中才退化为数字 evdev 码,于是单个数字按 Qt::Key
   名字解释:`event key 5` 注入 KEY_5(6),不再是 evdev 5(KEY_4),
   `event key 1` 也不再注入 Escape。只有多位数字才是原始 evdev 码
   (`057` = 57)。
2. 文档写明准确语义:注入的是 US 参考布局上的物理键位,最终产出
   什么字符取决于当前布局(德语布局下 `event key Z` 打出 `y`);
   `Enter` 是小键盘回车。
3. 根目录两个 README 删掉 Qt 从不认的 `esc`/`del`,换成真正能解析
   的 Qt 键名,并与 tools README 用同一套说法。
4. 示例 `event key enter tap` 统一改成 `Return tap`。
5. 测试补上数字用例的断言,并按 clang-format 期望调整 include 顺序。

Log: `event key 5` 及任何单个数字现在按下对应数字键,不再按该数字的
evdev 码(可能是 Escape 或别的字符)。根目录两个 README、tools
README、--help 与 treeland-debug skill 的键参数口径一致。

Influence:
1. `event key 1`..`event key 9` 分别按下 1..9,`event key 0` 按下 0。
2. 要传 1-9 的原始码需加前导零(`057` = 空格);`30`、`57` 这类
   多位数字不变。
3. 德语布局下 `event key Z` 打出 `y`(物理键位语义)。
4. `esc`/`del` 仍报 "unknown key",文档已改为 `Escape`/`Delete`。

Multica Issue: WM-953
1. Trim the key name once at entry: `" 5"` missed the Qt::Key lookup
   and fell through to the numeric branch, injecting evdev 5 (KEY_4)
   while still reporting ok. `" 5 "`, `"\t5\n"` and `" 057 "` now
   resolve like their trimmed forms, and `" "` is rejected.
2. Spell out in the MCP tool schema that Qt key names win over numbers
   and only multi-digit numbers are raw evdev codes, matching the
   READMEs; that schema is what an automated caller (an LLM in
   particular) reads.
3. Assert the whitespace-padded digit case in the tests and reflow the
   touched README paragraph.

Log: A key name with surrounding whitespace -- a stray space in a shell
argument or in a JSON payload -- injected a different key and reported
ok; it now resolves to the named key. The MCP tool description states
the same name-over-number rule as the docs.

Influence:
1. `event key " 5"` presses the 5 key (KEY_5), not KEY_4.
2. `event key " "` reports "unknown key" instead of a silent success.
3. `event key " 057 "` still injects evdev 57.
4. An MCP or LLM caller reading the tool schema sees that names win and
   only multi-digit numbers are evdev codes.

fix(debug): 键名先去空白并写明数字回退规则

1. 进函数先对键名做 trimmed:`" 5"` 之前查不到 Qt::Key 名字会落到
   数字分支,注入 evdev 5(KEY_4)却仍返回 ok。现在 `" 5 "`、
   `"\t5\n"`、`" 057 "` 与去掉空白后一致,`" "` 被拒绝。
2. MCP 工具描述写明名字优先于数字、只有多位数字才是原始 evdev 码,
   与各 README 口径一致;自动化调用方(尤其是 LLM)读到的就是这份
   schema。
3. 测试补上带空白数字的断言,并重新折行改动过的 README 段落。

Log: 键名前后带空白时(shell 参数里多一个空格,或 JSON 拼装出的
`" 5"`)之前会注入别的键还返回 ok,现在按名字正确解析;MCP 工具
描述与文档采用同一条"名字优先于数字"的规则。

Influence:
1. `event key " 5"` 按下 5 键(KEY_5),不再是 KEY_4。
2. `event key " "` 报 "unknown key",不再静默成功。
3. `event key " 057 "` 仍注入 evdev 57。
4. 读工具描述的 MCP/LLM 调用方能看到名字优先、只有多位数字才是
   evdev 码。

Multica Issue: WM-953
@deepin-wm
deepin-wm force-pushed the agent/bot/74eaae9f95f5 branch from d316fbb to dd3e19e Compare November 6, 2026 10:39
@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: deepin-wm

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

@deepin-ci-robot

Copy link
Copy Markdown

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

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.

3 participants