mirror of
https://github.com/AkiChase/scrcpy-mask
synced 2025-02-23 07:22:17 +08:00
feat(KeyCommon): add macro setting button
This commit is contained in:
parent
50698231b0
commit
83d4e2bae0
@ -11,6 +11,7 @@ import { useDialog, useMessage } from "naive-ui";
|
||||
import { onBeforeRouteLeave } from "vue-router";
|
||||
import KeyObservation from "./KeyObservation.vue";
|
||||
|
||||
// TODO 按钮齿轮图标可修改
|
||||
// TODO 普通按钮 KeyMacro,KeyCancelSkill,KeyTap
|
||||
// KeyMacro有输入框
|
||||
// TODO 方向轮盘按钮 KeySteeringWheel
|
||||
@ -20,13 +21,13 @@ import KeyObservation from "./KeyObservation.vue";
|
||||
// TODO 添加视野按钮 KeyObservation
|
||||
// 有灵敏度scale
|
||||
|
||||
// TODO 按钮齿轮图标可修改、删除
|
||||
// TODO 右键空白区域添加按键
|
||||
// TODO 设置界面添加本地数据编辑器(类似utools)
|
||||
// TODO 添加开发者工具打开按钮
|
||||
|
||||
const showKeyInfoFlag = ref(false);
|
||||
const showSettingFlag = ref(false);
|
||||
const showButtonSettingFlag = ref(false);
|
||||
const store = useGlobalStore();
|
||||
const dialog = useDialog();
|
||||
const message = useMessage();
|
||||
@ -98,10 +99,11 @@ function handleClick(event: MouseEvent) {
|
||||
if (event.target === document.getElementById("keyboardElement")) {
|
||||
if (showSettingFlag.value) {
|
||||
showSettingFlag.value = false;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
activeButtonIndex.value = -1;
|
||||
activeSteeringWheelButtonKeyIndex.value = -1;
|
||||
showButtonSettingFlag.value = false;
|
||||
}
|
||||
}
|
||||
} else if (event.button === 2) {
|
||||
// right click
|
||||
@ -115,19 +117,20 @@ function handleClick(event: MouseEvent) {
|
||||
} else if (
|
||||
// modify key
|
||||
activeButtonIndex.value !== -1 &&
|
||||
activeButtonIndex.value < store.editKeyMappingList.length
|
||||
activeButtonIndex.value < store.editKeyMappingList.length &&
|
||||
!showButtonSettingFlag.value
|
||||
) {
|
||||
event.preventDefault();
|
||||
const curKey = `M${event.button}`;
|
||||
setCurButtonKey(curKey);
|
||||
}
|
||||
} else {
|
||||
// other click
|
||||
event.preventDefault();
|
||||
if (
|
||||
activeButtonIndex.value !== -1 &&
|
||||
activeButtonIndex.value < store.editKeyMappingList.length
|
||||
activeButtonIndex.value < store.editKeyMappingList.length &&
|
||||
!showButtonSettingFlag.value
|
||||
) {
|
||||
event.preventDefault();
|
||||
const curKey = `M${event.button}`;
|
||||
setCurButtonKey(curKey);
|
||||
}
|
||||
@ -137,9 +140,9 @@ function handleClick(event: MouseEvent) {
|
||||
function handleKeyUp(event: KeyboardEvent) {
|
||||
if (
|
||||
activeButtonIndex.value !== -1 &&
|
||||
activeButtonIndex.value < store.editKeyMappingList.length
|
||||
activeButtonIndex.value < store.editKeyMappingList.length &&
|
||||
!showButtonSettingFlag.value
|
||||
) {
|
||||
event.preventDefault();
|
||||
const curKey = event.code;
|
||||
setCurButtonKey(curKey);
|
||||
}
|
||||
@ -148,9 +151,9 @@ function handleKeyUp(event: KeyboardEvent) {
|
||||
function handleMouseWheel(event: WheelEvent) {
|
||||
if (
|
||||
activeButtonIndex.value !== -1 &&
|
||||
activeButtonIndex.value < store.editKeyMappingList.length
|
||||
activeButtonIndex.value < store.editKeyMappingList.length &&
|
||||
!showButtonSettingFlag.value
|
||||
) {
|
||||
event.preventDefault();
|
||||
if (event.deltaY > 0) {
|
||||
// WheelDown
|
||||
setCurButtonKey("WheelDown");
|
||||
@ -161,6 +164,14 @@ function handleMouseWheel(event: WheelEvent) {
|
||||
}
|
||||
}
|
||||
|
||||
function resetEditKeyMappingList() {
|
||||
showSettingFlag.value = false;
|
||||
activeButtonIndex.value = -1;
|
||||
activeSteeringWheelButtonKeyIndex.value = -1;
|
||||
store.resetEditKeyMappingList();
|
||||
edited.value = false;
|
||||
}
|
||||
|
||||
onActivated(() => {
|
||||
document.addEventListener("keyup", handleKeyUp);
|
||||
document.addEventListener("wheel", handleMouseWheel);
|
||||
@ -183,8 +194,7 @@ onBeforeRouteLeave(() => {
|
||||
}
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
store.resetEditKeyMappingList();
|
||||
edited.value = false;
|
||||
resetEditKeyMappingList();
|
||||
},
|
||||
});
|
||||
}
|
||||
@ -203,6 +213,7 @@ onBeforeRouteLeave(() => {
|
||||
v-model:show-key-info-flag="showKeyInfoFlag"
|
||||
v-model:show-setting-flag="showSettingFlag"
|
||||
v-model:edited="edited"
|
||||
@reset-edit-key-mapping-list="resetEditKeyMappingList"
|
||||
/>
|
||||
<KeyInfo v-model:showKeyInfoFlag="showKeyInfoFlag" />
|
||||
<template v-for="(_, index) in store.editKeyMappingList">
|
||||
@ -214,6 +225,7 @@ onBeforeRouteLeave(() => {
|
||||
v-model:active-steering-wheel-button-key-index="
|
||||
activeSteeringWheelButtonKeyIndex
|
||||
"
|
||||
v-model:show-button-setting-flag="showButtonSettingFlag"
|
||||
/>
|
||||
<KeySkill
|
||||
v-else-if="
|
||||
@ -224,18 +236,21 @@ onBeforeRouteLeave(() => {
|
||||
@edit="edited = true"
|
||||
:index="index"
|
||||
v-model:active-index="activeButtonIndex"
|
||||
v-model:show-button-setting-flag="showButtonSettingFlag"
|
||||
/>
|
||||
<KeyObservation
|
||||
v-else-if="store.editKeyMappingList[index].type === 'Observation'"
|
||||
@edit="edited = true"
|
||||
:index="index"
|
||||
v-model:active-index="activeButtonIndex"
|
||||
v-model:show-button-setting-flag="showButtonSettingFlag"
|
||||
/>
|
||||
<KeyCommon
|
||||
v-else
|
||||
@edit="edited = true"
|
||||
:index="index"
|
||||
v-model:active-index="activeButtonIndex"
|
||||
v-model:show-button-setting-flag="showButtonSettingFlag"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
|
@ -1,6 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { computed, ref } from "vue";
|
||||
import { useGlobalStore } from "../../store/global";
|
||||
import {
|
||||
NButton,
|
||||
NFormItem,
|
||||
NH4,
|
||||
NIcon,
|
||||
NInput,
|
||||
NModal,
|
||||
NCard,
|
||||
useMessage,
|
||||
NFlex,
|
||||
} from "naive-ui";
|
||||
import { CloseCircle, Settings } from "@vicons/ionicons5";
|
||||
import { KeyMacro, KeyMacroList } from "../../keyMappingConfig";
|
||||
|
||||
const emit = defineEmits<{
|
||||
edit: [];
|
||||
@ -11,14 +24,29 @@ const props = defineProps<{
|
||||
}>();
|
||||
|
||||
const activeIndex = defineModel("activeIndex", { required: true });
|
||||
const showButtonSettingFlag = defineModel("showButtonSettingFlag", {
|
||||
required: true,
|
||||
});
|
||||
|
||||
const store = useGlobalStore();
|
||||
const message = useMessage();
|
||||
const elementRef = ref<HTMLElement | null>(null);
|
||||
|
||||
const isActive = computed(() => props.index === activeIndex.value);
|
||||
const keyMapping = computed(() => store.editKeyMappingList[props.index]);
|
||||
|
||||
const showMacroModal = ref(false);
|
||||
const editedMacroRaw = ref({
|
||||
down: "",
|
||||
loop: "",
|
||||
up: "",
|
||||
});
|
||||
|
||||
function dragHandler(downEvent: MouseEvent) {
|
||||
activeIndex.value = props.index;
|
||||
const oldX = store.editKeyMappingList[props.index].posX;
|
||||
const oldY = store.editKeyMappingList[props.index].posY;
|
||||
showButtonSettingFlag.value = false;
|
||||
const oldX = keyMapping.value.posX;
|
||||
const oldY = keyMapping.value.posY;
|
||||
const element = elementRef.value;
|
||||
if (element) {
|
||||
const keyboardElement = document.getElementById(
|
||||
@ -34,41 +62,207 @@ function dragHandler(downEvent: MouseEvent) {
|
||||
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;
|
||||
keyMapping.value.posX = newX;
|
||||
keyMapping.value.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
|
||||
) {
|
||||
if (oldX !== keyMapping.value.posX || oldY !== keyMapping.value.posY) {
|
||||
emit("edit");
|
||||
}
|
||||
};
|
||||
window.addEventListener("mouseup", upHandler);
|
||||
}
|
||||
}
|
||||
|
||||
function delCurKeyMapping() {
|
||||
emit("edit");
|
||||
activeIndex.value = -1;
|
||||
store.editKeyMappingList.splice(props.index, 1);
|
||||
}
|
||||
|
||||
function parseMacro(macroRaw: string): KeyMacroList {
|
||||
// simple parsing and possible to let the wrong code pass
|
||||
if (macroRaw === "") {
|
||||
return null;
|
||||
}
|
||||
const macro: KeyMacroList = JSON.parse(macroRaw);
|
||||
if (macro === null) return macro;
|
||||
for (const macroItem of macro) {
|
||||
if (typeof macroItem !== "object") {
|
||||
throw ["macroItem is not object", macroItem];
|
||||
}
|
||||
if (!("type" in macroItem)) {
|
||||
throw ["macroItem has no type attribute", macroItem];
|
||||
}
|
||||
if (!("args" in macroItem)) {
|
||||
throw ["macroItem has no args attribute", macroItem];
|
||||
}
|
||||
}
|
||||
return macro;
|
||||
}
|
||||
|
||||
let editedFlag = false;
|
||||
function editMacro() {
|
||||
editedFlag = false;
|
||||
const macro = (keyMapping.value as KeyMacro).macro;
|
||||
editedMacroRaw.value = {
|
||||
down: macro.down === null ? "" : JSON.stringify(macro.down, null, 2),
|
||||
loop: macro.loop === null ? "" : JSON.stringify(macro.loop, null, 2),
|
||||
up: macro.up === null ? "" : JSON.stringify(macro.up, null, 2),
|
||||
};
|
||||
showMacroModal.value = true;
|
||||
}
|
||||
|
||||
function saveMacro() {
|
||||
if (!editedFlag) return;
|
||||
try {
|
||||
const macro: {
|
||||
down: KeyMacroList;
|
||||
loop: KeyMacroList;
|
||||
up: KeyMacroList;
|
||||
} = {
|
||||
down: null,
|
||||
loop: null,
|
||||
up: null,
|
||||
};
|
||||
const keyList: ["down", "loop", "up"] = ["down", "loop", "up"];
|
||||
for (const key of keyList) {
|
||||
const macroRaw = editedMacroRaw.value[key];
|
||||
macro[key] = parseMacro(macroRaw);
|
||||
}
|
||||
|
||||
(keyMapping.value as KeyMacro).macro = macro;
|
||||
showMacroModal.value = false;
|
||||
emit("edit");
|
||||
message.success("宏代码解析成功,但不保证代码正确性,请自行测试");
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
message.error("宏代码保存失败,请检查代码格式是否正确");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
:class="{ active: props.index === activeIndex }"
|
||||
:class="{ active: isActive }"
|
||||
:style="{
|
||||
left: `${store.editKeyMappingList[props.index].posX - 20}px`,
|
||||
top: `${store.editKeyMappingList[props.index].posY - 20}px`,
|
||||
left: `${keyMapping.posX - 20}px`,
|
||||
top: `${keyMapping.posY - 20}px`,
|
||||
}"
|
||||
@mousedown="dragHandler"
|
||||
class="key-common"
|
||||
ref="elementRef"
|
||||
>
|
||||
<span>{{ store.editKeyMappingList[props.index].key }}</span>
|
||||
<span>{{ keyMapping.key }}</span>
|
||||
<NButton
|
||||
class="key-close-btn"
|
||||
text
|
||||
@click="delCurKeyMapping"
|
||||
:type="isActive ? 'primary' : 'info'"
|
||||
>
|
||||
<template #icon>
|
||||
<NIcon size="15">
|
||||
<CloseCircle />
|
||||
</NIcon>
|
||||
</template>
|
||||
</NButton>
|
||||
<NButton
|
||||
class="key-setting-btn"
|
||||
text
|
||||
@click="showButtonSettingFlag = true"
|
||||
:type="isActive ? 'primary' : 'info'"
|
||||
>
|
||||
<template #icon>
|
||||
<NIcon size="15">
|
||||
<Settings />
|
||||
</NIcon>
|
||||
</template>
|
||||
</NButton>
|
||||
</div>
|
||||
<div
|
||||
class="key-setting"
|
||||
v-if="isActive && showButtonSettingFlag"
|
||||
:style="{
|
||||
left: `${keyMapping.posX + 25}px`,
|
||||
top: `${keyMapping.posY - 45}px`,
|
||||
}"
|
||||
>
|
||||
<NH4 prefix="bar">{{
|
||||
keyMapping.type === "CancelSkill"
|
||||
? "技能取消"
|
||||
: keyMapping.type === "Tap"
|
||||
? "普通点击"
|
||||
: "宏"
|
||||
}}</NH4>
|
||||
<NFormItem v-if="keyMapping.type === 'Macro'" label="宏代码">
|
||||
<NButton type="success" @click="editMacro"> 编辑代码 </NButton>
|
||||
</NFormItem>
|
||||
<NFormItem label="备注">
|
||||
<NInput
|
||||
v-model:value="keyMapping.note"
|
||||
placeholder="请输入备注"
|
||||
@update:value="emit('edit')"
|
||||
/>
|
||||
</NFormItem>
|
||||
<NModal
|
||||
v-if="keyMapping.type === 'Macro'"
|
||||
v-model:show="showMacroModal"
|
||||
@before-leave="saveMacro"
|
||||
>
|
||||
<NCard style="width: 50%; height: 80%" title="宏编辑">
|
||||
<NFlex vertical style="height: 100%">
|
||||
<div>按下按键执行</div>
|
||||
<NInput
|
||||
type="textarea"
|
||||
style="flex-grow: 1"
|
||||
placeholder="JSON宏代码, 可为空"
|
||||
v-model:value="editedMacroRaw.down"
|
||||
@update:value="editedFlag = true"
|
||||
round
|
||||
clearable
|
||||
/>
|
||||
<div>按住执行</div>
|
||||
<NInput
|
||||
type="textarea"
|
||||
style="flex-grow: 1"
|
||||
placeholder="JSON宏代码, 可为空"
|
||||
v-model:value="editedMacroRaw.loop"
|
||||
@update:value="editedFlag = true"
|
||||
round
|
||||
clearable
|
||||
/>
|
||||
<div>抬起执行</div>
|
||||
<NInput
|
||||
type="textarea"
|
||||
style="flex-grow: 1"
|
||||
placeholder="JSON宏代码, 可为空"
|
||||
v-model:value="editedMacroRaw.up"
|
||||
@update:value="editedFlag = true"
|
||||
round
|
||||
clearable
|
||||
/>
|
||||
</NFlex>
|
||||
</NCard>
|
||||
</NModal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.key-setting {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 10px 20px;
|
||||
width: 100px;
|
||||
border-radius: 5px;
|
||||
border: 2px solid var(--light-color);
|
||||
background-color: var(--bg-color);
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.key-common {
|
||||
position: absolute;
|
||||
height: 40px;
|
||||
@ -85,6 +279,18 @@ function dragHandler(downEvent: MouseEvent) {
|
||||
&:not(.active):hover {
|
||||
border: 2px solid var(--light-color);
|
||||
}
|
||||
|
||||
.key-close-btn {
|
||||
position: absolute;
|
||||
left: 45px;
|
||||
bottom: 25px;
|
||||
}
|
||||
|
||||
.key-setting-btn {
|
||||
position: absolute;
|
||||
left: 45px;
|
||||
top: 25px;
|
||||
}
|
||||
}
|
||||
.active {
|
||||
border: 2px solid var(--primary-color);
|
||||
|
@ -173,7 +173,7 @@ function delCurKeyMapping() {
|
||||
top: `${keyMapping.posY - 120}px`,
|
||||
}"
|
||||
>
|
||||
<NH4>方向键设置</NH4>
|
||||
<NH4 prefix="bar">键盘行走</NH4>
|
||||
<NFormItem label="偏移">
|
||||
<NInputNumber
|
||||
v-model:value="keyMapping.offset"
|
||||
|
Loading…
Reference in New Issue
Block a user