Skip to content

fix: consume hotkey events to prevent character key leak#59

Merged
hehehai merged 2 commits intohehehai:mainfrom
zhongyi-byte:fix/hotkey-key-leak
May 6, 2026
Merged

fix: consume hotkey events to prevent character key leak#59
hehehai merged 2 commits intohehehai:mainfrom
zhongyi-byte:fix/hotkey-key-leak

Conversation

@zhongyi-byte
Copy link
Copy Markdown

@zhongyi-byte zhongyi-byte commented May 6, 2026

问题描述

当用户按下不含修饰键的快捷键组合(例如 Fn+SpaceFn+Z)时,字符键事件会穿透到前台应用,导致当前输入框中意外插入字符。

例如:在文本编辑器中,按下快捷键 Fn+Space 本来应该触发语音转文字,但结果是在编辑器里插入了一个空格。

解决方案

CGEventTap仅监听模式(listen-only)改为活动模式(active tap)

  • 当检测到有配置的快捷键(非修饰键的 keyDown / keyUp)被触发时,返回 nil消费该事件,阻止其继续传递到前台应用。
  • 其他未匹配的按键事件不受影响,正常放行。

修复效果

修复前 修复后
按快捷键后,当前输入框会意外插入字符(如空格、字母等) 快捷键正常触发功能,不会向输入框插入任何字符
事件穿透导致前台应用响应了本应被拦截的按键 匹配的快捷键事件被正确消费,前台应用无感知

测试计划

  • xcodebuild test -project Voxt.xcodeproj -scheme Voxt -destination 'platform=macOS' CODE_SIGNING_ALLOWED=NO -only-testing:VoxtTests/HotkeyManagerTests — 全部 23 项测试通过
  • 手动测试 Fn+Space 和 Fn+Z 快捷键,确认字符不再泄漏到前台应用

When a non-modifier hotkey combo (e.g. Fn+Space, Fn+Z) is pressed,
the character key event was passed through to the foreground app,
causing unwanted text insertion. Change the CGEvent tap from
listen-only to an active tap that returns nil (consumes the event)
when a non-modifier keyDown/keyUp matches a configured hotkey.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@hehehai hehehai added Enhancement New feature or request bug Something isn't working labels May 6, 2026
@hehehai
Copy link
Copy Markdown
Owner

hehehai commented May 6, 2026

这次补充提交主要处理了 hotkey active tap 引入后的事件消费回归,并顺带把 ESC 取消链路一起收紧。

本次修改和优化:

  • 修复了非纯修饰键 tap 热键在 keyUp 阶段消费条件过宽的问题。现在只有先命中对应 keyDown 后,匹配的同一 keyUp 才会被消费,不会再吞掉无关按键释放事件。
  • 覆盖范围不只包含 transcription / meeting,也一并收紧了 translation / rewrite 的同类路径,避免相同模式下出现类似问题。
  • resetTransientState 相关取消 / 退出路径已经补齐,重置后不会残留待消费状态,避免后续释放事件被误吞。
  • ESC 取消录音的逻辑下沉到了 active tap 路径,通过 HotkeyManager 统一处理;命中取消条件时会真正消费 Esc,避免前台应用同时触发自己的取消行为。
  • 保持了左右修饰键区分逻辑,非纯修饰键组合在开启侧别区分时仍按正确侧别匹配。

补充测试:

  • 非纯修饰键 tap 热键未发生匹配 keyDown 时,不消费后续 keyUp
  • 命中热键后,只消费匹配释放事件,不消费无关释放事件
  • resetTransientState 后不再消费挂起释放事件
  • 左右修饰键区分开启时,非纯修饰键热键仍按正确侧别生效
  • Esc 回调在 active tap 下可真实消费;拒绝消费时正常透传

本地验证:

xcodebuild test -project Voxt.xcodeproj -scheme Voxt -destination 'platform=macOS' CODE_SIGNING_ALLOWED=NO -only-testing:VoxtTests/HotkeyManagerTests

已通过,结果为 32/32

另外也用 Xcode 运行中的 Dev App 做了手动回归:

  • tap 模式热键触发录音时不再向前台文本框泄漏字符
  • 转录中按 Esc 取消时,不再把前台窗口自己的取消动作一起带出来

@hehehai hehehai merged commit 760cb0a into hehehai:main May 6, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working Enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants