feat: 自定义按键

This commit is contained in:
unanmed 2023-11-19 23:37:37 +08:00
parent 1e58dbe411
commit 770e38202c
8 changed files with 258 additions and 22 deletions

View File

@ -59,22 +59,22 @@ function resize() {
if (has(props.right)) right.style.flexBasis = `${props.right}%`; if (has(props.right)) right.style.flexBasis = `${props.right}%`;
} }
function key(e: KeyboardEvent) { // function key(e: KeyboardEvent) {
const c = keycode(e.keyCode); // const c = keycode(e.keyCode);
if (c === KeyCode.Escape || c === KeyCode.KeyX) emits('close'); // if (c === KeyCode.Escape || c === KeyCode.KeyX) emits('close');
} // }
onMounted(async () => { onMounted(async () => {
resize(); resize();
await sleep(50); await sleep(50);
// if (mota.plugin.ui.transition.value) await sleep(600); // if (mota.plugin.ui.transition.value) await sleep(600);
document.addEventListener('keyup', key); // document.addEventListener('keyup', key);
}); });
onUpdated(resize); onUpdated(resize);
onUnmounted(() => { onUnmounted(() => {
document.removeEventListener('keyup', key); // document.removeEventListener('keyup', key);
}); });
</script> </script>

View File

@ -15,7 +15,10 @@ gameKey
.register({ .register({
id: 'book', id: 'book',
name: '怪物手册', name: '怪物手册',
defaults: KeyCode.KeyX defaults: KeyCode.KeyX,
ctrl: true,
shift: true,
alt: true
}) })
.register({ .register({
id: 'save', id: 'save',

View File

@ -1,6 +1,7 @@
import type { SettingComponent, SettingComponentProps } from '../setting'; import type { SettingComponent, SettingComponentProps } from '../setting';
import { Button, InputNumber } from 'ant-design-vue'; import { Button, InputNumber } from 'ant-design-vue';
import { mainUi } from './ui'; import { mainUi } from './ui';
import { gameKey } from './hotkey';
interface Components { interface Components {
DefaultSetting: SettingComponent; DefaultSetting: SettingComponent;
@ -70,13 +71,13 @@ function NumberSetting(props: SettingComponentProps) {
); );
} }
function showSpecialSetting(id: string) { function showSpecialSetting(id: string, vBind?: any) {
const ui = mainUi.get(id); const ui = mainUi.get(id);
mainUi.showEnd(); mainUi.showEnd();
ui.once('close', () => { ui.once('close', () => {
mainUi.showAll(); mainUi.showAll();
}); });
mainUi.open(id); mainUi.open(id, vBind);
} }
function HotkeySetting(props: SettingComponentProps) { function HotkeySetting(props: SettingComponentProps) {
@ -86,7 +87,11 @@ function HotkeySetting(props: SettingComponentProps) {
<Button <Button
type="primary" type="primary"
size="large" size="large"
onClick={() => showSpecialSetting('hotkey')} onClick={() =>
showSpecialSetting('hotkey', {
hotkey: gameKey
})
}
> >
</Button> </Button>

View File

@ -15,7 +15,8 @@ mainUi.register(
new GameUi('fixedDetail', UI.FixedDetail), new GameUi('fixedDetail', UI.FixedDetail),
new GameUi('shop', UI.Shop), new GameUi('shop', UI.Shop),
new GameUi('achievement', UI.Achievement), new GameUi('achievement', UI.Achievement),
new GameUi('bgm', UI.BgmList) new GameUi('bgm', UI.BgmList),
new GameUi('hotkey', UI.Hotkey)
// todo: 把游戏主 div 加入到 mainUi 里面 // todo: 把游戏主 div 加入到 mainUi 里面
); );
mainUi.showAll(); mainUi.showAll();

View File

@ -389,7 +389,7 @@ mainSetting
new MotaSetting() new MotaSetting()
.register('autoSkill', '自动切换技能', true, COM.BooleanSetting) .register('autoSkill', '自动切换技能', true, COM.BooleanSetting)
.register('fixed', '定点查看', true, COM.BooleanSetting) .register('fixed', '定点查看', true, COM.BooleanSetting)
.register('hotkey', '快捷键', false, COM.BooleanSetting) .register('hotkey', '快捷键', false, COM.HotkeySetting)
.setDisplayFunc('hotkey', () => '') .setDisplayFunc('hotkey', () => '')
.register('toolbar', '自定义工具栏', false, COM.BooleanSetting) .register('toolbar', '自定义工具栏', false, COM.BooleanSetting)
.setDisplayFunc('toolbar', () => '') .setDisplayFunc('toolbar', () => '')

229
src/ui/hotkey.vue Normal file
View File

@ -0,0 +1,229 @@
<template>
<Column @close="close" :left="30">
<template #left>
<div id="hotkey-group">
<span
class="hotkey-group-one selectable"
v-for="(name, group) of groupName"
:selected="selectedGroup === group"
@click="selectedGroup = group"
>
{{ name }}
</span>
</div>
</template>
<template #right>
<div id="hotkey-data">
<div class="hotkey-one" v-for="(data, id) of show">
<span class="hotkey-one-name"> {{ data.name }} </span>
<div class="hotkey-one-set">
<span
v-for="key of data.keys"
class="hotkey-one-set-item"
:selected="
data.id === selectedKey.id &&
key.index === selectedKey.index
"
@click="select(data.id, key.index)"
>
{{ getKeyShow(key.key, key.assist) }}
</span>
</div>
</div>
</div>
</template>
</Column>
</template>
<script lang="ts" setup>
import { Hotkey } from '@/core/main/custom/hotkey';
import { GameUi } from '@/core/main/custom/ui';
import Column from '@/components/colomn.vue';
import { mainUi } from '@/core/main/init/ui';
import { computed, onMounted, onUnmounted, reactive, ref } from 'vue';
import { KeyCode, KeyCodeUtils } from '@/plugin/keyCodes';
import { generateBinary, keycode } from '@/plugin/utils';
import { cloneDeep } from 'lodash-es';
import { gameKey } from '@/core/main/init/hotkey';
interface HotkeyKeys {
index: number;
key: KeyCode;
/** 从低到高依次为 `ctrl` `shift` `alt` */
assist: number;
}
interface HotkeySetting {
id: string;
name: string;
keys: HotkeyKeys[];
}
interface SelectedKey {
id: string;
index: number;
}
const props = defineProps<{
num: number;
ui: GameUi;
hotkey: Hotkey;
}>();
const hotkey = props.hotkey;
function close() {
mainUi.close(props.num);
}
const selectedGroup = ref('ui');
const keyData = generateData();
const show = computed(() => {
return keyData[selectedGroup.value];
});
const groupName = cloneDeep(hotkey.groupName);
delete groupName.none;
const selectedKey: SelectedKey = reactive({
id: 'none',
index: -1
});
function generateData() {
const res: Record<string, Record<string, HotkeySetting>> = {};
for (const [group, data] of Object.entries(hotkey.groups)) {
if (group === 'none') continue;
res[group] = {};
const d = res[group];
data.forEach(v => {
const split = v.split('_');
const isMulti = /^\d+$/.test(split.at(-1)!);
const id = isMulti ? split.slice(0, -1).join('_') : v;
const index = isMulti ? parseInt(split.at(-1)!) : -1;
const key = hotkey.data[v];
d[id] ??= {
id,
name: isMulti
? key.name.split('_').slice(0, -1).join('_')
: key.name,
keys: reactive([])
};
d[id].keys.push({
index,
key: key.key,
assist: generateBinary([key.ctrl, key.shift, key.alt])
});
});
}
return res;
}
function unwarpAssist(assist: number) {
let res = '';
if (assist & (1 << 0)) {
res += 'Ctrl + ';
}
if (assist & (1 << 1)) {
res += 'Shift + ';
}
if (assist & (1 << 2)) {
res += 'Alt + ';
}
return res;
}
function getKeyShow(key: KeyCode, assist: number) {
return unwarpAssist(assist) + KeyCodeUtils.toString(key);
}
function select(id: string, index: number) {
selectedKey.id = id;
selectedKey.index = index;
}
function keyup(e: KeyboardEvent) {
if (selectedKey.id === 'none') return;
const code = keycode(e.keyCode);
if (
code === KeyCode.Ctrl ||
code === KeyCode.Shift ||
code === KeyCode.Alt
) {
return;
}
const assist = generateBinary([e.ctrlKey, e.shiftKey, e.altKey]);
const id =
selectedKey.index === -1
? selectedKey.id
: `${selectedKey.id}_${selectedKey.index}`;
hotkey.set(id, code, assist);
const key = keyData[selectedGroup.value][selectedKey.id].keys.find(
v => v.index === selectedKey.index
);
if (key) {
key.key = code;
key.assist = assist;
}
selectedKey.id = 'none';
selectedKey.index = -1;
}
// ban other keys
gameKey.disable();
console.log(gameKey.enabled);
onMounted(() => {
document.addEventListener('keyup', keyup);
});
onUnmounted(() => {
gameKey.enable();
document.removeEventListener('keyup', keyup);
});
</script>
<style lang="less" scoped>
#hotkey-group {
display: flex;
flex-direction: column;
}
.hotkey-group-one {
margin: 2px 0;
}
.hotkey-one {
display: flex;
flex-direction: row;
justify-content: space-between;
margin: 2% 3%;
white-space: nowrap;
}
.hotkey-one-set {
display: flex;
flex-direction: column;
width: 50%;
text-overflow: clip;
align-items: end;
text-align: end;
.hotkey-one-set-item {
background-color: #4446;
padding: 0 5%;
margin: 1% 0;
width: 100%;
border: 1px solid transparent;
}
.hotkey-one-set-item[selected='true'] {
color: gold;
border: 1px solid gold;
}
}
</style>

View File

@ -19,3 +19,4 @@ export { default as StatusBar } from './statusBar.vue';
export { default as Studied } from './studied.vue'; export { default as Studied } from './studied.vue';
export { default as Study } from './study.vue'; export { default as Study } from './study.vue';
export { default as Toolbox } from './toolbox.vue'; export { default as Toolbox } from './toolbox.vue';
export { default as Hotkey } from './hotkey.vue';

View File

@ -83,11 +83,14 @@ import Scroll from '../components/scroll.vue';
import { isMobile } from '../plugin/use'; import { isMobile } from '../plugin/use';
import { sleep } from 'mutate-animate'; import { sleep } from 'mutate-animate';
import { KeyCode } from '../plugin/keyCodes'; import { KeyCode } from '../plugin/keyCodes';
import { gameKey } from '@/core/main/init/hotkey';
import { GameUi } from '@/core/main/custom/ui';
const props = defineProps<{ const props = defineProps<{
info?: MotaSetting; info?: MotaSetting;
text?: SettingText; text?: SettingText;
num: number; num: number;
ui: GameUi;
}>(); }>();
const setting = props.info ?? mainSetting; const setting = props.info ?? mainSetting;
@ -143,19 +146,13 @@ function exit() {
mota.ui.main.close(props.num); mota.ui.main.close(props.num);
} }
function key(e: KeyboardEvent) { gameKey.use(props.ui.symbol);
const c = keycode(e.keyCode); gameKey.realize('exit', () => {
if (c === KeyCode.Escape || c === KeyCode.KeyX) exit(); exit();
}
onMounted(async () => {
await sleep(50);
// if (mota.plugin.ui.transition.value) await sleep(600);
document.addEventListener('keyup', key);
}); });
onUnmounted(() => { onUnmounted(() => {
document.removeEventListener('keyup', key); gameKey.dispose(props.ui.symbol);
}); });
</script> </script>