mirror of
https://github.com/ayangweb/BongoCat.git
synced 2026-03-12 17:51:48 +08:00
feat: 新增「猫咪设置 > 窗口设置 > 鼠标移入隐藏」配置项 (#727)
Co-authored-by: ayang <473033518@qq.com>
This commit is contained in:
@@ -3,6 +3,10 @@ html {
|
||||
|
||||
color-scheme: light;
|
||||
|
||||
body {
|
||||
--uno: transition-opacity-300;
|
||||
}
|
||||
|
||||
&.dark {
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import type { CursorPoint } from '@/utils/monitor'
|
||||
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
import { isEqual, mapValues } from 'es-toolkit'
|
||||
import { ref } from 'vue'
|
||||
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'
|
||||
import { cursorPosition } from '@tauri-apps/api/window'
|
||||
|
||||
import { INVOKE_KEY, LISTEN_KEY } from '../constants'
|
||||
|
||||
@@ -11,6 +9,7 @@ import { useTauriListen } from './useTauriListen'
|
||||
|
||||
import { useCatStore } from '@/stores/cat'
|
||||
import { useModelStore } from '@/stores/model'
|
||||
import { inBetween } from '@/utils/is'
|
||||
import { isWindows } from '@/utils/platform'
|
||||
|
||||
interface MouseButtonEvent {
|
||||
@@ -18,6 +17,11 @@ interface MouseButtonEvent {
|
||||
value: string
|
||||
}
|
||||
|
||||
export interface CursorPoint {
|
||||
x: number
|
||||
y: number
|
||||
}
|
||||
|
||||
interface MouseMoveEvent {
|
||||
kind: 'MouseMove'
|
||||
value: CursorPoint
|
||||
@@ -32,7 +36,6 @@ type DeviceEvent = MouseButtonEvent | MouseMoveEvent | KeyboardEvent
|
||||
|
||||
export function useDevice() {
|
||||
const modelStore = useModelStore()
|
||||
const lastCursorPoint = ref<CursorPoint>({ x: 0, y: 0 })
|
||||
const releaseTimers = new Map<string, NodeJS.Timeout>()
|
||||
const catStore = useCatStore()
|
||||
const { handlePress, handleRelease, handleMouseChange, handleMouseMove } = useModel()
|
||||
@@ -60,14 +63,25 @@ export function useDevice() {
|
||||
return nextKey
|
||||
}
|
||||
|
||||
const processMouseMove = (point: CursorPoint) => {
|
||||
const roundedValue = mapValues(point, Math.round)
|
||||
const handleCursorMove = async () => {
|
||||
const cursorPoint = await cursorPosition()
|
||||
|
||||
if (isEqual(lastCursorPoint.value, roundedValue)) return
|
||||
handleMouseMove(cursorPoint)
|
||||
|
||||
lastCursorPoint.value = roundedValue
|
||||
if (catStore.window.hideOnHover) {
|
||||
const appWindow = getCurrentWebviewWindow()
|
||||
const position = await appWindow.outerPosition()
|
||||
const { width, height } = await appWindow.innerSize()
|
||||
|
||||
return handleMouseMove(point)
|
||||
const isInWindow = inBetween(cursorPoint.x, position.x, position.x + width)
|
||||
&& inBetween(cursorPoint.y, position.y, position.y + height)
|
||||
|
||||
document.body.style.setProperty('opacity', isInWindow ? '0' : 'unset')
|
||||
|
||||
if (!catStore.window.passThrough) {
|
||||
appWindow.setIgnoreCursorEvents(isInWindow)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleAutoRelease = (key: string, delay = 100) => {
|
||||
@@ -117,7 +131,7 @@ export function useDevice() {
|
||||
case 'MouseRelease':
|
||||
return handleMouseChange(value, false)
|
||||
case 'MouseMove':
|
||||
return processMouseMove(value)
|
||||
return handleCursorMove()
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { CursorPoint } from '@/utils/monitor'
|
||||
import type { PhysicalPosition } from '@tauri-apps/api/dpi'
|
||||
|
||||
import { LogicalSize } from '@tauri-apps/api/dpi'
|
||||
import { resolveResource, sep } from '@tauri-apps/api/path'
|
||||
@@ -107,12 +107,12 @@ export function useModel() {
|
||||
live2d.setParameterValue(id, pressed)
|
||||
}
|
||||
|
||||
async function handleMouseMove(point: CursorPoint) {
|
||||
const monitor = await getCursorMonitor(point)
|
||||
async function handleMouseMove(cursorPoint: PhysicalPosition) {
|
||||
const monitor = await getCursorMonitor(cursorPoint)
|
||||
|
||||
if (!monitor) return
|
||||
|
||||
const { size, position, cursorPoint } = monitor
|
||||
const { size, position } = monitor
|
||||
|
||||
const xRatio = (cursorPoint.x - position.x) / size.width
|
||||
const yRatio = (cursorPoint.y - position.y) / size.height
|
||||
|
||||
@@ -20,7 +20,8 @@
|
||||
"windowSize": "Window Size",
|
||||
"windowRadius": "Window Radius",
|
||||
"opacity": "Opacity",
|
||||
"autoReleaseDelay": "Auto Release Delay"
|
||||
"autoReleaseDelay": "Auto Release Delay",
|
||||
"hideOnHover": "Hide on Hover"
|
||||
},
|
||||
"hints": {
|
||||
"mirrorMode": "When enabled, the model will be horizontally flipped.",
|
||||
@@ -29,7 +30,8 @@
|
||||
"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.",
|
||||
"autoReleaseDelay": "Due to Windows not capturing the release events of certain system-level keys, they will be automatically treated as released after a timeout."
|
||||
"autoReleaseDelay": "Due to Windows not capturing the release events of certain system-level keys, they will be automatically treated as released after a timeout.",
|
||||
"hideOnHover": "When enabled, the window will hide when the mouse hovers over it."
|
||||
}
|
||||
},
|
||||
"general": {
|
||||
|
||||
@@ -20,7 +20,8 @@
|
||||
"windowSize": "Kích thước",
|
||||
"windowRadius": "Độ bo tròn cửa sổ",
|
||||
"opacity": "Độ mờ",
|
||||
"autoReleaseDelay": "Độ trễ tự động nhả phím"
|
||||
"autoReleaseDelay": "Độ trễ tự động nhả phím",
|
||||
"hideOnHover": "Ẩn khi di chuột"
|
||||
},
|
||||
"hints": {
|
||||
"mirrorMode": "Bật để lật ngang mô hình.",
|
||||
@@ -29,7 +30,8 @@
|
||||
"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.",
|
||||
"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ờ."
|
||||
"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ờ.",
|
||||
"hideOnHover": "Khi bật, cửa sổ sẽ ẩn khi chuột di chuyển vào."
|
||||
}
|
||||
},
|
||||
"general": {
|
||||
|
||||
@@ -20,7 +20,8 @@
|
||||
"windowSize": "窗口尺寸",
|
||||
"windowRadius": "窗口圆角",
|
||||
"opacity": "不透明度",
|
||||
"autoReleaseDelay": "按键自动释放延迟"
|
||||
"autoReleaseDelay": "按键自动释放延迟",
|
||||
"hideOnHover": "鼠标移入隐藏"
|
||||
},
|
||||
"hints": {
|
||||
"mirrorMode": "启用后,模型将水平镜像翻转。",
|
||||
@@ -29,7 +30,8 @@
|
||||
"passThrough": "启用后,窗口不影响对其他应用程序的操作。",
|
||||
"alwaysOnTop": "启用后,窗口始终显示在其他应用程序上方。",
|
||||
"windowSize": "将鼠标移至窗口边缘,或按住 Shift 并右键拖动,也可以调整窗口大小。",
|
||||
"autoReleaseDelay": "由于 Windows 下部分系统级按键无法捕获释放事件,超时后将自动视为已释放。"
|
||||
"autoReleaseDelay": "由于 Windows 下部分系统级按键无法捕获释放事件,超时后将自动视为已释放。",
|
||||
"hideOnHover": "启用后,鼠标悬停在窗口上时,窗口会隐藏。"
|
||||
}
|
||||
},
|
||||
"general": {
|
||||
|
||||
@@ -60,6 +60,13 @@ const catStore = useCatStore()
|
||||
<Switch v-model:checked="catStore.window.alwaysOnTop" />
|
||||
</ProListItem>
|
||||
|
||||
<ProListItem
|
||||
:description="$t('pages.preference.cat.hints.hideOnHover')"
|
||||
:title="$t('pages.preference.cat.labels.hideOnHover')"
|
||||
>
|
||||
<Switch v-model:checked="catStore.window.hideOnHover" />
|
||||
</ProListItem>
|
||||
|
||||
<ProListItem
|
||||
:description="$t('pages.preference.cat.hints.windowSize')"
|
||||
:title="$t('pages.preference.cat.labels.windowSize')"
|
||||
|
||||
@@ -15,6 +15,7 @@ export interface CatStore {
|
||||
scale: number
|
||||
opacity: number
|
||||
radius: number
|
||||
hideOnHover: boolean
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +60,7 @@ export const useCatStore = defineStore('cat', () => {
|
||||
scale: 100,
|
||||
opacity: 100,
|
||||
radius: 0,
|
||||
hideOnHover: false,
|
||||
})
|
||||
|
||||
const init = () => {
|
||||
|
||||
@@ -3,3 +3,7 @@ export function isImage(value: string) {
|
||||
|
||||
return regex.test(value)
|
||||
}
|
||||
|
||||
export function inBetween(value: number, minimum: number, maximum: number) {
|
||||
return value >= minimum && value <= maximum
|
||||
}
|
||||
|
||||
@@ -1,33 +1,17 @@
|
||||
import type { PhysicalPosition } from '@tauri-apps/api/window'
|
||||
|
||||
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'
|
||||
import { monitorFromPoint } from '@tauri-apps/api/window'
|
||||
import { mapValues } from 'es-toolkit'
|
||||
|
||||
import { isMac } from './platform'
|
||||
export async function getCursorMonitor(cursorPoint: PhysicalPosition) {
|
||||
const appWindow = getCurrentWebviewWindow()
|
||||
const scaleFactor = await appWindow.scaleFactor()
|
||||
|
||||
export interface CursorPoint {
|
||||
x: number
|
||||
y: number
|
||||
}
|
||||
|
||||
export async function getCursorMonitor(point: CursorPoint) {
|
||||
let cursorPoint = point
|
||||
|
||||
if (isMac) {
|
||||
const appWindow = getCurrentWebviewWindow()
|
||||
|
||||
const scaleFactor = await appWindow.scaleFactor()
|
||||
|
||||
cursorPoint = mapValues(cursorPoint, value => value * scaleFactor)
|
||||
}
|
||||
|
||||
const { x, y } = point
|
||||
const { x, y } = cursorPoint.toLogical(scaleFactor)
|
||||
|
||||
const monitor = await monitorFromPoint(x, y)
|
||||
|
||||
if (!monitor) return
|
||||
|
||||
return {
|
||||
...monitor,
|
||||
cursorPoint,
|
||||
}
|
||||
return monitor
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user