mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-01-31 23:29:27 +08:00
feat: 虚拟键盘显示与操作
This commit is contained in:
parent
e77ca3e376
commit
899d1fa68e
@ -5,13 +5,13 @@ export interface EmitableEvent {
|
||||
[event: string]: (...params: any) => any;
|
||||
}
|
||||
|
||||
interface Listener<T extends (...params: any) => any> {
|
||||
export interface Listener<T extends (...params: any) => any> {
|
||||
fn: T;
|
||||
once?: boolean;
|
||||
immediate?: boolean;
|
||||
}
|
||||
|
||||
interface ListenerOptions {
|
||||
export interface ListenerOptions {
|
||||
once: boolean;
|
||||
immediate: boolean;
|
||||
}
|
||||
@ -22,12 +22,12 @@ type EmitFn<F extends (...params: any) => any> = (
|
||||
) => any;
|
||||
|
||||
export class EventEmitter<T extends EmitableEvent = {}> {
|
||||
private events: {
|
||||
protected events: {
|
||||
[P in keyof T]?: Listener<T[P]>[];
|
||||
} = {};
|
||||
private emitted: (keyof T)[] = [];
|
||||
|
||||
private emitter: {
|
||||
protected emitter: {
|
||||
[P in keyof T]?: EmitFn<T[P]>;
|
||||
} = {};
|
||||
|
||||
|
@ -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<VirtualKeyboardEvent> {
|
||||
id: string;
|
||||
keys: KeyboardItem[] = [];
|
||||
assist: number = 0;
|
||||
fontSize: number = 18;
|
||||
|
||||
scope: symbol = Symbol();
|
||||
private scopeStack: symbol[] = [];
|
||||
private onEmitKey: Record<symbol, Listener<VirtualKeyEmitFn>[]> = {};
|
||||
|
||||
constructor(id: string) {
|
||||
super();
|
||||
@ -50,8 +74,10 @@ export class Keyboard extends EventEmitter<VirtualKeyboardEvent> {
|
||||
* @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<VirtualKeyboardEvent> {
|
||||
remove(item: KeyboardItem) {
|
||||
deleteWith(this.keys, item);
|
||||
this.emit('remove', item);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -71,14 +98,49 @@ export class Keyboard extends EventEmitter<VirtualKeyboardEvent> {
|
||||
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<VirtualKeyEmitFn>[] = [];
|
||||
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<VirtualKeyboardEvent> {
|
||||
});
|
||||
|
||||
this.keys.push(...toClone);
|
||||
this.emit('extend', keyboard);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -100,9 +163,14 @@ export class Keyboard extends EventEmitter<VirtualKeyboardEvent> {
|
||||
* @param key 要触发的按键
|
||||
*/
|
||||
emitKey(key: KeyboardItem, index: number) {
|
||||
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);
|
||||
this.emit('emit', key, this.assist, index);
|
||||
}
|
||||
}
|
||||
|
||||
static get(id: string) {
|
||||
|
@ -1,2 +1,3 @@
|
||||
import './fixed';
|
||||
import './hotkey';
|
||||
import './keyboard';
|
||||
|
27
src/core/main/init/keyboard.ts
Normal file
27
src/core/main/init/keyboard.ts
Normal file
@ -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
|
||||
});
|
@ -1,16 +1,35 @@
|
||||
<template>
|
||||
<div class="keyboard-container"></div>
|
||||
<div class="keyboard-container">
|
||||
<div
|
||||
v-for="(key, i) of keyboard.keys"
|
||||
class="keyboard-item"
|
||||
@click="keyboard.emitKey(key, i)"
|
||||
:active="!!key.active"
|
||||
:style="{
|
||||
left: `${key.x}px`,
|
||||
top: `${key.y}px`,
|
||||
width: `${key.width}px`,
|
||||
height: `${key.height}px`
|
||||
}"
|
||||
>
|
||||
<span class="keyboard-key button-text">{{
|
||||
key.text ?? KeyCodeUtils.toString(key.key)
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Keyboard } from '@/core/main/custom/keyboard';
|
||||
import { KeyboardEmits } from '@/core/main/custom/keyboard';
|
||||
import { ref } from 'vue';
|
||||
import { KeyCodeUtils } from '@/plugin/keyCodes';
|
||||
|
||||
const props = defineProps<{
|
||||
keyboard: Keyboard;
|
||||
}>();
|
||||
|
||||
const fontSize = props.keyboard.fontSize;
|
||||
|
||||
const [width, height] = (() => {
|
||||
const key = props.keyboard;
|
||||
const mw = Math.max(...key.keys.map(v => v.x));
|
||||
@ -28,5 +47,39 @@ const emits = defineEmits<{
|
||||
.keyboard-container {
|
||||
width: v-bind(width);
|
||||
height: v-bind(height);
|
||||
display: block;
|
||||
font-size: v-bind(fontSize);
|
||||
}
|
||||
|
||||
.keyboard-item {
|
||||
position: absolute;
|
||||
background-color: #222;
|
||||
border: 1.5px solid #ddd8;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
transition: all 0.1s linear;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.keyboard-item:hover,
|
||||
.keyboard-item[active='true'] {
|
||||
background-color: #555;
|
||||
}
|
||||
|
||||
.keyboard-key[active='true'] {
|
||||
color: gold;
|
||||
}
|
||||
|
||||
.keyboard-key {
|
||||
height: 100%;
|
||||
min-width: 50px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
text-overflow: clip;
|
||||
text-wrap: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
|
Loading…
Reference in New Issue
Block a user