From afde91b2c8c373a2cc9fa9a5ba233ead5672d436 Mon Sep 17 00:00:00 2001 From: Alexander Drozdov Date: Sat, 20 Jun 2020 01:10:17 +0300 Subject: [PATCH] price check refactor --- src/background.ts | 7 +- src/ipc/ipc-event.ts | 7 ++ src/ipc/main-process-bindings.ts | 6 +- src/main/PoeWindow.ts | 8 --- src/main/overlay-window.ts | 78 ++++++++++----------- src/main/{positioning.ts => price-check.ts} | 74 +++++-------------- src/main/shortcuts.ts | 25 +++---- src/web/price-check/PriceCheckWindow.vue | 38 ++++++---- 8 files changed, 107 insertions(+), 136 deletions(-) rename src/main/{positioning.ts => price-check.ts} (63%) diff --git a/src/background.ts b/src/background.ts index 6fc81a9a..9d5d10eb 100644 --- a/src/background.ts +++ b/src/background.ts @@ -4,11 +4,12 @@ import { app, protocol, ipcMain, screen } from 'electron' import { installVueDevtools } from 'vue-cli-plugin-electron-builder/lib' import { setupShortcuts } from './main/shortcuts' import { createTray } from './main/tray' -import { setupShowHide } from './main/positioning' +import { setupShowHide } from './main/price-check' import { setupConfigEvents, config } from './main/config' import { CLOSE_SETTINGS_WINDOW } from '@/ipc/ipc-event' import { closeWindow as closeSettings } from './main/SettingsWindow' import { logger } from './main/logger' +import { checkForUpdates } from './main/updates' import os from 'os' import { createOverlayWindow } from './main/overlay-window' import { setupAltVisibility } from './main/alt-visibility' @@ -64,6 +65,10 @@ app.on('ready', async () => { process.platform === 'linux' ? 1000 : 0 ) + if (!isDevelopment) { + checkForUpdates() + } + ipcMain.on(CLOSE_SETTINGS_WINDOW, closeSettings) }) diff --git a/src/ipc/ipc-event.ts b/src/ipc/ipc-event.ts index 67b1f0e5..421513f3 100644 --- a/src/ipc/ipc-event.ts +++ b/src/ipc/ipc-event.ts @@ -15,6 +15,13 @@ export const FOCUS_CHANGE = 'OVERLAY::focus-change' export const DPR_CHANGE = 'OVERLAY->MAIN::devicePixelRatio-change' +export const PRICE_CHECK = 'MAIN->OVERLAY::price-check' +export const PRICE_CHECK_CANCELED = 'MAIN->OVERLAY::price-check-canceled' +export interface IpcPriceCheck { + clipboard: string + position: { x: number, y: number } +} + export const SHOW_BROWSER = 'OVERLAY->MAIN::show-browser' export interface IpcShowBrowser { diff --git a/src/ipc/main-process-bindings.ts b/src/ipc/main-process-bindings.ts index 449e41bc..6814abee 100644 --- a/src/ipc/main-process-bindings.ts +++ b/src/ipc/main-process-bindings.ts @@ -48,9 +48,9 @@ class MainProcessBinding extends EventTarget { } } - selfEmitPriceCheck (data: { clipboard: string, position: string }) { - this.dispatchEvent(new CustomEvent('price-check', { - detail: data + selfEmitPriceCheck (e: ipcEvent.IpcPriceCheck) { + this.dispatchEvent(new CustomEvent(ipcEvent.PRICE_CHECK, { + detail: e })) } diff --git a/src/main/PoeWindow.ts b/src/main/PoeWindow.ts index 55735857..58d016fe 100644 --- a/src/main/PoeWindow.ts +++ b/src/main/PoeWindow.ts @@ -33,14 +33,6 @@ class PoeWindowClass extends EventEmitter { return Math.round(this.bounds!.height * ratio) } - getPoeUiPosition (mousePos: Point) { - if (mousePos.x > (this.bounds!.x + this.bounds!.width / 2)) { - return 'inventory' - } else { - return 'stash' // or chat/vendor/center of screen - } - } - attach (window: BrowserWindow) { OW.on('focus', () => { this.isActive = true }) OW.on('blur', () => { this.isActive = false }) diff --git a/src/main/overlay-window.ts b/src/main/overlay-window.ts index 6f1a0286..3fbeb820 100644 --- a/src/main/overlay-window.ts +++ b/src/main/overlay-window.ts @@ -2,20 +2,25 @@ import path from 'path' import { BrowserWindow, ipcMain, dialog } from 'electron' import { PoeWindow } from './PoeWindow' import { logger } from './logger' -import { OVERLAY_READY, FOCUS_CHANGE } from '@/ipc/ipc-event' +import * as ipc from '@/ipc/ipc-event' import { createProtocol } from 'vue-cli-plugin-electron-builder/lib' -import { checkForUpdates } from './updates' import { overlayWindow as OW } from 'electron-overlay-window' export let overlayWindow: BrowserWindow | undefined export let isInteractable = false +export let DPR = 1 -let _resolveOverlayReady: Function +let _resolveOverlayReady: () => void export const overlayReady = new Promise((resolve) => { _resolveOverlayReady = resolve }) export async function createOverlayWindow () { + ipcMain.once(ipc.OVERLAY_READY, _resolveOverlayReady) + ipcMain.on(ipc.DPR_CHANGE, (_: any, dpr: number) => handleDprChange(dpr)) + PoeWindow.on('active-change', handlePoeWindowActiveChange) + PoeWindow.onceAttached(handleOverlayAttached) + overlayWindow = new BrowserWindow({ icon: path.join(__static, 'icon.png'), ...OW.WINDOW_OPTS, @@ -28,49 +33,18 @@ export async function createOverlayWindow () { } }) + overlayWindow.setIgnoreMouseEvents(true) + if (process.env.WEBPACK_DEV_SERVER_URL) { overlayWindow.loadURL(process.env.WEBPACK_DEV_SERVER_URL + '#overlay') overlayWindow.webContents.openDevTools({ mode: 'detach', activate: false }) } else { createProtocol('app') overlayWindow.loadURL('app://./index.html#overlay') - checkForUpdates() } - overlayWindow.setIgnoreMouseEvents(true) - - ipcMain.once(OVERLAY_READY, () => { - _resolveOverlayReady() - }) - - PoeWindow.on('active-change', (isActive) => { - if (!overlayWindow) { - logger.error('Window is not ready') - return - } - - if (isActive && isInteractable) { - isInteractable = false - overlayWindow.setIgnoreMouseEvents(true) - } - overlayWindow.webContents.send(FOCUS_CHANGE, { game: isActive, overlay: isInteractable }) - }) - - PoeWindow.onceAttached((hasAccess) => { - if (hasAccess === false) { - dialog.showErrorBox( - 'PoE window - No access', - // ---------------------- - 'Path of Exile is running with administrator rights.\n' + - '\n' + - 'You need to restart Awakened PoE Trade with administrator rights.' - ) - } - }) - - const electronReadyToShow = new Promise((resolve) => { - overlayWindow!.once('ready-to-show', resolve) - }) + const electronReadyToShow = new Promise(resolve => + overlayWindow!.once('ready-to-show', resolve)) await electronReadyToShow await overlayReady PoeWindow.attach(overlayWindow) @@ -86,7 +60,15 @@ export function toggleOverlayState () { } else { focusOverlay() } - overlayWindow.webContents.send(FOCUS_CHANGE, { game: PoeWindow.isActive, overlay: isInteractable }) + overlayWindow.webContents.send(ipc.FOCUS_CHANGE, { game: PoeWindow.isActive, overlay: isInteractable }) +} + +function handlePoeWindowActiveChange (isActive: boolean) { + if (isActive && isInteractable) { + isInteractable = false + overlayWindow!.setIgnoreMouseEvents(true) + } + overlayWindow!.webContents.send(ipc.FOCUS_CHANGE, { game: isActive, overlay: isInteractable }) } export function assertOverlayActive () { @@ -118,3 +100,21 @@ function focusPoE () { OW.focusTarget() PoeWindow.isActive = true } + +function handleOverlayAttached (hasAccess?: boolean) { + if (hasAccess === false) { + dialog.showErrorBox( + 'PoE window - No access', + // ---------------------- + 'Path of Exile is running with administrator rights.\n' + + '\n' + + 'You need to restart Awakened PoE Trade with administrator rights.' + ) + } +} + +function handleDprChange (devicePixelRatio: number) { + if (process.platform === 'win32') { + DPR = devicePixelRatio + } +} diff --git a/src/main/positioning.ts b/src/main/price-check.ts similarity index 63% rename from src/main/positioning.ts rename to src/main/price-check.ts index 458a6e37..02117a39 100644 --- a/src/main/positioning.ts +++ b/src/main/price-check.ts @@ -1,25 +1,31 @@ -import { ipcMain, screen, Rectangle, BrowserView, Point, shell } from 'electron' +import { ipcMain, Rectangle, Point } from 'electron' import { uIOhook } from 'uiohook-napi' -import { checkPressPosition, isPollingClipboard } from './shortcuts' +import { isPollingClipboard } from './shortcuts' import { PoeWindow } from './PoeWindow' -import { PRICE_CHECK_HIDE, PRICE_CHECK_MOUSE, OPEN_LINK, OPEN_LINK_EXTERNAL, PRICE_CHECK_CANCELED, DPR_CHANGE } from '@/ipc/ipc-event' +import * as ipc from '@/ipc/ipc-event' import { config } from './config' import { logger } from './logger' -import { overlayWindow, isInteractable, assertOverlayActive, assertPoEActive } from './overlay-window' +import { overlayWindow, isInteractable, assertOverlayActive, assertPoEActive, DPR } from './overlay-window' const WIDTH_96DPI = 460 const CLOSE_THRESHOLD_96DPI = 40 -let DPR = 1 let isPriceCheckShown = false let isClickedAfterLock = false +let checkPressPosition: Point | undefined let activeAreaRect: Rectangle | undefined let isMouseInside = false -let browserViewExternal: BrowserView | undefined +export function showWidget (opts: { + clipboard: string + hotkeyPressPosition: Point + lockedMode: boolean +}) { + checkPressPosition = opts.hotkeyPressPosition + + overlayWindow!.webContents.send(ipc.PRICE_CHECK, { clipboard: opts.clipboard, position: checkPressPosition } as ipc.IpcPriceCheck) -export function showWindow () { const poeBounds = PoeWindow.bounds! activeAreaRect = { x: getOffsetX(checkPressPosition!, poeBounds), @@ -31,21 +37,9 @@ export function showWindow () { isPriceCheckShown = true isClickedAfterLock = false isMouseInside = false -} -function hideWindow () { - isPriceCheckShown = false - isMouseInside = false - activeAreaRect = undefined - - if (isInteractable) { - if (browserViewExternal) { - overlayWindow!.removeBrowserView(browserViewExternal) - // uncomment to trade performance for less memory usage (1 process & 13 MB) - // browserViewExternal.destroy() - // browserViewExternal = undefined - browserViewExternal.webContents.loadURL('about:blank') - } + if (opts.lockedMode) { + lockWindow(true) } } @@ -56,7 +50,7 @@ export function lockWindow (syntheticClick = false) { } export function setupShowHide () { - ipcMain.on(PRICE_CHECK_HIDE, () => { + ipcMain.on(ipc.PRICE_CHECK_HIDE, () => { logger.debug('Closing', { source: 'price-check', reason: 'Close button or hotkey' }) isPriceCheckShown = false assertPoEActive() @@ -69,13 +63,7 @@ export function setupShowHide () { } }) - ipcMain.on(DPR_CHANGE, (_: any, devicePixelRatio: number) => { - if (process.platform === 'win32') { - DPR = devicePixelRatio - } - }) - - ipcMain.on(PRICE_CHECK_MOUSE, (e, name: string, modifier?: string) => { + ipcMain.on(ipc.PRICE_CHECK_MOUSE, (e, name: string, modifier?: string) => { if (name === 'click') { isClickedAfterLock = true logger.debug('Clicked inside window after lock', { source: 'price-check' }) @@ -100,30 +88,6 @@ export function setupShowHide () { } }) - ipcMain.on(OPEN_LINK, (e, link) => { - if (!browserViewExternal) { - browserViewExternal = new BrowserView() - } - - overlayWindow!.setBrowserView(browserViewExternal) - let browserBounds = { - x: 0, - y: 0, - width: PoeWindow.bounds!.width - Math.floor(WIDTH_96DPI * DPR), - height: PoeWindow.bounds!.height - } - if (process.platform === 'win32') { - browserBounds = screen.screenToDipRect(overlayWindow!, browserBounds) - } - browserViewExternal.setBounds(browserBounds) - browserViewExternal.webContents.loadURL(link) - }) - - ipcMain.on(OPEN_LINK_EXTERNAL, (e, link) => { - hideWindow() - shell.openExternal(link) - }) - uIOhook.on('mousemove', (e) => { if (!isPriceCheckShown) return @@ -134,7 +98,7 @@ export function setupShowHide () { if (distance > (CLOSE_THRESHOLD_96DPI * DPR)) { logger.debug('Closing', { source: 'price-check', reason: 'Auto-hide on mouse move', distance, threshold: CLOSE_THRESHOLD_96DPI }) - overlayWindow!.webContents.send(PRICE_CHECK_CANCELED) + overlayWindow!.webContents.send(ipc.PRICE_CHECK_CANCELED) isPriceCheckShown = false } } else if (!isMouseInside) { @@ -146,7 +110,7 @@ export function setupShowHide () { mousePos.y > activeAreaRect!.y && mousePos.y < activeAreaRect!.y + activeAreaRect!.height ) { - ipcMain.emit(PRICE_CHECK_MOUSE, undefined, 'enter', modifier) + ipcMain.emit(ipc.PRICE_CHECK_MOUSE, undefined, 'enter', modifier) } } }) diff --git a/src/main/shortcuts.ts b/src/main/shortcuts.ts index 1d0a0849..72adc91b 100644 --- a/src/main/shortcuts.ts +++ b/src/main/shortcuts.ts @@ -2,17 +2,16 @@ import { screen, Point, clipboard, globalShortcut, Notification } from 'electron import robotjs from 'robotjs' import { uIOhook, UiohookKey } from 'uiohook-napi' import { pollClipboard } from './PollClipboard' -import { showWindow, lockWindow } from './positioning' +import { showWidget as showPriceCheck } from './price-check' import { KeyToElectron } from '@/ipc/KeyToCode' -import { PRICE_CHECK } from '@/ipc/ipc-event' import { config } from './config' import { PoeWindow } from './PoeWindow' import { openWiki } from './wiki' import { logger } from './logger' -import { toggleOverlayState, overlayWindow } from './overlay-window' +import { toggleOverlayState } from './overlay-window' export let isPollingClipboard = false -export let checkPressPosition: Point | undefined +export let hotkeyPressPosition: Point | undefined export const UiohookToName = Object.fromEntries(Object.entries(UiohookKey).map(([k, v]) => ([v, k]))) @@ -22,20 +21,16 @@ function priceCheck (lockedMode: boolean) { if (!isPollingClipboard) { isPollingClipboard = true pollClipboard(32, 500) - .then(async (clipboard) => { - overlayWindow!.webContents.send(PRICE_CHECK, { clipboard, position: PoeWindow.getPoeUiPosition(checkPressPosition!) }) - showWindow() - if (lockedMode) { - lockWindow(true) - } - }) + .then(clipboard => + showPriceCheck({ clipboard, hotkeyPressPosition: hotkeyPressPosition!, lockedMode }) + ) .catch(() => { /* nothing bad */ }) .finally(() => { isPollingClipboard = false }) } - checkPressPosition = screen.getCursorScreenPoint() - if (process.platform === 'win32') { - checkPressPosition = screen.dipToScreenPoint(checkPressPosition) - } + hotkeyPressPosition = screen.getCursorScreenPoint() + // if (process.platform === 'win32') { + // hotkeyPressPosition = screen.dipToScreenPoint(hotkeyPressPosition) + // } if (!lockedMode) { if (config.get('priceCheckKeyHold') === 'Ctrl') { diff --git a/src/web/price-check/PriceCheckWindow.vue b/src/web/price-check/PriceCheckWindow.vue index 64f815eb..8f2dc625 100644 --- a/src/web/price-check/PriceCheckWindow.vue +++ b/src/web/price-check/PriceCheckWindow.vue @@ -71,7 +71,7 @@ import BrowserMode from './BrowserMode' import CheckedItem from './CheckedItem' import AppBootstrap from './AppBootstrap' import { MainProcess } from '@/ipc/main-process-bindings' -import { PRICE_CHECK_CANCELED } from '@/ipc/ipc-event' +import { PRICE_CHECK, PRICE_CHECK_CANCELED } from '@/ipc/ipc-event' import { Prices, displayRounding } from './Prices' import { Leagues } from './Leagues' import { parseClipboard } from '@/parser' @@ -100,34 +100,29 @@ export default { } }, created () { - MainProcess.addEventListener('price-check', ({ detail: { position, clipboard } }) => { - this.clickPosition = position - this.isBrowserShown = false + MainProcess.addEventListener(PRICE_CHECK, ({ detail: e }) => { + this.wm.closeBrowser(this.config.wmId) this.wm.show(this.config.wmId) - this.item = parseClipboard(clipboard) + this.checkPosition = { + x: e.position.x - window.screenX, + y: e.position.y - window.screenY + } + this.item = parseClipboard(e.clipboard) }) MainProcess.addEventListener(PRICE_CHECK_CANCELED, () => { this.wm.hide(this.config.wmId) }) - MainProcess.addEventListener('open-link', () => { - this.clickPosition = 'inventory' - this.isBrowserShown = true - }) window.addEventListener('resize', this.updatePoeUiWidth) this.updatePoeUiWidth() }, data () { return { - poeUiWidth: '0px', - clickPosition: 'stash', - isBrowserShown: false, + poeUiWidth: '1px', + checkPosition: { x: 1, y: 1 }, item: null } }, computed: { - browserMode () { - return !MainProcess.isElectron - }, title () { if (!Leagues.isLoaded) { return 'Awakened PoE Trade' @@ -140,6 +135,19 @@ export default { if (!Prices.isLoaded) return null return Math.round(Prices.exaToChaos(1)) + }, + isBrowserShown () { + return this.config.wmFlags.includes('has-browser') + }, + clickPosition () { + if (this.isBrowserShown) { + return 'inventory' + } else { + return this.checkPosition.x > (window.innerWidth / 2) + ? 'inventory' + : 'stash' + // or {chat, vendor, center of screen} + } } }, methods: {