feat(KeyBoard): add skill and observation button

This commit is contained in:
AkiChase 2024-04-28 16:46:43 +08:00
parent 3b4cb410dc
commit a37896c2cb
4 changed files with 243 additions and 52 deletions

View File

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { Ref, onActivated, ref } from "vue"; import { onActivated } from "vue";
import { NDialog, useMessage } from "naive-ui"; import { NDialog, useMessage } from "naive-ui";
import { useGlobalStore } from "../store/global"; import { useGlobalStore } from "../store/global";
import { onBeforeRouteLeave, useRouter } from "vue-router"; import { onBeforeRouteLeave, useRouter } from "vue-router";
@ -10,14 +10,12 @@ import {
unlistenToKeyEvent, unlistenToKeyEvent,
updateScreenSizeAndMaskArea, updateScreenSizeAndMaskArea,
} from "../hotkey"; } from "../hotkey";
import { getCurrent } from "@tauri-apps/api/window"; import { KeySteeringWheel } from "../keyMappingConfig";
const store = useGlobalStore(); const store = useGlobalStore();
const router = useRouter(); const router = useRouter();
const message = useMessage(); const message = useMessage();
const renderedButtons: Ref<any[]> = ref([]);
onBeforeRouteLeave(() => { onBeforeRouteLeave(() => {
const maskElement = document.getElementById("maskElement") as HTMLElement; const maskElement = document.getElementById("maskElement") as HTMLElement;
@ -31,15 +29,9 @@ onActivated(async () => {
const maskElement = document.getElementById("maskElement") as HTMLElement; const maskElement = document.getElementById("maskElement") as HTMLElement;
if (store.controledDevice) { if (store.controledDevice) {
const mt = 30;
const ml = 70;
const appWindow = getCurrent();
const size = (await appWindow.outerSize()).toLogical(
await appWindow.scaleFactor()
);
updateScreenSizeAndMaskArea( updateScreenSizeAndMaskArea(
[store.screenSizeW, store.screenSizeH], [store.screenSizeW, store.screenSizeH],
[size.width - ml, size.height - mt] [maskElement.clientWidth, maskElement.clientHeight]
); );
if ( if (
@ -48,7 +40,6 @@ onActivated(async () => {
store.keyMappingConfigList[store.curKeyMappingIndex] store.keyMappingConfigList[store.curKeyMappingIndex]
) )
) { ) {
refreshKeyMappingButton();
listenToKeyEvent(); listenToKeyEvent();
} else { } else {
message.error("按键方案异常,请删除此方案"); message.error("按键方案异常,请删除此方案");
@ -59,32 +50,6 @@ onActivated(async () => {
function toStartServer() { function toStartServer() {
router.replace({ name: "device" }); router.replace({ name: "device" });
} }
function refreshKeyMappingButton() {
const maskElement = document.getElementById("maskElement") as HTMLElement;
const curKeyMappingConfig =
store.keyMappingConfigList[store.curKeyMappingIndex];
const relativeSize = curKeyMappingConfig.relativeSize;
const maskSizeW = maskElement.clientWidth;
const maskSizeH = maskElement.clientHeight;
const relativePosToMaskPos = (x: number, y: number) => {
return {
x: Math.round((x / relativeSize.w) * maskSizeW),
y: Math.round((y / relativeSize.h) * maskSizeH),
};
};
const buttons = [];
for (let keyObject of curKeyMappingConfig.list) {
const { x, y } = relativePosToMaskPos(keyObject.posX, keyObject.posY);
buttons.push({
...keyObject,
x,
y,
});
}
renderedButtons.value = buttons;
}
</script> </script>
<template> <template>
@ -101,29 +66,32 @@ function refreshKeyMappingButton() {
</div> </div>
</div> </div>
<div <div
v-show="store.controledDevice" v-if="store.keyMappingConfigList.length"
@contextmenu.prevent @contextmenu.prevent
class="mask" class="mask"
id="maskElement" id="maskElement"
> >
<template v-for="button in renderedButtons"> <template
v-for="button in store.keyMappingConfigList[store.curKeyMappingIndex]
.list"
>
<div <div
v-if="button.type === 'SteeringWheel'" v-if="button.type === 'SteeringWheel'"
class="mask-steering-wheel" class="mask-steering-wheel"
:style="{ :style="{
left: button.x - 75 + 'px', left: button.posX - 75 + 'px',
top: button.y - 75 + 'px', top: button.posY - 75 + 'px',
}" }"
> >
<div class="wheel-container"> <div class="wheel-container">
<i /> <i />
<span>{{ button.key.up }}</span> <span>{{ (button as KeySteeringWheel).key.up }}</span>
<i /> <i />
<span>{{ button.key.left }}</span> <span>{{ (button as KeySteeringWheel).key.left }}</span>
<i /> <i />
<span>{{ button.key.right }}</span> <span>{{ (button as KeySteeringWheel).key.right }}</span>
<i /> <i />
<span>{{ button.key.down }}</span> <span>{{ (button as KeySteeringWheel).key.down }}</span>
<i /> <i />
</div> </div>
</div> </div>
@ -131,8 +99,8 @@ function refreshKeyMappingButton() {
v-else v-else
class="mask-button" class="mask-button"
:style="{ :style="{
left: button.x + 'px', left: button.posX + 'px',
top: button.y - 14 + 'px', top: button.posY - 14 + 'px',
}" }"
> >
{{ button.key }} {{ button.key }}
@ -183,6 +151,12 @@ function refreshKeyMappingButton() {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
z-index: 1;
position: absolute;
left: 70px;
top: 30px;
right: 0;
bottom: 0;
.content { .content {
width: 80%; width: 80%;

View File

@ -4,19 +4,22 @@ import KeyInfo from "./KeyInfo.vue";
import KeySetting from "./KeySetting.vue"; import KeySetting from "./KeySetting.vue";
import KeyCommon from "./KeyCommon.vue"; import KeyCommon from "./KeyCommon.vue";
import KeySteeringWheel from "./KeySteeringWheel.vue"; import KeySteeringWheel from "./KeySteeringWheel.vue";
import KeySkill from "./KeySkill.vue";
import { KeySteeringWheel as KeyMappingSteeringWheel } from "../../keyMappingConfig"; import { KeySteeringWheel as KeyMappingSteeringWheel } from "../../keyMappingConfig";
import { useGlobalStore } from "../../store/global"; import { useGlobalStore } from "../../store/global";
import { useDialog, useMessage } from "naive-ui"; import { useDialog, useMessage } from "naive-ui";
import { onBeforeRouteLeave } from "vue-router"; import { onBeforeRouteLeave } from "vue-router";
import KeyObservation from "./KeyObservation.vue";
// TODO KeyMacroKeyCancelSkillKeyTap // TODO KeyMacroKeyCancelSkillKeyTap
// KeyMacro // KeyMacro
// TODO KeySteeringWheel // TODO KeySteeringWheel
// +offset // offset
// TODO KeyDirectionalSkillKeyDirectionlessSkillKeyTriggerWhenPressedSkilldirectional) // TODO KeyDirectionalSkillKeyDirectionlessSkillKeyTriggerWhenPressedSkilldirectional)
// flagrangetime // flagrangetime
// TODO KeyObservation // TODO KeyObservation
// scale // scale
// TODO 齿 // TODO 齿
// TODO // TODO
// TODO utools // TODO utools
@ -190,6 +193,7 @@ onBeforeRouteLeave(() => {
<template> <template>
<div <div
v-if="store.keyMappingConfigList.length"
id="keyboardElement" id="keyboardElement"
class="keyboard" class="keyboard"
@mousedown="handleClick" @mousedown="handleClick"
@ -211,6 +215,22 @@ onBeforeRouteLeave(() => {
activeSteeringWheelButtonKeyIndex activeSteeringWheelButtonKeyIndex
" "
/> />
<KeySkill
v-else-if="
store.editKeyMappingList[index].type === 'DirectionalSkill' ||
store.editKeyMappingList[index].type === 'DirectionlessSkill' ||
store.editKeyMappingList[index].type === 'TriggerWhenPressedSkill'
"
@edit="edited = true"
:index="index"
v-model:active-index="activeButtonIndex"
/>
<KeyObservation
v-else-if="store.editKeyMappingList[index].type === 'Observation'"
@edit="edited = true"
:index="index"
v-model:active-index="activeButtonIndex"
/>
<KeyCommon <KeyCommon
v-else v-else
@edit="edited = true" @edit="edited = true"
@ -227,6 +247,8 @@ onBeforeRouteLeave(() => {
background-color: rgba(0, 0, 0, 0.5); background-color: rgba(0, 0, 0, 0.5);
overflow: hidden; overflow: hidden;
position: relative; position: relative;
user-select: none;
-webkit-user-select: none;
.keyboard-button { .keyboard-button {
position: absolute; position: absolute;

View File

@ -0,0 +1,98 @@
<script setup lang="ts">
import { ref } from "vue";
import { useGlobalStore } from "../../store/global";
import { NIcon } from "naive-ui";
import { Eye } from "@vicons/ionicons5";
const emit = defineEmits<{
edit: [];
}>();
const props = defineProps<{
index: number;
}>();
const activeIndex = defineModel("activeIndex", { required: true });
const store = useGlobalStore();
const elementRef = ref<HTMLElement | null>(null);
function dragHandler(downEvent: MouseEvent) {
activeIndex.value = props.index;
const oldX = store.editKeyMappingList[props.index].posX;
const oldY = store.editKeyMappingList[props.index].posY;
const element = elementRef.value;
if (element) {
const keyboardElement = document.getElementById(
"keyboardElement"
) as HTMLElement;
const maxX = keyboardElement.clientWidth - 60;
const maxY = keyboardElement.clientHeight - 60;
const x = downEvent.clientX;
const y = downEvent.clientY;
const moveHandler = (moveEvent: MouseEvent) => {
let newX = oldX + moveEvent.clientX - x;
let newY = oldY + moveEvent.clientY - y;
newX = Math.max(0, Math.min(newX, maxX));
newY = Math.max(0, Math.min(newY, maxY));
store.editKeyMappingList[props.index].posX = newX;
store.editKeyMappingList[props.index].posY = newY;
};
window.addEventListener("mousemove", moveHandler);
const upHandler = () => {
window.removeEventListener("mousemove", moveHandler);
window.removeEventListener("mouseup", upHandler);
if (
oldX !== store.editKeyMappingList[props.index].posX ||
oldY !== store.editKeyMappingList[props.index].posY
) {
emit("edit");
}
};
window.addEventListener("mouseup", upHandler);
}
}
</script>
<template>
<div
:class="{ active: props.index === activeIndex }"
:style="{
left: `${store.editKeyMappingList[props.index].posX - 30}px`,
top: `${store.editKeyMappingList[props.index].posY - 30}px`,
}"
@mousedown="dragHandler"
class="key-observation"
ref="elementRef"
>
<NIcon size="25"><Eye style="color: var(--blue-color)" /></NIcon>
<span>{{ store.editKeyMappingList[props.index].key }}</span>
</div>
</template>
<style scoped lang="scss">
.key-observation {
position: absolute;
height: 60px;
width: 60px;
border-radius: 50%;
border: 2px solid var(--blue-color);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 10px;
font-weight: bold;
cursor: pointer;
&:not(.active):hover {
border: 2px solid var(--light-color);
}
}
.active {
border: 2px solid var(--primary-color);
color: var(--primary-color);
z-index: 2;
}
</style>

View File

@ -0,0 +1,97 @@
<script setup lang="ts">
import { ref } from "vue";
import { useGlobalStore } from "../../store/global";
import { Flash } from "@vicons/ionicons5";
import { NIcon } from "naive-ui";
const emit = defineEmits<{
edit: [];
}>();
const props = defineProps<{
index: number;
}>();
const activeIndex = defineModel("activeIndex", { required: true });
const store = useGlobalStore();
const elementRef = ref<HTMLElement | null>(null);
function dragHandler(downEvent: MouseEvent) {
activeIndex.value = props.index;
const oldX = store.editKeyMappingList[props.index].posX;
const oldY = store.editKeyMappingList[props.index].posY;
const element = elementRef.value;
if (element) {
const keyboardElement = document.getElementById(
"keyboardElement"
) as HTMLElement;
const maxX = keyboardElement.clientWidth - 60;
const maxY = keyboardElement.clientHeight - 60;
const x = downEvent.clientX;
const y = downEvent.clientY;
const moveHandler = (moveEvent: MouseEvent) => {
let newX = oldX + moveEvent.clientX - x;
let newY = oldY + moveEvent.clientY - y;
newX = Math.max(0, Math.min(newX, maxX));
newY = Math.max(0, Math.min(newY, maxY));
store.editKeyMappingList[props.index].posX = newX;
store.editKeyMappingList[props.index].posY = newY;
};
window.addEventListener("mousemove", moveHandler);
const upHandler = () => {
window.removeEventListener("mousemove", moveHandler);
window.removeEventListener("mouseup", upHandler);
if (
oldX !== store.editKeyMappingList[props.index].posX ||
oldY !== store.editKeyMappingList[props.index].posY
) {
emit("edit");
}
};
window.addEventListener("mouseup", upHandler);
}
}
</script>
<template>
<div
:class="{ active: props.index === activeIndex }"
:style="{
left: `${store.editKeyMappingList[props.index].posX - 30}px`,
top: `${store.editKeyMappingList[props.index].posY - 30}px`,
}"
@mousedown="dragHandler"
class="key-skill"
ref="elementRef"
>
<NIcon size="25"><Flash style="color: var(--blue-color)" /></NIcon>
<span>{{ store.editKeyMappingList[props.index].key }}</span>
</div>
</template>
<style scoped lang="scss">
.key-skill {
position: absolute;
height: 60px;
width: 60px;
border-radius: 50%;
border: 2px solid var(--blue-color);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 10px;
font-weight: bold;
cursor: pointer;
&:not(.active):hover {
border: 2px solid var(--light-color);
}
}
.active {
border: 2px solid var(--primary-color);
color: var(--primary-color);
z-index: 2;
}
</style>