fix(stage-tamagotchi): let AIRI start on Linux ARM64 (#2253)

This commit is contained in:
Doji
2026-08-11 20:26:54 +08:00
committed by GitHub
parent 28dec4bc5f
commit d0b809a1f8
4 changed files with 35 additions and 22 deletions
@@ -106,14 +106,13 @@ async function setupMocks() {
},
}))
vi.doMock('uiohook-napi', () => ({
uIOhook: {
on: vi.fn(),
removeListener: vi.fn(),
start: vi.fn(),
stop: vi.fn(),
},
UiohookKey: new Proxy({}, { get: () => 0 }),
vi.doMock('./global-shortcut-uiohook', () => ({
createUiohookDriver: () => ({
tryRegister: vi.fn(async (binding: ShortcutBinding) => ({ id: binding.id, ok: true })),
unregisterById: vi.fn(),
unregisterAll: vi.fn(),
dispose: vi.fn(),
}),
}))
vi.doMock('@moeru/eventa', async (importOriginal) => {
@@ -182,7 +181,7 @@ describe('setupGlobalShortcutService', () => {
registerMockWindow(service, ctx)
const handler = ctx.invokeHandlers.get('eventa:invoke:electron:shortcut:register')!
const result = handler({ ...exampleBinding('ptt'), receiveKeyUps: true }) as { id: string, ok: boolean }
const result = await handler({ ...exampleBinding('ptt'), receiveKeyUps: true }) as { id: string, ok: boolean }
expect(result).toEqual({ id: 'ptt', ok: true })
expect(m.registerMock).not.toHaveBeenCalled()
})
@@ -2,6 +2,8 @@ import type { createContext } from '@moeru/eventa/adapters/electron/main'
import type { ShortcutBinding, ShortcutRegistrationResult } from '@proj-airi/stage-shared/global-shortcut'
import type { BrowserWindow } from 'electron'
import type { UiohookDriver } from './global-shortcut-uiohook'
import { useLogg } from '@guiiai/logg'
import { defineInvokeHandler } from '@moeru/eventa'
import { formatElectronAccelerator, ShortcutFailureReasons } from '@proj-airi/stage-shared/global-shortcut'
@@ -15,7 +17,6 @@ import {
electronShortcutUnregisterAll,
} from '../../../shared/eventa'
import { onAppBeforeQuit } from '../../libs/bootkit/lifecycle'
import { createUiohookDriver } from './global-shortcut-uiohook'
export type EventaContext = ReturnType<typeof createContext>['context']
@@ -57,10 +58,7 @@ export function setupGlobalShortcutService(): GlobalShortcutService {
}
}
const uiohookDriver = createUiohookDriver({
broadcastTriggered,
logger: log,
})
let uiohookDriver: UiohookDriver | undefined
function tryRegisterElectron(binding: ShortcutBinding): ShortcutRegistrationResult {
const electronAccelerator = formatElectronAccelerator(binding.accelerator)
@@ -79,7 +77,23 @@ export function setupGlobalShortcutService(): GlobalShortcutService {
return { id: binding.id, ok: true }
}
function tryRegisterUiohook(binding: ShortcutBinding): ShortcutRegistrationResult {
async function tryRegisterUiohook(binding: ShortcutBinding): Promise<ShortcutRegistrationResult> {
if (!uiohookDriver) {
// NOTICE:
// uiohook-napi@1.5.5 ships an x86-64 binary in its Linux ARM64 prebuild.
// Loading the existing driver only when needed keeps AIRI startup working.
// Source: https://app.unpkg.com/uiohook-napi@1.5.5/files/prebuilds/linux-arm64
// Remove this workaround when that prebuild contains an ARM64 binary.
try {
const { createUiohookDriver } = await import('./global-shortcut-uiohook')
uiohookDriver = createUiohookDriver({ broadcastTriggered, logger: log })
}
catch (error) {
log.withError(error).warn('uiohook driver is unavailable on this system')
return { id: binding.id, ok: false, reason: ShortcutFailureReasons.Unsupported }
}
}
const result = uiohookDriver.tryRegister(binding)
if (result.ok)
active.set(binding.id, { binding, owner: 'renderer', driver: 'uiohook' })
@@ -127,12 +141,12 @@ export function setupGlobalShortcutService(): GlobalShortcutService {
}
}
else {
uiohookDriver.unregisterById(id)
uiohookDriver?.unregisterById(id)
}
active.delete(id)
}
function tryRegister(binding: ShortcutBinding): ShortcutRegistrationResult {
function tryRegister(binding: ShortcutBinding): ShortcutRegistrationResult | Promise<ShortcutRegistrationResult> {
if (active.has(binding.id)) {
return { id: binding.id, ok: false, reason: ShortcutFailureReasons.DuplicateId }
}
@@ -189,7 +203,7 @@ export function setupGlobalShortcutService(): GlobalShortcutService {
const dispose: GlobalShortcutService['dispose'] = () => {
unregisterAll(true)
uiohookDriver.dispose()
uiohookDriver?.dispose()
contexts.clear()
}
@@ -10,8 +10,6 @@ import { dirname, join, resolve } from 'node:path'
import { env } from 'node:process'
import { fileURLToPath } from 'node:url'
import clickDragPlugin from 'electron-click-drag-plugin'
import { is } from '@electron-toolkit/utils'
import { defineInvokeHandler } from '@moeru/eventa'
import { createContext } from '@moeru/eventa/adapters/electron/main'
@@ -149,6 +147,8 @@ export async function setupDashboardWindow(params: {
* Workaround: https://github.com/noobfromph/electron-click-drag-plugin
*/
if (!isLinux) {
const { default: clickDragPlugin } = await import('electron-click-drag-plugin')
function handleStartDraggingWindow() {
try {
const windowId = window.getNativeWindowHandle()
@@ -17,8 +17,6 @@ import { dirname, join, resolve } from 'node:path'
import { env } from 'node:process'
import { fileURLToPath } from 'node:url'
import clickDragPlugin from 'electron-click-drag-plugin'
import { is } from '@electron-toolkit/utils'
import { defineInvokeHandler } from '@moeru/eventa'
import { createContext } from '@moeru/eventa/adapters/electron/main'
@@ -201,6 +199,8 @@ export async function setupMainWindow(params: {
* Workaround: https://github.com/noobfromph/electron-click-drag-plugin
*/
if (!isLinux) {
const { default: clickDragPlugin } = await import('electron-click-drag-plugin')
function handleStartDraggingWindow() {
try {
const windowId = window.getNativeWindowHandle()