Skip to content

Commit ab001a7

Browse files
committed
fix(stage-tamagotchi): live2d focus issue & added useElectronAllDisplays, useElectronRelativeMouse, and updated devtools
1 parent 78a9a77 commit ab001a7

File tree

19 files changed

+244
-97
lines changed

19 files changed

+244
-97
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export * from './screen'
2+
export * from './window'

apps/stage-tamagotchi/src/main/services/electron/screen.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,23 @@ import type { BrowserWindow } from 'electron'
44
import { defineInvokeHandler } from '@unbird/eventa'
55
import { screen } from 'electron'
66

7+
import { cursorScreenPoint, startLoopGetCursorScreenPoint } from '../../../shared/electron/screen'
78
import { electron } from '../../../shared/eventa'
9+
import { onAppBeforeQuit, onAppWindowAllClosed } from '../../libs/bootkit/lifecycle'
10+
import { useLoop } from '../../libs/event-loop'
811

912
export function createScreenService(params: { context: ReturnType<typeof createContext>['context'], window: BrowserWindow }) {
13+
const { start, stop } = useLoop(() => {
14+
const dipPos = screen.getCursorScreenPoint()
15+
params.context.emit(cursorScreenPoint, dipPos)
16+
}, {
17+
autoStart: false,
18+
})
19+
20+
onAppWindowAllClosed(() => stop())
21+
onAppBeforeQuit(() => stop())
22+
defineInvokeHandler(params.context, startLoopGetCursorScreenPoint, () => start())
23+
1024
defineInvokeHandler(params.context, electron.screen.getAllDisplays, () => screen.getAllDisplays())
1125
defineInvokeHandler(params.context, electron.screen.getPrimaryDisplay, () => screen.getPrimaryDisplay())
1226
defineInvokeHandler(params.context, electron.screen.dipToScreenPoint, point => screen.dipToScreenPoint(point))
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import type { createContext } from '@unbird/eventa/adapters/electron/main'
2+
import type { BrowserWindow } from 'electron'
3+
4+
import { defineInvokeHandler } from '@unbird/eventa'
5+
6+
import { bounds, startLoopGetBounds } from '../../../shared/electron/window'
7+
import { electron } from '../../../shared/eventa'
8+
import { onAppBeforeQuit, onAppWindowAllClosed } from '../../libs/bootkit/lifecycle'
9+
import { useLoop } from '../../libs/event-loop'
10+
11+
export function createWindowService(params: { context: ReturnType<typeof createContext>['context'], window: BrowserWindow }) {
12+
const { start, stop } = useLoop(() => {
13+
if (params.window.isDestroyed()) {
14+
return
15+
}
16+
17+
params.context.emit(bounds, params.window.getBounds())
18+
}, {
19+
autoStart: false,
20+
})
21+
22+
onAppWindowAllClosed(() => stop())
23+
onAppBeforeQuit(() => stop())
24+
defineInvokeHandler(params.context, startLoopGetBounds, () => start())
25+
26+
defineInvokeHandler(params.context, electron.window.getBounds, () => params.window.getBounds())
27+
}

apps/stage-tamagotchi/src/main/services/fade-on-hover/index.ts

Lines changed: 0 additions & 5 deletions
This file was deleted.

apps/stage-tamagotchi/src/main/services/misc/mouse.ts

Lines changed: 0 additions & 21 deletions
This file was deleted.

apps/stage-tamagotchi/src/main/windows/main/rpc/index.electron.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,14 @@ import { createContext } from '@unbird/eventa/adapters/electron/main'
55
import { ipcMain } from 'electron'
66

77
import { electronOpenMainDevtools, electronOpenSettings } from '../../../../shared/eventa'
8-
import { createScreenService } from '../../../services/electron'
9-
import { createFadeOnHoverService } from '../../../services/fade-on-hover'
10-
import { createMouseService } from '../../../services/misc/mouse'
8+
import { createScreenService, createWindowService } from '../../../services/electron'
119
import { toggleWindowShow } from '../../shared'
1210

1311
export function setupMainWindowElectronInvokes(params: { window: BrowserWindow, settingsWindow: () => Promise<BrowserWindow> }) {
1412
const { context } = createContext(ipcMain, params.window)
1513

16-
createFadeOnHoverService(context)
17-
createMouseService(context)
1814
createScreenService({ context, window: params.window })
15+
createWindowService({ context, window: params.window })
1916

2017
defineInvokeHandler(context, electronOpenMainDevtools, () => params.window.webContents.openDevTools({ mode: 'detach' }))
2118
defineInvokeHandler(context, electronOpenSettings, async () => toggleWindowShow(await params.settingsWindow()))

apps/stage-tamagotchi/src/main/windows/settings/rpc/index.electron.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@ import { createContext } from '@unbird/eventa/adapters/electron/main'
55
import { ipcMain } from 'electron'
66

77
import { electronOpenSettingsDevtools } from '../../../../shared/eventa'
8-
import { createScreenService } from '../../../services/electron'
9-
import { createFadeOnHoverService } from '../../../services/fade-on-hover'
8+
import { createScreenService, createWindowService } from '../../../services/electron'
109

1110
export async function setupSettingsWindowInvokes(params: { settingsWindow: BrowserWindow }) {
1211
const { context } = createContext(ipcMain, params.settingsWindow)
1312

14-
createFadeOnHoverService(context)
1513
createScreenService({ context, window: params.settingsWindow })
14+
createWindowService({ context, window: params.settingsWindow })
1615

1716
defineInvokeHandler(context, electronOpenSettingsDevtools, async () => params.settingsWindow.webContents.openDevTools({ mode: 'detach' }))
1817
}

apps/stage-tamagotchi/src/renderer/layouts/default.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { RouterView } from 'vue-router'
33
</script>
44

55
<template>
6-
<div h-full w-full p-4 flex="~ col gap-4">
6+
<div h-full w-full flex="~ col gap-4">
77
<RouterView />
88
</div>
99
</template>

apps/stage-tamagotchi/src/renderer/pages/devtools/electron-display.vue renamed to apps/stage-tamagotchi/src/renderer/pages/devtools/use-electron-all-displays.vue

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,15 @@
11
<script setup lang="ts">
2-
import { defineInvoke } from '@unbird/eventa'
3-
import { createContext } from '@unbird/eventa/adapters/electron/renderer'
4-
import { computedAsync, useIntervalFn, useWindowSize } from '@vueuse/core'
2+
import { useWindowSize } from '@vueuse/core'
53
import { computed, ref } from 'vue'
64
7-
import { electron } from '../../../shared/electron'
5+
import { useElectronAllDisplays, useElectronMouse } from '../../stores/window'
86
9-
const { context: ctx } = createContext(window.electron.ipcRenderer)
10-
const getAllDisplays = defineInvoke(ctx, electron.screen.getAllDisplays)
11-
const getCursorScreenPoint = defineInvoke(ctx, electron.screen.getCursorScreenPoint)
7+
const allDisplays = useElectronAllDisplays()
8+
const { x: cursorX, y: cursorY } = useElectronMouse()
129
13-
const allDisplays = computedAsync(async () => getAllDisplays(), [])
14-
const cursorPoint = ref({ x: 0, y: 0 })
15-
16-
// Update cursor position periodically
17-
useIntervalFn(async () => {
18-
const newPoint = await getCursorScreenPoint()
19-
cursorPoint.value = newPoint
20-
}, 1000 / 60)
21-
22-
// Get container element and its bounds
2310
const containerRef = ref<HTMLElement>()
2411
const windowSize = useWindowSize()
2512
26-
// Calculate bounds for all displays
2713
const displayBounds = computed(() => {
2814
if (!allDisplays.value.length)
2915
return { minX: 0, minY: 0, maxX: 0, maxY: 0, width: 0, height: 0 }
@@ -85,8 +71,8 @@ function transformDisplay(display: any) {
8571
const transformedCursor = computed(() => {
8672
const { minX, minY } = displayBounds.value
8773
return {
88-
x: (cursorPoint.value.x - minX) * scale.value,
89-
y: (cursorPoint.value.y - minY) * scale.value,
74+
x: (cursorX.value - minX) * scale.value,
75+
y: (cursorY.value - minY) * scale.value,
9076
}
9177
})
9278
@@ -148,7 +134,7 @@ const containerDimensions = computed(() => {
148134
}"
149135
>
150136
<div class="absolute left-3 whitespace-nowrap text-[11px] text-primary-400 font-bold -top-1.25">
151-
{{ cursorPoint.x }}, {{ cursorPoint.y }}
137+
{{ cursorX }}, {{ cursorY }}
152138
</div>
153139
</div>
154140
</div>
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<script setup lang="ts">
2+
import { useElectronMouse, useElectronRelativeMouse, useElectronWindowBounds } from '../../stores/window'
3+
4+
const { x: cursorX, y: cursorY } = useElectronMouse()
5+
6+
const windowRelativeMouse = useElectronRelativeMouse()
7+
const windowBounds = useElectronWindowBounds()
8+
</script>
9+
10+
<template>
11+
<div class="space-y-6">
12+
<div class="rounded bg-neutral-100 p-3 text-xs font-mono space-y-2 dark:bg-neutral-800">
13+
<div>windowX = screenX - windowBounds.x</div>
14+
<div>windowY = screenY - windowBounds.y</div>
15+
<div class="border-t border-neutral-300 pt-2 dark:border-neutral-700">
16+
<div>
17+
{{ windowRelativeMouse.x.value }} = {{ cursorX }} - {{ windowBounds.x.value }}
18+
</div>
19+
<div>
20+
{{ windowRelativeMouse.y.value }} = {{ cursorY }} - {{ windowBounds.y.value }}
21+
</div>
22+
</div>
23+
</div>
24+
25+
<!-- Visual Representation -->
26+
<div class="relative border-2 border-neutral-300 rounded bg-white p-8 dark:border-neutral-700 dark:bg-neutral-950" style="height: 400px;">
27+
<!-- Window representation -->
28+
<div class="absolute inset-8 border-2 border-primary-500 rounded bg-primary-50/20 dark:bg-primary-950/20">
29+
<div class="absolute left-0 text-xs text-primary-600 font-semibold -top-6">
30+
Window ({{ windowBounds.width.value }}×{{ windowBounds.height.value }})
31+
</div>
32+
33+
<!-- Center crosshair -->
34+
<div class="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2">
35+
<div class="h-8 w-0.5 bg-neutral-300 dark:bg-neutral-700" />
36+
<div class="absolute left-1/2 top-1/2 h-0.5 w-8 bg-neutral-300 -translate-x-1/2 -translate-y-1/2 dark:bg-neutral-700" />
37+
<div class="absolute left-1/2 top-6 whitespace-nowrap text-[10px] text-neutral-500 -translate-x-1/2">
38+
Center ({{ Math.round(windowBounds.width.value / 2) }}, {{ Math.round(windowBounds.height.value / 2) }})
39+
</div>
40+
</div>
41+
42+
<!-- Current cursor position (scaled to fit) -->
43+
<div
44+
class="absolute h-3 w-3 border-2 border-green-600 rounded-full bg-green-500 -translate-x-1/2 -translate-y-1/2"
45+
:style="{
46+
left: `${Math.max(0, Math.min(100, (windowRelativeMouse.x.value / windowBounds.width.value) * 100))}%`,
47+
top: `${Math.max(0, Math.min(100, (windowRelativeMouse.y.value / windowBounds.height.value) * 100))}%`,
48+
}"
49+
>
50+
<div class="absolute left-4 whitespace-nowrap text-[10px] text-green-600 font-semibold -top-1">
51+
({{ Math.round(windowRelativeMouse.x.value) }}, {{ Math.round(windowRelativeMouse.y.value) }})
52+
</div>
53+
</div>
54+
55+
<!-- Corner labels -->
56+
<div class="absolute text-[10px] text-neutral-500 -left-5 -top-5">
57+
(0, 0)
58+
</div>
59+
<div class="absolute text-[10px] text-neutral-500 -right-5 -top-5">
60+
({{ windowBounds.width.value }}, 0)
61+
</div>
62+
<div class="absolute text-[10px] text-neutral-500 -bottom-5 -left-5">
63+
(0, {{ windowBounds.height.value }})
64+
</div>
65+
<div class="absolute text-[10px] text-neutral-500 -bottom-5 -right-5">
66+
({{ windowBounds.width.value }}, {{ windowBounds.height.value }})
67+
</div>
68+
</div>
69+
70+
<div class="absolute left-0 text-xs text-neutral-600 -bottom-6 dark:text-neutral-400">
71+
Green dot shows current window-relative cursor position
72+
</div>
73+
</div>
74+
</div>
75+
</template>
76+
77+
<route lang="yaml">
78+
meta:
79+
layout: settings
80+
</route>

0 commit comments

Comments
 (0)