refactor(stage-tamagotchi): cleanup code
This commit is contained in:
@@ -1,34 +0,0 @@
|
||||
// import { useMagicKeys } from '@vueuse/core'
|
||||
// import { until, whenever } from '@vueuse/shared'
|
||||
// import { storeToRefs } from 'pinia'
|
||||
// import { watch } from 'vue'
|
||||
|
||||
// import { useShortcutsStore } from '../stores/shortcuts'
|
||||
// import { useAppRuntime } from './runtime'
|
||||
// import { useTauriRdevEventTarget } from './tauri-rdev'
|
||||
|
||||
// export function useTauriGlobalShortcuts() {
|
||||
// const { shortcuts } = storeToRefs(useShortcutsStore())
|
||||
// const { platform, isInitialized } = useAppRuntime()
|
||||
// const eventTarget = useTauriRdevEventTarget()
|
||||
// const keys = useMagicKeys({ target: eventTarget })
|
||||
|
||||
// watch(shortcuts, async () => {
|
||||
// await until(isInitialized).toBeTruthy()
|
||||
// if (platform.value === 'web') {
|
||||
// return
|
||||
// }
|
||||
|
||||
// for (const handler of shortcuts.value) {
|
||||
// if (!handler.shortcut) {
|
||||
// return
|
||||
// }
|
||||
|
||||
// whenever(keys[handler.shortcut], async () => {
|
||||
// handler.handle().catch((error) => {
|
||||
// console.error('Error handling shortcut', error)
|
||||
// })
|
||||
// })
|
||||
// }
|
||||
// }, { immediate: true })
|
||||
// }
|
||||
@@ -1,42 +0,0 @@
|
||||
// import type { Position } from '@tauri-apps/plugin-positioner'
|
||||
|
||||
// import { computedAsync, until } from '@vueuse/core'
|
||||
|
||||
// import { useAppRuntime } from './runtime'
|
||||
// import { untilImported } from './tauri'
|
||||
|
||||
// export function useTauriPositioner() {
|
||||
// const { platform, isInitialized } = useAppRuntime()
|
||||
|
||||
// const tauriPositionerApi = computedAsync(async () => {
|
||||
// await until(isInitialized).toBeTruthy()
|
||||
|
||||
// if (platform.value !== 'web') {
|
||||
// return untilImported(() => import('@tauri-apps/plugin-positioner'), console.warn)
|
||||
// }
|
||||
// })
|
||||
|
||||
// async function ensureImported() {
|
||||
// await until(isInitialized).toBeTruthy()
|
||||
|
||||
// if (platform.value === 'web') {
|
||||
// console.warn('Attempted to use Tauri positioner in web platform')
|
||||
// return
|
||||
// }
|
||||
|
||||
// await until(tauriPositionerApi).toBeTruthy()
|
||||
// const imported = await tauriPositionerApi.value
|
||||
// if (!imported) {
|
||||
// throw new Error('Tauri positioner API not available')
|
||||
// }
|
||||
// }
|
||||
|
||||
// async function moveWindow(to: Position) {
|
||||
// await ensureImported()
|
||||
// return tauriPositionerApi.value?.moveWindow(to)
|
||||
// }
|
||||
|
||||
// return {
|
||||
// moveWindow,
|
||||
// }
|
||||
// }
|
||||
@@ -1,117 +0,0 @@
|
||||
// import type { AiriTamagotchiEvents } from './tauri'
|
||||
|
||||
// import { onMounted, onUnmounted } from 'vue'
|
||||
|
||||
// import { KeyCode, mapKeyCode, mapKeyKey } from '../tauri/rdev'
|
||||
// import { useTauriEvent } from './tauri'
|
||||
|
||||
// export function useTauriRdevEventTarget(): EventTarget {
|
||||
// const unListenFuncs: (() => void)[] = []
|
||||
// const eventTarget = new EventTarget()
|
||||
|
||||
// const { listen } = useTauriEvent<AiriTamagotchiEvents>()
|
||||
|
||||
// async function setup() {
|
||||
// window.addEventListener('keyup', (event) => {
|
||||
// event.preventDefault()
|
||||
// event.stopPropagation()
|
||||
|
||||
// const e = new KeyboardEvent('keyup', {
|
||||
// key: event.key,
|
||||
// code: event.code,
|
||||
// metaKey: event.metaKey,
|
||||
// ctrlKey: event.ctrlKey,
|
||||
// altKey: event.altKey,
|
||||
// shiftKey: event.shiftKey,
|
||||
// })
|
||||
// eventTarget.dispatchEvent(e)
|
||||
// })
|
||||
|
||||
// window.addEventListener('keydown', (event) => {
|
||||
// event.preventDefault()
|
||||
// event.stopPropagation()
|
||||
|
||||
// const e = new KeyboardEvent('keydown', {
|
||||
// key: event.key,
|
||||
// code: event.code,
|
||||
// metaKey: event.metaKey,
|
||||
// ctrlKey: event.ctrlKey,
|
||||
// altKey: event.altKey,
|
||||
// shiftKey: event.shiftKey,
|
||||
// })
|
||||
// eventTarget.dispatchEvent(e)
|
||||
// })
|
||||
|
||||
// unListenFuncs.push(await listen('tauri-plugins:tauri-plugin-rdev:mousemove', (event) => {
|
||||
// if (event.payload.event_type.MouseMove) {
|
||||
// const { x, y } = event.payload.event_type.MouseMove
|
||||
// const e = new MouseEvent('mousemove', {
|
||||
// clientX: x,
|
||||
// clientY: y,
|
||||
// })
|
||||
// eventTarget.dispatchEvent(e)
|
||||
// }
|
||||
// }))
|
||||
|
||||
// unListenFuncs.push(await listen('tauri-plugins:tauri-plugin-rdev:keyup', (event) => {
|
||||
// if (typeof event.payload.event_type.KeyRelease === 'object' && 'Unknown' in event.payload.event_type.KeyRelease) {
|
||||
// if (event.payload.event_type.KeyRelease.Unknown === 62) {
|
||||
// event.payload.event_type = { KeyRelease: KeyCode.ControlLeft }
|
||||
// }
|
||||
// }
|
||||
// if (typeof event.payload.event_type.KeyRelease !== 'string') {
|
||||
// console.warn('unknown key release event:', event.payload.event_type.KeyRelease)
|
||||
// return
|
||||
// }
|
||||
|
||||
// const e = new KeyboardEvent('keyup', {
|
||||
// key: mapKeyKey[event.payload.event_type.KeyRelease],
|
||||
// code: mapKeyCode[event.payload.event_type.KeyRelease],
|
||||
// metaKey: mapKeyKey[event.payload.event_type.KeyRelease] === 'Meta',
|
||||
// ctrlKey: mapKeyKey[event.payload.event_type.KeyRelease] === 'Control',
|
||||
// altKey: mapKeyKey[event.payload.event_type.KeyRelease] === 'Alt',
|
||||
// shiftKey: mapKeyKey[event.payload.event_type.KeyRelease] === 'Shift',
|
||||
// })
|
||||
|
||||
// eventTarget.dispatchEvent(e)
|
||||
// }))
|
||||
|
||||
// unListenFuncs.push(await listen('tauri-plugins:tauri-plugin-rdev:keydown', (event) => {
|
||||
// if (typeof event.payload.event_type.KeyPress === 'object' && 'Unknown' in event.payload.event_type.KeyPress) {
|
||||
// if (event.payload.event_type.KeyPress.Unknown === 62) {
|
||||
// event.payload.event_type = { KeyPress: KeyCode.ControlLeft }
|
||||
// }
|
||||
// }
|
||||
// if (typeof event.payload.event_type.KeyPress !== 'string') {
|
||||
// console.warn('unknown key release event:', event.payload.event_type.KeyPress)
|
||||
// return
|
||||
// }
|
||||
|
||||
// const e = new KeyboardEvent('keydown', {
|
||||
// key: mapKeyKey[event.payload.event_type.KeyPress],
|
||||
// code: mapKeyCode[event.payload.event_type.KeyPress],
|
||||
// metaKey: mapKeyKey[event.payload.event_type.KeyPress] === 'Meta',
|
||||
// ctrlKey: mapKeyKey[event.payload.event_type.KeyPress] === 'Control',
|
||||
// altKey: mapKeyKey[event.payload.event_type.KeyPress] === 'Alt',
|
||||
// shiftKey: mapKeyKey[event.payload.event_type.KeyPress] === 'Shift',
|
||||
// })
|
||||
|
||||
// eventTarget.dispatchEvent(e)
|
||||
// }))
|
||||
// }
|
||||
|
||||
// function cleanup() {
|
||||
// unListenFuncs.forEach(unListen => unListen())
|
||||
// unListenFuncs.length = 0
|
||||
// }
|
||||
|
||||
// onMounted(() => setup())
|
||||
// onUnmounted(() => cleanup())
|
||||
|
||||
// if (import.meta.hot) { // For better DX
|
||||
// import.meta.hot.on('vite:beforeUpdate', () => cleanup())
|
||||
// import.meta.hot.on('vite:afterUpdate', async () => await setup())
|
||||
// }
|
||||
|
||||
// return eventTarget
|
||||
// }
|
||||
@@ -1,134 +0,0 @@
|
||||
// import type { MaybeRefOrGetter } from 'vue'
|
||||
|
||||
// import type { AiriTamagotchiEvents, Point, WindowFrame } from './tauri'
|
||||
|
||||
// import { onMounted, onUnmounted, ref, toValue, watch } from 'vue'
|
||||
|
||||
// import { startClickThrough, stopClickThrough } from '../utils/windows'
|
||||
// import { useAppRuntime } from './runtime'
|
||||
// import { useTauriCore, useTauriEvent } from './tauri'
|
||||
|
||||
// export function useTauriPointAndWindowFrame() {
|
||||
// const { listen } = useTauriEvent<AiriTamagotchiEvents>()
|
||||
// const { invoke } = useTauriCore()
|
||||
|
||||
// const unListenFuncs = ref<(() => void)[]>([])
|
||||
|
||||
// const mousePos = ref<Point>({ x: 0, y: 0 })
|
||||
// const windowFrame = ref<WindowFrame>({
|
||||
// origin: { x: 0, y: 0 },
|
||||
// size: { width: 0, height: 0 },
|
||||
// })
|
||||
|
||||
// function _onCursorPosition(event: { payload: Point }) {
|
||||
// mousePos.value = event.payload
|
||||
// }
|
||||
|
||||
// function _onWindowFrame(event: { payload: WindowFrame }) {
|
||||
// windowFrame.value = event.payload
|
||||
// }
|
||||
|
||||
// function addListeners() {
|
||||
// listen('tauri-plugins:tauri-plugin-window-pass-through-on-hover:cursor-position', (event) => {
|
||||
// _onCursorPosition(event)
|
||||
// }).then((fn) => {
|
||||
// unListenFuncs.value.push(fn)
|
||||
// })
|
||||
|
||||
// listen('tauri-plugins:tauri-plugin-window-pass-through-on-hover:window-frame', (event) => {
|
||||
// _onWindowFrame(event)
|
||||
// }).then((fn) => {
|
||||
// unListenFuncs.value.push(fn)
|
||||
// })
|
||||
// }
|
||||
|
||||
// onMounted(() => {
|
||||
// addListeners()
|
||||
// invoke('plugin:window-pass-through-on-hover|start_tracing_cursor')
|
||||
// })
|
||||
|
||||
// onUnmounted(() => {
|
||||
// unListenFuncs.value.forEach(fn => fn?.())
|
||||
// unListenFuncs.value.length = 0
|
||||
|
||||
// invoke('plugin:window-pass-through-on-hover|stop_tracing_cursor')
|
||||
// })
|
||||
|
||||
// if (import.meta.hot) { // For better DX
|
||||
// import.meta.hot.on('vite:beforeUpdate', () => {
|
||||
// unListenFuncs.value.forEach(fn => fn?.())
|
||||
// unListenFuncs.value.length = 0
|
||||
|
||||
// invoke('plugin:window-pass-through-on-hover|stop_tracing_cursor')
|
||||
// })
|
||||
|
||||
// import.meta.hot.on('vite:afterUpdate', () => {
|
||||
// addListeners()
|
||||
// invoke('plugin:window-pass-through-on-hover|start_tracing_cursor')
|
||||
// })
|
||||
// }
|
||||
|
||||
// return {
|
||||
// mousePos,
|
||||
// windowFrame,
|
||||
// }
|
||||
// }
|
||||
|
||||
// export function useTauriWindowClickThrough(live2DLookAtDefault: MaybeRefOrGetter<{ x: number, y: number }>) {
|
||||
// const { platform, isInitialized } = useAppRuntime()
|
||||
// const { mousePos, windowFrame } = useTauriPointAndWindowFrame()
|
||||
|
||||
// const live2dLookAtX = ref(toValue(live2DLookAtDefault).x)
|
||||
// const live2dLookAtY = ref(toValue(live2DLookAtDefault).y)
|
||||
|
||||
// const isCursorInside = ref(false)
|
||||
|
||||
// function updateLive2DLookAt() {
|
||||
// if (platform.value === 'macos') {
|
||||
// live2dLookAtX.value = mousePos.value.x - windowFrame.value.origin.x
|
||||
// live2dLookAtY.value = windowFrame.value.size.height - mousePos.value.y + windowFrame.value.origin.y
|
||||
|
||||
// return
|
||||
// }
|
||||
|
||||
// live2dLookAtX.value = mousePos.value.x - windowFrame.value.origin.x
|
||||
// live2dLookAtY.value = mousePos.value.y - windowFrame.value.origin.y
|
||||
// }
|
||||
|
||||
// watch(mousePos, () => {
|
||||
// updateLive2DLookAt()
|
||||
// })
|
||||
|
||||
// function updateIsCursorInside() {
|
||||
// isCursorInside.value
|
||||
// = mousePos.value.x >= windowFrame.value.origin.x
|
||||
// && mousePos.value.x <= windowFrame.value.origin.x + windowFrame.value.size.width
|
||||
// && mousePos.value.y >= windowFrame.value.origin.y
|
||||
// && mousePos.value.y <= windowFrame.value.origin.y + windowFrame.value.size.height
|
||||
// }
|
||||
|
||||
// watch([mousePos, windowFrame], () => {
|
||||
// updateIsCursorInside()
|
||||
// })
|
||||
|
||||
// watch(isInitialized, async (initialized) => {
|
||||
// if (initialized) {
|
||||
// updateLive2DLookAt()
|
||||
// updateIsCursorInside()
|
||||
// }
|
||||
// })
|
||||
|
||||
// onMounted(async () => {
|
||||
// await startClickThrough()
|
||||
// })
|
||||
|
||||
// onUnmounted(async () => {
|
||||
// await stopClickThrough()
|
||||
// })
|
||||
|
||||
// return {
|
||||
// isCursorInside,
|
||||
// live2dLookAtX,
|
||||
// live2dLookAtY,
|
||||
// }
|
||||
// }
|
||||
@@ -1,77 +0,0 @@
|
||||
// import { computedAsync, until } from '@vueuse/core'
|
||||
|
||||
// import { useAppRuntime } from './runtime'
|
||||
// import { untilImported } from './tauri'
|
||||
|
||||
// export enum StateFlags {
|
||||
// SIZE = 1,
|
||||
// POSITION = 2,
|
||||
// MAXIMIZED = 4,
|
||||
// VISIBLE = 8,
|
||||
// DECORATIONS = 16,
|
||||
// FULLSCREEN = 32,
|
||||
// ALL = 63,
|
||||
// }
|
||||
|
||||
// export function useTauriWindowState() {
|
||||
// const { platform, isInitialized } = useAppRuntime()
|
||||
|
||||
// const tauriWindowStateApi = computedAsync(async () => {
|
||||
// await until(isInitialized).toBeTruthy()
|
||||
|
||||
// if (platform.value !== 'web') {
|
||||
// return untilImported(() => import('@tauri-apps/plugin-window-state'), console.warn)
|
||||
// }
|
||||
// })
|
||||
|
||||
// async function ensureImported() {
|
||||
// await until(isInitialized).toBeTruthy()
|
||||
|
||||
// if (platform.value === 'web') {
|
||||
// console.warn('Attempted to save window state in web platform')
|
||||
// return
|
||||
// }
|
||||
|
||||
// await until(tauriWindowStateApi).toBeTruthy()
|
||||
// const imported = await tauriWindowStateApi.value
|
||||
// if (!imported) {
|
||||
// throw new Error('Tauri window state API not available')
|
||||
// }
|
||||
// }
|
||||
|
||||
// async function saveWindowState(stateFlag?: StateFlags) {
|
||||
// await ensureImported()
|
||||
// if (stateFlag != null) {
|
||||
// return tauriWindowStateApi.value?.saveWindowState(stateFlag)
|
||||
// }
|
||||
// else {
|
||||
// return tauriWindowStateApi.value?.saveWindowState(tauriWindowStateApi.value.StateFlags.ALL)
|
||||
// }
|
||||
// }
|
||||
|
||||
// async function restoreState(stateFlag?: StateFlags, windowLabel = 'main') {
|
||||
// await ensureImported()
|
||||
// if (stateFlag != null) {
|
||||
// return tauriWindowStateApi.value?.restoreState(windowLabel, stateFlag)
|
||||
// }
|
||||
// else {
|
||||
// return tauriWindowStateApi.value?.restoreState(windowLabel, tauriWindowStateApi.value.StateFlags.ALL)
|
||||
// }
|
||||
// }
|
||||
|
||||
// async function restoreStateCurrent(stateFlag?: StateFlags) {
|
||||
// await ensureImported()
|
||||
// if (stateFlag != null) {
|
||||
// return tauriWindowStateApi.value?.restoreStateCurrent(stateFlag)
|
||||
// }
|
||||
// else {
|
||||
// return tauriWindowStateApi.value?.restoreStateCurrent(tauriWindowStateApi.value.StateFlags.ALL)
|
||||
// }
|
||||
// }
|
||||
|
||||
// return {
|
||||
// saveWindowState,
|
||||
// restoreState,
|
||||
// restoreStateCurrent,
|
||||
// }
|
||||
// }
|
||||
@@ -1,340 +0,0 @@
|
||||
// import type { InvokeArgs, InvokeOptions } from '@tauri-apps/api/core'
|
||||
// import type { EventCallback, EventName, UnlistenFn } from '@tauri-apps/api/event'
|
||||
// import type { Monitor } from '@tauri-apps/api/window'
|
||||
|
||||
// import type { InvokeMethods, InvokeMethodShape } from '../tauri/invoke'
|
||||
// import type { KeyCode } from '../tauri/rdev'
|
||||
|
||||
// import { withRetry } from '@moeru/std'
|
||||
// import { computedAsync, until } from '@vueuse/core'
|
||||
|
||||
// import { useAppRuntime } from './runtime'
|
||||
|
||||
// export async function untilNoError<T>(fn: () => Promise<T>, onError?: (err?: unknown | null) => void): Promise<T> {
|
||||
// const fnRetry = withRetry(fn, { retryDelay: 5000, retry: 5, onError })
|
||||
// return await fnRetry()
|
||||
// }
|
||||
|
||||
// export async function untilImported<T>(fn: () => Promise<T>, onError?: (err?: unknown | null) => void): Promise<T> {
|
||||
// return await untilNoError(fn, onError)
|
||||
// }
|
||||
|
||||
// export interface Point {
|
||||
// x: number
|
||||
// y: number
|
||||
// }
|
||||
|
||||
// export interface Size {
|
||||
// width: number
|
||||
// height: number
|
||||
// }
|
||||
|
||||
// export interface WindowFrame {
|
||||
// origin: Point
|
||||
// size: Size
|
||||
// }
|
||||
|
||||
// interface Events {
|
||||
// 'tauri://resize': unknown
|
||||
// 'tauri://move': { x: number, y: number }
|
||||
// 'tauri://close-requested': unknown
|
||||
// 'tauri://destroyed': unknown
|
||||
// 'tauri://focus': unknown
|
||||
// 'tauri://blur': unknown
|
||||
// 'tauri://scale-change': unknown
|
||||
// 'tauri://theme-changed': unknown
|
||||
// 'tauri://window-created': unknown
|
||||
// 'tauri://webview-created': unknown
|
||||
// 'tauri://drag-enter': unknown
|
||||
// 'tauri://drag-over': unknown
|
||||
// 'tauri://drag-drop': unknown
|
||||
// 'tauri://drag-leave': unknown
|
||||
// }
|
||||
|
||||
// export interface AiriTamagotchiEvents extends Events {
|
||||
// // from main
|
||||
// 'tauri-main:main:window-mode:fade-on-hover': true
|
||||
// 'tauri-main:main:window-mode:move': true
|
||||
// 'tauri-main:main:window-mode:resize': true
|
||||
|
||||
// // from tauri-plugin-window-pass-through-on-hover
|
||||
// 'tauri-plugins:tauri-plugin-window-pass-through-on-hover:cursor-position': Point
|
||||
// 'tauri-plugins:tauri-plugin-window-pass-through-on-hover:window-frame': WindowFrame
|
||||
// 'tauri-plugins:tauri-plugin-window-pass-through-on-hover:pass-through-enabled': boolean
|
||||
|
||||
// // from tauri-plugin-ipc-audio-transcription-ort
|
||||
// 'tauri-plugins:tauri-plugin-ipc-audio-vad-ort:load-model-silero-vad-progress': [boolean, string, number, number, number]
|
||||
// // from tauri-plugin-ipc-audio-vad-ort
|
||||
// 'tauri-plugins:tauri-plugin-ipc-audio-transcription-ort:load-model-whisper-progress': [boolean, string, number, number, number]
|
||||
|
||||
// // from tauri-plugin-rdev
|
||||
// 'tauri-plugins:tauri-plugin-rdev:keydown': { time: { secs_since_epoch: number, nanos_since_epoch: number }, name: string, event_type: { KeyPress: KeyCode | { Unknown: number } } } // similar to 'keydown' events from DOM elements
|
||||
// 'tauri-plugins:tauri-plugin-rdev:keyup': { time: { secs_since_epoch: number, nanos_since_epoch: number }, name: string, event_type: { KeyRelease: KeyCode | { Unknown: number } } } // similar to 'keyup' events from DOM elements
|
||||
// 'tauri-plugins:tauri-plugin-rdev:mousedown': { time: { secs_since_epoch: number, nanos_since_epoch: number }, name: string, event_type: { ButtonPress: string } } // similar to 'mousedown' events from DOM elements
|
||||
// 'tauri-plugins:tauri-plugin-rdev:mouseup': { time: { secs_since_epoch: number, nanos_since_epoch: number }, name: string, event_type: { ButtonRelease: string } } // similar to 'mouseup' events from DOM elements
|
||||
// 'tauri-plugins:tauri-plugin-rdev:mousemove': { time: { secs_since_epoch: number, nanos_since_epoch: number }, name: string, event_type: { MouseMove: { x: number, y: number } } } // similar to 'mousemove' events from DOM elements
|
||||
|
||||
// // MCP
|
||||
// 'mcp_plugin_destroyed': undefined
|
||||
// }
|
||||
|
||||
// export interface DisplayInfo {
|
||||
// monitors: Monitor[]
|
||||
// primaryMonitor: Monitor
|
||||
// }
|
||||
|
||||
// export enum PlacementStrategy {
|
||||
// Center = 'Center',
|
||||
// TopLeft = 'TopLeft',
|
||||
// TopRight = 'TopRight',
|
||||
// BottomLeft = 'BottomLeft',
|
||||
// BottomRight = 'BottomRight',
|
||||
// NearCursor = 'NearCursor',
|
||||
// RestorePrevious = 'RestorePrevious',
|
||||
// AvoidOverlap = 'AvoidOverlap',
|
||||
// }
|
||||
|
||||
// export interface WindowPlacementRequest {
|
||||
// window_size: Size
|
||||
// preferred_position?: Point
|
||||
// placement_strategy: PlacementStrategy
|
||||
// }
|
||||
|
||||
// export interface WindowPlacementResult {
|
||||
// position: Point
|
||||
// target_monitor_id: number
|
||||
// is_constrained: boolean
|
||||
// }
|
||||
|
||||
// export function useTauriEvent<ES = Events>() {
|
||||
// const { platform, isInitialized } = useAppRuntime()
|
||||
|
||||
// const tauriEventApi = computedAsync(async () => {
|
||||
// await until(isInitialized).toBeTruthy()
|
||||
|
||||
// if (platform.value !== 'web') {
|
||||
// return untilImported(() => import('@tauri-apps/api/event'), console.warn)
|
||||
// }
|
||||
// })
|
||||
|
||||
// async function _listen<E extends keyof ES>(event: E, callback: EventCallback<ES[E]>) {
|
||||
// await until(isInitialized).toBeTruthy()
|
||||
|
||||
// if (platform.value === 'web') {
|
||||
// return () => {}
|
||||
// }
|
||||
|
||||
// await until(tauriEventApi).toBeTruthy()
|
||||
// const imported = await tauriEventApi.value
|
||||
// if (!imported) {
|
||||
// throw new Error('Tauri event API not available')
|
||||
// }
|
||||
|
||||
// return await imported.listen(event as EventName, callback)
|
||||
// }
|
||||
|
||||
// async function listen<E extends keyof ES>(event: E, callback: EventCallback<ES[E]>) {
|
||||
// let cleanupListener: UnlistenFn | undefined
|
||||
|
||||
// _listen(event, callback).then((listener) => {
|
||||
// cleanupListener = listener
|
||||
// })
|
||||
|
||||
// return () => {
|
||||
// cleanupListener?.()
|
||||
// }
|
||||
// }
|
||||
|
||||
// return {
|
||||
// listen,
|
||||
// }
|
||||
// }
|
||||
|
||||
// export function useTauriCore<IM extends Record<keyof IM, InvokeMethodShape> = InvokeMethods>() {
|
||||
// const { platform, isInitialized } = useAppRuntime()
|
||||
|
||||
// const tauriCoreApi = computedAsync(async () => {
|
||||
// await until(isInitialized).toBeTruthy()
|
||||
|
||||
// if (platform.value !== 'web') {
|
||||
// return untilImported(() => import('@tauri-apps/api/core'), console.warn)
|
||||
// }
|
||||
// })
|
||||
|
||||
// const tauriCoreApiInvoke = computedAsync(async () => {
|
||||
// await until(isInitialized).toBeTruthy()
|
||||
|
||||
// if (platform.value !== 'web') {
|
||||
// return untilImported(() => import('../tauri/invoke'), console.warn)
|
||||
// }
|
||||
// })
|
||||
|
||||
// async function invoke<C extends keyof IM>(
|
||||
// command: C,
|
||||
// args?: IM[C]['args'],
|
||||
// options?: IM[C]['options'],
|
||||
// ): Promise<IM[C]['returns'] | undefined> {
|
||||
// await until(isInitialized).toBeTruthy()
|
||||
|
||||
// if (platform.value === 'web') {
|
||||
// console.warn(`Attempted to invoke Tauri command "${String(command)}" in web platform`)
|
||||
// return
|
||||
// }
|
||||
|
||||
// await until(tauriCoreApiInvoke).toBeTruthy()
|
||||
// const imported = await tauriCoreApiInvoke.value
|
||||
// if (!imported) {
|
||||
// throw new Error('Tauri core API not available')
|
||||
// }
|
||||
|
||||
// return await imported.invoke<C, IM>(command, args as InvokeArgs | undefined, options as InvokeOptions | undefined)
|
||||
// }
|
||||
|
||||
// return {
|
||||
// invoke,
|
||||
// core: tauriCoreApi,
|
||||
// }
|
||||
// }
|
||||
|
||||
// export function useTauriDpi() {
|
||||
// const { platform, isInitialized } = useAppRuntime()
|
||||
|
||||
// const tauriDpiApi = computedAsync(async () => {
|
||||
// await until(isInitialized).toBeTruthy()
|
||||
|
||||
// if (platform.value !== 'web') {
|
||||
// return untilImported(() => import('@tauri-apps/api/window'), console.warn)
|
||||
// }
|
||||
// })
|
||||
|
||||
// async function createLogicalPosition(x: number, y: number) {
|
||||
// const imported = await tauriDpiApi.value
|
||||
// if (!imported) {
|
||||
// throw new Error('Tauri DPI API not available')
|
||||
// }
|
||||
|
||||
// return new imported.LogicalPosition(x, y)
|
||||
// }
|
||||
|
||||
// return {
|
||||
// createLogicalPosition,
|
||||
// }
|
||||
// }
|
||||
|
||||
// export function useTauriWindow() {
|
||||
// const { platform, isInitialized } = useAppRuntime()
|
||||
// const { createLogicalPosition } = useTauriDpi()
|
||||
|
||||
// const tauriWindowApi = computedAsync(async () => {
|
||||
// await until(isInitialized).toBeTruthy()
|
||||
|
||||
// if (platform.value !== 'web') {
|
||||
// return untilImported(() => import('@tauri-apps/api/window'), console.warn)
|
||||
// }
|
||||
// })
|
||||
|
||||
// async function _ensureImported() {
|
||||
// await until(isInitialized).toBeTruthy()
|
||||
// if (platform.value === 'web') {
|
||||
// throw new Error('Tauri Window API is not available in web platform')
|
||||
// }
|
||||
|
||||
// await until(tauriWindowApi).toBeTruthy()
|
||||
// const imported = await tauriWindowApi.value
|
||||
// if (!imported) {
|
||||
// throw new Error('Tauri Window API not available')
|
||||
// }
|
||||
|
||||
// return imported
|
||||
// }
|
||||
|
||||
// async function getCurrentMonitor() {
|
||||
// try {
|
||||
// return await _ensureImported().then(imported => imported.currentMonitor())
|
||||
// }
|
||||
// catch (error) {
|
||||
// console.error('Failed to get current monitor:', error)
|
||||
// return undefined
|
||||
// }
|
||||
// }
|
||||
|
||||
// async function getAvailableMonitors() {
|
||||
// try {
|
||||
// return await _ensureImported().then(imported => imported.availableMonitors())
|
||||
// }
|
||||
// catch (error) {
|
||||
// console.error('Failed to get available monitors:', error)
|
||||
// return []
|
||||
// }
|
||||
// }
|
||||
|
||||
// async function getPrimaryMonitor() {
|
||||
// try {
|
||||
// return await _ensureImported().then(imported => imported.primaryMonitor())
|
||||
// }
|
||||
// catch (error) {
|
||||
// console.error('Failed to get primary monitor:', error)
|
||||
// return undefined
|
||||
// }
|
||||
// }
|
||||
|
||||
// async function setPosition(x: number, y: number) {
|
||||
// try {
|
||||
// const imported = await _ensureImported()
|
||||
// const window = imported.getCurrentWindow()
|
||||
// return await window.setPosition(await createLogicalPosition(x, y))
|
||||
// }
|
||||
// catch (error) {
|
||||
// console.error('Failed to set window position:', error)
|
||||
// }
|
||||
// }
|
||||
|
||||
// async function getPosition() {
|
||||
// try {
|
||||
// const imported = await _ensureImported()
|
||||
// const window = imported.getCurrentWindow()
|
||||
// return await window.innerPosition()
|
||||
// }
|
||||
// catch (error) {
|
||||
// console.error('Failed to get window position:', error)
|
||||
// return undefined
|
||||
// }
|
||||
// }
|
||||
|
||||
// async function closeWindow(label?: string) {
|
||||
// try {
|
||||
// const imported = await _ensureImported()
|
||||
// if (!label) {
|
||||
// const window = imported.getCurrentWindow()
|
||||
// return await window.close()
|
||||
// }
|
||||
// else {
|
||||
// const windows = await imported.getAllWindows()
|
||||
// const targetWindow = windows.find(win => win.label === label)
|
||||
// if (targetWindow) {
|
||||
// return await targetWindow.close()
|
||||
// }
|
||||
// else {
|
||||
// console.warn(`No window found with label: ${label}`)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// catch (error) {
|
||||
// console.error('Failed to close window:', error)
|
||||
// }
|
||||
// }
|
||||
|
||||
// return {
|
||||
// getAvailableMonitors,
|
||||
// getCurrentMonitor,
|
||||
// getPrimaryMonitor,
|
||||
// setPosition,
|
||||
// getPosition,
|
||||
// closeWindow,
|
||||
// }
|
||||
// }
|
||||
|
||||
// export function createTauriEventTarget(): EventTarget {
|
||||
// const eventTarget = new EventTarget()
|
||||
// return eventTarget
|
||||
// }
|
||||
@@ -1,30 +0,0 @@
|
||||
// import type { AiriTamagotchiEvents } from './tauri'
|
||||
|
||||
// import { createSharedComposable } from '@vueuse/core'
|
||||
// import { ref } from 'vue'
|
||||
|
||||
// import { useTauriEvent } from './tauri'
|
||||
|
||||
// export const useRdevMouse = createSharedComposable(() => {
|
||||
// const mouseX = ref(0)
|
||||
// const mouseY = ref(0)
|
||||
|
||||
// const { listen } = useTauriEvent<AiriTamagotchiEvents>()
|
||||
|
||||
// async function setup() {
|
||||
// await listen('tauri-plugins:tauri-plugin-rdev:mousemove', (event) => {
|
||||
// if (event.payload.event_type.MouseMove) {
|
||||
// const { x, y } = event.payload.event_type.MouseMove
|
||||
// mouseX.value = x
|
||||
// mouseY.value = y
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
|
||||
// setup()
|
||||
|
||||
// return {
|
||||
// mouseX,
|
||||
// mouseY,
|
||||
// }
|
||||
// })
|
||||
@@ -4,7 +4,7 @@ import { useCanvasPixelIsTransparentAtPoint } from '@proj-airi/stage-ui/composab
|
||||
import { useLive2d } from '@proj-airi/stage-ui/stores/live2d'
|
||||
import { debouncedRef, watchPausable } from '@vueuse/core'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, ref, toRef, watch } from 'vue'
|
||||
import { ref, toRef, watch } from 'vue'
|
||||
|
||||
import ControlsIsland from '../components/Widgets/ControlsIsland/index.vue'
|
||||
import ResourceStatusIsland from '../components/Widgets/ResourceStatusIsland/index.vue'
|
||||
@@ -12,8 +12,6 @@ import ResourceStatusIsland from '../components/Widgets/ResourceStatusIsland/ind
|
||||
import { electron } from '../../shared/electron'
|
||||
import { useElectronEventaInvoke, useElectronMouseInElement, useElectronRelativeMouse } from '../composables/electron-vueuse'
|
||||
import { useWindowStore } from '../stores/window'
|
||||
import { useWindowControlStore } from '../stores/window-controls'
|
||||
import { WindowControlMode } from '../types/window-controls'
|
||||
|
||||
const resourceStatusIslandRef = ref<InstanceType<typeof ResourceStatusIsland>>()
|
||||
const controlsIslandRef = ref<InstanceType<typeof ControlsIsland>>()
|
||||
@@ -24,7 +22,6 @@ const isPassingThrough = ref(false)
|
||||
const isLoading = ref(true)
|
||||
const componentStateStage = ref<'pending' | 'loading' | 'mounted'>('pending')
|
||||
|
||||
const windowControlStore = useWindowControlStore()
|
||||
const { x: relativeMouseX, y: relativeMouseY } = useElectronRelativeMouse()
|
||||
const isTransparent = useCanvasPixelIsTransparentAtPoint(stageCanvas, relativeMouseX, relativeMouseY)
|
||||
const setIgnoreMouseEvents = useElectronEventaInvoke(electron.window.setIgnoreMouseEvents)
|
||||
@@ -34,26 +31,12 @@ const isOutsideFor250Ms = debouncedRef(isOutside, 250)
|
||||
const { scale, positionInPercentageString } = storeToRefs(useLive2d())
|
||||
const { live2dLookAtX, live2dLookAtY } = storeToRefs(useWindowStore())
|
||||
|
||||
const modeIndicatorClass = computed(() => {
|
||||
switch (windowControlStore.controlMode) {
|
||||
case WindowControlMode.MOVE:
|
||||
return 'cursor-move'
|
||||
case WindowControlMode.RESIZE:
|
||||
return 'cursor-se-resize'
|
||||
case WindowControlMode.DEBUG:
|
||||
return 'debug-mode'
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
})
|
||||
|
||||
watch(componentStateStage, () => isLoading.value = componentStateStage.value !== 'mounted', { immediate: true })
|
||||
const { pause, resume } = watchPausable(isTransparent, (transparent) => {
|
||||
isClickThrough.value = transparent
|
||||
isPassingThrough.value = !transparent
|
||||
windowControlStore.isIgnoringMouseEvent = !transparent
|
||||
|
||||
if (windowControlStore.isIgnoringMouseEvent) {
|
||||
if (isPassingThrough.value) {
|
||||
setIgnoreMouseEvents([true, { forward: true }])
|
||||
}
|
||||
else {
|
||||
@@ -65,14 +48,12 @@ watch(isOutsideFor250Ms, () => {
|
||||
if (!isOutsideFor250Ms.value) {
|
||||
isClickThrough.value = false
|
||||
isPassingThrough.value = false
|
||||
windowControlStore.isIgnoringMouseEvent = false
|
||||
setIgnoreMouseEvents([false, { forward: true }])
|
||||
pause()
|
||||
}
|
||||
else {
|
||||
isClickThrough.value = true
|
||||
isPassingThrough.value = true
|
||||
windowControlStore.isIgnoringMouseEvent = true
|
||||
setIgnoreMouseEvents([true, { forward: true }])
|
||||
resume()
|
||||
}
|
||||
@@ -81,7 +62,6 @@ watch(isOutsideFor250Ms, () => {
|
||||
|
||||
<template>
|
||||
<div
|
||||
:class="[modeIndicatorClass]"
|
||||
max-h="[100vh]"
|
||||
max-w="[100vw]"
|
||||
flex="~ col"
|
||||
@@ -97,7 +77,7 @@ watch(isOutsideFor250Ms, () => {
|
||||
>
|
||||
<div
|
||||
:class="[
|
||||
windowControlStore.isIgnoringMouseEvent && !isClickThrough ? 'op-0' : 'op-100',
|
||||
isPassingThrough && !isClickThrough ? 'op-0' : 'op-100',
|
||||
'absolute',
|
||||
'top-0 left-0 w-full h-full',
|
||||
'transition-opacity duration-250 ease-in-out',
|
||||
@@ -153,7 +133,7 @@ watch(isOutsideFor250Ms, () => {
|
||||
leave-to-class="opacity-0"
|
||||
>
|
||||
<div
|
||||
v-if="windowControlStore.controlMode === WindowControlMode.MOVE"
|
||||
v-if="false"
|
||||
class="absolute left-0 top-0 z-99 h-full w-full flex cursor-grab items-center justify-center overflow-hidden drag-region"
|
||||
>
|
||||
<div
|
||||
@@ -177,7 +157,7 @@ watch(isOutsideFor250Ms, () => {
|
||||
leave-to-class="opacity-50"
|
||||
>
|
||||
<div
|
||||
v-if="windowControlStore.controlMode === WindowControlMode.RESIZE"
|
||||
v-if="false"
|
||||
class="absolute left-0 top-0 z-999 h-full w-full"
|
||||
>
|
||||
<div h-full w-full animate-flash animate-duration-2.5s animate-count-infinite b-4 b-primary rounded-2xl />
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
import { OnboardingScreen } from '@proj-airi/stage-ui/components'
|
||||
import { useOnboardingStore } from '@proj-airi/stage-ui/stores/onboarding'
|
||||
|
||||
// import { useTauriWindow } from '../composables/tauri'
|
||||
|
||||
// const window = useTauriWindow()
|
||||
const onboardingStore = useOnboardingStore()
|
||||
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
// import type { AiriTamagotchiEvents } from '../composables/tauri'
|
||||
|
||||
// import { getCurrentWindow } from '@tauri-apps/api/window'
|
||||
import { defineStore } from 'pinia'
|
||||
import { onMounted, onUnmounted, ref } from 'vue'
|
||||
|
||||
// import { useTauriEvent } from '../composables/tauri'
|
||||
import { WindowControlMode } from '../types/window-controls'
|
||||
import { startClickThrough, stopClickThrough } from '../utils/windows'
|
||||
|
||||
export const useWindowControlStore = defineStore('windowControl', () => {
|
||||
const controlMode = ref<WindowControlMode>(WindowControlMode.NONE)
|
||||
const isControlActive = ref(false)
|
||||
const isIgnoringMouseEvent = ref(false)
|
||||
|
||||
function toggleMode(mode: WindowControlMode) {
|
||||
controlMode.value = mode
|
||||
isControlActive.value = !isControlActive.value
|
||||
if (!isControlActive.value) {
|
||||
controlMode.value = WindowControlMode.NONE
|
||||
if (isIgnoringMouseEvent.value)
|
||||
startClickThrough()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
stopClickThrough()
|
||||
|
||||
// const window = getCurrentWindow()
|
||||
// window.setFocus()
|
||||
}
|
||||
|
||||
return {
|
||||
controlMode,
|
||||
isControlActive,
|
||||
isIgnoringMouseEvent,
|
||||
toggleMode,
|
||||
}
|
||||
})
|
||||
|
||||
export const useWindowMode = defineStore('window-mode', () => {
|
||||
// const { listen } = useTauriEvent<AiriTamagotchiEvents>()
|
||||
// const windowStore = useWindowControlStore()
|
||||
|
||||
const unlistenFuncs = ref<(() => void)[]>([])
|
||||
|
||||
async function setup() {
|
||||
// unlistenFuncs.value.push(await listen('tauri-main:main:window-mode:move', () => {
|
||||
// windowStore.toggleMode(WindowControlMode.MOVE)
|
||||
// }))
|
||||
|
||||
// unlistenFuncs.value.push(await listen('tauri-main:main:window-mode:resize', () => {
|
||||
// windowStore.toggleMode(WindowControlMode.RESIZE)
|
||||
// }))
|
||||
|
||||
// unlistenFuncs.value.push(await listen('tauri-main:main:window-mode:fade-on-hover', async () => {
|
||||
// windowStore.isIgnoringMouseEvent = !windowStore.isIgnoringMouseEvent
|
||||
// }))
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
unlistenFuncs.value.forEach(unlisten => unlisten())
|
||||
unlistenFuncs.value.length = 0
|
||||
}
|
||||
|
||||
onMounted(setup)
|
||||
onUnmounted(cleanup)
|
||||
|
||||
if (import.meta.hot) { // For better DX
|
||||
import.meta.hot.on('vite:beforeUpdate', () => cleanup())
|
||||
import.meta.hot.on('vite:afterUpdate', async () => await setup())
|
||||
}
|
||||
})
|
||||
@@ -1,13 +1,10 @@
|
||||
import { useWindowSize } from '@vueuse/core'
|
||||
import { defineStore } from 'pinia'
|
||||
import { computed, ref } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
|
||||
import { useElectronRelativeMouse } from '../composables/electron-vueuse'
|
||||
import { useWindowControlStore } from './window-controls'
|
||||
|
||||
export const useWindowStore = defineStore('tamagotchi-window', () => {
|
||||
const windowControlStore = useWindowControlStore()
|
||||
|
||||
const { width, height } = useWindowSize()
|
||||
const centerPos = computed(() => ({ x: width.value / 2, y: height.value / 2 }))
|
||||
|
||||
@@ -15,16 +12,11 @@ export const useWindowStore = defineStore('tamagotchi-window', () => {
|
||||
// Transforms screen coordinates to window-relative coordinates
|
||||
const { x: live2dLookAtX, y: live2dLookAtY } = useElectronRelativeMouse({ initialValue: centerPos.value })
|
||||
|
||||
const isCursorInside = ref(false)
|
||||
const shouldHideView = computed(() => isCursorInside.value && !windowControlStore.isControlActive && windowControlStore.isIgnoringMouseEvent)
|
||||
|
||||
return {
|
||||
width,
|
||||
height,
|
||||
centerPos,
|
||||
live2dLookAtX,
|
||||
live2dLookAtY,
|
||||
isCursorInside,
|
||||
shouldHideView,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
// import type { InvokeArgs, InvokeOptions } from '@tauri-apps/api/core'
|
||||
|
||||
// import { invoke as tauriInvoke } from '@tauri-apps/api/core'
|
||||
|
||||
// export interface InvokeMethods {
|
||||
// // app windows
|
||||
// 'open_settings_window': { args: undefined, options: undefined, returns: void }
|
||||
// 'open_chat_window': { args: undefined, options: undefined, returns: void }
|
||||
|
||||
// // Plugin - Audio Transcription
|
||||
// 'plugin:ipc-audio-transcription-ort|load_ort_model_whisper': { args: { modelType: 'base' | 'largev3' | 'tiny' | 'medium' }, options: undefined, returns: void }
|
||||
// 'plugin:ipc-audio-transcription-ort|ipc_audio_transcription': { args: { chunk: number[], language: string }, options: undefined, returns: string }
|
||||
|
||||
// // Plugin - Audio VAD
|
||||
// 'plugin:ipc-audio-vad-ort|load_ort_model_silero_vad': { args: undefined, options: undefined, returns: void }
|
||||
// 'plugin:ipc-audio-vad-ort|ipc_audio_vad': { args: { inputData: { input: number[], sr: number, state: number[] } }, options: undefined, returns: number }
|
||||
|
||||
// // Plugin - Window Pass through on hover
|
||||
// 'plugin:window-pass-through-on-hover|start_tracing_cursor': { args: undefined, options: undefined, returns: void }
|
||||
// 'plugin:window-pass-through-on-hover|stop_tracing_cursor': { args: undefined, options: undefined, returns: void }
|
||||
// }
|
||||
|
||||
// export interface InvokeMethodShape {
|
||||
// args: InvokeArgs | undefined
|
||||
// options: InvokeOptions | undefined
|
||||
// returns: any
|
||||
// }
|
||||
|
||||
// export async function invoke<C extends keyof IM, IM extends Record<keyof IM, InvokeMethodShape> = InvokeMethods>(
|
||||
// command: C,
|
||||
// args?: IM[C]['args'],
|
||||
// options?: IM[C]['options'],
|
||||
// ): Promise<IM[C]['returns'] | undefined> {
|
||||
// return await tauriInvoke(command as string, args as InvokeArgs | undefined, options as InvokeOptions | undefined)
|
||||
// }
|
||||
@@ -1,407 +0,0 @@
|
||||
// rdev enums
|
||||
export enum KeyCode {
|
||||
// Alt key on Linux and Windows (option key on macOS)
|
||||
Alt = 'Alt',
|
||||
AltGr = 'AltGr',
|
||||
Backspace = 'Backspace',
|
||||
CapsLock = 'CapsLock',
|
||||
ControlLeft = 'ControlLeft',
|
||||
ControlRight = 'ControlRight',
|
||||
Delete = 'Delete',
|
||||
DownArrow = 'DownArrow',
|
||||
End = 'End',
|
||||
Escape = 'Escape',
|
||||
F1 = 'F1',
|
||||
F10 = 'F10',
|
||||
F11 = 'F11',
|
||||
F12 = 'F12',
|
||||
F13 = 'F13',
|
||||
F14 = 'F14',
|
||||
F15 = 'F15',
|
||||
F16 = 'F16',
|
||||
F17 = 'F17',
|
||||
F18 = 'F18',
|
||||
F19 = 'F19',
|
||||
F20 = 'F20',
|
||||
F21 = 'F21',
|
||||
F22 = 'F22',
|
||||
F23 = 'F23',
|
||||
F24 = 'F24',
|
||||
F2 = 'F2',
|
||||
F3 = 'F3',
|
||||
F4 = 'F4',
|
||||
F5 = 'F5',
|
||||
F6 = 'F6',
|
||||
F7 = 'F7',
|
||||
F8 = 'F8',
|
||||
F9 = 'F9',
|
||||
Home = 'Home',
|
||||
LeftArrow = 'LeftArrow',
|
||||
/// also known as "windows", "super", and "command"
|
||||
MetaLeft = 'MetaLeft',
|
||||
/// also known as "windows", "super", and "command"
|
||||
MetaRight = 'MetaRight',
|
||||
PageDown = 'PageDown',
|
||||
PageUp = 'PageUp',
|
||||
Return = 'Return',
|
||||
RightArrow = 'RightArrow',
|
||||
ShiftLeft = 'ShiftLeft',
|
||||
ShiftRight = 'ShiftRight',
|
||||
Space = 'Space',
|
||||
Tab = 'Tab',
|
||||
UpArrow = 'UpArrow',
|
||||
PrintScreen = 'PrintScreen',
|
||||
ScrollLock = 'ScrollLock',
|
||||
Pause = 'Pause',
|
||||
NumLock = 'NumLock',
|
||||
BackQuote = 'BackQuote',
|
||||
Num1 = 'Num1',
|
||||
Num2 = 'Num2',
|
||||
Num3 = 'Num3',
|
||||
Num4 = 'Num4',
|
||||
Num5 = 'Num5',
|
||||
Num6 = 'Num6',
|
||||
Num7 = 'Num7',
|
||||
Num8 = 'Num8',
|
||||
Num9 = 'Num9',
|
||||
Num0 = 'Num0',
|
||||
Minus = 'Minus',
|
||||
Equal = 'Equal',
|
||||
KeyQ = 'KeyQ',
|
||||
KeyW = 'KeyW',
|
||||
KeyE = 'KeyE',
|
||||
KeyR = 'KeyR',
|
||||
KeyT = 'KeyT',
|
||||
KeyY = 'KeyY',
|
||||
KeyU = 'KeyU',
|
||||
KeyI = 'KeyI',
|
||||
KeyO = 'KeyO',
|
||||
KeyP = 'KeyP',
|
||||
LeftBracket = 'LeftBracket',
|
||||
RightBracket = 'RightBracket',
|
||||
KeyA = 'KeyA',
|
||||
KeyS = 'KeyS',
|
||||
KeyD = 'KeyD',
|
||||
KeyF = 'KeyF',
|
||||
KeyG = 'KeyG',
|
||||
KeyH = 'KeyH',
|
||||
KeyJ = 'KeyJ',
|
||||
KeyK = 'KeyK',
|
||||
KeyL = 'KeyL',
|
||||
SemiColon = 'SemiColon',
|
||||
Quote = 'Quote',
|
||||
BackSlash = 'BackSlash',
|
||||
IntlBackslash = 'IntlBackslash',
|
||||
KeyZ = 'KeyZ',
|
||||
KeyX = 'KeyX',
|
||||
KeyC = 'KeyC',
|
||||
KeyV = 'KeyV',
|
||||
KeyB = 'KeyB',
|
||||
KeyN = 'KeyN',
|
||||
KeyM = 'KeyM',
|
||||
Comma = 'Comma',
|
||||
Dot = 'Dot',
|
||||
Slash = 'Slash',
|
||||
Insert = 'Insert',
|
||||
KpReturn = 'KpReturn',
|
||||
KpMinus = 'KpMinus',
|
||||
KpPlus = 'KpPlus',
|
||||
KpMultiply = 'KpMultiply',
|
||||
KpDivide = 'KpDivide',
|
||||
Kp0 = 'Kp0',
|
||||
Kp1 = 'Kp1',
|
||||
Kp2 = 'Kp2',
|
||||
Kp3 = 'Kp3',
|
||||
Kp4 = 'Kp4',
|
||||
Kp5 = 'Kp5',
|
||||
Kp6 = 'Kp6',
|
||||
Kp7 = 'Kp7',
|
||||
Kp8 = 'Kp8',
|
||||
Kp9 = 'Kp9',
|
||||
KpDelete = 'KpDelete',
|
||||
Function = 'Function',
|
||||
VolumeUp = 'VolumeUp',
|
||||
VolumeDown = 'VolumeDown',
|
||||
VolumeMute = 'VolumeMute',
|
||||
BrightnessUp = 'BrightnessUp',
|
||||
BrightnessDown = 'BrightnessDown',
|
||||
PreviousTrack = 'PreviousTrack',
|
||||
PlayPause = 'PlayPause',
|
||||
PlayCd = 'PlayCd',
|
||||
NextTrack = 'NextTrack',
|
||||
Unknown = 'Unknown',
|
||||
}
|
||||
|
||||
// Follows the exact order
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_code_values#code_values_on_windows
|
||||
export const mapKeyCode: Record<KeyCode, string> = {
|
||||
[KeyCode.Escape]: 'Escape',
|
||||
[KeyCode.Kp0]: 'Digit0',
|
||||
[KeyCode.Kp1]: 'Digit1',
|
||||
[KeyCode.Kp2]: 'Digit2',
|
||||
[KeyCode.Kp3]: 'Digit3',
|
||||
[KeyCode.Kp4]: 'Digit4',
|
||||
[KeyCode.Kp5]: 'Digit5',
|
||||
[KeyCode.Kp6]: 'Digit6',
|
||||
[KeyCode.Kp7]: 'Digit7',
|
||||
[KeyCode.Kp8]: 'Digit8',
|
||||
[KeyCode.Kp9]: 'Digit9',
|
||||
[KeyCode.Minus]: 'Minus',
|
||||
[KeyCode.Equal]: 'Equal',
|
||||
[KeyCode.Backspace]: 'Backspace',
|
||||
[KeyCode.Tab]: 'Tab',
|
||||
[KeyCode.KeyQ]: 'KeyQ',
|
||||
[KeyCode.KeyW]: 'KeyW',
|
||||
[KeyCode.KeyE]: 'KeyE',
|
||||
[KeyCode.KeyR]: 'KeyR',
|
||||
[KeyCode.KeyT]: 'KeyT',
|
||||
[KeyCode.KeyY]: 'KeyY',
|
||||
[KeyCode.KeyU]: 'KeyU',
|
||||
[KeyCode.KeyI]: 'KeyI',
|
||||
[KeyCode.KeyO]: 'KeyO',
|
||||
[KeyCode.KeyP]: 'KeyP',
|
||||
[KeyCode.LeftBracket]: 'BracketLeft',
|
||||
[KeyCode.RightBracket]: 'BracketRight',
|
||||
[KeyCode.Return]: 'Enter',
|
||||
[KeyCode.ControlLeft]: 'ControlLeft',
|
||||
[KeyCode.KeyA]: 'KeyA',
|
||||
[KeyCode.KeyS]: 'KeyS',
|
||||
[KeyCode.KeyD]: 'KeyD',
|
||||
[KeyCode.KeyF]: 'KeyF',
|
||||
[KeyCode.KeyG]: 'KeyG',
|
||||
[KeyCode.KeyH]: 'KeyH',
|
||||
[KeyCode.KeyJ]: 'KeyJ',
|
||||
[KeyCode.KeyK]: 'KeyK',
|
||||
[KeyCode.KeyL]: 'KeyL',
|
||||
[KeyCode.SemiColon]: 'SemiColon',
|
||||
[KeyCode.Quote]: 'Quote',
|
||||
[KeyCode.BackQuote]: 'BackQuote',
|
||||
[KeyCode.ShiftLeft]: 'ShiftLeft',
|
||||
[KeyCode.BackSlash]: 'BackSlash',
|
||||
[KeyCode.KeyZ]: 'KeyZ',
|
||||
[KeyCode.KeyX]: 'KeyX',
|
||||
[KeyCode.KeyC]: 'KeyC',
|
||||
[KeyCode.KeyV]: 'KeyV',
|
||||
[KeyCode.KeyB]: 'KeyB',
|
||||
[KeyCode.KeyN]: 'KeyN',
|
||||
[KeyCode.KeyM]: 'KeyM',
|
||||
[KeyCode.Comma]: 'Comma',
|
||||
[KeyCode.Dot]: 'Period',
|
||||
[KeyCode.Slash]: 'Slash',
|
||||
[KeyCode.ShiftRight]: 'ShiftRight',
|
||||
[KeyCode.KpMultiply]: 'NumpadMultiply',
|
||||
[KeyCode.Alt]: 'Alt',
|
||||
[KeyCode.Space]: 'Space',
|
||||
[KeyCode.CapsLock]: 'CapsLock',
|
||||
[KeyCode.F1]: 'F1',
|
||||
[KeyCode.F2]: 'F2',
|
||||
[KeyCode.F3]: 'F3',
|
||||
[KeyCode.F4]: 'F4',
|
||||
[KeyCode.F5]: 'F5',
|
||||
[KeyCode.F6]: 'F6',
|
||||
[KeyCode.F7]: 'F7',
|
||||
[KeyCode.F8]: 'F8',
|
||||
[KeyCode.F9]: 'F9',
|
||||
[KeyCode.F10]: 'F10',
|
||||
[KeyCode.ScrollLock]: 'ScrollLock',
|
||||
[KeyCode.Num7]: 'Numpad7',
|
||||
[KeyCode.Num8]: 'Numpad8',
|
||||
[KeyCode.Num9]: 'Numpad9',
|
||||
[KeyCode.KpMinus]: 'NumpadSubtract',
|
||||
[KeyCode.Num4]: 'Numpad4',
|
||||
[KeyCode.Num5]: 'Numpad5',
|
||||
[KeyCode.Num6]: 'Numpad6',
|
||||
[KeyCode.KpPlus]: 'NumpadAdd',
|
||||
[KeyCode.Num1]: 'Numpad1',
|
||||
[KeyCode.Num2]: 'Numpad2',
|
||||
[KeyCode.Num3]: 'Numpad3',
|
||||
[KeyCode.Num0]: 'Numpad0',
|
||||
// Numpad Decimal?
|
||||
[KeyCode.IntlBackslash]: 'IntlBackslash',
|
||||
[KeyCode.F11]: 'F11',
|
||||
[KeyCode.F12]: 'F12',
|
||||
// NumpadEqual?
|
||||
[KeyCode.F13]: 'F13',
|
||||
[KeyCode.F14]: 'F14',
|
||||
[KeyCode.F15]: 'F15',
|
||||
[KeyCode.F16]: 'F16',
|
||||
[KeyCode.F17]: 'F17',
|
||||
[KeyCode.F18]: 'F18',
|
||||
[KeyCode.F19]: 'F19',
|
||||
[KeyCode.F20]: 'F20',
|
||||
[KeyCode.F21]: 'F21',
|
||||
[KeyCode.F22]: 'F22',
|
||||
[KeyCode.F23]: 'F23',
|
||||
[KeyCode.F24]: 'F24',
|
||||
// NumpadComma?
|
||||
[KeyCode.PreviousTrack]: 'MediaTrackPrevious',
|
||||
[KeyCode.NextTrack]: 'MediaTrackNext',
|
||||
[KeyCode.KpReturn]: 'NumpadEnter',
|
||||
[KeyCode.ControlRight]: 'ControlRight',
|
||||
[KeyCode.VolumeMute]: 'VolumeMute',
|
||||
[KeyCode.PlayPause]: 'MediaPlayPause',
|
||||
[KeyCode.VolumeDown]: 'VolumeDown',
|
||||
[KeyCode.VolumeUp]: 'VolumeUp',
|
||||
[KeyCode.KpDivide]: 'NumpadDivide',
|
||||
[KeyCode.PrintScreen]: 'PrintScreen',
|
||||
[KeyCode.AltGr]: 'AltGr',
|
||||
[KeyCode.NumLock]: 'NumLock',
|
||||
[KeyCode.Pause]: 'Pause',
|
||||
[KeyCode.Home]: 'Home',
|
||||
[KeyCode.UpArrow]: 'ArrowUp',
|
||||
[KeyCode.PageUp]: 'PageUp',
|
||||
[KeyCode.LeftArrow]: 'ArrowLeft',
|
||||
[KeyCode.RightArrow]: 'ArrowRight',
|
||||
[KeyCode.End]: 'End',
|
||||
[KeyCode.DownArrow]: 'ArrowDown',
|
||||
[KeyCode.PageDown]: 'PageDown',
|
||||
[KeyCode.Insert]: 'Insert',
|
||||
[KeyCode.Delete]: 'Delete',
|
||||
// also known as "windows", "super", and "command"
|
||||
[KeyCode.MetaLeft]: 'MetaLeft',
|
||||
// also known as "windows", "super", and "command"
|
||||
[KeyCode.MetaRight]: 'MetaRight',
|
||||
|
||||
[KeyCode.KpDelete]: 'NumpadDelete',
|
||||
[KeyCode.Function]: 'Function',
|
||||
[KeyCode.BrightnessUp]: 'BrightnessUp',
|
||||
[KeyCode.BrightnessDown]: 'BrightnessDown',
|
||||
[KeyCode.PlayCd]: 'PlayCd',
|
||||
[KeyCode.Unknown]: 'Unknown',
|
||||
}
|
||||
|
||||
export const mapKeyKey: Record<KeyCode, string> = {
|
||||
[KeyCode.Escape]: 'Escape',
|
||||
[KeyCode.Kp0]: '0',
|
||||
[KeyCode.Kp1]: '1',
|
||||
[KeyCode.Kp2]: '2',
|
||||
[KeyCode.Kp3]: '3',
|
||||
[KeyCode.Kp4]: '4',
|
||||
[KeyCode.Kp5]: '5',
|
||||
[KeyCode.Kp6]: '6',
|
||||
[KeyCode.Kp7]: '7',
|
||||
[KeyCode.Kp8]: '8',
|
||||
[KeyCode.Kp9]: '9',
|
||||
[KeyCode.Minus]: '-',
|
||||
[KeyCode.Equal]: '=',
|
||||
[KeyCode.Backspace]: 'Backspace',
|
||||
[KeyCode.Tab]: 'Tab',
|
||||
[KeyCode.KeyQ]: 'q',
|
||||
[KeyCode.KeyW]: 'w',
|
||||
[KeyCode.KeyE]: 'e',
|
||||
[KeyCode.KeyR]: 'r',
|
||||
[KeyCode.KeyT]: 't',
|
||||
[KeyCode.KeyY]: 'y',
|
||||
[KeyCode.KeyU]: 'u',
|
||||
[KeyCode.KeyI]: 'i',
|
||||
[KeyCode.KeyO]: 'o',
|
||||
[KeyCode.KeyP]: 'p',
|
||||
[KeyCode.LeftBracket]: '[',
|
||||
[KeyCode.RightBracket]: ']',
|
||||
[KeyCode.Return]: 'Enter',
|
||||
[KeyCode.ControlLeft]: 'Control',
|
||||
[KeyCode.KeyA]: 'a',
|
||||
[KeyCode.KeyS]: 's',
|
||||
[KeyCode.KeyD]: 'd',
|
||||
[KeyCode.KeyF]: 'f',
|
||||
[KeyCode.KeyG]: 'g',
|
||||
[KeyCode.KeyH]: 'h',
|
||||
[KeyCode.KeyJ]: 'j',
|
||||
[KeyCode.KeyK]: 'k',
|
||||
[KeyCode.KeyL]: 'l',
|
||||
[KeyCode.SemiColon]: ';',
|
||||
[KeyCode.Quote]: '\'',
|
||||
[KeyCode.BackQuote]: '`',
|
||||
[KeyCode.ShiftLeft]: 'Shift',
|
||||
[KeyCode.BackSlash]: '\\',
|
||||
[KeyCode.KeyZ]: 'z',
|
||||
[KeyCode.KeyX]: 'x',
|
||||
[KeyCode.KeyC]: 'c',
|
||||
[KeyCode.KeyV]: 'v',
|
||||
[KeyCode.KeyB]: 'b',
|
||||
[KeyCode.KeyN]: 'n',
|
||||
[KeyCode.KeyM]: 'm',
|
||||
[KeyCode.Comma]: ',',
|
||||
[KeyCode.Dot]: '.',
|
||||
[KeyCode.Slash]: '/',
|
||||
[KeyCode.ShiftRight]: 'Shift',
|
||||
[KeyCode.KpMultiply]: '*',
|
||||
[KeyCode.Alt]: 'Alt',
|
||||
[KeyCode.Space]: ' ',
|
||||
[KeyCode.CapsLock]: 'CapsLock',
|
||||
[KeyCode.F1]: 'F1',
|
||||
[KeyCode.F2]: 'F2',
|
||||
[KeyCode.F3]: 'F3',
|
||||
[KeyCode.F4]: 'F4',
|
||||
[KeyCode.F5]: 'F5',
|
||||
[KeyCode.F6]: 'F6',
|
||||
[KeyCode.F7]: 'F7',
|
||||
[KeyCode.F8]: 'F8',
|
||||
[KeyCode.F9]: 'F9',
|
||||
[KeyCode.F10]: 'F10',
|
||||
[KeyCode.ScrollLock]: 'ScrollLock',
|
||||
[KeyCode.Num7]: '7',
|
||||
[KeyCode.Num8]: '8',
|
||||
[KeyCode.Num9]: '9',
|
||||
[KeyCode.KpMinus]: '-',
|
||||
[KeyCode.Num4]: '4',
|
||||
[KeyCode.Num5]: '5',
|
||||
[KeyCode.Num6]: '6',
|
||||
[KeyCode.KpPlus]: '+',
|
||||
[KeyCode.Num1]: '1',
|
||||
[KeyCode.Num2]: '2',
|
||||
[KeyCode.Num3]: '3',
|
||||
[KeyCode.Num0]: '0',
|
||||
// Numpad Decimal?
|
||||
[KeyCode.IntlBackslash]: 'IntlBackslash',
|
||||
[KeyCode.F11]: 'F11',
|
||||
[KeyCode.F12]: 'F12',
|
||||
// NumpadEqual?
|
||||
[KeyCode.F13]: 'F13',
|
||||
[KeyCode.F14]: 'F14',
|
||||
[KeyCode.F15]: 'F15',
|
||||
[KeyCode.F16]: 'F16',
|
||||
[KeyCode.F17]: 'F17',
|
||||
[KeyCode.F18]: 'F18',
|
||||
[KeyCode.F19]: 'F19',
|
||||
[KeyCode.F20]: 'F20',
|
||||
[KeyCode.F21]: 'F21',
|
||||
[KeyCode.F22]: 'F22',
|
||||
[KeyCode.F23]: 'F23',
|
||||
[KeyCode.F24]: 'F24',
|
||||
// NumpadComma?
|
||||
[KeyCode.PreviousTrack]: 'MediaTrackPrevious',
|
||||
[KeyCode.NextTrack]: 'MediaTrackNext',
|
||||
[KeyCode.KpReturn]: 'Enter',
|
||||
[KeyCode.ControlRight]: 'Control',
|
||||
[KeyCode.VolumeMute]: 'VolumeMute',
|
||||
[KeyCode.PlayPause]: 'MediaPlayPause',
|
||||
[KeyCode.VolumeDown]: 'VolumeDown',
|
||||
[KeyCode.VolumeUp]: 'VolumeUp',
|
||||
[KeyCode.KpDivide]: '/',
|
||||
[KeyCode.PrintScreen]: 'PrintScreen',
|
||||
[KeyCode.AltGr]: 'Alt',
|
||||
[KeyCode.NumLock]: 'NumLock',
|
||||
[KeyCode.Pause]: 'Pause',
|
||||
[KeyCode.Home]: 'Home',
|
||||
[KeyCode.UpArrow]: 'ArrowUp',
|
||||
[KeyCode.PageUp]: 'PageUp',
|
||||
[KeyCode.LeftArrow]: 'ArrowLeft',
|
||||
[KeyCode.RightArrow]: 'ArrowRight',
|
||||
[KeyCode.End]: 'End',
|
||||
[KeyCode.DownArrow]: 'ArrowDown',
|
||||
[KeyCode.PageDown]: 'PageDown',
|
||||
[KeyCode.Insert]: 'Insert',
|
||||
[KeyCode.Delete]: 'Delete',
|
||||
// also known as "windows", "super", and "command"
|
||||
[KeyCode.MetaLeft]: 'Meta',
|
||||
// also known as "windows", "super", and "command"
|
||||
[KeyCode.MetaRight]: 'Meta',
|
||||
|
||||
[KeyCode.KpDelete]: 'Delete',
|
||||
[KeyCode.Function]: 'Function',
|
||||
[KeyCode.BrightnessUp]: 'BrightnessUp',
|
||||
[KeyCode.BrightnessDown]: 'BrightnessDown',
|
||||
[KeyCode.PlayCd]: 'PlayCd',
|
||||
[KeyCode.Unknown]: 'Unknown',
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
// export { createVADStates } from './manager'
|
||||
// export type { VADAudioOptions } from './manager'
|
||||
// export { createVAD, VAD } from './vad'
|
||||
@@ -1,2 +0,0 @@
|
||||
// export type { VADAudioOptions } from '@proj-airi/stage-ui/libs/audio/vad'
|
||||
// export { createVADStates } from '@proj-airi/stage-ui/libs/audio/vad'
|
||||
@@ -1,53 +0,0 @@
|
||||
// // vad-worklet-processor.ts
|
||||
// // This file needs to be registered as an AudioWorklet
|
||||
|
||||
// /**
|
||||
// * Minimum chunk size for processing audio
|
||||
// */
|
||||
// const MIN_CHUNK_SIZE = 512
|
||||
|
||||
// /**
|
||||
// * Global state for audio buffer accumulation
|
||||
// */
|
||||
// let globalPointer = 0
|
||||
// const globalBuffer = new Float32Array(MIN_CHUNK_SIZE)
|
||||
|
||||
// /**
|
||||
// * VAD AudioWorklet Processor - processes audio chunks and sends them to the main thread
|
||||
// */
|
||||
// class VADProcessor extends AudioWorkletProcessor {
|
||||
// process(inputs: Float32Array[][], _outputs: Float32Array[][], _parameters: Record<string, Float32Array>) {
|
||||
// const buffer = inputs[0][0]
|
||||
// if (!buffer)
|
||||
// return true // buffer is null when the stream ends
|
||||
|
||||
// if (buffer.length > MIN_CHUNK_SIZE) {
|
||||
// // If the buffer is larger than the minimum chunk size, send the entire buffer
|
||||
// this.port.postMessage({ buffer })
|
||||
// }
|
||||
// else {
|
||||
// const remaining = MIN_CHUNK_SIZE - globalPointer
|
||||
// if (buffer.length >= remaining) {
|
||||
// // If the buffer is larger than (or equal to) the remaining space in the global buffer, copy the remaining space
|
||||
// globalBuffer.set(buffer.subarray(0, remaining), globalPointer)
|
||||
|
||||
// // Send the global buffer
|
||||
// this.port.postMessage({ buffer: globalBuffer })
|
||||
|
||||
// // Reset the global buffer and set the remaining buffer
|
||||
// globalBuffer.fill(0)
|
||||
// globalBuffer.set(buffer.subarray(remaining), 0)
|
||||
// globalPointer = buffer.length - remaining
|
||||
// }
|
||||
// else {
|
||||
// // If the buffer is smaller than the remaining space in the global buffer, copy the buffer to the global buffer
|
||||
// globalBuffer.set(buffer, globalPointer)
|
||||
// globalPointer += buffer.length
|
||||
// }
|
||||
// }
|
||||
|
||||
// return true
|
||||
// }
|
||||
// }
|
||||
|
||||
// registerProcessor('vad-audio-worklet-processor', VADProcessor)
|
||||
@@ -1,217 +0,0 @@
|
||||
// import type { BaseVAD, BaseVADConfig, VADEventCallback, VADEvents } from '@proj-airi/stage-ui/libs/audio/vad'
|
||||
|
||||
// import { invoke } from '../invoke'
|
||||
|
||||
// export class VAD implements BaseVAD {
|
||||
// private config: BaseVADConfig
|
||||
// private state: Float32Array = new Float32Array(2 * 1 * 128) // 2, 1, 128
|
||||
// private buffer: Float32Array
|
||||
// private bufferPointer: number = 0
|
||||
// private isRecording: boolean = false
|
||||
// private postSpeechSamples: number = 0
|
||||
// private prevBuffers: Float32Array[] = []
|
||||
// private inferenceChain: Promise<any> = Promise.resolve()
|
||||
// private eventListeners: Partial<Record<keyof VADEvents, VADEventCallback<any>[]>> = {}
|
||||
// private isReady: boolean = false
|
||||
|
||||
// constructor(userConfig: Partial<BaseVADConfig> = {}) {
|
||||
// const defaultConfig: BaseVADConfig = {
|
||||
// sampleRate: 16000,
|
||||
// speechThreshold: 0.3,
|
||||
// exitThreshold: 0.1,
|
||||
// minSilenceDurationMs: 400,
|
||||
// speechPadMs: 80,
|
||||
// minSpeechDurationMs: 250,
|
||||
// maxBufferDuration: 30,
|
||||
// newBufferSize: 512,
|
||||
// }
|
||||
|
||||
// this.config = { ...defaultConfig, ...userConfig }
|
||||
// this.buffer = new Float32Array(this.config.maxBufferDuration * this.config.sampleRate)
|
||||
// }
|
||||
|
||||
// public async initialize(): Promise<void> {
|
||||
// try {
|
||||
// this.emit('status', { type: 'info', message: 'Loading VAD model...' })
|
||||
|
||||
// await invoke('plugin:ipc-audio-vad-ort|load_ort_model_silero_vad')
|
||||
// this.isReady = true
|
||||
|
||||
// this.emit('status', { type: 'info', message: 'VAD model loaded successfully' })
|
||||
// }
|
||||
// catch (error) {
|
||||
// this.emit('status', { type: 'error', message: `Failed to load VAD model: ${error}` })
|
||||
// throw error
|
||||
// }
|
||||
// }
|
||||
|
||||
// public on<K extends keyof VADEvents>(event: K, callback: VADEventCallback<K>): void {
|
||||
// if (!this.eventListeners[event]) {
|
||||
// this.eventListeners[event] = []
|
||||
// }
|
||||
// this.eventListeners[event]!.push(callback as any)
|
||||
// }
|
||||
|
||||
// public off<K extends keyof VADEvents>(event: K, callback: VADEventCallback<K>): void {
|
||||
// if (!this.eventListeners[event])
|
||||
// return
|
||||
// this.eventListeners[event] = this.eventListeners[event]!.filter(cb => cb !== callback)
|
||||
// }
|
||||
|
||||
// private emit<K extends keyof VADEvents>(event: K, data: VADEvents[K]): void {
|
||||
// if (!this.eventListeners[event])
|
||||
// return
|
||||
// for (const callback of this.eventListeners[event]!) {
|
||||
// callback(data)
|
||||
// }
|
||||
// }
|
||||
|
||||
// public async processAudio(inputBuffer: Float32Array): Promise<void> {
|
||||
// if (!this.isReady) {
|
||||
// throw new Error('VAD model is not initialized. Call initialize() first.')
|
||||
// }
|
||||
|
||||
// const wasRecording = this.isRecording
|
||||
|
||||
// // Perform VAD using Rust backend
|
||||
// const isSpeech = await this.detectSpeech(inputBuffer)
|
||||
|
||||
// // The rest of the logic remains the same as your original implementation
|
||||
// const sampleRateMs = this.config.sampleRate / 1000
|
||||
// const minSilenceDurationSamples = this.config.minSilenceDurationMs * sampleRateMs
|
||||
// const speechPadSamples = this.config.speechPadMs * sampleRateMs
|
||||
// const minSpeechDurationSamples = this.config.minSpeechDurationMs * sampleRateMs
|
||||
// const maxPrevBuffers = Math.ceil(speechPadSamples / this.config.newBufferSize)
|
||||
|
||||
// if (!wasRecording && !isSpeech) {
|
||||
// if (this.prevBuffers.length >= maxPrevBuffers) {
|
||||
// this.prevBuffers.shift()
|
||||
// }
|
||||
// this.prevBuffers.push(inputBuffer.slice(0))
|
||||
// return
|
||||
// }
|
||||
|
||||
// const remaining = this.buffer.length - this.bufferPointer
|
||||
// if (inputBuffer.length >= remaining) {
|
||||
// this.buffer.set(inputBuffer.subarray(0, remaining), this.bufferPointer)
|
||||
// this.bufferPointer += remaining
|
||||
|
||||
// const overflow = inputBuffer.subarray(remaining)
|
||||
// this.processSpeechSegment(overflow)
|
||||
// return
|
||||
// }
|
||||
// else {
|
||||
// this.buffer.set(inputBuffer, this.bufferPointer)
|
||||
// this.bufferPointer += inputBuffer.length
|
||||
// }
|
||||
|
||||
// if (isSpeech) {
|
||||
// if (!this.isRecording) {
|
||||
// this.emit('speech-start', undefined)
|
||||
// this.emit('status', { type: 'info', message: 'Speech detected' })
|
||||
// }
|
||||
|
||||
// this.isRecording = true
|
||||
// this.postSpeechSamples = 0
|
||||
// return
|
||||
// }
|
||||
|
||||
// this.postSpeechSamples += inputBuffer.length
|
||||
|
||||
// if (this.postSpeechSamples >= minSilenceDurationSamples) {
|
||||
// if (this.bufferPointer < minSpeechDurationSamples) {
|
||||
// this.reset()
|
||||
// return
|
||||
// }
|
||||
|
||||
// this.processSpeechSegment()
|
||||
// }
|
||||
// }
|
||||
|
||||
// private async detectSpeech(buffer: Float32Array): Promise<boolean> {
|
||||
// // Use Rust backend for inference
|
||||
// const result = await (this.inferenceChain = this.inferenceChain.then(() =>
|
||||
// invoke('plugin:ipc-audio-vad-ort|ipc_audio_vad', {
|
||||
// inputData: {
|
||||
// input: Array.from(buffer),
|
||||
// sr: this.config.sampleRate,
|
||||
// state: Array.from(this.state),
|
||||
// },
|
||||
// }),
|
||||
// )) as { output: number[], state: number[] }
|
||||
|
||||
// // Update the state
|
||||
// this.state = new Float32Array(result.state)
|
||||
|
||||
// // Get the speech probability
|
||||
// const speechProb = result.output[0]
|
||||
|
||||
// this.emit('debug', {
|
||||
// message: 'VAD score',
|
||||
// data: { probability: speechProb },
|
||||
// })
|
||||
|
||||
// // Apply thresholds
|
||||
// return (
|
||||
// speechProb > this.config.speechThreshold
|
||||
// || (this.isRecording && speechProb >= this.config.exitThreshold)
|
||||
// )
|
||||
// }
|
||||
|
||||
// private processSpeechSegment(overflow?: Float32Array): void {
|
||||
// const sampleRateMs = this.config.sampleRate / 1000
|
||||
// const speechPadSamples = this.config.speechPadMs * sampleRateMs
|
||||
|
||||
// const duration = (this.bufferPointer / this.config.sampleRate) * 1000
|
||||
// const overflowLength = overflow?.length ?? 0
|
||||
|
||||
// const prevLength = this.prevBuffers.reduce((acc, b) => acc + b.length, 0)
|
||||
// const finalBuffer = new Float32Array(prevLength + this.bufferPointer + speechPadSamples)
|
||||
|
||||
// let offset = 0
|
||||
// for (const prev of this.prevBuffers) {
|
||||
// finalBuffer.set(prev, offset)
|
||||
// offset += prev.length
|
||||
// }
|
||||
|
||||
// finalBuffer.set(this.buffer.slice(0, this.bufferPointer + speechPadSamples), offset)
|
||||
|
||||
// this.emit('speech-end', undefined)
|
||||
// this.emit('speech-ready', {
|
||||
// buffer: finalBuffer,
|
||||
// duration,
|
||||
// })
|
||||
|
||||
// if (overflow) {
|
||||
// this.buffer.set(overflow, 0)
|
||||
// }
|
||||
// this.reset(overflowLength)
|
||||
// }
|
||||
|
||||
// private reset(offset: number = 0): void {
|
||||
// this.buffer.fill(0, offset)
|
||||
// this.bufferPointer = offset
|
||||
// this.isRecording = false
|
||||
// this.postSpeechSamples = 0
|
||||
// this.prevBuffers = []
|
||||
// }
|
||||
|
||||
// public updateConfig(newConfig: Partial<BaseVADConfig>): void {
|
||||
// this.config = { ...this.config, ...newConfig }
|
||||
|
||||
// if (newConfig.maxBufferDuration || newConfig.sampleRate) {
|
||||
// this.buffer = new Float32Array(this.config.maxBufferDuration * this.config.sampleRate)
|
||||
// this.bufferPointer = 0
|
||||
// }
|
||||
// }
|
||||
|
||||
// public isCurrentlyRecording(): boolean {
|
||||
// return this.isRecording
|
||||
// }
|
||||
// }
|
||||
|
||||
// export async function createVAD(config?: Partial<BaseVADConfig>): Promise<VAD> {
|
||||
// const vad = new VAD(config)
|
||||
// await vad.initialize()
|
||||
// return vad
|
||||
// }
|
||||
@@ -1,6 +0,0 @@
|
||||
export enum WindowControlMode {
|
||||
NONE = 'none',
|
||||
MOVE = 'move',
|
||||
RESIZE = 'resize',
|
||||
DEBUG = 'debug',
|
||||
}
|
||||
Reference in New Issue
Block a user