一、最终代码(带满屏注释)
// Babylon.js 键盘事件枚举
import { KeyboardEventTypes } from "@babylonjs/core";
// 全局事件总线(mitt)
import { emitter } from "../../utils/EventBus";
// 编辑器系统,内部有 keyboardController
import type { EditorSystem } from "../EditorSystem";
/**
* 快捷键管理器
* 职责:
* 1. 监听键盘事件
* 2. 根据规则分发事件到 EventBus
* 3. 支持单键 & Ctrl+? 组合键
*/
export class ShortCutsManager {
// 编辑器引用,主要用来拿 keyboardController
private _editorSystem: EditorSystem;
/**
* 单键映射
* key -> EventName
*/
private _shortcutDictionary: ShortcutDictionary = {
q: "selectMode",
w: "moveMode",
e: "rotateMode",
r: "scaleMode",
delete: "openDeleteConfirm"
};
/**
* Ctrl+? 组合键映射
* 仅记录“字母部分”,判断时再加前缀 "Control"
*/
private _ctrlShortcutDictionary: ShortcutDictionary = {
s: "saveScene", // Ctrl+S
o: "openScene", // Ctrl+O
n: "newScene", // Ctrl+N
z: "undo", // Ctrl+Z
y: "redo" // Ctrl+Y
};
constructor(editorSystem: EditorSystem) {
this._editorSystem = editorSystem;
this._init();
}
/** 初始化:注册键盘事件 */
private _init(): void {
const keyboardController = this._editorSystem.keyboardController;
if (!keyboardController) {
console.error("GlobalKeyboardController is not initialized.");
return;
}
// 监听所有 KEYDOWN 事件
keyboardController.addListener(KeyboardEventTypes.KEYDOWN, () => {
// 当前按下的单个字符(已转成小写)
const onlyKey = keyboardController.pressedSingleNormalKey?.trim().toLowerCase();
if (!onlyKey) return; // 没按字符键直接返回
// ---------- 组合键优先 ----------
if (keyboardController.isModifierKeysCombined(["Control"])) {
const eventName = this._ctrlShortcutDictionary[onlyKey];
if (eventName) {
emitter.emit(eventName);
return; // 命中组合键后不再走单键
}
}
// ---------- 单键 ----------
const eventName = this._shortcutDictionary[onlyKey];
if (eventName) {
emitter.emit(eventName);
}
});
}
}
/** 字典类型:string -> string */
interface ShortcutDictionary {
[key: string]: string;
}
二、怎么用
任意地方监听
import { emitter } from '@/utils/EventBus';
emitter.on('undo', () => console.log('撤销'));
emitter.on('saveScene', () => scene.save());