Appearance
快捷键注册表
背景:快捷键分散在各模块中,没有统一注册和冲突检测。shortcut-registry 提供集中管理。 过程:定义 ShortcutRegistry 类 → 注册/注销 API → 冲突检测 → 全局键盘事件监听 → 快捷键设置 UI。
序
七月十日,上午。
Riku 打开应用,按下 Ctrl+Space。什么也没发生。
"快捷键不工作了," 他对 Jieling 说。
"哪个快捷键?"
"Ctrl+Space,切换动作模式。"
Riku 打开代码,搜索 Ctrl+Space。找到三处:
main.ts里注册了Ctrl+Space→ 切换动作模式scene.ts里注册了Ctrl+Space→ 切换相机模式outfit.ts里注册了Ctrl+Space→ 切换服装预设
"三个模块抢同一个快捷键," Riku 说,"最后一个注册的覆盖前面的。"
"所以 Ctrl+Space 现在是切换服装预设?"
"对。"
"这不行。"
注册表
Riku 打开 src/core/shortcut-registry.ts。
核心思路:所有快捷键统一注册到一个 Registry,Registry 负责冲突检测和事件分发。
typescript
class ShortcutRegistry {
private shortcuts: Map<string, ShortcutHandler>;
private conflicts: Map<string, string[]>;
constructor() {
this.shortcuts = new Map();
this.conflicts = new Map();
}
register(key: string, handler: ShortcutHandler, source: string): void {
if (this.shortcuts.has(key)) {
// 冲突!记录两个来源
const existing = this.shortcuts.get(key)!;
this.conflicts.set(key, [existing.source, source]);
console.warn(`快捷键冲突: ${key} 被 ${existing.source} 和 ${source} 注册`);
}
this.shortcuts.set(key, { handler, source });
}
unregister(key: string, source: string): void {
const existing = this.shortcuts.get(key);
if (existing?.source === source) {
this.shortcuts.delete(key);
}
}
}"冲突检测是关键," Riku 说,"如果两个模块注册同一个快捷键,Registry 会记录冲突并打印警告。开发者在控制台就能看到。"
"但不会阻止注册?" Jieling 问。
"不会," Riku 说,"先注册的生效,后注册的被忽略。但警告会提醒开发者修复冲突。"
事件
Registry 监听全局键盘事件:
typescript
function _initKeyboardListener(): void {
document.addEventListener('keydown', (e) => {
const key = _buildKeyString(e); // 如 'Ctrl+Space'
const shortcut = registry.get(key);
if (shortcut) {
e.preventDefault();
shortcut.handler(e);
}
});
}"_buildKeyString 把键盘事件转换成标准化的 key 字符串," Riku 解释,"比如 Ctrl+Shift+A、Alt+Space、F5。"
"修饰键顺序呢?" Jieling 问。
"按 Ctrl → Alt → Shift → 普通键排序," Riku 说,"保证 Ctrl+Shift+A 和 Shift+Ctrl+A 是同一个 key。"
设置
Riku 在 src/menus/settings-shortcuts.ts 里加了快捷键设置 UI:
- 列出所有已注册的快捷键
- 显示当前绑定的 key
- 允许用户修改绑定
typescript
function buildShortcutsLevel(): PopupLevel {
const shortcuts = shortcutRegistry.getAll();
return {
title: '快捷键设置',
items: shortcuts.map(s => ({
text: s.description,
subText: s.key,
onClick: () => _editShortcut(s),
})),
};
}"用户可以修改绑定," Riku 说,"但不能删除快捷键。只能改 key。"
"为什么不能删除?" Jieling 问。
"因为快捷键是功能入口," Riku 说,"删除快捷键等于隐藏功能。用户找不到功能,会以为功能不存在。"
尾声
Riku 提交了代码。
feat: ShortcutRegistry 快捷键注册表(集中管理 + 冲突检测)
feat: 快捷键设置 UI(settings-shortcuts.ts)他打开应用,按下 Ctrl+Space。现在它切换动作模式了。
"冲突修复了?" Jieling 问。
"对," Riku 说,"scene.ts 和 outfit.ts 的 Ctrl+Space 改成了其他 key。"
他站在窗边,看着远处的天际线。七月的阳光已经落下去了,路灯一盏一盏亮起来。
快捷键注册表。不是复杂的配置系统,只是一个 Map + 冲突检测。但它把"三个模块抢同一个快捷键"的问题解决了。
"快捷键是城市的交通规则," Riku 对自己说,"注册表是交通管理局。"
教训:快捷键管理不是"注册事件监听"那么简单。集中注册、冲突检测、标准化 key 字符串——这些是让快捷键"不打架"的基础。ShortcutRegistry 不是银弹,但它把"快捷键冲突"的问题从运行时提前到了注册时。