mirror of
https://github.com/AkiChase/scrcpy-mask
synced 2024-11-09 09:41:17 +08:00
feat(KeySwipe): add swipe key setting
This commit is contained in:
parent
996bc2517b
commit
fbbdb1b4b8
@ -63,16 +63,6 @@ let deviceWaitForScreenSizeTask: ((w: number, h: number) => void) | null = null;
|
||||
let unlisten: UnlistenFn | undefined;
|
||||
let lastClipboard = "";
|
||||
|
||||
// TODO 添加一个滑动的按键,相当于调用swipe,难点在于如何设定多个坐标点
|
||||
// 当滑动按键激活时
|
||||
// 1. 使用svg的polyline,可见gpt配合vue来渲染直线
|
||||
// 2. 并使用svg的circle单独渲染每个圆点
|
||||
// 当滑动按键激活并点开设置后
|
||||
// 1. 停止原来的按键监听,创建一个新的透明蒙版
|
||||
// 2. 在新的透明蒙版上使用svg来画线,但是用新元素来渲染每个圆点,每个圆点右上角添加删除按钮
|
||||
// 3. 每个圆点都添加点击监听来拖动
|
||||
// 4. 点击蒙版其他位置则插入新的圆点(到列表末尾)
|
||||
|
||||
onMounted(async () => {
|
||||
unlisten = await listen("device-reply", (event) => {
|
||||
try {
|
||||
|
@ -8,6 +8,7 @@ import KeySkill from "./KeySkill.vue";
|
||||
import KeyObservation from "./KeyObservation.vue";
|
||||
import KeySight from "./KeySight.vue";
|
||||
import KeyFire from "./KeyFire.vue";
|
||||
import KeySwipe from "./KeySwipe.vue";
|
||||
import ScreenStream from "../ScreenStream.vue";
|
||||
|
||||
import {
|
||||
@ -17,6 +18,7 @@ import {
|
||||
KeyTap,
|
||||
KeyMacro,
|
||||
KeyMapping,
|
||||
KeySwipe as KeyMappingKeySwipe,
|
||||
KeySight as KeyMappingKeySight,
|
||||
KeyFire as KeyMappingKeyFire,
|
||||
} from "../../keyMappingConfig";
|
||||
@ -43,6 +45,10 @@ const addButtonOptions: DropdownOption[] = [
|
||||
label: () => t("pages.KeyBoard.addButton.SteeringWheel"),
|
||||
key: "SteeringWheel",
|
||||
},
|
||||
{
|
||||
label: () => t("pages.KeyBoard.addButton.Swipe"),
|
||||
key: "Swipe",
|
||||
},
|
||||
{
|
||||
label: () => t("pages.KeyBoard.addButton.Skill"),
|
||||
key: "DirectionalSkill",
|
||||
@ -72,6 +78,7 @@ const addButtonOptions: DropdownOption[] = [
|
||||
function onAddButtonSelect(
|
||||
type:
|
||||
| "Tap"
|
||||
| "Swipe"
|
||||
| "SteeringWheel"
|
||||
| "DirectionalSkill"
|
||||
| "CancelSkill"
|
||||
@ -92,6 +99,12 @@ function onAddButtonSelect(
|
||||
if (type === "Tap") {
|
||||
keyMapping.pointerId = 3;
|
||||
(keyMapping as KeyTap).time = 80;
|
||||
} else if (type === "Swipe") {
|
||||
keyMapping.pointerId = 3;
|
||||
(keyMapping as KeyMappingKeySwipe).pos = [
|
||||
{ x: keyMapping.posX, y: keyMapping.posY },
|
||||
];
|
||||
(keyMapping as KeyMappingKeySwipe).intervalBetweenPos = 0;
|
||||
} else if (type === "SteeringWheel") {
|
||||
keyMapping.pointerId = 1;
|
||||
(keyMapping as unknown as KeyMappingSteeringWheel).key = {
|
||||
@ -173,6 +186,7 @@ function setCurButtonKey(curKey: string) {
|
||||
keyboardStore.showButtonSettingFlag ||
|
||||
keyboardStore.activeButtonIndex >= store.editKeyMappingList.length ||
|
||||
keyboardStore.showButtonSettingFlag ||
|
||||
keyboardStore.editSwipePointsFlag ||
|
||||
keyboardStore.showButtonAddFlag
|
||||
)
|
||||
return;
|
||||
@ -363,6 +377,10 @@ onBeforeRouteLeave(() => {
|
||||
v-else-if="store.editKeyMappingList[index].type === 'Observation'"
|
||||
:index="index"
|
||||
/>
|
||||
<KeySwipe
|
||||
v-else-if="store.editKeyMappingList[index].type === 'Swipe'"
|
||||
:index="index"
|
||||
/>
|
||||
<KeySight
|
||||
v-else-if="store.editKeyMappingList[index].type === 'Sight'"
|
||||
:index="index"
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { Settings, CloseCircle } from "@vicons/ionicons5";
|
||||
import { Settings, CloseCircle, ReturnUpBack } from "@vicons/ionicons5";
|
||||
import {
|
||||
NButton,
|
||||
NIcon,
|
||||
@ -122,14 +122,18 @@ function dragHandler(downEvent: MouseEvent) {
|
||||
localStore.set("keySettingPos", keySettingPos.value);
|
||||
} else {
|
||||
// click up
|
||||
keyboardStore.activeButtonIndex = -1;
|
||||
keyboardStore.activeSteeringWheelButtonKeyIndex = -1;
|
||||
keyboardStore.showSettingFlag = !keyboardStore.showSettingFlag;
|
||||
if (
|
||||
keyboardStore.showSettingFlag &&
|
||||
store.keyMappingConfigList.length === 1
|
||||
) {
|
||||
message.info(t("pages.KeyBoard.KeySetting.onlyOneConfig"));
|
||||
if (keyboardStore.editSwipePointsFlag) {
|
||||
keyboardStore.editSwipePointsFlag = false;
|
||||
} else {
|
||||
keyboardStore.activeButtonIndex = -1;
|
||||
keyboardStore.activeSteeringWheelButtonKeyIndex = -1;
|
||||
keyboardStore.showSettingFlag = !keyboardStore.showSettingFlag;
|
||||
if (
|
||||
keyboardStore.showSettingFlag &&
|
||||
store.keyMappingConfigList.length === 1
|
||||
) {
|
||||
message.info(t("pages.KeyBoard.KeySetting.onlyOneConfig"));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -374,7 +378,10 @@ function resetKeyMappingConfig() {
|
||||
}"
|
||||
>
|
||||
<template #icon>
|
||||
<NIcon><Settings /></NIcon>
|
||||
<NIcon>
|
||||
<ReturnUpBack v-if="keyboardStore.editSwipePointsFlag" />
|
||||
<Settings v-else />
|
||||
</NIcon>
|
||||
</template>
|
||||
</NButton>
|
||||
<div
|
||||
|
354
src/components/keyboard/KeySwipe.vue
Normal file
354
src/components/keyboard/KeySwipe.vue
Normal file
@ -0,0 +1,354 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from "vue";
|
||||
import { useGlobalStore } from "../../store/global";
|
||||
import {
|
||||
NIcon,
|
||||
NButton,
|
||||
NFormItem,
|
||||
NInput,
|
||||
NH4,
|
||||
NInputNumber,
|
||||
useMessage,
|
||||
} from "naive-ui";
|
||||
import { Analytics, CloseCircle, Settings } from "@vicons/ionicons5";
|
||||
import { useKeyboardStore } from "../../store/keyboard";
|
||||
import { KeySwipe } from "../../keyMappingConfig";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const props = defineProps<{
|
||||
index: number;
|
||||
}>();
|
||||
|
||||
const keyboardStore = useKeyboardStore();
|
||||
const message = useMessage();
|
||||
const store = useGlobalStore();
|
||||
const { t } = useI18n();
|
||||
|
||||
const elementRef = ref<HTMLElement | null>(null);
|
||||
|
||||
const isActive = computed(
|
||||
() => props.index === keyboardStore.activeButtonIndex
|
||||
);
|
||||
const keyMapping = computed(
|
||||
() => store.editKeyMappingList[props.index] as KeySwipe
|
||||
);
|
||||
|
||||
const trackPoints = computed(() => {
|
||||
let s = "";
|
||||
if (isActive.value) {
|
||||
for (const point of keyMapping.value.pos) {
|
||||
s += `${point.x},${point.y} `;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
});
|
||||
|
||||
function dragHandler(downEvent: MouseEvent) {
|
||||
keyboardStore.activeButtonIndex = props.index;
|
||||
keyboardStore.showButtonSettingFlag = false;
|
||||
const oldX = keyMapping.value.posX;
|
||||
const oldY = keyMapping.value.posY;
|
||||
const element = elementRef.value;
|
||||
if (element) {
|
||||
const keyboardElement = document.getElementById(
|
||||
"keyboardElement"
|
||||
) as HTMLElement;
|
||||
const maxX = keyboardElement.clientWidth - 30;
|
||||
const maxY = keyboardElement.clientHeight - 30;
|
||||
|
||||
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(30, Math.min(newX, maxX));
|
||||
newY = Math.max(30, Math.min(newY, maxY));
|
||||
keyMapping.value.posX = newX;
|
||||
keyMapping.value.posY = newY;
|
||||
};
|
||||
window.addEventListener("mousemove", moveHandler);
|
||||
const upHandler = () => {
|
||||
window.removeEventListener("mousemove", moveHandler);
|
||||
window.removeEventListener("mouseup", upHandler);
|
||||
if (oldX !== keyMapping.value.posX || oldY !== keyMapping.value.posY) {
|
||||
keyboardStore.edited = true;
|
||||
}
|
||||
};
|
||||
window.addEventListener("mouseup", upHandler);
|
||||
}
|
||||
}
|
||||
|
||||
function delCurKeyMapping() {
|
||||
keyboardStore.edited = true;
|
||||
keyboardStore.activeButtonIndex = -1;
|
||||
store.editKeyMappingList.splice(props.index, 1);
|
||||
}
|
||||
|
||||
const settingPosX = ref(0);
|
||||
const settingPosY = ref(0);
|
||||
function showSetting() {
|
||||
const keyboardElement = document.getElementById(
|
||||
"keyboardElement"
|
||||
) as HTMLElement;
|
||||
const maxWidth = keyboardElement.clientWidth - 150;
|
||||
const maxHeight = keyboardElement.clientHeight - 380;
|
||||
|
||||
settingPosX.value = Math.min(keyMapping.value.posX + 40, maxWidth);
|
||||
settingPosY.value = Math.min(keyMapping.value.posY - 40, maxHeight);
|
||||
keyboardStore.showButtonSettingFlag = true;
|
||||
}
|
||||
|
||||
function editSwipePoints() {
|
||||
message.info(t("pages.KeyBoard.Swipe.editTips"));
|
||||
keyboardStore.showButtonSettingFlag = false;
|
||||
keyboardStore.editSwipePointsFlag = true;
|
||||
}
|
||||
|
||||
function swipePointDragHandlue(downEvent: MouseEvent, index: number) {
|
||||
if (downEvent.button === 2) {
|
||||
// del point
|
||||
keyMapping.value.pos.splice(index, 1);
|
||||
return;
|
||||
}
|
||||
if (downEvent.button !== 0) return;
|
||||
|
||||
const oldX = keyMapping.value.pos[index].x;
|
||||
const oldY = keyMapping.value.pos[index].y;
|
||||
const keyboardElement = document.getElementById(
|
||||
"keyboardElement"
|
||||
) as HTMLElement;
|
||||
const maxX = keyboardElement.clientWidth;
|
||||
const maxY = keyboardElement.clientHeight;
|
||||
|
||||
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));
|
||||
keyMapping.value.pos[index].x = newX;
|
||||
keyMapping.value.pos[index].y = newY;
|
||||
};
|
||||
const upHandler = () => {
|
||||
window.removeEventListener("mousemove", moveHandler);
|
||||
window.removeEventListener("mouseup", upHandler);
|
||||
};
|
||||
window.addEventListener("mousemove", moveHandler);
|
||||
window.addEventListener("mouseup", upHandler);
|
||||
}
|
||||
|
||||
function swipeTrackClickHandler(event: MouseEvent) {
|
||||
if (event.button !== 0) return;
|
||||
console.log(event.target, event.currentTarget);
|
||||
if (event.target !== event.currentTarget) return;
|
||||
keyMapping.value.pos.push({ x: event.clientX - 70, y: event.clientY - 30 });
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
:class="{ active: isActive }"
|
||||
:style="{
|
||||
left: `${keyMapping.posX - 30}px`,
|
||||
top: `${keyMapping.posY - 30}px`,
|
||||
}"
|
||||
@mousedown="dragHandler"
|
||||
class="key-swipe"
|
||||
ref="elementRef"
|
||||
>
|
||||
<NIcon size="30"><Analytics /></NIcon>
|
||||
<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="showSetting"
|
||||
:type="isActive ? 'primary' : 'info'"
|
||||
>
|
||||
<template #icon>
|
||||
<NIcon size="15">
|
||||
<Settings />
|
||||
</NIcon>
|
||||
</template>
|
||||
</NButton>
|
||||
</div>
|
||||
<div
|
||||
class="key-setting"
|
||||
v-if="isActive && keyboardStore.showButtonSettingFlag"
|
||||
:style="{
|
||||
left: `${settingPosX}px`,
|
||||
top: `${settingPosY}px`,
|
||||
}"
|
||||
>
|
||||
<NH4 prefix="bar">{{ $t("pages.KeyBoard.Swipe.swipe") }}</NH4>
|
||||
<NFormItem :label="$t('pages.KeyBoard.Swipe.pos')">
|
||||
<NButton type="success" @click="editSwipePoints">{{
|
||||
$t("pages.KeyBoard.Swipe.editPos")
|
||||
}}</NButton>
|
||||
</NFormItem>
|
||||
<NFormItem :label="$t('pages.KeyBoard.Swipe.interval')">
|
||||
<NInputNumber
|
||||
v-model:value="keyMapping.intervalBetweenPos"
|
||||
:placeholder="$t('pages.KeyBoard.Swipe.intervalPlaceholder')"
|
||||
@update:value="keyboardStore.edited = true"
|
||||
/>
|
||||
</NFormItem>
|
||||
<NFormItem :label="$t('pages.KeyBoard.setting.pointerID')">
|
||||
<NInputNumber
|
||||
v-model:value="keyMapping.pointerId"
|
||||
:min="0"
|
||||
:placeholder="$t('pages.KeyBoard.setting.pointerIDPlaceholder')"
|
||||
@update:value="keyboardStore.edited = true"
|
||||
/>
|
||||
</NFormItem>
|
||||
<NFormItem :label="$t('pages.KeyBoard.setting.note')">
|
||||
<NInput
|
||||
v-model:value="keyMapping.note"
|
||||
:placeholder="$t('pages.KeyBoard.setting.notePlaceholder')"
|
||||
@update:value="keyboardStore.edited = true"
|
||||
/>
|
||||
</NFormItem>
|
||||
</div>
|
||||
|
||||
<template v-if="isActive">
|
||||
<div
|
||||
v-if="isActive"
|
||||
class="track"
|
||||
:class="{ 'edit-track': keyboardStore.editSwipePointsFlag }"
|
||||
>
|
||||
<svg @click="swipeTrackClickHandler">
|
||||
<polyline :points="trackPoints" />
|
||||
<circle
|
||||
v-for="(pos, i) in keyMapping.pos"
|
||||
:cx="pos.x"
|
||||
:cy="pos.y"
|
||||
r="5"
|
||||
@mousedown="(e) => swipePointDragHandlue(e, i)"
|
||||
/>
|
||||
<text v-for="(pos, i) in keyMapping.pos" :x="pos.x + 5" :y="pos.y - 5">
|
||||
{{ i }}
|
||||
</text>
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.track {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
z-index: -1;
|
||||
|
||||
svg {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
polyline {
|
||||
fill: none;
|
||||
stroke: var(--primary-hover-color);
|
||||
stroke-width: 2;
|
||||
}
|
||||
|
||||
circle {
|
||||
cursor: pointer;
|
||||
fill: var(--primary-color);
|
||||
|
||||
&:hover {
|
||||
fill: var(--primary-pressed-color);
|
||||
}
|
||||
}
|
||||
|
||||
text {
|
||||
cursor: default;
|
||||
fill: var(--primary-pressed-color);
|
||||
font-size: 15px;
|
||||
text-anchor: end-alignment;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.edit-track {
|
||||
z-index: 4;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
.key-setting {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 10px 20px;
|
||||
box-sizing: border-box;
|
||||
width: 150px;
|
||||
height: 380px;
|
||||
border-radius: 5px;
|
||||
border: 2px solid var(--light-color);
|
||||
background-color: var(--bg-color);
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.key-swipe {
|
||||
position: absolute;
|
||||
height: 60px;
|
||||
width: 60px;
|
||||
box-sizing: border-box;
|
||||
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;
|
||||
|
||||
.n-icon {
|
||||
color: var(--blue-color);
|
||||
}
|
||||
|
||||
&:not(.active):hover {
|
||||
border: 2px solid var(--light-color);
|
||||
color: var(--light-color);
|
||||
|
||||
.n-icon {
|
||||
color: var(--light-color);
|
||||
}
|
||||
}
|
||||
|
||||
.key-close-btn {
|
||||
position: absolute;
|
||||
left: 65px;
|
||||
bottom: 45px;
|
||||
}
|
||||
|
||||
.key-setting-btn {
|
||||
position: absolute;
|
||||
left: 65px;
|
||||
top: 45px;
|
||||
}
|
||||
}
|
||||
|
||||
.active {
|
||||
border: 2px solid var(--primary-color);
|
||||
color: var(--primary-color);
|
||||
z-index: 2;
|
||||
|
||||
.n-icon {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
}
|
||||
</style>
|
@ -151,7 +151,8 @@
|
||||
"Sight": "Front sight",
|
||||
"Fire": "Fire",
|
||||
"existFire": "Fire button already exists",
|
||||
"existSight": "Front sight button already exists"
|
||||
"existSight": "Front sight button already exists",
|
||||
"Swipe": "Swipe"
|
||||
},
|
||||
"buttonKeyRepeat": "Key repeat: {0}",
|
||||
"KeyCommon": {
|
||||
@ -253,6 +254,14 @@
|
||||
"scaleX": "Horizontal sensitivity",
|
||||
"scalePlaceholder": "Please enter sensitivity",
|
||||
"scaleY": "Vertical sensitivity"
|
||||
},
|
||||
"Swipe": {
|
||||
"swipe": "Swipe",
|
||||
"interval": "Swipe time interval",
|
||||
"intervalPlaceholder": "Enter the time interval between points",
|
||||
"pos": "Points",
|
||||
"editPos": "Edit",
|
||||
"editTips": "Left-click on a blank area to add a new coordinate point. \nLeft-click and drag to move a specific point, and right-click to delete the point."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -144,7 +144,8 @@
|
||||
"Sight": "准星",
|
||||
"Fire": "开火",
|
||||
"existSight": "已存在准星按钮",
|
||||
"existFire": "已存在开火按钮"
|
||||
"existFire": "已存在开火按钮",
|
||||
"Swipe": "滑动"
|
||||
},
|
||||
"buttonKeyRepeat": "按键重复: {0}",
|
||||
"noSaveDialog": {
|
||||
@ -253,6 +254,14 @@
|
||||
"scaleX": "水平灵敏度",
|
||||
"scaleY": "垂直灵敏度",
|
||||
"scalePlaceholder": "请输入灵敏度"
|
||||
},
|
||||
"Swipe": {
|
||||
"swipe": "滑动",
|
||||
"interval": "滑动时间间隔",
|
||||
"intervalPlaceholder": "输入坐标点之间的时间间隔",
|
||||
"pos": "坐标点",
|
||||
"editPos": "编辑",
|
||||
"editTips": "左键点击空白区域添加新坐标点。左键拖拽移动特定坐标点,右键删除特定坐标点"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -6,6 +6,7 @@ export const useKeyboardStore = defineStore("keyboard", () => {
|
||||
const showSettingFlag = ref(false);
|
||||
const showButtonSettingFlag = ref(false);
|
||||
const showButtonAddFlag = ref(false);
|
||||
const editSwipePointsFlag = ref(false);
|
||||
const activeButtonIndex = ref(-1);
|
||||
const activeSteeringWheelButtonKeyIndex = ref(-1);
|
||||
const edited = ref(false);
|
||||
@ -15,6 +16,7 @@ export const useKeyboardStore = defineStore("keyboard", () => {
|
||||
showSettingFlag,
|
||||
showButtonSettingFlag,
|
||||
showButtonAddFlag,
|
||||
editSwipePointsFlag,
|
||||
activeButtonIndex,
|
||||
activeSteeringWheelButtonKeyIndex,
|
||||
edited,
|
||||
|
Loading…
Reference in New Issue
Block a user