From 02088aae00ac4f3ffb7493ce86f9bcb4fd02b40c Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Sat, 18 Nov 2023 21:46:11 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=B8=B8=E6=88=8F=E6=8C=89?= =?UTF-8?q?=E9=94=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/main/custom/hotkey.ts | 242 ++++++----------------- src/core/main/init/hotkey.ts | 338 +++++++++++++++++++++++++++++++++ src/core/main/init/index.ts | 1 + src/ui/settings.vue | 5 - 4 files changed, 394 insertions(+), 192 deletions(-) create mode 100644 src/core/main/init/hotkey.ts diff --git a/src/core/main/custom/hotkey.ts b/src/core/main/custom/hotkey.ts index e2fb619..05b6595 100644 --- a/src/core/main/custom/hotkey.ts +++ b/src/core/main/custom/hotkey.ts @@ -6,6 +6,8 @@ import { GameStorage } from '../storage'; interface HotkeyEvent extends EmitableEvent {} +type KeyEmitType = 'down' | 'up'; + interface AssistHoykey { ctrl: boolean; shift: boolean; @@ -16,11 +18,13 @@ interface RegisterHotkeyData extends Partial { id: string; name: string; defaults: KeyCode; + type?: KeyEmitType; } interface HotkeyData extends Required { key: KeyCode; func: Map; + group?: string; } type HotkeyFunc = (code: KeyCode, ev: KeyboardEvent) => void; @@ -32,9 +36,19 @@ export class Hotkey extends EventEmitter { name: string; data: Record = {}; keyMap: Map = new Map(); + /** id to name */ + groupName: Record = { + none: '未分类按键' + }; + /** id to keys */ + groups: Record = { + none: [] + }; + enabled: boolean = false; private scope: symbol = Symbol(); private scopeStack: symbol[] = []; + private grouping: string = 'none'; constructor(id: string, name: string) { super(); @@ -53,12 +67,19 @@ export class Hotkey extends EventEmitter { shift: !!data.shift, alt: !!data.alt, key: data.defaults, - func: new Map() + func: new Map(), + group: this.grouping, + type: data.type ?? 'up' }; 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; } /** @@ -126,11 +147,18 @@ export class Hotkey extends EventEmitter { * @param key 要触发的按键 * @param assist 辅助按键,三位二进制数据,从低到高依次为`ctrl` `shift` `alt` */ - emitKey(key: KeyCode, assist: number, ev: KeyboardEvent) { + emitKey( + key: KeyCode, + assist: number, + type: KeyEmitType, + ev: KeyboardEvent + ) { + if (!this.enabled) return; const toEmit = this.keyMap.get(key); if (!toEmit) return; const { ctrl, shift, alt } = this.unwarpBinary(assist); toEmit.forEach(v => { + if (type !== v.type) return; if (ctrl === v.ctrl && shift === v.shift && alt === v.alt) { const func = v.func.get(this.scope); if (!func) { @@ -141,6 +169,31 @@ export class Hotkey extends EventEmitter { }); } + /** + * 按键分组,执行后 register 的按键将会加入此分组 + * @param id 组的id + * @param name 组的名称 + */ + group(id: string, name: string) { + this.grouping = id; + this.groupName[id] = name; + return this; + } + + /** + * 启用这个按键控制器 + */ + enable() { + this.enabled = true; + } + + /** + * 禁用这个按键控制器 + */ + disable() { + this.enabled = false; + } + private unwarpBinary(bin: number): AssistHoykey { return { ctrl: !!(bin & (1 << 0)), @@ -163,188 +216,3 @@ export class Hotkey extends EventEmitter { return this.list.find(v => v.id === id); } } - -// export const hotkey = new Hotkey('gameKey'); - -// hotkey -// .register('book', '怪物手册', { -// defaults: KeyCode.KeyX, -// func: () => { -// core.openBook(true); -// } -// }) -// .register('save', '存档界面', { -// defaults: KeyCode.KeyS, -// func: () => { -// core.save(true); -// } -// }) -// .register('load', '读档界面', { -// defaults: KeyCode.KeyD, -// func: () => { -// core.load(true); -// } -// }) -// .register('undo', '回退', { -// defaults: KeyCode.KeyA, -// func: () => { -// core.doSL('autoSave', 'load'); -// } -// }) -// .register('redo', '恢复', { -// defaults: KeyCode.KeyW, -// func: () => { -// core.doSL('autoSave', 'reload'); -// } -// }) -// .register('toolbox', '道具栏', { -// defaults: KeyCode.KeyT, -// func: () => { -// core.openToolbox(true); -// } -// }) -// .register('equipbox', '装备栏', { -// defaults: KeyCode.KeyQ, -// func: () => { -// core.openEquipbox(true); -// } -// }) -// .register('fly', '楼层传送', { -// defaults: KeyCode.KeyG, -// func: () => { -// core.useFly(true); -// } -// }) -// .register('turn', '勇士转向', { -// defaults: KeyCode.KeyZ, -// func: () => { -// core.turnHero(); -// } -// }) -// .register('getNext', '轻按', { -// defaults: KeyCode.Space, -// func: () => { -// core.getNextItem(); -// } -// }) -// .register('menu', '菜单', { -// defaults: KeyCode.Escape, -// func: () => { -// core.openSettings(true); -// } -// }) -// .register('replay', '录像回放', { -// defaults: KeyCode.KeyR, -// func: () => { -// core.ui._drawReplay(); -// } -// }) -// .register('restart', '开始菜单', { -// defaults: KeyCode.KeyN, -// func: () => { -// core.confirmRestart(); -// } -// }) -// .register('shop', '快捷商店', { -// defaults: KeyCode.KeyV, -// func: () => { -// core.openQuickShop(true); -// } -// }) -// .register('statistics', '数据统计', { -// defaults: KeyCode.KeyB, -// func: () => { -// core.ui._drawStatistics(); -// } -// }) -// .register('viewMap1', '浏览地图', { -// defaults: KeyCode.PageUp, -// func: () => { -// core.ui._drawViewMaps(); -// } -// }) -// .register('viewMap2', '浏览地图', { -// defaults: KeyCode.PageDown, -// func: () => { -// core.ui._drawViewMaps(); -// } -// }) -// .register('comment', '评论区', { -// defaults: KeyCode.KeyP, -// func: () => { -// core.actions._clickGameInfo_openComments(); -// } -// }) -// .register('mark', '标记怪物', { -// defaults: KeyCode.KeyM, -// func: () => { -// // todo: refactor -// const [x, y] = flags.mouseLoc ?? []; -// const [mx, my] = getLocFromMouseLoc(x, y); -// } -// }) -// .register('skillTree', '技能树', { -// defaults: KeyCode.KeyJ, -// func: () => { -// core.useItem('skill1', true); -// } -// }) -// .register('desc', '百科全书', { -// defaults: KeyCode.KeyH, -// func: () => { -// core.useItem('I560', true); -// } -// }) -// .register('special', '鼠标位置怪物属性', { -// defaults: KeyCode.KeyE, -// func: () => { -// const [x, y] = flags.mouseLoc ?? []; -// const [mx, my] = getLocFromMouseLoc(x, y); -// if (core.getBlockCls(mx, my)?.startsWith('enemy')) { -// // mota.plugin.fixed.showFixed.value = false; -// mota.ui.main.open('fixedDetail', { -// panel: 'special' -// }); -// } -// } -// }) -// .register('critical', '鼠标位置怪物临界', { -// defaults: KeyCode.KeyC, -// func: () => { -// const [x, y] = flags.mouseLoc ?? []; -// const [mx, my] = getLocFromMouseLoc(x, y); -// if (core.getBlockCls(mx, my)?.startsWith('enemy')) { -// // mota.plugin.fixed.showFixed.value = false; -// mota.ui.main.open('fixedDetail', { -// panel: 'critical' -// }); -// } -// } -// }) -// .group('action', '游戏操作', [ -// 'save', -// 'load', -// 'undo', -// 'redo', -// 'turn', -// 'getNext', -// 'mark' -// ]) -// .group('view', '快捷查看', [ -// 'book', -// 'toolbox', -// 'equipbox', -// 'fly', -// 'menu', -// 'replay', -// 'shop', -// 'statistics', -// 'viewMap1', -// 'viewMap2', -// 'skillTree', -// 'desc', -// 'special', -// 'critical' -// ]) -// .group('system', '系统按键', ['comment']) -// .groupRest('unClassed', '未分类按键'); diff --git a/src/core/main/init/hotkey.ts b/src/core/main/init/hotkey.ts new file mode 100644 index 0000000..dc16483 --- /dev/null +++ b/src/core/main/init/hotkey.ts @@ -0,0 +1,338 @@ +import { KeyCode } from '@/plugin/keyCodes'; +import { Hotkey } from '../custom/hotkey'; +import { generateBinary, keycode } from '@/plugin/utils'; + +export const mainScope = Symbol.for('@key_main'); +export const gameKey = new Hotkey('gameKey', '游戏按键'); + +// ----- Register +gameKey + // -------------------- + .group('ui', 'ui界面') + .register({ + id: 'book', + name: '怪物手册', + defaults: KeyCode.KeyX + }) + .register({ + id: 'save', + name: '存档界面', + defaults: KeyCode.KeyS + }) + .register({ + id: 'load', + name: '读档界面', + defaults: KeyCode.KeyD + }) + .register({ + id: 'toolbox', + name: '道具栏', + defaults: KeyCode.KeyT + }) + .register({ + id: 'equipbox', + name: '装备栏', + defaults: KeyCode.KeyQ + }) + .register({ + id: 'fly', + name: '楼层传送', + defaults: KeyCode.KeyG + }) + .register({ + id: 'menu', + name: '菜单', + defaults: KeyCode.Escape + }) + .register({ + id: 'replay', + name: '录像回放', + defaults: KeyCode.KeyR + }) + .register({ + id: 'shop', + name: '快捷商店', + defaults: KeyCode.KeyV + }) + .register({ + id: 'statistics', + name: '数据统计', + defaults: KeyCode.KeyB + }) + .register({ + id: 'viewMap_1', + name: '浏览地图_1', + defaults: KeyCode.PageUp + }) + .register({ + id: 'viewMap_2', + name: '浏览地图_2', + defaults: KeyCode.PageDown + }) + .register({ + id: 'skillTree', + name: '技能树', + defaults: KeyCode.KeyJ + }) + .register({ + id: 'desc', + name: '百科全书', + defaults: KeyCode.KeyH + }) + // -------------------- + .group('function', '功能按键') + .register({ + id: 'undo', + name: '回退', + defaults: KeyCode.KeyA + }) + .register({ + id: 'redo', + name: '恢复', + defaults: KeyCode.KeyW + }) + .register({ + id: 'turn', + name: '勇士转向', + defaults: KeyCode.KeyZ + }) + .register({ + id: 'getNext', + name: '轻按', + defaults: KeyCode.Space + }) + .register({ + id: 'mark', + name: '标记怪物', + defaults: KeyCode.KeyM + }) + .register({ + id: 'special', + name: '鼠标位置怪物属性', + defaults: KeyCode.KeyE + }) + .register({ + id: 'critical', + name: '鼠标位置怪物临界', + defaults: KeyCode.KeyC + }) + // -------------------- + .group('system', '系统按键') + .register({ + id: 'restart', + name: '回到开始界面', + defaults: KeyCode.KeyN + }) + .register({ + id: 'comment', + name: '评论区', + defaults: KeyCode.KeyP + }) + // -------------------- + .group('general', '通用按键') + .register({ + id: 'exit_1', + name: '退出ui界面_1', + defaults: KeyCode.KeyX + }) + .register({ + id: 'exit_2', + name: '退出ui界面_2', + defaults: KeyCode.Escape + }) + .register({ + id: 'confirm_1', + name: '确认_1', + defaults: KeyCode.Enter + }) + .register({ + id: 'confirm_2', + name: '确认_2', + defaults: KeyCode.Space + }) + .register({ + id: 'confirm_3', + name: '确认_3', + defaults: KeyCode.KeyC + }) + // -------------------- + .group('@ui_start', '开始界面') + .register({ + id: '@start_up', + name: '上移光标', + defaults: KeyCode.UpArrow + }) + .register({ + id: '@start_down', + name: '下移光标', + defaults: KeyCode.DownArrow + }) + // -------------------- + .group('@ui_book', '怪物手册') + .register({ + id: '@book_up', + name: '上移光标', + defaults: KeyCode.UpArrow, + type: 'down' + }) + .register({ + id: '@book_down', + name: '下移光标', + defaults: KeyCode.DownArrow, + type: 'down' + }) + .register({ + id: '@book_pageDown_1', + name: '下移5个怪物_1', + defaults: KeyCode.RightArrow, + type: 'down' + }) + .register({ + id: '@book_pageDown_2', + name: '下移5个怪物_2', + defaults: KeyCode.PageDown, + type: 'down' + }) + .register({ + id: '@book_pageUp_1', + name: '上移5个怪物_1', + defaults: KeyCode.LeftArrow, + type: 'down' + }) + .register({ + id: '@book_pageUp_2', + name: '上移5个怪物_2', + defaults: KeyCode.PageUp, + type: 'down' + }) + // -------------------- + .group('@ui_toolbox', '道具栏') + .register({ + id: '@toolbox_right', + name: '光标右移', + defaults: KeyCode.RightArrow, + type: 'down' + }) + .register({ + id: '@toolbox_left', + name: '光标左移', + defaults: KeyCode.LeftArrow, + type: 'down' + }) + .register({ + id: '@toolbox_up', + name: '光标上移', + defaults: KeyCode.UpArrow, + type: 'down' + }) + .register({ + id: '@toolbox_right', + name: '光标下移', + defaults: KeyCode.DownArrow, + type: 'down' + }) + // -------------------- + .group('@ui_shop', '商店') + .register({ + id: '@shop_up', + name: '上移光标', + defaults: KeyCode.UpArrow + }) + .register({ + id: '@shop_down', + name: '下移光标', + defaults: KeyCode.DownArrow + }) + .register({ + id: '@shop_add', + name: '增加购买量', + defaults: KeyCode.RightArrow, + type: 'down' + }) + .register({ + id: '@shop_min', + name: '减少购买量', + defaults: KeyCode.LeftArrow, + type: 'down' + }) + // -------------------- + .group('@ui_fly', '楼层传送') + .register({ + id: '@fly_left', + name: '左移地图', + defaults: KeyCode.LeftArrow + }) + .register({ + id: '@fly_right', + name: '右移地图', + defaults: KeyCode.RightArrow + }) + .register({ + id: '@fly_up', + name: '上移地图', + defaults: KeyCode.UpArrow + }) + .register({ + id: '@fly_down', + name: '下移地图', + defaults: KeyCode.DownArrow + }) + .register({ + id: '@fly_last', + name: '上一张地图', + defaults: KeyCode.PageDown + }) + .register({ + id: '@fly_next', + name: '下一张地图', + defaults: KeyCode.PageUp + }) + // -------------------- + .group('@ui_fly_tradition', '楼层传送-传统按键') + .register({ + id: '@fly_down_t', + name: '上一张地图', + defaults: KeyCode.DownArrow + }) + .register({ + id: '@fly_up_t', + name: '下一张地图', + defaults: KeyCode.UpArrow + }) + .register({ + id: '@fly_left_t_1', + name: '前10张地图_1', + defaults: KeyCode.LeftArrow + }) + .register({ + id: '@fly_left_t_2', + name: '前10张地图_2', + defaults: KeyCode.PageDown + }) + .register({ + id: '@fly_right_t_1', + name: '后10张地图_1', + defaults: KeyCode.RightArrow + }) + .register({ + id: '@fly_right_t_2', + name: '后10张地图_2', + defaults: KeyCode.PageUp + }); + +gameKey.enable(); +gameKey.use(mainScope); + +// ----- Realization + +// ----- Listening +document.addEventListener('keyup', e => { + const assist = generateBinary([e.ctrlKey, e.shiftKey, e.altKey]); + const code = keycode(e.keyCode); + gameKey.emitKey(code, assist, 'up', e); +}); +document.addEventListener('keydown', e => { + const assist = generateBinary([e.ctrlKey, e.shiftKey, e.altKey]); + const code = keycode(e.keyCode); + gameKey.emitKey(code, assist, 'down', e); +}); diff --git a/src/core/main/init/index.ts b/src/core/main/init/index.ts index 12a857d..f03e3ef 100644 --- a/src/core/main/init/index.ts +++ b/src/core/main/init/index.ts @@ -1 +1,2 @@ import './fixed'; +import './hotkey'; diff --git a/src/ui/settings.vue b/src/ui/settings.vue index fdb98ac..ee4bf96 100644 --- a/src/ui/settings.vue +++ b/src/ui/settings.vue @@ -139,11 +139,6 @@ function click(key: string, index: number, item: MotaSettingItem) { } } -function changeValue(value: number | boolean) { - setting.setValue(displayer.selectStack.join('.'), value); - displayer.update(); -} - function exit() { mota.ui.main.close(props.num); }