治理归属
族群:E 族群 / helper-window 与输入交互契约
canonical PR:docs(windows): 跟踪双热键事件源生命周期 #155
主修范围:Windows 双热键事件源、input source ownership、state-machine precedence、mixed-source regression
不默认并入:主窗口外观、capsule geometry、helper-window hidden-state 语义、startup visible/ready 视觉暴露
参考:
docs/windows-window-governance-board.zh-CN.md
docs/2026-05-02-window-capability-family-audit.md
docs/github-tracking/windows-window-family-canonical-map.md
现象 / Symptom
Windows 的听写生命周期目前有两条事件入口:
OS-level low-level keyboard hook
主窗口聚焦时的 renderer-level window hotkey forwarder
macOS/Linux 则只有 backend/global listener 这一条主入口。也就是说,Windows 当前不是“同一状态机的同一输入源”,而是“双事件源共同驱动同一个 lifecycle state machine”。
这类设计即使暂时没有稳定复现的 field bug,也属于高风险不一致:
press / release 次序可能来自不同来源
focus 切换时可能只收到一半边沿
hold mode 与 toggle mode 都可能出现 Windows-only stuck / double-trigger / phase drift
证据 / Evidence
openless-all/app/src/App.tsx:63-80
Windows 前端在 keydown/keyup 上主动转发 window-local hotkey event
openless-all/app/src-tauri/src/coordinator.rs:739-779
backend 额外提供 handle_window_hotkey_event 入口
openless-all/app/src-tauri/src/hotkey.rs
Windows 还有独立的 WH_KEYBOARD_LL low-level hook
openless-all/app/src-tauri/src/coordinator.rs:645-709
当前只靠 hotkey_trigger_held 做共享 edge dedupe,没有源级别的 precedence contract
5 Whys / 根因分析
为什么这是生命周期问题,而不只是“多一条 fallback”?
因为它不是只读 telemetry,而是第二条会真正触发 start/stop/cancel 的状态机输入源。
为什么双事件源会带来风险?
因为同一个 session phase 可能由 source A 按下、source B 抬起,形成部分边沿丢失或重复。
为什么这个问题主要在 Windows?
因为只有 Windows 同时保留了 OS hook 和 renderer forwarder 两套路径。
为什么这偏离了 macOS 的原始设计意图?
原始意图是“用户一个手势对应一个稳定的生命周期转换”;Windows 当前更像“一个手势可能穿过两条不同的输入链路”。
为什么之前没有完全暴露?
因为现有 smoke 主要验证“某条路径能工作”,没有验证 mixed-source ordering、focus switch 和 hold/release 失配。
平台边界 / Platform Scope
直接风险范围:Windows-only 实现风险。
问题层面:input source ownership、state-machine edge contract、focus-sensitive lifecycle driving。
全平台风险判断:症状只在 Windows 这条实现链上产生,但它影响的是核心 dictation lifecycle,而不是纯 Windows UI 细节。
认领 / Ownership
影响 / Impact
可能导致 Windows-only 的听写开始/结束失配
会增加“热键偶发不稳定、卡住、重复触发”的排障成本
会妨碍后续把生命周期问题与 UI 问题拆开判断
建议接受标准 / Proposed Acceptance Criteria
TODO / 不确定项
是否应最终把窗口前台路径下沉回 backend hotkey adapter,而不是继续暴露一条 renderer IPC lifecycle input
是否需要把该问题与现有前台热键兼容性问题单独区分,避免“能用”和“生命周期一致”被混为一谈
治理归属
docs/windows-window-governance-board.zh-CN.mddocs/2026-05-02-window-capability-family-audit.mddocs/github-tracking/windows-window-family-canonical-map.md现象 / Symptom
Windows 的听写生命周期目前有两条事件入口:
macOS/Linux 则只有 backend/global listener 这一条主入口。也就是说,Windows 当前不是“同一状态机的同一输入源”,而是“双事件源共同驱动同一个 lifecycle state machine”。
这类设计即使暂时没有稳定复现的 field bug,也属于高风险不一致:
证据 / Evidence
openless-all/app/src/App.tsx:63-80keydown/keyup上主动转发 window-local hotkey eventopenless-all/app/src-tauri/src/coordinator.rs:739-779handle_window_hotkey_event入口openless-all/app/src-tauri/src/hotkey.rsWH_KEYBOARD_LLlow-level hookopenless-all/app/src-tauri/src/coordinator.rs:645-709hotkey_trigger_held做共享 edge dedupe,没有源级别的 precedence contract5 Whys / 根因分析
平台边界 / Platform Scope
认领 / Ownership
@Cooper-X-Oak影响 / Impact
建议接受标准 / Proposed Acceptance Criteria
TODO / 不确定项