116 lines
2.7 KiB
TypeScript
116 lines
2.7 KiB
TypeScript
type KeyboardCallback = (e: KeyboardEvent) => void
|
|
|
|
export class KeyboardManager {
|
|
private shortcuts: Map<string, KeyboardCallback> = new Map()
|
|
private pressedKeys: Set<string> = new Set()
|
|
private enabled: boolean = false
|
|
|
|
constructor() {
|
|
this.handleKeyDown = this.handleKeyDown.bind(this)
|
|
this.handleKeyUp = this.handleKeyUp.bind(this)
|
|
}
|
|
|
|
/**
|
|
* 启用快捷键监听
|
|
*/
|
|
enable(): void {
|
|
if (!this.enabled) {
|
|
window.addEventListener('keydown', this.handleKeyDown)
|
|
window.addEventListener('keyup', this.handleKeyUp)
|
|
this.enabled = true
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 禁用快捷键监听
|
|
*/
|
|
disable(): void {
|
|
if (this.enabled) {
|
|
window.removeEventListener('keydown', this.handleKeyDown)
|
|
window.removeEventListener('keyup', this.handleKeyUp)
|
|
this.enabled = false
|
|
this.pressedKeys.clear()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 绑定快捷键
|
|
*/
|
|
bind(shortcut: string, callback: KeyboardCallback): void {
|
|
this.shortcuts.set(this.normalizeShortcut(shortcut), callback)
|
|
}
|
|
|
|
/**
|
|
* 解绑快捷键
|
|
*/
|
|
unbind(shortcut: string): void {
|
|
this.shortcuts.delete(this.normalizeShortcut(shortcut))
|
|
}
|
|
|
|
/**
|
|
* 清除所有快捷键绑定
|
|
*/
|
|
clear(): void {
|
|
this.shortcuts.clear()
|
|
this.pressedKeys.clear()
|
|
}
|
|
|
|
private handleKeyDown(e: KeyboardEvent): void {
|
|
// 忽略在输入框中的按键
|
|
if (this.shouldIgnoreInput(e)) {
|
|
return
|
|
}
|
|
|
|
const key = this.normalizeKey(e.key.toLowerCase())
|
|
this.pressedKeys.add(key)
|
|
|
|
const currentShortcut = Array.from(this.pressedKeys).sort().join('+')
|
|
const callback = this.shortcuts.get(currentShortcut)
|
|
|
|
if (callback) {
|
|
e.preventDefault()
|
|
e.stopPropagation()
|
|
callback(e)
|
|
}
|
|
}
|
|
|
|
private handleKeyUp(e: KeyboardEvent): void {
|
|
const key = this.normalizeKey(e.key.toLowerCase())
|
|
this.pressedKeys.delete(key)
|
|
}
|
|
|
|
private normalizeKey(key: string): string {
|
|
const keyMap: Record<string, string> = {
|
|
'control': 'ctrl',
|
|
'command': 'cmd',
|
|
'meta': 'cmd',
|
|
'escape': 'esc',
|
|
' ': 'space',
|
|
'arrowup': 'up',
|
|
'arrowdown': 'down',
|
|
'arrowleft': 'left',
|
|
'arrowright': 'right',
|
|
}
|
|
return keyMap[key] || key
|
|
}
|
|
|
|
private normalizeShortcut(shortcut: string): string {
|
|
return shortcut
|
|
.toLowerCase()
|
|
.split('+')
|
|
.map(key => this.normalizeKey(key.trim()))
|
|
.sort()
|
|
.join('+')
|
|
}
|
|
|
|
private shouldIgnoreInput(e: KeyboardEvent): boolean {
|
|
const element = e.target as HTMLElement
|
|
return element.tagName === 'INPUT' ||
|
|
element.tagName === 'TEXTAREA' ||
|
|
element.tagName === 'SELECT' ||
|
|
element.isContentEditable
|
|
}
|
|
}
|
|
|
|
// 导出单例实例
|
|
export const keyboardManager = new KeyboardManager()
|