为快捷键明确焦点和输入法组合输入边界

使用 AI 辅助编写与复核。

本文目录

描述快捷键时,先说明它可能打断什么工作。用于预览笔记的组合键,不应同时确认输入法候选词、改变无关工具栏操作,或在按住不放时反复触发。请先给编程 Agent 一份焦点地图、组合输入处理规则和明确的操作边界,再要求它添加事件监听。

下面的虚构 Cove Review 编辑器只有一个快捷键:Control+Enter 预览当前笔记。预览只更新本地面板,不发送、不发布,也不保存任何内容。这是一份人为编写的交互约定,不是浏览器缺陷的实录。

说清焦点可能位于哪三个位置

页面包含多行笔记编辑器、Preview 按钮,以及无关的页面背景。保留可见按钮,让这项操作不必依赖快捷键。

焦点位置 对象 普通键盘行为由谁处理?
E · 编辑器 note-draft,一个 textarea 文本编辑和当前输入法
T · 工具栏 preview-note,一个原生按钮 当前焦点按钮的正常激活行为
B · 背景 页面 body 或其他非编辑器位置 该位置本身;应用不借用它来执行这个快捷键

MDN 的 keydown 参考文档说明,按键事件以当前焦点元素为目标,并且可以冒泡。因此,页面级监听器需要明确的作用范围。在 document 收到编辑器事件,不代表每个 document 事件都属于编辑器命令。

本例中,只有笔记包含非空白文字时才允许预览。内容应原样复制到本地预览,源草稿和焦点都留在原处。空白判断只用于决定操作是否可用,不能借此裁剪一份有效笔记的内容。

把组合键定义准确

拟采用的组合键是 Control+Enter:按住 Control,同时不按 Shift、Alt/Option 或 Meta/Command。这是本例选择的绑定,不代表它在所有键盘设置中都没有冲突。

按以下顺序应用规则:

  1. 如果嵌套控件已经处理了事件,就不要干预。
  2. 如果焦点不在 note-draft 中,不执行快捷键。
  3. 如果这次按键动作属于组合输入或其提交边界,把它留给文本输入处理。
  4. 如果任一修饰键与精确组合不符,不执行快捷键。
  5. 如果按键仍被按住,或同一次物理按键已经触发预览,不再次预览。
  6. 如果笔记为空,导致预览不可用,不执行预览。
  7. 其余情况下,在符合条件的 keydown 上预览一次。取消这次已处理快捷键的默认动作,避免它同时编辑笔记。

这个快捷键处理器不取消被忽略的事件。尤其是普通 Enter,仍应供编辑器和输入法使用。可见 Preview 按钮的原生激活,是调用同一预览操作的另一条独立路径。

把组合输入与一次新命令分开

KeyboardEvent.isComposing说明事件是否处于组合输入会话期间。它是有用的信号,但单个 false 值不足以判断所有边界事件。MDN 的 keydown 指引讨论了组合输入的首尾按键:事件先后顺序可能使它们落在该区间之外。

在请求中采用三个有实际含义的阶段:

  • 组合输入前就绪: 当前没有组合输入,也没有尚未结束的提交按键动作。
  • 正在组合输入或提交: 候选选择、确认及其边界按键动作都属于输入过程。
  • 组合输入后就绪: 提交按键动作已经释放,用户开始一次新的命令按键。

“之后”不等于收到 compositionend 通知后的下一次 keydown。它意味着一次独立、符合条件的用户按键动作。实施时需要在选定的浏览器/输入法组合上区分这些状态。不要用猜测的延时掩盖不确定的边界,否则可能吞掉下一次有意触发的快捷键。

下面是完整的三乘三规则矩阵。每个单元格都假设组合键精确匹配、笔记非空、事件未被处理,并且在阶段允许时,按下的是一次新的、非重复的按键。

焦点 组合输入前就绪 正在组合输入或提交 组合输入后就绪
E · 编辑器 预览一次;焦点留在编辑器 不执行快捷键;保留文本输入处理 在新的按键上预览一次;焦点留在编辑器
T · 工具栏 不执行快捷键 不执行快捷键 不执行快捷键
B · 背景 不执行快捷键 不执行快捷键 不执行快捷键

工具栏一行中的“不执行快捷键”针对的是这个组合键。在获得焦点的 Preview 按钮上按普通 Enter,仍可正常激活按钮。不能为了让快捷键符合条件,就把焦点转移到编辑器。

用一份完整笔记走过这些规则

在这段虚构会话中,用户希望预览日文笔记 旅のメモ。各行描述的是预期用户操作,不是捕获的 DOM 事件序列;输入法事件的真实先后顺序,正是之后浏览器运行需要查明的事项之一。

步骤 用户操作或状态 预期应用结果
K1 让空编辑器获得焦点 预览不可用;尚未预览
K2 开始日文输入,并选择候选 旅のメモ 候选操作留在文本输入内;不预览
K3 用 Enter 确认候选 提交候选;提交按键动作不触发预览
K4 释放这次 Enter 按键动作,完成组合输入 笔记包含 旅のメモ;现在才可考虑新的快捷键
K5 在编辑器中重新按下 Control+Enter 预览次数变为 1;文字和焦点留在编辑器
K6 继续按住这个组合键,重复 keydown 到达 次数保持 1
K7 释放后,再按 Control+Shift+Enter 次数保持 1;多出的修饰键不匹配
K8 让 Preview 按钮获得焦点,并按 Control+Enter 快捷键不执行;次数保持 1
K9 释放组合键,在按钮上按普通 Enter 原生按钮激活产生预览;次数变为 2
K10 让页面背景获得焦点,并按 Control+Enter 次数保持 2;不跳转焦点
K11 回到编辑器,把笔记换成空格,再重新按下 Control+Enter 次数保持 2;空预览不替换已有预览
K12 输入 Review outline,释放输入按键,再重新按下 Control+Enter 次数变为 3;预览显示这份原样笔记

K3 值得按选定输入法的真实确认行为再运行一次。如果浏览器在相关 keydown 之前发出结束通知,该事件仍不能变成预览命令。同样,开始组合输入的按键,也不能仅仅因为开始通知尚未到达,就漏进应用操作。

复制这份实施请求

为虚构 Cove Review 编辑器增加一个本地预览快捷键。

对象:note-draft textarea、preview-note 原生按钮、本地预览面板。
首个验证目标:macOS 26 上的 Safari 26,输入源为 Japanese—Romaji
和 English (U.S.)。这些是选定目标,不是检测到的已安装版本。
实际运行时记录浏览器/操作系统的精确构建版本和输入设置。

Control+Enter 表示只按 Control,不按 Shift、Alt/Option 或 Meta/Command。
只有 note-draft 中符合条件的一次新按键,才可调用一次预览。
保留草稿原文,焦点留在编辑器。
可见按钮继续提供独立的原生激活路径。

按给定要求实现九个焦点/阶段单元格及 K1–K12。
不要处理已被嵌套控件消费的事件。
不要抢占普通 Enter、IME 确认、不匹配的修饰键、
背景事件或按住/重复按键。空内容或仅空白内容
不替换之前的预览。

检查真实的组合输入开始/结束顺序,以及提交键释放时点。
不要把 isComposing 单独作为依据,也不要用合成 KeyboardEvents
证明边界正常。说明兼容性后备处理及其适用范围。
如果无法可靠地区分,就对该输入组合禁用快捷键,
并保留可见 Preview 按钮。

保留普通编辑、其余工具栏,以及所有发送/保存行为。
返回限定范围的改动、事件顺序观察和填好的运行记录表。
不要修改 CueSpec 的 Fn 设置,也不要增加操作系统快捷键。

把实际观察放在预期旁边

对每个选定输入源使用这份运行记录表。作者尚未为这个示例运行浏览器或真实输入法。

检查项 预期 实际观察 运行状态
编辑器中的普通 Enter 正常文本输入行为;不预览 NOT_RUN
候选确认及开始/结束边界 提交成功;不漏出预览动作 NOT_RUN
编辑器中重新按下 Control+Enter 预览一次;保留草稿和焦点 NOT_RUN
按住组合键 同一次按键不产生第二次预览 NOT_RUN
多出的修饰键 不执行快捷键 NOT_RUN
工具栏组合键与原生 Enter 只有原生按钮激活产生预览 NOT_RUN
背景与仅空白的笔记 不执行快捷键 NOT_RUN

如果操作系统或输入法绑定拦截了这个组合键,先记录该结果,再选择其他绑定。真正有用的交付,是一个适合其输入上下文的快捷键,以及在它不适用时仍可使用的按钮。