SuperAPI AI 工具集

diagnose-dead-global-hotkey

办公与效率

查看项目

更新于 10-23 10:08

技能介绍

用途

该技能用于诊断一种特定故障:macOS 全局快捷键(如截图工具、启动器、剪贴板管理器)在其他地方都正常,唯独某个应用处于前台、全屏或仅仅在运行时失效。按下快捷键要么毫无反应,要么在该应用内部触发了别的行为。技能的目标是找出快捷键在输入路径的哪一层丢失或被改写,然后只修复那一层。

输入路径模型

技能把输入路径自下而上描述为:

键盘 → DriverKit 重映射器(Karabiner-Elements)→ HID tap 点 → Session tap 点 → 快捷键分发(Carbon RegisterEventHotKey)→ 前台应用

其中重映射器工作在所有 tap 层之下,其规则(例如针对前台应用的 frontmost_application_if 规则,把 Command 改成 Control 以适配远程桌面查看器)会在任何事件 tap、日志器或快捷键看到之前就改变按键组合。

tap-census.swift 还能报告第三个点 AnnotatedSession 上的 tap。窗口服务器会在事件到达该点之前处理部分快捷键,因此该点的 tap 不太可能是元凶,日志器也不监视它。如果四个位置都干净,而普查显示问题应用有一个 ACTIVE 的 AnnotatedSession tap,则应怀疑它。

两个关键事实贯穿整个方法:

  1. 重映射器工作在 tap 层之下。Karabiner 的规则会在任何事件 tap、日志器或快捷键看到之前改变按键组合。
  2. 合成测试按键进入点在重映射器之上。CGEventPost 探针可能报告“快捷键触发”,而物理按键仍然失败。绝不能仅凭合成探针下结论,必须用日志器中的真实按键确认。

主要能力(脚本)

脚本位于 scripts/ 目录,用 swift <file> 运行,无需构建步骤。先解析目录:S="$(cc-plugin-root macro-keyboard)/skills/diagnose-dead-global-hotkey/scripts"。

  • tap-census.swift:列出每个键盘事件 tap 的归属、HID 或 Session 点、ACTIVE(可吞掉事件)或仅监听状态。只读。
  • key-path-logger.swift:在四个位置(HID 头/尾、Session 头/尾)设置仅监听 tap。只记录按住 Cmd、Ctrl 或 Opt 的 key-down:修饰键、键码、前台应用,以及被监视应用是否打开了窗口。
  • hotkey-probe.swift:在 HID tap 处发送合成按键组合,报告被监视应用是否响应(FIRED / DID NOT FIRE)。适合测试 tap 和窗口状态,但对重映射器不可见。

日志器需要运行它的终端拥有“输入监控”权限。它从不记录普通打字。

使用方式(工作流)

1. 建立基线与故障状态

  • 在问题应用关闭时运行 tap-census.swift。
  • 打开问题应用,复现故障状态(窗口化?全屏?聚焦?)。
  • 再次运行 tap-census.swift,对比差异:问题应用拥有的新 ACTIVE tap 是头号嫌疑。
  • 运行 ioreg -l -w 0 | grep -o '"kCGSSessionSecureInputPID"=[0-9]*' | sort -u,非空表示安全事件输入已开启(对应 pid)。

记录用户所处的确切状态。全屏与窗口化有区别:某些查看器只在全屏时抓取键盘。

2. 观察真实按键

运行 swift "$S/key-path-logger.swift" 600 "<快捷键归属进程名>",让用户先在 Finder 等中性应用中按快捷键,再在问题应用前台时按。根据日志判断:

  • 修饰键与按下不符(如按下 Cmd+Shift+X 却记录为 Ctrl+Shift+X),且 front= 问题应用:该应用作用域内的重映射规则改写了组合,需给规则加例外(修复 A)。
  • 在 HID 头可见、在后续位置缺失:两者之间的 ACTIVE tap 吞掉了它。用 tap-census.swift 找归属;若是问题应用,用修复 B。
  • 到处可见、未改变,但快捷键归属应用没有打开任何窗口:归属应用注册了不同的组合,或注册失败。检查其快捷键设置并重新注册。
  • 问题应用前台时到处都看不到,但中性应用可见:安全事件输入。它会把按键事件对其他进程的 tap 和快捷键隐藏。找到安全输入 pid(步骤 1),归属应用必须关闭它(通常是聚焦的密码框)。
  • 即使中性应用也到处看不到:在窗口服务器之前就丢失了,可能是硬件、KVM 或共享软件,或丢弃该键的重映射规则。检查 Karabiner-EventViewer 和重映射规则。

3. 修复失败层并用真实按键复验

重新运行日志器,让用户再按一次。当日志在四个位置都显示原始组合,且被监视应用的窗口数增加时,即完成。

修复 A:Karabiner 按应用修饰键重映射

类似“远程桌面查看器前台时 Command → Control”的规则(使 Cmd+C/V 在远程机器上表现为 Ctrl+C/V)也会把快捷键组合变成 Control 组合,被远程机器接收。在该规则的修饰键 manipulator 之前加入例外 manipulator,用 Command 重新发出该组合。技能给出了两段 JSON 示例,分别匹配 command+shift 和 control+shift 两种 from 情况,并建议两个变体都保留,因为无法确定 from.modifiers 看到的是物理 Command 还是已被改写的 Control,保留两者可保证规则在两种情况下都正确。需告知用户的副作用:在该应用中物理按下 Ctrl+Shift+X 现在也会变成该快捷键。Karabiner 保存 karabiner.json 后会自动重载;可通过日志确认。若文件由 dotfile 管理器(如 chezmoi)管理,也要更新其源文件。

为什么“先点另一个应用”没用:浮动、非激活窗口(时钟、HUD、调色板)永远不会成为前台应用,因此 frontmost_application_if 仍然匹配查看器。应看日志器中的 front=,而不是用户点了什么。

修复 B:应用的键盘抓取

远程桌面查看器、虚拟机和游戏常安装 ACTIVE 的 Session 级 CGEventTap,接管每个按键事件并重新发给自己,使系统快捷键到达远程端。快捷键分发永远看不到该键。需寻找禁用抓取的选项。技能给出的例子:TigerVNC viewer 在全屏且 FullscreenSystemKeys 开启(默认)或手动抓取开关时触发抓取,可通过命令行 -FullscreenSystemKeys=0 或查看器配置文件中的 FullscreenSystemKeys=0 禁用。用 tap-census.swift 验证故障状态下该应用的 ACTIVE tap 消失,并用 hotkey-probe.swift 验证组合触发(tap 在重映射器之上,因此探针对此修复有效)。代价:Cmd+Tab 等系统快捷键将作用于 Mac 而非远程机器。

适用场景

  • 全局快捷键只在某个远程桌面查看器、虚拟机或游戏前台/全屏时失效。
  • 需要区分是重映射器改写、事件 tap 吞掉、安全事件输入,还是应用键盘抓取导致的问题。
  • 需要在修复后验证真实按键在四个位置都保持原始组合。

限制与注意事项

  • 日志器需要终端拥有“输入监控”权限。
  • 只记录带 Cmd、Ctrl 或 Opt 的按键,不记录普通打字。
  • 合成探针无法证明重映射器相关问题,必须用真实按键确认。
  • 一个修复可能不够:查看器可能同时命中两个原因(重映射规则在任何窗口状态、键盘抓取仅全屏),需在用户使用的每种状态下重新测试。
  • 探针的组合在快捷键未触发时会去往某处:前台应用,或经查看器到远程机器。应在前面放一个无害应用再运行。
  • 技能为自演进型:若说明有误、API 或应用选项变化、或需要变通,应立即修正文件和脚本,但仅针对真实、可复现的问题更新。

执行后反思

技能完成后检查:诊断是否匹配表格某一行,若日志出现未列出的模式则补充该行及修复;应用选项或 API 是否变化,若是则更新表格或脚本;是否需要变通,若是则并入工作流或注意事项。仅在问题真实且可复现时更新,不做推测性修改。