Description 现象 在 Windows 运行态里,Selection Ask / 划词追问 的 QA hotkey 如果通过设置页修改或禁用,前端 prefs.qaHotkey 会更新,但后端运行中的 QaHotkeyMonitor 不一定同步刷新。 结果是旧热键可能继续生效,或者 UI 显示已禁用 / 已改键,但用户按旧组合键仍能打开 QA panel。 这次本地调查时,代码路径显示 openless-all/app/src-tauri/src/commands.rs 的 set_settings 只调用了 update_hotkey_binding(),没有调用 update_qa_hotkey_binding()。 运行态证据:最新 debug build 启动后,日志可以看到 QA hotkey listener installed on main thread;手工发送热键时,日志命中 QA hotkey edge (panel_visible=false) 与 QA panel opened,说明监听器本身工作,但设置写回链路与监听器生命周期脱节。 问题层面 / Problem layer 层面判定:应用逻辑层 / cross-platform settings-to-runtime contract bug 。 当前证据来自 Windows,但根因不是 Windows API 特有逻辑,而是通用设置写回链路漏掉了 QA 监听器刷新。 更准确的判断是:全平台逻辑问题,当前先在 Windows 运行态被观测到 ;是否在 macOS 复现,需要再补运行态验证,但 issue 目标不应收窄成纯 Windows-only bug。 证据 代码证据:openless-all/app/src-tauri/src/commands.rsset_settings(...) 走统一偏好写回,但之前只刷新主听写 hotkey。QA 专用刷新逻辑只存在于 set_qa_hotkey(...)。 日志证据(Windows, latest debug run)
[coord] QA hotkey listener installed on main thread (after 1 attempt(s))[coord] QA hotkey edge (panel_visible=false)[coord] QA panel opened (awaiting Option to record) 这说明“监听器能工作”与“设置变更能否更新监听器”是两条不同生命周期;当前问题出在后者。 与 macOS 原始设计意图的偏差 macOS 上原始设计意图是:用户改掉 QA shortcut 后,运行态监听器应立刻切到新绑定,行为与 UI 保持 single source of truth。 当前 Tauri 实现把 QA hotkey 拆成了单独 monitor,但通用设置写回没有承担这条 monitor 的刷新责任,导致“偏好已变更”与“运行态仍持有旧注册”分离。 这不是单纯的 API 漏调,更是生命周期边界没有从 macOS 语义完整移植到跨平台实现。 生命周期差异 / Platform lifecycle notes Windows 上全局热键注册是显式 runtime object;一旦注册成功,就会持续存活直到主动更新或卸载,所以更容易把这个 contract 缺口暴露出来。 macOS 即使最终表现相同,它暴露问题的节奏也可能不同,因为前台 app、global monitor、window activation 的系统路径不同。 这条 issue 的重点不是“哪个平台更容易坏”,而是设置生命周期与监听器生命周期没有被统一建模 。 5 Whys 为什么用户改了 QA hotkey 后旧热键还可能生效?
因为运行中的 QaHotkeyMonitor 没有被重新注册。 为什么 QaHotkeyMonitor 没有重注册?
因为通用设置入口 set_settings 没有调用 update_qa_hotkey_binding()。 为什么只有 set_qa_hotkey 调用了 QA 刷新?
因为实现上把 QA hotkey 视为“专门命令负责”的特例,但设置页实际又通过通用 set_settings 持久化 qaHotkey。 为什么会出现两条写回路径并且语义不一致?
因为 Tauri/React 层把偏好持久化与运行态监听器刷新拆开了,但没有建立统一 contract。 为什么这个 contract 在 Windows 上更容易暴露?
因为 Windows 下全局热键注册是显式生命周期对象;一旦注册成功,就会持续存活直到主动更新或卸载。macOS 原始设计更偏向“设置即生效”的产品语义,但跨平台移植时没有把这层生命周期一致性补齐。 影响 划词追问 / selection ask / QA panel 的入口行为变得不可预测,用户会遇到 “UI state != runtime state”。测试与回归也会被误导:看起来设置已经保存,但真实触发仍旧跟旧配置走。 对后续 Windows 行为对齐 macOS 的工作有干扰,因为我们无法信任偏好状态是否真实落到监听器。 建议接受标准 TODO / 不确定项 TODO: 需要确认是否还有其他入口会绕过 set_qa_hotkey 直接写 prefs.qaHotkey。 TODO: 需要确认 macOS 当前是否也能通过相同路径复现,还是仅在 Windows 先暴露。 TODO: 需要确认 release build 与 debug build 在监听器更新时的行为是否完全一致。 Reactions are currently unavailable
You can’t perform that action at this time.
现象
Selection Ask/划词追问的 QA hotkey 如果通过设置页修改或禁用,前端prefs.qaHotkey会更新,但后端运行中的QaHotkeyMonitor不一定同步刷新。openless-all/app/src-tauri/src/commands.rs的set_settings只调用了update_hotkey_binding(),没有调用update_qa_hotkey_binding()。QA hotkey listener installed on main thread;手工发送热键时,日志命中QA hotkey edge (panel_visible=false)与QA panel opened,说明监听器本身工作,但设置写回链路与监听器生命周期脱节。问题层面 / Problem layer
证据
openless-all/app/src-tauri/src/commands.rsset_settings(...)走统一偏好写回,但之前只刷新主听写 hotkey。set_qa_hotkey(...)。[coord] QA hotkey listener installed on main thread (after 1 attempt(s))[coord] QA hotkey edge (panel_visible=false)[coord] QA panel opened (awaiting Option to record)与 macOS 原始设计意图的偏差
生命周期差异 / Platform lifecycle notes
5 Whys
QaHotkeyMonitor没有被重新注册。QaHotkeyMonitor没有重注册?set_settings没有调用update_qa_hotkey_binding()。set_qa_hotkey调用了 QA 刷新?set_settings持久化qaHotkey。影响
划词追问 / selection ask / QA panel的入口行为变得不可预测,用户会遇到 “UI state != runtime state”。建议接受标准
set_settings写入qaHotkey变更时,运行态 QA 监听器与主听写监听器一样立即刷新。TODO / 不确定项
set_qa_hotkey直接写prefs.qaHotkey。