diff --git a/src/core/common/eventEmitter.ts b/src/core/common/eventEmitter.ts index f8834eb..8b9c1b4 100644 --- a/src/core/common/eventEmitter.ts +++ b/src/core/common/eventEmitter.ts @@ -5,13 +5,13 @@ export interface EmitableEvent { [event: string]: (...params: any) => any; } -interface Listener any> { +export interface Listener any> { fn: T; once?: boolean; immediate?: boolean; } -interface ListenerOptions { +export interface ListenerOptions { once: boolean; immediate: boolean; } @@ -22,12 +22,12 @@ type EmitFn any> = ( ) => any; export class EventEmitter { - private events: { + protected events: { [P in keyof T]?: Listener[]; } = {}; private emitted: (keyof T)[] = []; - private emitter: { + protected emitter: { [P in keyof T]?: EmitFn; } = {}; diff --git a/src/core/main/custom/keyboard.ts b/src/core/main/custom/keyboard.ts index 6c1bc5c..1ca75e8 100644 --- a/src/core/main/custom/keyboard.ts +++ b/src/core/main/custom/keyboard.ts @@ -1,9 +1,14 @@ -import { EmitableEvent, EventEmitter } from '@/core/common/eventEmitter'; +import { + EmitableEvent, + EventEmitter, + Listener +} from '@/core/common/eventEmitter'; import { KeyCode } from '@/plugin/keyCodes'; import { gameKey } from '../init/hotkey'; import { unwarpBinary } from './hotkey'; import { deleteWith } from '@/plugin/utils'; import { cloneDeep } from 'lodash-es'; +import { shallowReactive } from 'vue'; export interface KeyboardEmits { key: KeyCode; @@ -17,16 +22,30 @@ interface KeyboardItem { y: number; width: number; height: number; + active?: boolean; } interface AssistManager { + symbol: symbol; end(): void; } +interface VirtualKeyEmit { + preventDefault(): void; +} + +type VirtualKeyEmitFn = ( + item: KeyboardItem, + assist: number, + index: number, + ev: VirtualKeyEmit +) => void; + interface VirtualKeyboardEvent extends EmitableEvent { add: (item: KeyboardItem) => void; remove: (item: KeyboardItem) => void; - emit: (item: KeyboardItem, assist: number, index: number) => void; + extend: (extended: Keyboard) => void; + emit: VirtualKeyEmitFn; } /** @@ -38,6 +57,11 @@ export class Keyboard extends EventEmitter { id: string; keys: KeyboardItem[] = []; assist: number = 0; + fontSize: number = 18; + + scope: symbol = Symbol(); + private scopeStack: symbol[] = []; + private onEmitKey: Record[]> = {}; constructor(id: string) { super(); @@ -50,8 +74,10 @@ export class Keyboard extends EventEmitter { * @param item 按键信息 */ add(item: KeyboardItem) { - this.keys.push(item); - this.emit('add', item); + const i = shallowReactive(item); + this.keys.push(i); + this.emit('add', i); + return this; } /** @@ -61,6 +87,7 @@ export class Keyboard extends EventEmitter { remove(item: KeyboardItem) { deleteWith(this.keys, item); this.emit('remove', item); + return this; } /** @@ -71,14 +98,49 @@ export class Keyboard extends EventEmitter { withAssist(assist: number): AssistManager { const thisAssist = this.assist; this.assist = assist; + const symbol = this.createScope(); return { + symbol, end: () => { this.assist = thisAssist; } }; } + /** + * 创造一个虚拟按键作用域,所有监听的事件与其他作用域不冲突 + * @returns 作用域的唯一标识符 + */ + createScope() { + const symbol = Symbol(); + this.scope = symbol; + this.scopeStack.push(symbol); + const ev: Listener[] = []; + this.onEmitKey[symbol] = ev; + // @ts-ignore + this.events = ev; + return symbol; + } + + /** + * 释放一个作用域,同时删除其中的所有监听器 + */ + disposeScope() { + if (this.scopeStack.length === 0) { + throw new Error( + `Cannot dispose virtual key scope since there's no scope to be disposed.` + ); + } + const now = this.scopeStack.pop()!; + delete this.onEmitKey[now]; + const symbol = this.scopeStack.at(-1); + if (!symbol) return; + this.scope = symbol; + // @ts-ignore + this.events = this.onEmitKey[symbol]; + } + /** * 继承一个按键的按键信息 * @param keyboard 要被继承的按键 @@ -93,6 +155,7 @@ export class Keyboard extends EventEmitter { }); this.keys.push(...toClone); + this.emit('extend', keyboard); } /** @@ -100,9 +163,14 @@ export class Keyboard extends EventEmitter { * @param key 要触发的按键 */ emitKey(key: KeyboardItem, index: number) { - const ev = generateKeyboardEvent(key.key, this.assist); - gameKey.emitKey(key.key, this.assist, 'up', ev); - this.emit('emit', key, this.assist, index); + let prevent = false; + const preventDefault = () => (prevent = true); + this.emit('emit', key, this.assist, index, { preventDefault }); + + if (!prevent) { + const ev = generateKeyboardEvent(key.key, this.assist); + gameKey.emitKey(key.key, this.assist, 'up', ev); + } } static get(id: string) { diff --git a/src/core/main/init/index.ts b/src/core/main/init/index.ts index f03e3ef..076c3d8 100644 --- a/src/core/main/init/index.ts +++ b/src/core/main/init/index.ts @@ -1,2 +1,3 @@ import './fixed'; import './hotkey'; +import './keyboard'; diff --git a/src/core/main/init/keyboard.ts b/src/core/main/init/keyboard.ts new file mode 100644 index 0000000..6474cd6 --- /dev/null +++ b/src/core/main/init/keyboard.ts @@ -0,0 +1,27 @@ +import { KeyCode } from '@/plugin/keyCodes'; +import { Keyboard } from '../custom/keyboard'; + +const qweKey = new Keyboard('qwe'); +qweKey.fontSize = 20; +qweKey + .add({ + key: KeyCode.KeyQ, + x: 0, + y: 0, + width: 45, + height: 45 + }) + .add({ + key: KeyCode.KeyW, + x: 50, + y: 0, + width: 45, + height: 45 + }) + .add({ + key: KeyCode.KeyA, + x: 10, + y: 50, + width: 45, + height: 45 + }); diff --git a/src/panel/keyboard.vue b/src/panel/keyboard.vue index 1562da6..c216379 100644 --- a/src/panel/keyboard.vue +++ b/src/panel/keyboard.vue @@ -1,16 +1,35 @@