edit | blame | history | raw

TagLauncher WindowServer 会诊风险复核

日期:2026-07-01

用户目标

对照 /Users/ar/Projects/Taglauncher-doc/chat-history/codex-sessionhistory/2026-07-01-WindowServer会诊.md,以最新代码重新核查会诊中提到的 WindowServer / TextInput / 鼠标事件风险,拉上架构师和代码审核员判断还有哪些确实需要提前修复。

当前起点

  • 仓库:/Users/ar/Projects/Taglauncher
  • 源码根目录:/Users/ar/Projects/Taglauncher/src
  • 当前分支:codex/pro-custom-hotkeys-8.2.0
  • 当前 HEAD:0ae3a93,tag v8.3.1-build20260701.2302
  • 工作区:源码未新增本轮改动;已有脏文件为历史 src/Release/... 发布资料,未触碰。
  • 会诊基线:2026-07-01-WindowServer会诊.md

已完成事项

  • 读取项目治理、CODEGRAPH、调试和交付门禁规则。
  • 由架构师子 agent 和代码审核员子 agent 分别只读复核会诊意见与最新源码。
  • 主线程复核关键源码路径:
  • src/Apptag/QuickSearch.swift
  • src/Apptag/ApptagApp.swift
  • src/Apptag/ContentView.swift
  • src/Apptag/TagNavigationView.swift
  • src/Apptag/AppGridCollectionView.swift
  • src/Apptag/AppGridSupport.swift
  • src/Apptag/OverlayWindowController.swift
  • 本轮未修改源码、未打包、未启动 GUI 自动化。

核心事实 / 变更快照

  • 变更对象:WindowServer 会诊中列出的风险状态复核。
  • 事实来源:当前源码 0ae3a93CODEGRAPH.md、会诊纪要和两个子 agent 只读复核。
  • 变更前:会诊纪要将旧 8.3.0 20260701.2029 的主要高危点归因为标签编辑时同一 NSEvent 被转发给 NSTextField.mouseDown,并列出 Quick Search / IME、外部点击、窗口置前、TagNavigation 阻塞循环等剩余风险。
  • 变更后:旧标签编辑 mouseDown 转发风险在当前源码已不成立;Quick Search / IME、外部点击关闭、重复置前、TagNavigation 阻塞循环仍有当前源码证据。
  • 范围边界:本轮是只读风险复核,不代表已完成修复,也不替代后续真实 GUI / 中文输入法验收。

关键结论

建议提前修复

  1. Quick Search 仍缺 IME marked-text guard。
  • 证据:src/Apptag/QuickSearch.swift:1706doCommandBy 直接拦截 Up / Down / Return / Esc;src/Apptag/QuickSearch.swift:1735keyDown 也直接处理同一组键。
  • 对照:src/Apptag/ContentView.swift:141 的标签编辑路径已有 textView.hasMarkedText() guard。
  • 风险:中文输入法候选态下,方向键、回车和 Esc 可能被 Quick Search 消费,错误变成移动搜索结果、启动 App 或关闭面板。
  1. Quick Search global mouse monitor 仍可能在点击 IME 候选窗时关闭文本客户端。
  • 证据:src/Apptag/ApptagApp.swift:1922 对任意 global mouseDown 发关闭请求;src/Apptag/ContentView.swift:894 关闭时清空 query/results/selection。
  • 风险:IME 候选窗点击可能被当成外部点击,composition 未结束时撤掉 Quick Search 文本输入上下文。
  1. Quick Search 输入更新期间重复激活 / 置前窗口。
  • 证据:src/Apptag/ContentView.swift:614 query 变化刷新结果;src/Apptag/QuickSearch.swift:823 / :855 每次 applyNSApp.activatemakeKeyAndOrderFrontorderFrontRegardlesssrc/Apptag/QuickSearch.swift:1668 还有多次 delayed focus。
  • 风险:输入和结果刷新期间反复重排面板和 first responder,放大 WindowServer / TextInput churn。
  1. TagNavigation 仍有阻塞式 mouseDown 事件循环。
  • 证据:src/Apptag/TagNavigationView.swift:488mouseDownwhile !finishedsrc/Apptag/TagNavigationView.swift:510 只等 .leftMouseDragged/.leftMouseUpnextEvent 为 nil 时继续循环。
  • 风险:mouseUp 丢失、窗口隐藏、App 失活或事件被 monitor 吞掉时,主线程可能困在 eventTracking loop。

可暂缓但应记录

  1. App note 泡泡仍是 SwiftUI TextField + 非激活 overlay + 主动抢焦点组合。
  • 证据:src/Apptag/AppGridSupport.swift:62 使用 SwiftUI TextFieldsrc/Apptag/AppGridSupport.swift:117 setter 直接 prefix 截断;src/Apptag/OverlayWindowController.swift:232 overlay 是 .nonactivatingPanel
  • 判断:风险真实,但目前没有用户报告直接指向备注泡泡;优先级低于 Quick Search 和 TagNavigation。
  1. Usage Tips local monitor 可能跨同 App 窗口误吞鼠标事件。
  • 证据:src/Apptag/AppGridCollectionView.swift:754 安装 local monitor;src/Apptag/AppGridCollectionView.swift:777 对非本窗口事件用 NSEvent.mouseLocation 映射;命中后可返回 nil
  • 判断:风险真实但偏 UI 事件误路由,建议后续顺手收窄到 event.window === self.window

已不成立

  1. 标签编辑中同一 NSEvent 被手动转发给 NSTextField.mouseDown
  • 证据:src/Apptag/ContentView.swift:84 现在只 focusTextField()src/Apptag/ApptagApp.swift:2171 / :2175 是 focus-only,不再调用 container.mouseDown(with:)tf.mouseDown(with:)
  • QA:tag_editor_mouse_event_qa.sh PASS。
  1. Quick Search panel 是 nonactivating 导致 Return 落到前台 App。
  • 证据:src/Apptag/QuickSearch.swift 当前 Quick Search panel 是可 key panel;quick_search_launch_contract_qa.sh PASS。
  1. Quick Search local mouse monitor 吞掉 overlay 内结果行点击。
  • 证据:local monitor 对 overlay window 内事件直接放行,且 panel-level sendEvent 有点击兜底。
  • QA:quick_search_launch_contract_qa.sh PASS。

可复用命令 / Runbook

用途:复查当前源码是否仍有标签编辑 mouseDown 回归、Quick Search 点击/回车启动合同,以及快速定位 IME / monitor / event loop 风险点。

前置条件:在 /Users/ar/Projects/Taglauncher/src 或仓库根目录运行;不需要启动 App,不会修改源码。

标签编辑 mouseDown 防回归

cd /Users/ar/Projects/Taglauncher/src
bash Scripts/tag_editor_mouse_event_qa.sh

验证结果:本轮输出 PASS Tag editor mouse event QA: text-field clicks focus without recursive mouseDown forwarding

Quick Search 点击 / 回车启动合同

cd /Users/ar/Projects/Taglauncher/src
bash Scripts/quick_search_launch_contract_qa.sh

验证结果:本轮输出 PASS quick search launch contract

静态定位仍存风险

cd /Users/ar/Projects/Taglauncher
rg -n "hasMarkedText|markedText|doCommandBy|keyDown\\(|addGlobalMonitorForEvents|nextEvent\\(" src/Apptag/QuickSearch.swift src/Apptag/ApptagApp.swift src/Apptag/TagNavigationView.swift src/Apptag/ContentView.swift

搜索关键词:WindowServerCursorUIViewServiceQuick Search IMEhasMarkedTextmarkedTextaddGlobalMonitorForEventsTagNavigation nextEventtag_editor_mouse_event_qaquick_search_launch_contract_qa

未决问题

  • 是否在发布前先修 Quick Search IME marked-text guard 和外部候选窗点击关闭问题。
  • 是否同时把 Quick Search 重复 activate/orderFront 降到只在打开和必要状态转换时执行。
  • 是否把 TagNavigation 的阻塞式 mouseDown 事件循环改成状态机,或先加最小退出条件。

后续建议

发布前建议优先做一个小修复批次:

  1. Quick Search 输入法组合态保护。
  2. Quick Search global mouse dismiss 在 marked-text / composition 期间不关闭。
  3. Quick Search orderFront / focus 去重。
  4. TagNavigation mouseDown 循环增加兜底退出,或改为非阻塞事件状态机。