diff --git a/src/components/pro-list-item/index.vue b/src/components/pro-list-item/index.vue index 59bcb31..932fd3f 100644 --- a/src/components/pro-list-item/index.vue +++ b/src/components/pro-list-item/index.vue @@ -23,7 +23,10 @@ const hasDescription = computed(() => { justify="space-between" :vertical="vertical" > - +
{{ title }} diff --git a/src/composables/useDevice.ts b/src/composables/useDevice.ts index 41e9d3e..b9207d1 100644 --- a/src/composables/useDevice.ts +++ b/src/composables/useDevice.ts @@ -1,7 +1,6 @@ import type { CursorPoint } from '@/utils/monitor' import { invoke } from '@tauri-apps/api/core' -import { useDebounceFn } from '@vueuse/core' import { isEqual, mapValues } from 'es-toolkit' import { ref } from 'vue' @@ -10,7 +9,9 @@ import { INVOKE_KEY, LISTEN_KEY } from '../constants' import { useModel } from './useModel' import { useTauriListen } from './useTauriListen' +import { useCatStore } from '@/stores/cat' import { useModelStore } from '@/stores/model' +import { isWindows } from '@/utils/platform' interface MouseButtonEvent { kind: 'MousePress' | 'MouseRelease' @@ -32,14 +33,14 @@ type DeviceEvent = MouseButtonEvent | MouseMoveEvent | KeyboardEvent export function useDevice() { const modelStore = useModelStore() const lastCursorPoint = ref({ x: 0, y: 0 }) + const releaseTimers = new Map() + const catStore = useCatStore() const { handlePress, handleRelease, handleMouseChange, handleMouseMove } = useModel() const startListening = () => { invoke(INVOKE_KEY.START_DEVICE_LISTENING) } - const debouncedRelease = useDebounceFn(handleRelease, 100) - const getSupportedKey = (key: string) => { let nextKey = key @@ -69,6 +70,22 @@ export function useDevice() { return handleMouseMove(point) } + const handleAutoRelease = (key: string, delay = 100) => { + handlePress(key) + + if (releaseTimers.has(key)) { + clearTimeout(releaseTimers.get(key)) + } + + const timer = setTimeout(() => { + handleRelease(key) + + releaseTimers.delete(key) + }, delay) + + releaseTimers.set(key, timer) + } + useTauriListen(LISTEN_KEY.DEVICE_CHANGED, ({ payload }) => { const { kind, value } = payload @@ -78,12 +95,16 @@ export function useDevice() { if (!nextValue) return if (nextValue === 'CapsLock') { - handlePress(nextValue) - - return debouncedRelease(nextValue) + return handleAutoRelease(nextValue) } if (kind === 'KeyboardPress') { + if (isWindows) { + const delay = catStore.model.autoReleaseDelay * 1000 + + return handleAutoRelease(nextValue, delay) + } + return handlePress(nextValue) } diff --git a/src/locales/en-US.json b/src/locales/en-US.json index 5b7cfc5..97b2e07 100644 --- a/src/locales/en-US.json +++ b/src/locales/en-US.json @@ -19,7 +19,8 @@ "alwaysOnTop": "Always On Top", "windowSize": "Window Size", "windowRadius": "Window Radius", - "opacity": "Opacity" + "opacity": "Opacity", + "autoReleaseDelay": "Auto Release Delay" }, "hints": { "mirrorMode": "When enabled, the model will be horizontally flipped.", @@ -27,7 +28,8 @@ "mouseMirror": "When enabled, the mouse will mirror follow the hand movement.", "passThrough": "When enabled, the window will not affect operations on other applications.", "alwaysOnTop": "When enabled, the window will always stay above other applications.", - "windowSize": "Move the mouse to the edge of the window or hold Shift and right-drag to resize." + "windowSize": "Move the mouse to the edge of the window or hold Shift and right-drag to resize.", + "autoReleaseDelay": "Due to Windows not capturing the release events of certain system-level keys, they will be automatically treated as released after a timeout." } }, "general": { diff --git a/src/locales/vi-VN.json b/src/locales/vi-VN.json index 5aec764..30458d8 100644 --- a/src/locales/vi-VN.json +++ b/src/locales/vi-VN.json @@ -19,7 +19,8 @@ "alwaysOnTop": "Luôn trên cùng", "windowSize": "Kích thước", "windowRadius": "Độ bo tròn cửa sổ", - "opacity": "Độ mờ" + "opacity": "Độ mờ", + "autoReleaseDelay": "Độ trễ tự động nhả phím" }, "hints": { "mirrorMode": "Bật để lật ngang mô hình.", @@ -27,7 +28,8 @@ "mouseMirror": "Khi bật, chuột của mô hình sẽ phản chiếu theo chuyển động chuột thực tế.", "passThrough": "Bật để cửa sổ không ảnh hưởng đến thao tác trên ứng dụng khác.", "alwaysOnTop": "Bật để cửa sổ luôn nằm trên ứng dụng khác.", - "windowSize": "Di chuyển chuột đến mép cửa sổ hoặc giữ Shift và kéo chuột phải để thay đổi kích thước." + "windowSize": "Di chuyển chuột đến mép cửa sổ hoặc giữ Shift và kéo chuột phải để thay đổi kích thước.", + "autoReleaseDelay": "Do Windows không bắt được sự kiện nhả của một số phím hệ thống, các phím đó sẽ được tự động xem như đã nhả sau khi hết thời gian chờ." } }, "general": { diff --git a/src/locales/zh-CN.json b/src/locales/zh-CN.json index 6f0f966..abfcfc7 100644 --- a/src/locales/zh-CN.json +++ b/src/locales/zh-CN.json @@ -19,7 +19,8 @@ "alwaysOnTop": "窗口置顶", "windowSize": "窗口尺寸", "windowRadius": "窗口圆角", - "opacity": "不透明度" + "opacity": "不透明度", + "autoReleaseDelay": "按键自动释放延迟" }, "hints": { "mirrorMode": "启用后,模型将水平镜像翻转。", @@ -27,7 +28,8 @@ "mouseMirror": "启用后,鼠标将镜像跟随手部移动。", "passThrough": "启用后,窗口不影响对其他应用程序的操作。", "alwaysOnTop": "启用后,窗口始终显示在其他应用程序上方。", - "windowSize": "将鼠标移至窗口边缘,或按住 Shift 并右键拖动,也可以调整窗口大小。" + "windowSize": "将鼠标移至窗口边缘,或按住 Shift 并右键拖动,也可以调整窗口大小。", + "autoReleaseDelay": "由于 Windows 下部分系统级按键无法捕获释放事件,超时后将自动视为已释放。" } }, "general": { diff --git a/src/pages/preference/components/cat/index.vue b/src/pages/preference/components/cat/index.vue index 0e8ccd1..512db24 100644 --- a/src/pages/preference/components/cat/index.vue +++ b/src/pages/preference/components/cat/index.vue @@ -4,6 +4,7 @@ import { InputNumber, Slider, Switch } from 'ant-design-vue' import ProList from '@/components/pro-list/index.vue' import ProListItem from '@/components/pro-list-item/index.vue' import { useCatStore } from '@/stores/cat' +import { isWindows } from '@/utils/platform' const catStore = useCatStore() @@ -30,6 +31,18 @@ const catStore = useCatStore() > + + + + @@ -74,7 +87,7 @@ const catStore = useCatStore() > { mirror: false, single: false, mouseMirror: false, + autoReleaseDelay: 3, }) const window = reactive({