import * as electron from 'electron' import { app, BrowserWindow, desktopCapturer, ipcMain, Menu, Notification, screen, shell, Tray } from 'electron' import path, { join } from 'path' import { electronApp, is, optimizer } from '@electron-toolkit/utils' // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore import { useCheckUpdate } from './useCheckUpdate' import vimConfig from '/src/renderer/src/config/VimConfig' //刷新托盘定时器 let flashIconTimer: NodeJS.Timeout | null = null let cutWindow: BrowserWindow | null = null const iconPath = process.platform === 'win32' ? '../../resources/icon.ico' : '../../resources/icon.png' const emptyIconPath = process.platform === 'win32' ? '../../resources/empty.ico' : '../../resources/empty.png' let appIcon: Electron.Tray | null = null function createWindow(): void { // Create the browser window. const mainWindow = new BrowserWindow({ show: false, autoHideMenuBar: true, webPreferences: { contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION, webSecurity: true, nodeIntegration: true, // 解决require is not defined问题 webviewTag: true, // 解决webview无法显示问题 preload: join(__dirname, '../preload/index.js'), sandbox: false }, useContentSize: true, width: 1000, height: 600, frame: false }) mainWindow.on('ready-to-show', () => { mainWindow.show() useCheckUpdate(app) }) // 处理窗口失去焦点事件 mainWindow.on('blur', () => { mainWindow.webContents.send('BLUR', true) }) // 处理窗口获得焦点事件 mainWindow.on('focus', () => { mainWindow.webContents.send('FOCUS', false) }) /** * 系统休眠 */ electron.powerMonitor.on('suspend', () => { mainWindow.webContents.send('SLEEP') }) /** * 系统唤醒 */ electron.powerMonitor.on('resume', () => { mainWindow.webContents.send('RESUME') }) mainWindow.webContents.setWindowOpenHandler((details) => { shell.openExternal(details.url).then() return { action: 'deny' } }) // HMR for renderer base on electron-vite cli. // Load the remote URL for development or the local html file for production. if (is.dev && process.env['ELECTRON_RENDERER_URL']) { mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL']).then() } else { mainWindow.loadFile(join(__dirname, '../renderer/index.html')).then() } ipcMain.on('min', () => { mainWindow.minimize() }) ipcMain.on('openURL', (e: Electron.IpcMainEvent, url: string) => { e.preventDefault() shell.openExternal(url).then() }) ipcMain.on('max', () => { if (mainWindow.isMaximized()) { mainWindow.unmaximize() } else { mainWindow.maximize() } }) // 只是隐藏任务栏 ipcMain.on('close', () => { hideMain(mainWindow) }) // 闪烁任务栏 ipcMain.on('flashFrame', () => { //没有聚焦 if (!mainWindow.isFocused()) { mainWindow.flashFrame(true) } }) /** * 发生系统通知 * @param content 通知内容 * @param url 点击通知跳转的url */ ipcMain.on( 'NOTIFICATION', (e: Electron.IpcMainEvent, content: string, url: string | undefined) => { e.preventDefault() if (!mainWindow.isFocused()) { new Notification({ title: vimConfig.name, body: content, timeoutType: 'never' }) .on('click', (event) => { event.preventDefault() showMain(mainWindow) if (url) { shell.openExternal(url).then() } }) .show() } } ) appIcon = createTray(mainWindow, iconPath) // 闪烁任务栏 ipcMain.on('flashIcon', () => { if (!mainWindow.isVisible()) { clearFlashIconTimer() let count = 0 flashIconTimer = setInterval(() => { count++ if (appIcon) { if (count % 2 === 0) { appIcon.setImage(path.join(__dirname, emptyIconPath)) } else { appIcon.setImage(path.join(__dirname, iconPath)) } } }, 500) } }) ipcMain.on('clearFlashIcon', () => { clearFlashIconTimer() if (appIcon) { appIcon.setImage(path.join(__dirname, iconPath)) } }) // 获取设备窗口信息 ipcMain.handle('getSource', async () => { const sources = await desktopCapturer.getSources({ types: ['screen'], thumbnailSize: getSize() }) //当前的屏幕id const { id } = screen.getDisplayNearestPoint(screen.getCursorScreenPoint()) //多屏情况下,只截图当前的屏幕 return sources.find((source) => source.display_id === id + '') ?? sources[0] }) /** * 点击截屏弹出截屏窗口 */ ipcMain.on('OPEN_CUT_SCREEN', async (event, args) => { event.preventDefault() closeCutWindow() if (args) { mainWindow.hide() } await createCutWindow() if (cutWindow) { cutWindow.show() } }) /** * 截屏事件 */ ipcMain.on('CUT_SCREEN', async (e, cutInfo) => { e.preventDefault() closeCutWindow() mainWindow.webContents.send('GET_CUT_INFO', cutInfo) mainWindow.show() }) /** * 关闭截屏窗口 */ ipcMain.on('CLOSE_CUT_SCREEN', async () => { closeCutWindow() mainWindow.show() }) } /** * 隐藏窗口,隐藏任务栏 */ function hideMain(win: BrowserWindow) { win.setSkipTaskbar(true) win.hide() } /** * 清除图片闪烁的定时器 */ function clearFlashIconTimer() { if (flashIconTimer) { clearInterval(flashIconTimer) if (appIcon) { appIcon.setImage(path.join(__dirname, iconPath)) } } } /** * 获取截屏的size */ function getSize() { const { size, scaleFactor } = screen.getDisplayNearestPoint(screen.getCursorScreenPoint()) return { width: Math.floor(size.width * scaleFactor), height: Math.floor(size.height * scaleFactor) } } /** * 创建一个截屏窗口 */ async function createCutWindow() { cutWindow = new BrowserWindow({ useContentSize: true, autoHideMenuBar: true, movable: false, frame: false, resizable: false, hasShadow: false, transparent: true, fullscreen: true, simpleFullscreen: true, alwaysOnTop: false, webPreferences: { contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION, webSecurity: false, nodeIntegration: true, // 解决require is not defined问题 webviewTag: true, // 解决webview无法显示问题 preload: join(__dirname, '../preload/index.js'), sandbox: false } }) const cutPage = process.platform === 'win32' ? 'cutWin32' : 'cutLinux' if (process.env['ELECTRON_RENDERER_URL']) { await cutWindow.loadURL(`${process.env['ELECTRON_RENDERER_URL']}#/${cutPage}`) if (!process.env.IS_TEST) cutWindow.webContents.openDevTools() } else { await cutWindow.loadFile(join(__dirname, '../renderer/index.html'), { hash: cutPage }) } cutWindow.maximize() cutWindow.setFullScreen(true) } function closeCutWindow() { cutWindow && cutWindow.close() cutWindow = null } app.whenReady().then(() => { electronApp.setAppUserModelId('com.electron') app.on('browser-window-created', (_, window) => { optimizer.watchWindowShortcuts(window) }) createWindow() app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) createWindow() }) }) app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit() } }) app.on('browser-window-focus', () => { clearFlashIconTimer() }) /** * 创建托盘图标 * @param win * @param iconPath */ function createTray(win: BrowserWindow, iconPath: string) { // 托盘 const appIcon = new Tray(path.join(__dirname, iconPath)) const contextMenu = Menu.buildFromTemplate([ { label: '显示', click: () => { showMain(win) } }, { label: '退出', click: () => { app.quit() } } ]) appIcon.setToolTip(vimConfig.name) appIcon.setContextMenu(contextMenu) appIcon.on('click', () => { showMain(win) }) return appIcon } /** * 展示窗口,打开任务栏 */ function showMain(win: BrowserWindow) { win.setSkipTaskbar(false) win.show() clearFlashIconTimer() }