main.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  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. this.loadingWin.loadFile('loading.html')
  40. this.loadingWin.on('close', () => {
  41. this.loadingWin = null
  42. })
  43. }
  44. createWindow() {
  45. this.mainWin = new BrowserWindow({
  46. minWidth: 1300,
  47. minHeight: 760,
  48. width: 1300,
  49. height: 760,
  50. frame: false,
  51. transparent: true,
  52. icon: this.icon,
  53. webPreferences: {
  54. contextIsolation: true,
  55. nodeIntegration: true,
  56. webSecurity: false, // 去掉跨越
  57. nodeIntegrationInWorker: true,
  58. preload: join(__dirname, './preload.js')
  59. },
  60. show: false
  61. })// 创建一个窗口
  62. // 不同环境加载不同文件
  63. if (app.isPackaged) {
  64. this.mainWin.loadFile('dist/index.html')
  65. } else {
  66. this.mainWin.loadURL('http://localhost:6547/')
  67. }
  68. // 事件监听
  69. this.mainWin.on('close', () => { this.mainWin = null })
  70. }
  71. onRead() {
  72. this.createLoading()
  73. this.createWindow()
  74. // 图标
  75. const tray = new Tray(this.icon)
  76. const contextMenu = Menu.buildFromTemplate([
  77. {
  78. label: '退出',
  79. click: () => {
  80. this.mainWin.close()
  81. app.quit()
  82. }
  83. }
  84. ])
  85. tray.setToolTip('控制端')
  86. tray.on('click', () => this.mainWin.show())
  87. // 注册调试模式
  88. globalShortcut.register('Ctrl+F12', () => {
  89. this.mainWin.webContents.toggleDevTools()
  90. })
  91. // 系统环境
  92. if (platform === 'win32') {
  93. // 右键
  94. tray.setContextMenu(contextMenu)
  95. // 禁用右键
  96. this.mainWin.hookWindowMessage(278, () => {
  97. this.mainWin.setEnabled(false);//窗口禁用
  98. setTimeout(() => {
  99. this.mainWin.setEnabled(true);
  100. }, 100) //延时太快会立刻启动,太慢会妨碍窗口其他操作,可自行测试最佳时间
  101. return true
  102. })
  103. } else if (platform === 'darwin') {
  104. app.dock.setIcon(join(__dirname, './icon/playGame@2x.png'))
  105. }
  106. // 通信
  107. ipcMain.on('signal', (_, evt, data) => {
  108. if (evt === 'close-loading') {
  109. if (this.loadingWin) this.loadingWin.close()
  110. this.mainWin.show()
  111. // if (this.mainWin.isVisible()) this.connectLogi()
  112. } else if (evt === 'minWin') {
  113. this.mainWin.minimize()
  114. } else if (evt === 'closeWin') {
  115. this.#closeMqtt()
  116. this.mainWin.close()
  117. } else if (evt === 'maxWin') {
  118. const { width, height } = screen.getPrimaryDisplay().size
  119. if (data) { this.mainWin.setBounds({ x: 0, y: 0, width, height }) } else {
  120. this.mainWin.setBounds({ width: 1300, height: 760 })
  121. this.mainWin.center()
  122. }
  123. } else if (evt === 'loginMqtt') {
  124. this.#initMqtt(data)
  125. } else if (evt === 'closeMqtt') {
  126. this.#closeMqtt()
  127. } else if (evt === 'sendMqtt') {
  128. try {
  129. const db = JSON.stringify(data)
  130. if (this.#client.connected && this.#mqttChannel) this.#client.publish(this.#mqttChannel, db)
  131. } catch (error) {
  132. console.log(error);
  133. }
  134. }
  135. })
  136. }
  137. #initMqtt(data) {
  138. this.#closeMqtt()
  139. this.#client = mqtt.connect(data.url, { username: data.room, password: data.name })
  140. // 监听
  141. this.#client.on('connect', () => this.mainWin.webContents.send('message', { type: 'connect' }))
  142. this.#client.on('message', (_, msg, __) => {
  143. try {
  144. const db = JSON.parse(msg.toString())
  145. if (db.type === 'join') this.#mqttChannel = db.channel
  146. this.mainWin.webContents.send('message', db)
  147. } catch (error) {
  148. console.log(error);
  149. }
  150. })
  151. this.#client.on('error', (e) => this.#closeMqtt())
  152. }
  153. #closeMqtt() {
  154. if (this.#client) this.#client.end()
  155. this.#client = null
  156. this.#mqttChannel = null
  157. }
  158. connectLogi() {
  159. this.contrlEvent = fork(join(__dirname, './logiControl.js'));
  160. this.contrlEvent.on('message', msg => {
  161. if (!msg || msg.type === 'err' || !msg.data || !msg.data[44]) {
  162. this.contrlEvent.disconnect()
  163. this.contrlEvent.kill(msg.pid ?? 'SIGKILL')
  164. this.contrlEvent = null
  165. dialog.showMessageBox(this.mainWin, { message: '请尝试旋转方向或重新插入USB或重启客户端!', type: 'error', title: '连接错误' }).then(async ({ response }) => {
  166. if (!response) {
  167. await sleep(2000)
  168. this.connectLogi()
  169. }
  170. })
  171. } else {
  172. if (this.mainWin && !this.mainWin.isDestroyed() && this.contrlEvent) this.mainWin?.webContents.send('message', { type: 'contrl', content: msg.data })
  173. }
  174. })
  175. }
  176. };
  177. new MainSerivce()