Files
feishin/src/preload/utils.ts
T
muckymucky 22d37135ae fix: strip playback accelerators whenever any text input is focused (#2059)
The command-palette-specific IPC approach didn't cover other modals
with inputs (settings search, playlist creation, etc.). Replace it
with document-level focusin/focusout listeners that signal the main
process whenever any input/textarea/contenteditable gains or loses
focus, so the menu rebuild is triggered automatically for all current
and future input surfaces.

Co-authored-by: muckymucky <muckymucky@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 13:35:45 -07:00

114 lines
3.0 KiB
TypeScript

import { ipcRenderer, webFrame } from 'electron';
import { disableAutoUpdates, isLinux, isMacOS, isWindows } from '../main/env';
const openItem = async (path: string) => {
return ipcRenderer.invoke('open-item', path);
};
const openApplicationDirectory = async () => {
return ipcRenderer.invoke('open-application-directory');
};
const playerErrorListener = (cb: (data: { code: number }) => void) => {
ipcRenderer.on('player-error-listener', (_, data) => cb(data));
};
const mainMessageListener = (
cb: (data: { message: string; type: 'error' | 'info' | 'success' | 'warning' }) => void,
) => {
ipcRenderer.on('toast-from-main', (_, data) => cb(data));
};
const download = (url: string) => {
ipcRenderer.send('download-url', url);
};
const checkForUpdates = (): Promise<{ updateAvailable: boolean; version?: string }> => {
return ipcRenderer.invoke('app-check-for-updates');
};
const startPowerSaveBlocker = (full: boolean) => {
return ipcRenderer.invoke('power-save-blocker-start', { full });
};
const stopPowerSaveBlocker = () => {
return ipcRenderer.invoke('power-save-blocker-stop');
};
const forceGarbageCollection = (): boolean => {
try {
if (typeof global.gc === 'function') {
global.gc();
webFrame.clearCache();
return true;
}
if (typeof window.gc === 'function') {
window.gc();
webFrame.clearCache();
return true;
}
return false;
} catch {
return false;
}
};
const setInputFocused = (focused: boolean) => {
ipcRenderer.send('input-focus-state', focused);
};
const rendererOpenSettings = (cb: () => void) => {
ipcRenderer.on('renderer-open-settings', () => cb());
};
const rendererOpenCommandPalette = (cb: () => void) => {
ipcRenderer.on('renderer-open-command-palette', () => cb());
};
const rendererOpenManageServers = (cb: () => void) => {
ipcRenderer.on('renderer-open-manage-servers', () => cb());
};
const rendererTogglePrivateMode = (cb: () => void) => {
ipcRenderer.on('renderer-toggle-private-mode', cb);
};
const rendererToggleSidebar = (cb: () => void) => {
ipcRenderer.on('renderer-toggle-sidebar', () => cb());
};
const rendererOpenReleaseNotes = (cb: () => void) => {
ipcRenderer.on('renderer-open-release-notes', () => cb());
};
const rendererUpdateAvailable = (cb: (version: string) => void) => {
ipcRenderer.on('update-available', (_, version) => cb(version));
};
export const utils = {
checkForUpdates,
disableAutoUpdates,
download,
forceGarbageCollection,
isLinux,
isMacOS,
isWindows,
mainMessageListener,
openApplicationDirectory,
openItem,
playerErrorListener,
rendererOpenCommandPalette,
rendererOpenManageServers,
rendererOpenReleaseNotes,
rendererOpenSettings,
rendererTogglePrivateMode,
rendererToggleSidebar,
rendererUpdateAvailable,
setInputFocused,
startPowerSaveBlocker,
stopPowerSaveBlocker,
};
export type Utils = typeof utils;