commands.ts
1 import { Application } from './types' 2 import { app, BrowserWindow, screen } from 'electron' 3 import { createWindow, ensureOnCurrentScreen, releaseFocus, loadWindowUrl } from './index' 4 //import MacosAutomator from '../../automations/macos'; 5 //import WindowsAutomator from '../../automations/windows'; 6 //import Computer from '../../automations/computer_nut'; 7 import { wait, anyDict } from './utils' 8 import Constants from '../utils/Constants' 9 10 export let commandPicker: BrowserWindow = null 11 12 const width = 300 13 const height = 320 14 15 const POPUP_NAME = 'popup' 16 const POPUP_HASH = `/${POPUP_NAME}` 17 18 let commanderStartTime: number | undefined 19 let sourceApp: Application | undefined 20 let cursorAtOpen: { x: number; y: number } | undefined 21 22 export const prepareCommandPicker = (queryParams?: anyDict): void => { 23 const macOS = process.platform === 'darwin' 24 25 // open a new one 26 commandPicker = createWindow({ 27 hash: POPUP_HASH, 28 title: `${Constants.APP_NAME} - ${POPUP_NAME}`, 29 x: 0, 30 y: 0, 31 width: width, 32 height: height, 33 frame: false, 34 skipTaskbar: true, 35 alwaysOnTop: true, 36 transparent: macOS, 37 resizable: process.env.DEBUG ? true : false, 38 hiddenInMissionControl: true, 39 queryParams: queryParams, 40 keepHidden: true, 41 hasShadow: macOS 42 }) 43 44 // focus tricks 45 commandPicker.on('show', () => { 46 // macos can use app.focus which is more elegant 47 // windows will use activateCommandPicker 48 49 if (macOS) { 50 app.focus({ steal: true }) 51 } 52 53 // focus 54 commandPicker.moveTop() 55 commandPicker.focusOnWebView() 56 57 // try to activate (make foremost) 58 activateCommandPicker() 59 60 // log 61 if (commanderStartTime) { 62 console.log(`Command picker total time: ${Date.now() - commanderStartTime}ms`) 63 } 64 }) 65 66 // prevent close with keyboard shortcut 67 commandPicker.on('close', (event) => { 68 closeCommandPicker(sourceApp) 69 event.preventDefault() 70 }) 71 } 72 73 export const openCommandPicker = (params: anyDict): void => { 74 // save 75 sourceApp = params.sourceApp 76 commanderStartTime = params.startTime 77 78 // if we don't have a window, create one 79 if (!commandPicker || commandPicker.isDestroyed()) { 80 prepareCommandPicker(params) 81 } else { 82 loadWindowUrl(commandPicker, { queryParams: params, hash: POPUP_HASH }) 83 // commandPicker.webContents.send('show', params) 84 } 85 86 // check prompt is on the right screen 87 ensureOnCurrentScreen(commandPicker) 88 89 // and at right location 90 cursorAtOpen = screen.getCursorScreenPoint() 91 92 const screenBounds = screen.getDisplayNearestPoint(cursorAtOpen).bounds 93 const adjustedX = Math.max(0, Math.min(cursorAtOpen.x - width / 2, screenBounds.width - width)) 94 const adjustedY = Math.max( 95 0, 96 Math.min(cursorAtOpen.y - (params.sourceApp ? 64 : 24), screenBounds.height - height) 97 ) 98 99 commandPicker.setBounds({ 100 x: adjustedX, 101 y: adjustedY, 102 width: width, 103 height: height 104 }) 105 106 // done 107 commandPicker.show() 108 } 109 110 export const closeCommandPicker = async (sourceApp?: Application): Promise<void> => { 111 // check 112 if (commandPicker === null || commandPicker.isDestroyed()) { 113 return 114 } 115 116 try { 117 // remove blur handler 118 //console.log('Removing blur handler from command picker'); 119 commandPicker.removeAllListeners('blur') 120 commandPicker.setOpacity(0) 121 122 // now release focus 123 await releaseFocus({ sourceApp }) 124 125 // now hide 126 commandPicker.hide() 127 commandPicker.setOpacity(1) 128 } catch (error) { 129 console.error('Error while hiding command picker', error) 130 commandPicker = null 131 } 132 } 133 134 const activateCommandPicker = async () => { 135 const isThere = () => 136 commandPicker && 137 !commandPicker.isDestroyed() && 138 commandPicker.isVisible() && 139 commandPicker.getOpacity() > 0 140 141 // wait for command picker to be visible 142 const start = Date.now() 143 const totalWait = 1000 144 while (!isThere() && Date.now() - start < totalWait) { 145 await wait(50) 146 } 147 148 if (!isThere()) { 149 console.log('Command picker is not visible after 1 second, not activating') 150 return 151 } 152 153 commandPicker.removeAllListeners('blur') 154 155 if (isThere()) { 156 //console.log('Adding blur handler to command picker'); 157 commandPicker.removeAllListeners('blur') 158 commandPicker.on('blur', () => { 159 closeCommandPicker(sourceApp) 160 }) 161 } 162 }