mirror of
https://github.com/motajs/template.git
synced 2026-10-30 04:40:18 +08:00
refactor: 删除旧 hotkey
This commit is contained in:
parent
85d4b9f610
commit
a9b9be33d5
@ -1,508 +0,0 @@
|
||||
import { KeyCode } from '@motajs/client-base';
|
||||
import {
|
||||
deleteWith,
|
||||
generateBinary,
|
||||
keycode,
|
||||
spliceBy
|
||||
} from '@motajs/legacy-common';
|
||||
import { EventEmitter } from 'eventemitter3';
|
||||
import { isNil } from 'lodash-es';
|
||||
|
||||
// todo: 按下加速节流触发
|
||||
|
||||
interface HotkeyEvent {
|
||||
set: [id: string, key: KeyCode, assist: number];
|
||||
emit: [key: KeyCode, assist: number, type: KeyEmitType];
|
||||
press: [key: KeyCode];
|
||||
release: [key: KeyCode];
|
||||
}
|
||||
|
||||
type KeyEmitType =
|
||||
| 'up'
|
||||
| 'down'
|
||||
| 'down-repeat'
|
||||
| 'down-throttle'
|
||||
// todo: | 'down-accelerate'
|
||||
| 'down-timeout';
|
||||
|
||||
type KeyEventType = 'up' | 'down';
|
||||
|
||||
interface AssistHoykey {
|
||||
ctrl: boolean;
|
||||
shift: boolean;
|
||||
alt: boolean;
|
||||
}
|
||||
|
||||
interface RegisterHotkeyData extends Partial<AssistHoykey> {
|
||||
id: string;
|
||||
name: string;
|
||||
defaults: KeyCode;
|
||||
}
|
||||
|
||||
export interface HotkeyData extends Required<RegisterHotkeyData> {
|
||||
key: KeyCode;
|
||||
emits: Map<symbol, HotkeyEmitData>;
|
||||
group?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id 此处的id包含数字后缀
|
||||
* @returns 返回 `@void` 时,表示此次触发没有包含副作用,不会致使 `preventDefault` 被执行
|
||||
*/
|
||||
type HotkeyFunc = (
|
||||
id: string,
|
||||
code: KeyCode,
|
||||
assist: number,
|
||||
ev: KeyboardEvent
|
||||
) => void | '@void';
|
||||
|
||||
interface HotkeyEmitData {
|
||||
func: HotkeyFunc;
|
||||
onUp?: HotkeyFunc;
|
||||
config?: HotkeyEmitConfig;
|
||||
}
|
||||
|
||||
export interface HotkeyJSON {
|
||||
key: KeyCode;
|
||||
assist: number;
|
||||
}
|
||||
|
||||
export interface HotkeyEmitConfig {
|
||||
type: KeyEmitType;
|
||||
throttle?: number;
|
||||
accelerate?: number;
|
||||
timeout?: number;
|
||||
}
|
||||
|
||||
export class Hotkey extends EventEmitter<HotkeyEvent> {
|
||||
static list: Hotkey[];
|
||||
|
||||
id: string;
|
||||
name: string;
|
||||
data: Record<string, HotkeyData> = {};
|
||||
keyMap: Map<KeyCode, HotkeyData[]> = new Map();
|
||||
/** id to name */
|
||||
groupName: Record<string, string> = {
|
||||
none: '未分类按键'
|
||||
};
|
||||
/** id to keys */
|
||||
groups: Record<string, string[]> = {
|
||||
none: []
|
||||
};
|
||||
enabled: boolean = false;
|
||||
conditionMap: Map<symbol, () => boolean> = new Map();
|
||||
|
||||
/** 当前作用域 */
|
||||
scope: symbol = Symbol();
|
||||
private scopeStack: symbol[] = [];
|
||||
private grouping: string = 'none';
|
||||
|
||||
/** 当前正在按下的按键 */
|
||||
private pressed: Set<KeyCode> = new Set();
|
||||
/** 有哪些单次按下的按键已经触发 */
|
||||
private downEmitted: Set<KeyCode> = new Set();
|
||||
/** 按键按下时的时间 */
|
||||
private pressTime: Map<KeyCode, number> = new Map();
|
||||
/** 按键节流时间 */
|
||||
private throttleMap: Map<KeyCode, number> = new Map();
|
||||
|
||||
constructor(id: string, name: string) {
|
||||
super();
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册一个按键,id可以包含数字后缀,可以显示为同一个按键操作拥有多个按键可以触发
|
||||
* @param data 要注册的按键信息
|
||||
*/
|
||||
register(data: RegisterHotkeyData): this {
|
||||
const d: HotkeyData = {
|
||||
...data,
|
||||
ctrl: !!data.ctrl,
|
||||
shift: !!data.shift,
|
||||
alt: !!data.alt,
|
||||
key: data.defaults,
|
||||
emits: new Map(),
|
||||
group: this.grouping
|
||||
};
|
||||
this.ensureMap(d.key);
|
||||
if (d.id in this.data) {
|
||||
// console.warn(`已存在id为${d.id}的按键,已将其覆盖`);
|
||||
}
|
||||
this.data[d.id] = d;
|
||||
const arr = this.keyMap.get(d.key)!;
|
||||
arr.push(d);
|
||||
this.groups[this.grouping].push(d.id);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 实现一个按键按下时的操作
|
||||
* @param id 要实现的按键id,可以不包含数字后缀
|
||||
* @param func 按键按下时执行的函数
|
||||
* @param config 按键的配置信息
|
||||
*/
|
||||
realize(id: string, func: HotkeyFunc, config?: HotkeyEmitConfig): this {
|
||||
const toSet = Object.values(this.data).filter(v => {
|
||||
const split = v.id.split('_');
|
||||
const last = !isNaN(Number(split.at(-1)));
|
||||
return v.id === id || (last && split.slice(0, -1).join('_') === id);
|
||||
});
|
||||
if (toSet.length === 0) {
|
||||
throw new Error(`Realize nonexistent key '${id}'.`);
|
||||
}
|
||||
for (const key of toSet) {
|
||||
const data = key.emits.get(this.scope);
|
||||
if (!data) {
|
||||
key.emits.set(this.scope, { func, config });
|
||||
} else {
|
||||
// 同时注册抬起和按下
|
||||
const dataType = data.config?.type ?? 'up';
|
||||
const configType = config?.type ?? 'up';
|
||||
if (dataType === 'up' && configType !== 'up') {
|
||||
data.onUp = func;
|
||||
data.config ??= { type: configType };
|
||||
data.config.type = configType;
|
||||
} else if (dataType !== 'up' && configType === 'up') {
|
||||
data.onUp = func;
|
||||
} else {
|
||||
data.config = config;
|
||||
data.func = func;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用一个symbol作为当前作用域,之后调用{@link realize}所实现的按键功能将会添加至此作用域
|
||||
* @param symbol 当前作用域的symbol
|
||||
*/
|
||||
use(symbol: symbol): void {
|
||||
if (symbol === this.scope) return;
|
||||
this.dispose(symbol);
|
||||
this.scopeStack.push(symbol);
|
||||
this.scope = symbol;
|
||||
this.conditionMap.set(symbol, () => true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放一个作用域,释放后作用域将退回至删除的作用域的上一级
|
||||
* @param symbol 要释放的作用域的symbol
|
||||
*/
|
||||
dispose(symbol: symbol = this.scopeStack.at(-1) ?? Symbol()): void {
|
||||
const disposed = spliceBy(this.scopeStack, symbol);
|
||||
disposed.forEach(v => {
|
||||
for (const key of Object.values(this.data)) {
|
||||
key.emits.delete(v);
|
||||
}
|
||||
});
|
||||
this.scope = this.scopeStack.at(-1) ?? Symbol();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置一个按键信息
|
||||
* @param id 要设置的按键的id
|
||||
* @param key 要设置成的按键
|
||||
* @param assist 辅助按键,三位二进制数据,从低到高依次为`ctrl` `shift` `alt`
|
||||
* @param emit 是否触发set事件,当且仅当从fromJSON方法调用时为false
|
||||
*/
|
||||
set(id: string, key: KeyCode, assist: number, emit: boolean = true): void {
|
||||
const { ctrl, shift, alt } = unwarpBinary(assist);
|
||||
const data = this.data[id];
|
||||
if (!data) return;
|
||||
const before = this.keyMap.get(data?.key ?? KeyCode.Unknown)! ?? [];
|
||||
deleteWith(before, data);
|
||||
this.ensureMap(key);
|
||||
const after = this.keyMap.get(key)!;
|
||||
after.push(data);
|
||||
data.key = key;
|
||||
data.ctrl = ctrl;
|
||||
data.shift = shift;
|
||||
data.alt = alt;
|
||||
if (emit) this.emit('set', id, key, assist);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断指定按键和辅助按键是否可能会触发给定 id 的按键操作
|
||||
* @param key 按键
|
||||
* @param assist 辅助按键
|
||||
* @param id 注册的按键操作 id
|
||||
*/
|
||||
willEmit(key: KeyCode, assist: number, id: string) {
|
||||
const emittable = this.keyMap.get(key);
|
||||
if (!emittable) return false;
|
||||
const { ctrl, shift, alt } = unwarpBinary(assist);
|
||||
return emittable.some(v => {
|
||||
if (
|
||||
v.id === id &&
|
||||
v.ctrl === ctrl &&
|
||||
v.shift === shift &&
|
||||
v.alt === alt
|
||||
) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发一个按键
|
||||
* @param key 要触发的按键
|
||||
* @param assist 辅助按键,三位二进制数据,从低到高依次为`ctrl` `shift` `alt`
|
||||
* @returns 是否有按键被触发
|
||||
*/
|
||||
emitKey(
|
||||
key: KeyCode,
|
||||
assist: number,
|
||||
type: KeyEventType,
|
||||
ev: KeyboardEvent
|
||||
): boolean {
|
||||
// 检查全局启用情况
|
||||
if (!this.enabled) return false;
|
||||
const when = this.conditionMap.get(this.scope);
|
||||
if (type === 'up') this.checkPressEnd(key);
|
||||
else if (type === 'down') this.checkPress(key);
|
||||
if (when && !when()) return false;
|
||||
const toEmit = this.keyMap.get(key);
|
||||
if (!toEmit) return false;
|
||||
|
||||
// 进行按键初始处理
|
||||
const { ctrl, shift, alt } = unwarpBinary(assist);
|
||||
|
||||
// 真正开始触发按键
|
||||
let emitted = false;
|
||||
|
||||
toEmit.forEach(v => {
|
||||
if (ctrl === v.ctrl && shift === v.shift && alt === v.alt) {
|
||||
const data = v.emits.get(this.scope);
|
||||
if (!data) return;
|
||||
|
||||
if (type === 'up' && data.onUp) {
|
||||
data.onUp(v.id, key, assist, ev);
|
||||
emitted = true;
|
||||
return;
|
||||
}
|
||||
if (!this.canEmit(v.id, key, type, data)) return;
|
||||
const res = data.func(v.id, key, assist, ev);
|
||||
if (res !== '@void') emitted = true;
|
||||
}
|
||||
});
|
||||
this.emit('emit', key, assist, type);
|
||||
|
||||
if (type === 'down') {
|
||||
this.downEmitted.add(key);
|
||||
}
|
||||
|
||||
return emitted;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查按键按下情况,如果没有按下则添加
|
||||
* @param keyCode 按下的按键
|
||||
*/
|
||||
private checkPress(keyCode: KeyCode): void {
|
||||
if (this.pressed.has(keyCode)) return;
|
||||
this.pressed.add(keyCode);
|
||||
this.pressTime.set(keyCode, Date.now());
|
||||
this.emit('press', keyCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当按键松开时,移除相应的按下配置
|
||||
* @param keyCode 松开的按键
|
||||
*/
|
||||
private checkPressEnd(keyCode: KeyCode): void {
|
||||
if (!this.pressed.has(keyCode)) return;
|
||||
this.pressed.delete(keyCode);
|
||||
this.pressTime.delete(keyCode);
|
||||
this.downEmitted.delete(keyCode);
|
||||
this.emit('release', keyCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查一个按键是否可以被触发
|
||||
* @param id 触发的按键id
|
||||
* @param keyCode 按键码
|
||||
*/
|
||||
private canEmit(
|
||||
_id: string,
|
||||
keyCode: KeyCode,
|
||||
type: KeyEventType,
|
||||
data: HotkeyEmitData
|
||||
) {
|
||||
const config = data?.config;
|
||||
// 这时默认为抬起触发,始终可触发
|
||||
if (type === 'up') {
|
||||
if (!config || config.type === 'up') return true;
|
||||
else return false;
|
||||
}
|
||||
if (!config) return false;
|
||||
// 按下单次触发
|
||||
if (config.type === 'down') return !this.downEmitted.has(keyCode);
|
||||
// 按下重复触发
|
||||
if (config.type === 'down-repeat') return true;
|
||||
if (config.type === 'down-timeout') {
|
||||
const time = this.pressTime.get(keyCode);
|
||||
if (isNil(time) || isNil(config.timeout)) return false;
|
||||
return Date.now() - time >= config.timeout;
|
||||
}
|
||||
if (config.type === 'down-throttle') {
|
||||
const thorttleTime = this.throttleMap.get(keyCode);
|
||||
if (isNil(config.throttle)) return false;
|
||||
if (isNil(thorttleTime)) {
|
||||
this.throttleMap.set(keyCode, Date.now());
|
||||
return true;
|
||||
}
|
||||
if (Date.now() - thorttleTime >= config.throttle) {
|
||||
this.throttleMap.set(keyCode, Date.now());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按键分组,执行后 register 的按键将会加入此分组
|
||||
* @param id 组的id
|
||||
* @param name 组的名称
|
||||
*/
|
||||
group(id: string, name: string, keys?: RegisterHotkeyData[]): this {
|
||||
this.grouping = id;
|
||||
this.groupName[id] = name;
|
||||
this.groups[id] ??= [];
|
||||
keys?.forEach(v => this.register(v));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 启用这个按键控制器
|
||||
*/
|
||||
enable(): void {
|
||||
this.enabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 禁用这个按键控制器
|
||||
*/
|
||||
disable(): void {
|
||||
this.enabled = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 在当前作用域下,满足什么条件时触发按键
|
||||
* @param fn 条件函数
|
||||
*/
|
||||
when(fn: () => boolean): this {
|
||||
this.conditionMap.set(this.scope, fn);
|
||||
return this;
|
||||
}
|
||||
|
||||
toJSON(): string {
|
||||
const res: Record<string, HotkeyJSON> = {};
|
||||
for (const [key, data] of Object.entries(this.data)) {
|
||||
res[key] = {
|
||||
key: data.key,
|
||||
assist: generateBinary([data.ctrl, data.shift, data.alt])
|
||||
};
|
||||
}
|
||||
return JSON.stringify(res);
|
||||
}
|
||||
|
||||
fromJSON(data: string): void {
|
||||
const json: Record<string, HotkeyJSON> = JSON.parse(data);
|
||||
for (const [key, data] of Object.entries(json)) {
|
||||
this.set(key, data.key, data.assist, false);
|
||||
}
|
||||
}
|
||||
|
||||
private ensureMap(key: KeyCode) {
|
||||
if (!this.keyMap.has(key)) {
|
||||
this.keyMap.set(key, []);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据id获取hotkey实例
|
||||
* @param id 要获取的hotkey实例的id
|
||||
*/
|
||||
static get(id: string): Hotkey | undefined {
|
||||
return this.list.find(v => v.id === id);
|
||||
}
|
||||
}
|
||||
|
||||
export function unwarpBinary(bin: number): AssistHoykey {
|
||||
return {
|
||||
ctrl: !!(bin & (1 << 0)),
|
||||
shift: !!(bin & (1 << 1)),
|
||||
alt: !!(bin & (1 << 2))
|
||||
};
|
||||
}
|
||||
|
||||
export function checkAssist(bin: number, key: KeyCode): boolean {
|
||||
return (
|
||||
isAssist(key) &&
|
||||
!!(
|
||||
(1 << (key === KeyCode.Ctrl ? 0 : key === KeyCode.Shift ? 1 : 2)) &
|
||||
bin
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export function isAssist(
|
||||
key: KeyCode
|
||||
): key is KeyCode.Ctrl | KeyCode.Shift | KeyCode.Alt {
|
||||
return key === KeyCode.Ctrl || key === KeyCode.Shift || key === KeyCode.Alt;
|
||||
}
|
||||
|
||||
export const gameKey = new Hotkey('gameKey', '游戏按键');
|
||||
|
||||
// ----- Listening
|
||||
document.addEventListener('keyup', e => {
|
||||
const assist = generateBinary([e.ctrlKey, e.shiftKey, e.altKey]);
|
||||
const code = keycode(e.keyCode);
|
||||
if (
|
||||
code === KeyCode.Alt ||
|
||||
code === KeyCode.Shift ||
|
||||
code === KeyCode.Ctrl
|
||||
) {
|
||||
e.preventDefault();
|
||||
}
|
||||
if (gameKey.emitKey(code, assist, 'up', e)) {
|
||||
e.preventDefault();
|
||||
if (core.status.holdingKeys) {
|
||||
deleteWith(core.status.holdingKeys, e.keyCode);
|
||||
}
|
||||
} else {
|
||||
// polyfill样板
|
||||
if (main.dom.inputDiv.style.display === 'block') {
|
||||
if (e.keyCode === 13) {
|
||||
setTimeout(function () {
|
||||
main.dom.inputYes.click();
|
||||
}, 50);
|
||||
} else if (e.keyCode === 27) {
|
||||
setTimeout(function () {
|
||||
main.dom.inputNo.click();
|
||||
}, 50);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (
|
||||
core &&
|
||||
core.isPlaying &&
|
||||
core.status &&
|
||||
(core.isPlaying() || core.status.lockControl)
|
||||
)
|
||||
core.onkeyUp(e);
|
||||
}
|
||||
});
|
||||
document.addEventListener('keydown', e => {
|
||||
const assist = generateBinary([e.ctrlKey, e.shiftKey, e.altKey]);
|
||||
const code = keycode(e.keyCode);
|
||||
if (gameKey.emitKey(code, assist, 'down', e)) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
@ -1,205 +1,195 @@
|
||||
import {
|
||||
EventEmitter,
|
||||
Listener,
|
||||
deleteWith,
|
||||
flipBinary
|
||||
} from '@motajs/legacy-common';
|
||||
import { KeyCode } from '@motajs/client-base';
|
||||
import { gameKey } from './hotkey';
|
||||
import { unwarpBinary } from './hotkey';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { shallowReactive } from 'vue';
|
||||
// TODO: Refactor
|
||||
|
||||
export interface KeyboardEmits {
|
||||
key: KeyCode;
|
||||
assist: number;
|
||||
}
|
||||
// export interface KeyboardEmits {
|
||||
// key: KeyCode;
|
||||
// assist: number;
|
||||
// }
|
||||
|
||||
interface KeyboardItem {
|
||||
key: KeyCode;
|
||||
text?: string;
|
||||
x: number;
|
||||
y: number;
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
// interface KeyboardItem {
|
||||
// key: KeyCode;
|
||||
// text?: string;
|
||||
// x: number;
|
||||
// y: number;
|
||||
// width: number;
|
||||
// height: number;
|
||||
// }
|
||||
|
||||
interface VirtualKeyEmit {
|
||||
preventDefault(): void;
|
||||
preventAssist(): void;
|
||||
}
|
||||
// interface VirtualKeyEmit {
|
||||
// preventDefault(): void;
|
||||
// preventAssist(): void;
|
||||
// }
|
||||
|
||||
type VirtualKeyEmitFn = (
|
||||
item: KeyboardItem,
|
||||
assist: number,
|
||||
index: number,
|
||||
ev: VirtualKeyEmit
|
||||
) => void;
|
||||
// type VirtualKeyEmitFn = (
|
||||
// item: KeyboardItem,
|
||||
// assist: number,
|
||||
// index: number,
|
||||
// ev: VirtualKeyEmit
|
||||
// ) => void;
|
||||
|
||||
interface VirtualKeyboardEvent {
|
||||
add: (item: KeyboardItem) => void;
|
||||
remove: (item: KeyboardItem) => void;
|
||||
extend: (extended: Keyboard) => void;
|
||||
emit: VirtualKeyEmitFn;
|
||||
scopeCreate: (scope: symbol) => void;
|
||||
scopeDispose: (scope: symbol) => void;
|
||||
}
|
||||
// interface VirtualKeyboardEvent {
|
||||
// add: (item: KeyboardItem) => void;
|
||||
// remove: (item: KeyboardItem) => void;
|
||||
// extend: (extended: Keyboard) => void;
|
||||
// emit: VirtualKeyEmitFn;
|
||||
// scopeCreate: (scope: symbol) => void;
|
||||
// scopeDispose: (scope: symbol) => void;
|
||||
// }
|
||||
|
||||
/**
|
||||
* 虚拟按键,同一个虚拟按键实例应当只能同时操作一个,但可以显示多个
|
||||
*/
|
||||
export class Keyboard extends EventEmitter<VirtualKeyboardEvent> {
|
||||
static list: Keyboard[] = [];
|
||||
// /**
|
||||
// * 虚拟按键,同一个虚拟按键实例应当只能同时操作一个,但可以显示多个
|
||||
// */
|
||||
// export class Keyboard extends EventEmitter<VirtualKeyboardEvent> {
|
||||
// static list: Keyboard[] = [];
|
||||
|
||||
id: string;
|
||||
keys: KeyboardItem[] = [];
|
||||
assist: number = 0;
|
||||
fontSize: number = 18;
|
||||
// id: string;
|
||||
// keys: KeyboardItem[] = [];
|
||||
// assist: number = 0;
|
||||
// fontSize: number = 18;
|
||||
|
||||
scope: symbol = Symbol();
|
||||
private scopeStack: symbol[] = [];
|
||||
private onEmitKey: Record<symbol, Listener<VirtualKeyEmitFn>[]> = {};
|
||||
private scopeAssist: Record<symbol, number> = {};
|
||||
// scope: symbol = Symbol();
|
||||
// private scopeStack: symbol[] = [];
|
||||
// private onEmitKey: Record<symbol, Listener<VirtualKeyEmitFn>[]> = {};
|
||||
// private scopeAssist: Record<symbol, number> = {};
|
||||
|
||||
constructor(id: string) {
|
||||
super();
|
||||
this.id = id;
|
||||
Keyboard.list.push(this);
|
||||
}
|
||||
// constructor(id: string) {
|
||||
// super();
|
||||
// this.id = id;
|
||||
// Keyboard.list.push(this);
|
||||
// }
|
||||
|
||||
/**
|
||||
* 给虚拟键盘添加一个按键
|
||||
* @param item 按键信息
|
||||
*/
|
||||
add(item: KeyboardItem) {
|
||||
const i = shallowReactive(item);
|
||||
this.keys.push(i);
|
||||
this.emit('add', i);
|
||||
return this;
|
||||
}
|
||||
// /**
|
||||
// * 给虚拟键盘添加一个按键
|
||||
// * @param item 按键信息
|
||||
// */
|
||||
// add(item: KeyboardItem) {
|
||||
// const i = shallowReactive(item);
|
||||
// this.keys.push(i);
|
||||
// this.emit('add', i);
|
||||
// return this;
|
||||
// }
|
||||
|
||||
/**
|
||||
* 移除一个按键
|
||||
* @param item 按键信息
|
||||
*/
|
||||
remove(item: KeyboardItem) {
|
||||
deleteWith(this.keys, item);
|
||||
this.emit('remove', item);
|
||||
return this;
|
||||
}
|
||||
// /**
|
||||
// * 移除一个按键
|
||||
// * @param item 按键信息
|
||||
// */
|
||||
// remove(item: KeyboardItem) {
|
||||
// deleteWith(this.keys, item);
|
||||
// this.emit('remove', item);
|
||||
// return this;
|
||||
// }
|
||||
|
||||
/**
|
||||
* 创造一个在某些辅助按键已经按下的情况下的作用域,这些被按下的辅助按键还可以被玩家手动取消
|
||||
* @param assist 辅助按键
|
||||
*/
|
||||
withAssist(assist: number) {
|
||||
const symbol = this.createScope();
|
||||
this.assist = assist;
|
||||
return symbol;
|
||||
}
|
||||
// /**
|
||||
// * 创造一个在某些辅助按键已经按下的情况下的作用域,这些被按下的辅助按键还可以被玩家手动取消
|
||||
// * @param assist 辅助按键
|
||||
// */
|
||||
// withAssist(assist: number) {
|
||||
// const symbol = this.createScope();
|
||||
// this.assist = assist;
|
||||
// return symbol;
|
||||
// }
|
||||
|
||||
/**
|
||||
* 创造一个虚拟按键作用域,所有监听的事件与其他作用域不冲突
|
||||
* @returns 作用域的唯一标识符
|
||||
*/
|
||||
createScope() {
|
||||
const last = this.scopeStack.at(-1);
|
||||
const symbol = Symbol();
|
||||
this.scope = symbol;
|
||||
this.scopeStack.push(symbol);
|
||||
const ev: Listener<VirtualKeyEmitFn>[] = [];
|
||||
this.onEmitKey[symbol] = ev;
|
||||
// @ts-expect-error 无法推导
|
||||
this.events = ev;
|
||||
this.emit('scopeCreate', symbol);
|
||||
if (last) {
|
||||
this.scopeAssist[symbol] = this.assist;
|
||||
}
|
||||
this.assist = 0;
|
||||
this.scopeAssist[symbol] = 0;
|
||||
return symbol;
|
||||
}
|
||||
// /**
|
||||
// * 创造一个虚拟按键作用域,所有监听的事件与其他作用域不冲突
|
||||
// * @returns 作用域的唯一标识符
|
||||
// */
|
||||
// createScope() {
|
||||
// const last = this.scopeStack.at(-1);
|
||||
// const symbol = Symbol();
|
||||
// this.scope = symbol;
|
||||
// this.scopeStack.push(symbol);
|
||||
// const ev: Listener<VirtualKeyEmitFn>[] = [];
|
||||
// this.onEmitKey[symbol] = ev;
|
||||
// // @ts-expect-error 无法推导
|
||||
// this.events = ev;
|
||||
// this.emit('scopeCreate', symbol);
|
||||
// if (last) {
|
||||
// this.scopeAssist[symbol] = this.assist;
|
||||
// }
|
||||
// this.assist = 0;
|
||||
// this.scopeAssist[symbol] = 0;
|
||||
// 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];
|
||||
delete this.scopeAssist[now];
|
||||
const symbol = this.scopeStack.at(-1);
|
||||
this.emit('scopeDispose', now);
|
||||
if (!symbol) return;
|
||||
this.scope = symbol;
|
||||
this.assist = this.scopeAssist[symbol];
|
||||
// @ts-expect-error 无法推导
|
||||
this.events = this.onEmitKey[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];
|
||||
// delete this.scopeAssist[now];
|
||||
// const symbol = this.scopeStack.at(-1);
|
||||
// this.emit('scopeDispose', now);
|
||||
// if (!symbol) return;
|
||||
// this.scope = symbol;
|
||||
// this.assist = this.scopeAssist[symbol];
|
||||
// // @ts-expect-error 无法推导
|
||||
// this.events = this.onEmitKey[symbol];
|
||||
// }
|
||||
|
||||
/**
|
||||
* 继承一个按键的按键信息
|
||||
* @param keyboard 要被继承的按键
|
||||
* @param offsetX 被继承的按键的横坐标偏移量
|
||||
* @param offsetY 被继承的按键的纵坐标偏移量
|
||||
*/
|
||||
extend(keyboard: Keyboard, offsetX: number = 0, offsetY: number = 0) {
|
||||
const toClone = cloneDeep(keyboard.keys);
|
||||
toClone.forEach(v => {
|
||||
v.x += offsetX;
|
||||
v.y += offsetY;
|
||||
});
|
||||
// /**
|
||||
// * 继承一个按键的按键信息
|
||||
// * @param keyboard 要被继承的按键
|
||||
// * @param offsetX 被继承的按键的横坐标偏移量
|
||||
// * @param offsetY 被继承的按键的纵坐标偏移量
|
||||
// */
|
||||
// extend(keyboard: Keyboard, offsetX: number = 0, offsetY: number = 0) {
|
||||
// const toClone = cloneDeep(keyboard.keys);
|
||||
// toClone.forEach(v => {
|
||||
// v.x += offsetX;
|
||||
// v.y += offsetY;
|
||||
// });
|
||||
|
||||
this.keys.push(...toClone);
|
||||
this.emit('extend', keyboard);
|
||||
return this;
|
||||
}
|
||||
// this.keys.push(...toClone);
|
||||
// this.emit('extend', keyboard);
|
||||
// return this;
|
||||
// }
|
||||
|
||||
/**
|
||||
* 触发按键
|
||||
* @param key 要触发的按键
|
||||
*/
|
||||
emitKey(key: KeyboardItem, index: number) {
|
||||
let prevent = false;
|
||||
let preventAss = false;
|
||||
const preventDefault = () => (prevent = true);
|
||||
const preventAssist = () => (preventAss = true);
|
||||
this.emit('emit', key, this.assist, index, {
|
||||
preventDefault,
|
||||
preventAssist
|
||||
});
|
||||
// /**
|
||||
// * 触发按键
|
||||
// * @param key 要触发的按键
|
||||
// */
|
||||
// emitKey(key: KeyboardItem, index: number) {
|
||||
// let prevent = false;
|
||||
// let preventAss = false;
|
||||
// const preventDefault = () => (prevent = true);
|
||||
// const preventAssist = () => (preventAss = true);
|
||||
// this.emit('emit', key, this.assist, index, {
|
||||
// preventDefault,
|
||||
// preventAssist
|
||||
// });
|
||||
|
||||
if (!preventAss) {
|
||||
if (key.key === KeyCode.Ctrl) {
|
||||
this.assist = flipBinary(this.assist, 0);
|
||||
} else if (key.key === KeyCode.Shift) {
|
||||
this.assist = flipBinary(this.assist, 1);
|
||||
} else if (key.key === KeyCode.Alt) {
|
||||
this.assist = flipBinary(this.assist, 2);
|
||||
}
|
||||
}
|
||||
if (!prevent) {
|
||||
const ev = generateKeyboardEvent(key.key, this.assist);
|
||||
gameKey.emitKey(key.key, this.assist, 'up', ev);
|
||||
}
|
||||
}
|
||||
// if (!preventAss) {
|
||||
// if (key.key === KeyCode.Ctrl) {
|
||||
// this.assist = flipBinary(this.assist, 0);
|
||||
// } else if (key.key === KeyCode.Shift) {
|
||||
// this.assist = flipBinary(this.assist, 1);
|
||||
// } else if (key.key === KeyCode.Alt) {
|
||||
// this.assist = flipBinary(this.assist, 2);
|
||||
// }
|
||||
// }
|
||||
// if (!prevent) {
|
||||
// const ev = generateKeyboardEvent(key.key, this.assist);
|
||||
// gameKey.emitKey(key.key, this.assist, 'up', ev);
|
||||
// }
|
||||
// }
|
||||
|
||||
static get(id: string) {
|
||||
return this.list.find(v => v.id === id);
|
||||
}
|
||||
}
|
||||
// static get(id: string) {
|
||||
// return this.list.find(v => v.id === id);
|
||||
// }
|
||||
// }
|
||||
|
||||
export function generateKeyboardEvent(_key: KeyCode, assist: number) {
|
||||
const { ctrl, alt, shift } = unwarpBinary(assist);
|
||||
const ev = new KeyboardEvent('keyup', {
|
||||
ctrlKey: ctrl,
|
||||
shiftKey: shift,
|
||||
altKey: alt
|
||||
});
|
||||
// export function generateKeyboardEvent(_key: KeyCode, assist: number) {
|
||||
// const { ctrl, alt, shift } = unwarpBinary(assist);
|
||||
// const ev = new KeyboardEvent('keyup', {
|
||||
// ctrlKey: ctrl,
|
||||
// shiftKey: shift,
|
||||
// altKey: alt
|
||||
// });
|
||||
|
||||
return ev;
|
||||
}
|
||||
// return ev;
|
||||
// }
|
||||
|
||||
@ -11,7 +11,6 @@ import {
|
||||
IGameUIPropsBase,
|
||||
useKey
|
||||
} from '@user/client-base';
|
||||
import { gameKey, generateKeyboardEvent } from '@motajs/system';
|
||||
import { getInput } from '@user/client-base';
|
||||
import { openStatistics } from './statistics';
|
||||
import { saveWithExist } from './save';
|
||||
@ -68,14 +67,14 @@ export const MainSettings = defineComponent<MainSettingsProps>(props => {
|
||||
break;
|
||||
}
|
||||
case MainChoice.VirtualKey: {
|
||||
getVitualKeyOnce().then(value => {
|
||||
gameKey.emitKey(
|
||||
value.key,
|
||||
value.assist,
|
||||
'up',
|
||||
generateKeyboardEvent(value.key, value.assist)
|
||||
);
|
||||
});
|
||||
// getVitualKeyOnce().then(value => {
|
||||
// gameKey.emitKey(
|
||||
// value.key,
|
||||
// value.assist,
|
||||
// 'up',
|
||||
// generateKeyboardEvent(value.key, value.assist)
|
||||
// );
|
||||
// });
|
||||
break;
|
||||
}
|
||||
case MainChoice.ViewMap: {
|
||||
|
||||
@ -11,7 +11,6 @@ import {
|
||||
StepForward,
|
||||
ViewMapIcon
|
||||
} from '@user/client-base';
|
||||
import { gameKey, generateKeyboardEvent } from '@motajs/system';
|
||||
import { linear } from 'mutate-animate';
|
||||
import { KeyCode } from '@motajs/system';
|
||||
import { Progress } from '@user/client-base';
|
||||
@ -96,14 +95,14 @@ export const PlayingToolbar = defineComponent<
|
||||
const equip = () => core.openEquipbox(true);
|
||||
const shop = () => core.openQuickShop(true);
|
||||
const key = () => {
|
||||
getVitualKeyOnce().then(value => {
|
||||
gameKey.emitKey(
|
||||
value.key,
|
||||
value.assist,
|
||||
'up',
|
||||
generateKeyboardEvent(value.key, value.assist)
|
||||
);
|
||||
});
|
||||
// getVitualKeyOnce().then(value => {
|
||||
// gameKey.emitKey(
|
||||
// value.key,
|
||||
// value.assist,
|
||||
// 'up',
|
||||
// generateKeyboardEvent(value.key, value.assist)
|
||||
// );
|
||||
// });
|
||||
};
|
||||
const undo = () => core.doSL('autoSave', 'load');
|
||||
const redo = () => core.doSL('autoSave', 'reload');
|
||||
@ -299,13 +298,13 @@ export const NumpadToolbar = defineComponent<
|
||||
};
|
||||
|
||||
const clickNum = (num: number) => {
|
||||
const bin = generateBinary([
|
||||
ctrlEnabled.value,
|
||||
shiftEnabled.value,
|
||||
altEnabled.value
|
||||
]);
|
||||
const code = (KeyCode.Digit0 + num) as KeyCode;
|
||||
gameKey.emitKey(code, bin, 'up', generateKeyboardEvent(code, bin));
|
||||
// const bin = generateBinary([
|
||||
// ctrlEnabled.value,
|
||||
// shiftEnabled.value,
|
||||
// altEnabled.value
|
||||
// ]);
|
||||
// const code = (KeyCode.Digit0 + num) as KeyCode;
|
||||
// gameKey.emitKey(code, bin, 'up', generateKeyboardEvent(code, bin));
|
||||
};
|
||||
|
||||
return () => (
|
||||
|
||||
Loading…
Reference in New Issue
Block a user