|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- import { app, BrowserWindow, ipcMain } from 'electron'
- import { join } from 'path'
- import { readFile, stat, writeFile } from 'fs/promises'
- import { electronApp, optimizer, is } from '@electron-toolkit/utils'
- import icon from '../../resources/icon.png?asset'
- import { Config, defaultConfig } from '../common/config'
- import { getNaturalKeys } from './utils/display'
- import { Stats } from 'fs'
-
- const configPath = './config.json'
- const height = 160
-
- const ALLOWED_PERMISSIONS = ['midi']
-
- const defineWindowCommonSecurity = (browserWindow: BrowserWindow): void => {
- browserWindow.webContents.setWindowOpenHandler(() => {
- return { action: 'deny' }
- })
- }
-
- const addWindowEvents = (browserWindow: BrowserWindow): void => {
- browserWindow.on('ready-to-show', () => {
- browserWindow.show()
- })
- }
-
- const addMidiPermissions = (browserWindow: BrowserWindow): void => {
- browserWindow.webContents.session.setPermissionRequestHandler(
- (_webContents, permission, callback) => {
- callback(ALLOWED_PERMISSIONS.includes(permission))
- }
- )
-
- browserWindow.webContents.session.setPermissionCheckHandler((_webContents, permission) => {
- return ALLOWED_PERMISSIONS.includes(permission)
- })
- }
-
- const assignWindowView = async (
- browserWindow: BrowserWindow,
- routeName: string,
- config: Config
- ): Promise<BrowserWindow> => {
- let search = new URLSearchParams()
- let url: URL | undefined
- if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
- url = new URL(process.env['ELECTRON_RENDERER_URL'])
- search = new URLSearchParams(url.searchParams)
- }
-
- Object.entries(config).forEach(([key, value]) => {
- search.set(key, value)
- })
- search.set('window', routeName)
-
- if (typeof url !== 'undefined') {
- url.search = search.toString()
- await browserWindow.loadURL(url.toString())
- return browserWindow
- }
-
- await browserWindow.loadFile(join(__dirname, '../renderer/index.html'), {
- search: search.toString()
- })
- return browserWindow
- }
-
- const createMainWindow = async (config: Config): Promise<BrowserWindow> => {
- const naturalKeys = getNaturalKeys(config.range)
- const width = naturalKeys * Number(config.naturalKeyWidth || 20) + Number(config.scaleFactor)
- const mainWindow = new BrowserWindow({
- width,
- height,
- show: false,
- autoHideMenuBar: true,
- ...(process.platform === 'linux' ? { icon } : {}),
- webPreferences: {
- preload: join(__dirname, '../preload/index.js'),
- sandbox: false,
- devTools: is.dev
- },
- title: 'Piano MIDI Monitor',
- maximizable: is.dev,
- minimizable: false,
- maxHeight: is.dev ? undefined : height,
- minHeight: is.dev ? undefined : height,
- minWidth: is.dev ? undefined : width,
- maxWidth: is.dev ? undefined : width,
- fullscreenable: false,
- resizable: is.dev,
- useContentSize: true
- })
- defineWindowCommonSecurity(mainWindow)
- addMidiPermissions(mainWindow)
- addWindowEvents(mainWindow)
- return assignWindowView(mainWindow, 'main', config)
- }
-
- const createSettingsWindow = async (
- parent: BrowserWindow,
- config: Config
- ): Promise<BrowserWindow> => {
- const settingsWindow = new BrowserWindow({
- width: 360,
- height: 640,
- show: false,
- autoHideMenuBar: true,
- modal: true,
- ...(process.platform === 'linux' ? { icon } : {}),
- webPreferences: {
- preload: join(__dirname, '../preload/index.js'),
- sandbox: false,
- devTools: is.dev
- },
- title: 'Settings',
- maximizable: false,
- minimizable: false,
- fullscreenable: false,
- resizable: false,
- useContentSize: true,
- parent
- })
- defineWindowCommonSecurity(settingsWindow)
- addMidiPermissions(settingsWindow)
- addWindowEvents(settingsWindow)
- return assignWindowView(settingsWindow, 'settings', config)
- }
-
- const ensureConfig = async (defaultConfig: Config): Promise<Config> => {
- const effectiveConfig = { ...defaultConfig }
- let theStat: Stats
- try {
- theStat = await stat(configPath)
- } catch {
- await writeFile(configPath, JSON.stringify(defaultConfig))
- return effectiveConfig
- }
-
- if (theStat.isDirectory()) {
- throw new Error('Config path is a directory.')
- }
-
- try {
- const jsonRaw = await readFile(configPath, 'utf-8')
- const json = JSON.parse(jsonRaw)
- Object.entries(json).forEach(([key, value]) => {
- effectiveConfig[key] = value
- })
- } catch {
- await writeFile(configPath, JSON.stringify(defaultConfig))
- }
-
- return effectiveConfig
- }
-
- const main = async (): Promise<void> => {
- const effectiveConfig = await ensureConfig(defaultConfig)
-
- app.on('window-all-closed', () => {
- if (process.platform !== 'darwin') {
- app.quit()
- }
- })
-
- await app.whenReady()
- electronApp.setAppUserModelId('sh.modal.pianomidimonitor')
-
- app.on('browser-window-created', (_, window) => {
- optimizer.watchWindowShortcuts(window)
- })
-
- ipcMain.on('action', async (event, value, formData) => {
- const webContents = event.sender
- const win = BrowserWindow.fromWebContents(webContents)
- if (!win) {
- return
- }
- switch (value) {
- case 'showSettings': {
- await createSettingsWindow(win, effectiveConfig)
- return
- }
- case 'cancelSaveConfig': {
- win.close()
- return
- }
- case 'resetConfig': {
- Object.entries(defaultConfig).forEach(([key, value]) => {
- effectiveConfig[key] = value
- })
- await writeFile(configPath, JSON.stringify(effectiveConfig))
- win.close()
- win.getParentWindow()?.close()
- await createMainWindow(effectiveConfig)
- return
- }
- case 'saveConfig': {
- Object.entries(formData).forEach(([key, value]) => {
- effectiveConfig[key] = value
- })
- await writeFile(configPath, JSON.stringify(effectiveConfig))
- win.close()
- win.getParentWindow()?.close()
- await createMainWindow(effectiveConfig)
- return
- }
- }
- })
-
- await createMainWindow(effectiveConfig)
-
- app.on('activate', async () => {
- if (BrowserWindow.getAllWindows().length === 0) {
- await createMainWindow(effectiveConfig)
- }
- })
- }
-
- void main()
|