From efbc869c43376826b575cfc34edce8a8a049fd57 Mon Sep 17 00:00:00 2001 From: jliddev Date: Wed, 25 Nov 2020 12:02:39 -0600 Subject: [PATCH] Custom keyboard shortcuts --- wowup-electron/main.ts | 18 +++--- wowup-electron/src/app/app.component.ts | 11 +++- .../options-app-section.component.html | 30 +++------- .../options-app-section.component.ts | 58 ++++++++++--------- .../app/services/electron/electron.service.ts | 39 ++++++++++++- wowup-electron/src/app/utils/zoom.utils.ts | 40 +++++++++++++ 6 files changed, 136 insertions(+), 60 deletions(-) create mode 100644 wowup-electron/src/app/utils/zoom.utils.ts diff --git a/wowup-electron/main.ts b/wowup-electron/main.ts index c986ac01..99a6a77d 100644 --- a/wowup-electron/main.ts +++ b/wowup-electron/main.ts @@ -299,9 +299,9 @@ function getAppMenu(): Array { { role: "forceReload" }, { role: "toggleDevTools", accelerator: "CommandOrControl+Shift+I" }, { type: "separator" }, - { role: "resetZoom" }, - { role: "zoomIn", accelerator: "CommandOrControl+=" }, - { role: "zoomOut" }, + // { role: "resetZoom" }, + // { role: "zoomIn", accelerator: "CommandOrControl+=" }, + // { role: "zoomOut" }, { type: "separator" }, { role: "togglefullscreen" }, ], @@ -312,10 +312,10 @@ function getAppMenu(): Array { { label: "View", submenu: [ - { role: "resetZoom" }, + // { role: "resetZoom" }, { role: "toggleDevTools" }, - { role: "zoomIn", accelerator: "CommandOrControl+=" }, - { role: "zoomOut" }, + // { role: "zoomIn", accelerator: "CommandOrControl+=" }, + // { role: "zoomOut" }, { type: "separator" }, { role: "togglefullscreen" }, ], @@ -346,9 +346,9 @@ function getAppMenu(): Array { { role: "forceReload" }, { role: "toggleDevTools" }, { type: "separator" }, - { role: "resetZoom" }, - { role: "zoomIn", accelerator: "CommandOrControl+=" }, - { role: "zoomOut" }, + // { role: "resetZoom" }, + // { role: "zoomIn", accelerator: "CommandOrControl+=" }, + // { role: "zoomOut" }, { type: "separator" }, { role: "togglefullscreen" }, ], diff --git a/wowup-electron/src/app/app.component.ts b/wowup-electron/src/app/app.component.ts index 88f6f631..9f5e52c5 100644 --- a/wowup-electron/src/app/app.component.ts +++ b/wowup-electron/src/app/app.component.ts @@ -1,7 +1,8 @@ -import { AfterViewInit, ChangeDetectionStrategy, Component, OnInit } from "@angular/core"; +import { AfterViewInit, ChangeDetectionStrategy, Component, HostListener, OnInit } from "@angular/core"; import { MatDialog } from "@angular/material/dialog"; import { TranslateService } from "@ngx-translate/core"; import { OverlayContainer } from "@angular/cdk/overlay"; +import { filter } from "rxjs/operators"; import { ALLIANCE_LIGHT_THEME, ALLIANCE_THEME, @@ -21,7 +22,7 @@ import { FileService } from "./services/files/file.service"; import { WowUpService } from "./services/wowup/wowup.service"; import { IconService } from "./services/icons/icon.service"; import { SessionService } from "./services/session/session.service"; -import { filter } from "rxjs/operators"; +import { getZoomDirection, ZoomDirection } from "./utils/zoom.utils"; const AUTO_UPDATE_PERIOD_MS = 60 * 60 * 1000; // 1 hour @@ -34,6 +35,12 @@ const AUTO_UPDATE_PERIOD_MS = 60 * 60 * 1000; // 1 hour export class AppComponent implements OnInit, AfterViewInit { private _autoUpdateInterval?: number; + @HostListener("document:keydown", ["$event"]) + handleKeyboardEvent(event: KeyboardEvent) { + const zoomDirection = getZoomDirection(event); + this._electronService.applyZoom(zoomDirection); + } + public get quitEnabled() { return this._electronService.appOptions.quit; } diff --git a/wowup-electron/src/app/components/options-app-section/options-app-section.component.html b/wowup-electron/src/app/components/options-app-section/options-app-section.component.html index 92e1651d..7d3a758f 100644 --- a/wowup-electron/src/app/components/options-app-section/options-app-section.component.html +++ b/wowup-electron/src/app/components/options-app-section/options-app-section.component.html @@ -76,10 +76,8 @@ {{ "PAGES.OPTIONS.APPLICATION.ENABLE_SYSTEM_NOTIFICATIONS_LABEL" | translate }} - + @@ -108,11 +106,8 @@ {{ "PAGES.OPTIONS.APPLICATION.START_WITH_SYSTEM_DESCRIPTION" | translate }} - + @@ -125,12 +120,8 @@ {{ "PAGES.OPTIONS.APPLICATION.START_MINIMIZED_DESCRIPTION" | translate }} - + @@ -141,14 +132,11 @@ {{ "PAGES.OPTIONS.APPLICATION.SCALE_DESCRIPTION" | translate }} - - + + {{ value * 100 | number:'1.0-0' }} % - + \ No newline at end of file diff --git a/wowup-electron/src/app/components/options-app-section/options-app-section.component.ts b/wowup-electron/src/app/components/options-app-section/options-app-section.component.ts index 9c1838b2..85accafa 100644 --- a/wowup-electron/src/app/components/options-app-section/options-app-section.component.ts +++ b/wowup-electron/src/app/components/options-app-section/options-app-section.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from "@angular/core"; +import { ChangeDetectorRef, Component, OnInit } from "@angular/core"; import { MatDialog } from "@angular/material/dialog"; import { MatSelectChange } from "@angular/material/select"; import { MatSlideToggleChange } from "@angular/material/slide-toggle"; @@ -17,6 +17,7 @@ import { HORDE_LIGHT_THEME, HORDE_THEME, } from "../../../common/constants"; +import { ZOOM_SCALE } from "../../utils/zoom.utils"; interface LocaleListItem { localeId: string; @@ -36,6 +37,8 @@ export class OptionsAppSectionComponent implements OnInit { public telemetryEnabled = false; public useHardwareAcceleration = true; public currentLanguage: string = ""; + public zoomScale = ZOOM_SCALE; + public currentScale = 1; public languages: LocaleListItem[] = [ { localeId: "en", label: "English" }, { localeId: "de", label: "Deutsch" }, @@ -52,31 +55,29 @@ export class OptionsAppSectionComponent implements OnInit { public themeGroups: ThemeGroup[] = [ { - name: 'APP.THEME.GROUP_DARK', themes: [ + name: "APP.THEME.GROUP_DARK", + themes: [ { display: "APP.THEME.DEFAULT", class: DEFAULT_THEME }, { display: "APP.THEME.ALLIANCE", class: ALLIANCE_THEME }, { display: "APP.THEME.HORDE", class: HORDE_THEME }, - ] + ], }, { - name: 'APP.THEME.GROUP_LIGHT', themes: [ + name: "APP.THEME.GROUP_LIGHT", + themes: [ { display: "APP.THEME.DEFAULT", class: DEFAULT_LIGHT_THEME }, { display: "APP.THEME.ALLIANCE", class: ALLIANCE_LIGHT_THEME }, { display: "APP.THEME.HORDE", class: HORDE_LIGHT_THEME }, - ] + ], }, - ] - - public allowedScales = [-2.5, -2, -1.5, -1, -0.5, 0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6].map( - (x) => Math.pow(1.2, x) - ); - public currentScale = 1; + ]; constructor( private _analyticsService: AnalyticsService, private _dialog: MatDialog, - private _electronService: ElectronService, private _translateService: TranslateService, + private _cdRef: ChangeDetectorRef, + public electronService: ElectronService, public sessionService: SessionService, public wowupService: WowUpService ) {} @@ -86,7 +87,7 @@ export class OptionsAppSectionComponent implements OnInit { this.telemetryEnabled = enabled; }); - const minimizeOnCloseKey = this._electronService.isWin + const minimizeOnCloseKey = this.electronService.isWin ? "PAGES.OPTIONS.APPLICATION.MINIMIZE_ON_CLOSE_DESCRIPTION_WINDOWS" : "PAGES.OPTIONS.APPLICATION.MINIMIZE_ON_CLOSE_DESCRIPTION_MAC"; @@ -101,13 +102,18 @@ export class OptionsAppSectionComponent implements OnInit { this.startMinimized = this.wowupService.startMinimized; this.currentLanguage = this.wowupService.currentLanguage; - if (window.require("electron").remote) { + if (this.electronService.remote) { this.updateScale(); - const currentWindow = window.require("electron").remote.getCurrentWindow(); - currentWindow.webContents.on('zoom-changed', (event, arg) => { - this.updateScale() + const currentWindow = this.electronService.remote.getCurrentWindow(); + currentWindow.webContents.on("zoom-changed", (event, arg) => { + this.updateScale(); }); } + + this.electronService.zoomFactor$.subscribe((zoomFactor) => { + this.currentScale = zoomFactor; + this._cdRef.detectChanges(); + }); } onEnableSystemNotifications = (evt: MatSlideToggleChange) => { @@ -154,7 +160,7 @@ export class OptionsAppSectionComponent implements OnInit { } this.wowupService.useHardwareAcceleration = evt.checked; - this._electronService.restartApplication(); + this.electronService.restartApplication(); }); }; @@ -173,19 +179,17 @@ export class OptionsAppSectionComponent implements OnInit { } this.wowupService.currentLanguage = evt.value; - this._electronService.restartApplication(); + this.electronService.restartApplication(); }); }; - onScaleChange = (evt: MatSelectChange) => { - let newScale = evt.value; - const currentWindow = window.require("electron").remote.getCurrentWindow(); - currentWindow.webContents.zoomFactor = newScale; + public onScaleChange = (evt: MatSelectChange) => { + const newScale = evt.value; + this.electronService.setZoomFactor(newScale); this.currentScale = newScale; }; - updateScale() { - const currentWindow = window.require("electron").remote.getCurrentWindow(); - this.currentScale = currentWindow.webContents.zoomFactor; - }; + private updateScale() { + this.currentScale = this.electronService.getZoomFactor(); + } } diff --git a/wowup-electron/src/app/services/electron/electron.service.ts b/wowup-electron/src/app/services/electron/electron.service.ts index 311ba2a7..e6c9f450 100644 --- a/wowup-electron/src/app/services/electron/electron.service.ts +++ b/wowup-electron/src/app/services/electron/electron.service.ts @@ -6,6 +6,7 @@ import { APP_UPDATE_DOWNLOADED, APP_UPDATE_START_DOWNLOAD, } from "../../../common/constants"; +import * as minimist from "minimist"; // If you import a module but never use any of the imported values other than as TypeScript types, // the resulting javascript file will look as if you never imported the module at all. import { ipcRenderer, remote, Settings, shell, webFrame } from "electron"; @@ -17,7 +18,7 @@ import { IpcResponse } from "../../../common/models/ipc-response"; import { ValueRequest } from "../../../common/models/value-request"; import { ValueResponse } from "../../../common/models/value-response"; import { AppOptions } from "../../../common/wowup/app-options"; -import * as minimist from "minimist"; +import { ZoomDirection, ZOOM_MAX, ZOOM_MIN, ZOOM_STEP } from "../../utils/zoom.utils"; @Injectable({ providedIn: "root", @@ -26,6 +27,7 @@ export class ElectronService { private readonly _windowMaximizedSrc = new BehaviorSubject(false); private readonly _windowMinimizedSrc = new BehaviorSubject(false); private readonly _ipcEventReceivedSrc = new BehaviorSubject(""); + private readonly _zoomFactorChangeSrc = new BehaviorSubject(1.0); ipcRenderer: typeof ipcRenderer; webFrame: typeof webFrame; @@ -37,6 +39,7 @@ export class ElectronService { public readonly windowMaximized$ = this._windowMaximizedSrc.asObservable(); public readonly windowMinimized$ = this._windowMinimizedSrc.asObservable(); public readonly ipcEventReceived$ = this._ipcEventReceivedSrc.asObservable(); + public readonly zoomFactor$ = this._zoomFactorChangeSrc.asObservable(); public readonly isWin = process.platform === "win32"; public readonly isMac = process.platform === "darwin"; public readonly isLinux = process.platform === "linux"; @@ -128,6 +131,8 @@ export class ElectronService { } }); + this._zoomFactorChangeSrc.next(this.getZoomFactor()); + this.appOptions = (minimist(this.remote.process.argv.slice(1), { boolean: ["hidden", "quit"], })) as AppOptions; @@ -214,4 +219,36 @@ export class ElectronService { public async invoke(channel: string, ...args: any[]): Promise { return await this.ipcRenderer.invoke(channel, ...args); } + + public applyZoom = (zoomDirection: ZoomDirection) => { + const zoomFactor = this.getZoomFactor(); + const zoomInFactor = Math.min(ZOOM_MAX, zoomFactor + ZOOM_STEP); + const zoomOutFactor = Math.max(ZOOM_MIN, zoomFactor - ZOOM_STEP); + + switch (zoomDirection) { + case ZoomDirection.ZoomIn: + this.setZoomFactor(zoomInFactor); + break; + case ZoomDirection.ZoomOut: + this.setZoomFactor(zoomOutFactor); + break; + case ZoomDirection.ZoomReset: + this.setZoomFactor(1.0); + break; + case ZoomDirection.ZoomUnknown: + default: + break; + } + }; + + public setZoomFactor = (zoomFactor: number) => { + const currentWindow = this.remote.getCurrentWindow(); + currentWindow.webContents.zoomFactor = zoomFactor; + this._zoomFactorChangeSrc.next(zoomFactor); + }; + + public getZoomFactor(): number { + const currentWindow = this.remote.getCurrentWindow(); + return currentWindow.webContents.zoomFactor; + } } diff --git a/wowup-electron/src/app/utils/zoom.utils.ts b/wowup-electron/src/app/utils/zoom.utils.ts new file mode 100644 index 00000000..38e4b16f --- /dev/null +++ b/wowup-electron/src/app/utils/zoom.utils.ts @@ -0,0 +1,40 @@ +// See https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code/code_values +const ZOOM_IN_CODE = "Equal"; +const ZOOM_OUT_CODE = "Minus"; +const ZOOM_RESET_CODE = "Digit0"; + +export const ZOOM_SCALE = [0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0]; +export const ZOOM_MIN = ZOOM_SCALE[0]; +export const ZOOM_MAX = ZOOM_SCALE[ZOOM_SCALE.length - 1]; +export const ZOOM_STEP = 0.25; + +export enum ZoomDirection { + ZoomIn, + ZoomOut, + ZoomReset, + ZoomUnknown, +} + +export function isZoomInShortcut(event: KeyboardEvent) { + return event.ctrlKey && event.code === ZOOM_IN_CODE; +} + +export function isZoomOutShortcut(event: KeyboardEvent) { + return event.ctrlKey && event.code === ZOOM_OUT_CODE; +} + +export function isZoomResetShortcut(event: KeyboardEvent) { + return event.ctrlKey && event.code === ZOOM_RESET_CODE; +} + +export function getZoomDirection(event: KeyboardEvent): ZoomDirection { + if (isZoomInShortcut(event)) { + return ZoomDirection.ZoomIn; + } else if (isZoomOutShortcut(event)) { + return ZoomDirection.ZoomOut; + } else if (isZoomResetShortcut(event)) { + return ZoomDirection.ZoomReset; + } + + return ZoomDirection.ZoomUnknown; +}