main.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. const { app, BrowserWindow, Menu, ipcMain, globalShortcut, dialog, screen, Tray } = require('electron');
  2. const { join } = require('path');
  3. const { fork } = require('child_process');
  4. const { platform } = require('process');
  5. const mqtt = require('mqtt')
  6. const sleep = (ms) => new Promise(res => setTimeout(res, ms));
  7. class MainSerivce {
  8. #mqttChannel = null
  9. #client = null
  10. constructor() {
  11. Menu.setApplicationMenu(null) // 去掉菜单栏
  12. app.commandLine.appendSwitch('wm-window-animations-disabled') // 拖动闪屏
  13. app.commandLine.appendSwitch('autoplay-policy', 'no-user-gesture-required');
  14. this.loadingWin = null
  15. this.mainWin = null
  16. this.icon = join(__dirname, './icon/playGame.png')
  17. this.contrlEvent = null
  18. app.on('ready', this.onRead.bind(this))
  19. app.on('activate', (e, isVisible) => {
  20. if (!isVisible && this.mainWin) {
  21. // 兼容Mac dock 栏点击
  22. this.mainWin.show()
  23. }
  24. })
  25. app.on('window-all-closed', () => app.quit())
  26. }
  27. createLoading() {
  28. const { size: { width, height } } = screen.getPrimaryDisplay()
  29. this.loadingWin = new BrowserWindow({
  30. frame: false, // 无边框(窗口、工具栏等),只包含网页内容
  31. width,
  32. height,
  33. resizable: false,
  34. center: true,
  35. icon: this.icon,
  36. alwaysOnTop: true,
  37. transparent: true // 窗口是否支持透明,如果想做高级效果最好为true
  38. })
  39. if (app.isPackaged) {
  40. this.loadingWin.loadFile(join(__dirname, './loading.html'))
  41. } else {
  42. this.loadingWin.loadFile('loading.html')
  43. }
  44. this.loadingWin.on('close', () => {
  45. this.loadingWin = null
  46. })
  47. }
  48. createWindow() {
  49. this.mainWin = new BrowserWindow({
  50. minWidth: 1300,
  51. minHeight: 760,
  52. width: 1300,
  53. height: 760,
  54. frame: false,
  55. transparent: true,
  56. icon: this.icon,
  57. webPreferences: {
  58. contextIsolation: true,
  59. nodeIntegration: true,
  60. webSecurity: false, // 去掉跨越
  61. nodeIntegrationInWorker: true,
  62. preload: join(__dirname, './preload.js')
  63. },
  64. show: false
  65. })// 创建一个窗口
  66. // 不同环境加载不同文件
  67. if (app.isPackaged) {
  68. this.mainWin.loadFile(join(__dirname, './index.html'))
  69. } else {
  70. this.mainWin.loadURL('http://localhost:6547/')
  71. }
  72. // 事件监听
  73. this.mainWin.on('close', () => { this.mainWin = null })
  74. }
  75. onRead() {
  76. this.createLoading()
  77. this.createWindow()
  78. // 图标
  79. const tray = new Tray(this.icon)
  80. const contextMenu = Menu.buildFromTemplate([
  81. {
  82. label: '退出',
  83. click: () => {
  84. this.mainWin.close()
  85. app.quit()
  86. }
  87. }
  88. ])
  89. tray.setToolTip('控制端')
  90. tray.on('click', () => this.mainWin.show())
  91. // 注册调试模式
  92. globalShortcut.register('Ctrl+F12', () => {
  93. this.mainWin.webContents.toggleDevTools()
  94. })
  95. // 系统环境
  96. if (platform === 'win32') {
  97. // 右键
  98. tray.setContextMenu(contextMenu)
  99. // 禁用右键
  100. this.mainWin.hookWindowMessage(278, () => {
  101. this.mainWin.setEnabled(false);//窗口禁用
  102. setTimeout(() => {
  103. this.mainWin.setEnabled(true);
  104. }, 100) //延时太快会立刻启动,太慢会妨碍窗口其他操作,可自行测试最佳时间
  105. return true
  106. })
  107. } else if (platform === 'darwin') {
  108. app.dock.setIcon(join(__dirname, 'electron/icon/playGame@2x.png'))
  109. }
  110. // 通信
  111. ipcMain.on('signal', (_, evt, data) => {
  112. if (evt === 'close-loading') {
  113. if (this.loadingWin) this.loadingWin.close()
  114. this.mainWin.show()
  115. // if (this.mainWin.isVisible()) this.connectLogi()
  116. } else if (evt === 'minWin') {
  117. this.mainWin.minimize()
  118. } else if (evt === 'closeWin') {
  119. this.#closeMqtt()
  120. this.mainWin.close()
  121. } else if (evt === 'maxWin') {
  122. const { width, height } = screen.getPrimaryDisplay().size
  123. if (data) { this.mainWin.setBounds({ x: 0, y: 0, width, height }) } else {
  124. this.mainWin.setBounds({ width: 1300, height: 760 })
  125. this.mainWin.center()
  126. }
  127. } else if (evt === 'loginMqtt') {
  128. this.#initMqtt(data)
  129. } else if (evt === 'closeMqtt') {
  130. this.#closeMqtt()
  131. } else if (evt === 'sendMqtt') {
  132. try {
  133. const db = JSON.stringify(data)
  134. if (this.#client.connected && this.#mqttChannel) this.#client.publish(this.#mqttChannel, db)
  135. } catch (error) {
  136. console.log(error);
  137. }
  138. }
  139. })
  140. }
  141. #initMqtt(data) {
  142. this.#closeMqtt()
  143. try {
  144. this.#client = mqtt.connect(data.url, { username: data.room, password: data.name })
  145. // 监听
  146. this.#client.on('connect', () => this.mainWin.webContents.send('message', { type: 'connect' }))
  147. this.#client.on('message', (_, msg, __) => {
  148. try {
  149. const db = JSON.parse(msg.toString())
  150. if (db.type === 'join') this.#mqttChannel = db.channel
  151. this.mainWin.webContents.send('message', db)
  152. } catch (error) {
  153. console.log(error);
  154. }
  155. })
  156. this.#client.on('error', (e) => { this.mainWin.webContents.send('message', { type: 'disconnect' }); this.#closeMqtt() })
  157. } catch (error) {
  158. this.mainWin.webContents.send('message', { type: 'disconnect' })
  159. }
  160. }
  161. #closeMqtt() {
  162. if (this.#client) this.#client.end()
  163. this.#client = null
  164. this.#mqttChannel = null
  165. }
  166. connectLogi() {
  167. this.contrlEvent = fork(join(__dirname, 'electron/logiControl.js'));
  168. this.contrlEvent.on('message', msg => {
  169. if (!msg || msg.type === 'err' || !msg.data || !msg.data[44]) {
  170. this.contrlEvent.disconnect()
  171. this.contrlEvent.kill(msg.pid ?? 'SIGKILL')
  172. this.contrlEvent = null
  173. dialog.showMessageBox(this.mainWin, { message: '请尝试旋转方向或重新插入USB或重启客户端!', type: 'error', title: '连接错误' }).then(async ({ response }) => {
  174. if (!response) {
  175. await sleep(2000)
  176. this.connectLogi()
  177. }
  178. })
  179. } else {
  180. if (this.mainWin && !this.mainWin.isDestroyed() && this.contrlEvent) this.mainWin?.webContents.send('message', { type: 'contrl', content: msg.data })
  181. }
  182. })
  183. }
  184. };
  185. new MainSerivce()