From f764048f23ab889f7e70305fb6763222f9d554e0 Mon Sep 17 00:00:00 2001 From: isark Date: Sun, 23 Jul 2023 01:08:49 +0200 Subject: [PATCH] Added some basic chortcut handling --- src/app/app.component.html | 8 +-- src/app/app.component.ts | 52 +++++++++++++------ .../directives/record-key-chord.directive.ts | 12 +++-- src/app/services/events.service.ts | 2 +- src/app/services/shortcut.service.ts | 38 ++++++++++---- 5 files changed, 81 insertions(+), 31 deletions(-) diff --git a/src/app/app.component.html b/src/app/app.component.html index 3358da8..e3c8b71 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -14,8 +14,10 @@ {{interactable}} - - - + + + + + \ No newline at end of file diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 584f33e..9bd947e 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,7 +1,9 @@ -import { Component, Directive, HostListener, OnInit } from "@angular/core"; +import { Component, Directive, HostListener, OnDestroy, OnInit } from "@angular/core"; import { invoke } from "@tauri-apps/api/tauri"; import { ShortcutService } from "./services/shortcut.service"; import { EventsService } from "./services/events.service"; +import { Event } from "@tauri-apps/api/event"; +import { catchError } from "rxjs"; class StateEvent { Visible?: any; @@ -14,33 +16,53 @@ class StateEvent { templateUrl: "./app.component.html", styleUrls: ["./app.component.css"], }) -export class AppComponent implements OnInit { +export class AppComponent implements OnInit, OnDestroy { auto_hide: boolean = true; interactable: boolean = false; - test: boolean = false; + isBinding: boolean = false; constructor(private shortcuts: ShortcutService, private events: EventsService) { } + ngOnDestroy(): void { + this.shortcuts.unregister(this.onToggleOverlay); + } + ngOnInit(): void { invoke("set_auto_hide", { auto_hide: this.auto_hide }).then(); + this.shortcuts.register('F6', this.onToggleOverlay); + this.events.listen("OverlayStateChange").subscribe(this.onOverlayStateChange) + } + + onOverlayStateChange(event: Event) { + this.interactable = event.payload.Interactable != null; + } - this.shortcuts.register('F6').subscribe((s) => { - if (this.interactable) { - this.interactable = false; - } else { - this.interactable = true; - } - - invoke("set_interactable", { interactable: this.interactable }).then(); - }) + onToggleOverlay = () => { + console.log(this); + if (this.interactable) { + this.interactable = false; + } else { + this.interactable = true; + } - this.events.listen("OverlayStateChange").subscribe(event => { - this.interactable = event.payload.Interactable != null; - }) + invoke("set_interactable", { interactable: this.interactable }).then(); } toggleAutoHide() { console.log("toggle auto hide!!"); invoke("set_auto_hide", { autoHide: this.auto_hide }).then(); } + + onBindFinish(keys: string[]) { + this.isBinding = false; + let chord = keys.reduce((acc, curr) => { + if (acc === '') return curr; + + return acc.concat('+').concat(curr); + }, ''); + console.log(chord); + + this.shortcuts.rebind(chord, this.onToggleOverlay); + + } } \ No newline at end of file diff --git a/src/app/directives/record-key-chord.directive.ts b/src/app/directives/record-key-chord.directive.ts index 1c3f27e..485fdbf 100644 --- a/src/app/directives/record-key-chord.directive.ts +++ b/src/app/directives/record-key-chord.directive.ts @@ -1,20 +1,26 @@ -import { Directive, HostListener, Input } from '@angular/core'; +import { Directive, EventEmitter, HostListener, Input, Output } from '@angular/core'; @Directive({ selector: '[RecordKeyChord]' }) export class RecordKeyChord { - @Input('enable') enable: boolean = false; + @Output() finishedKeyChord = new EventEmitter; + + chordStack: string[] = []; @HostListener('window:keydown', ['$event']) handleKeyDown(event: KeyboardEvent) { console.log("keydown:", event); + this.chordStack.push(event.key); + } @HostListener('window:keyup', ['$event']) handleKeyUp(event: KeyboardEvent) { - console.log("keydown:", event); + console.log("keyup:", event); + this.finishedKeyChord.next(this.chordStack); + this.chordStack = []; } } \ No newline at end of file diff --git a/src/app/services/events.service.ts b/src/app/services/events.service.ts index 9719dad..85ab707 100644 --- a/src/app/services/events.service.ts +++ b/src/app/services/events.service.ts @@ -19,4 +19,4 @@ export class EventsService { emit(name: string, event: T): Observable { return from(emit(name, event)); } -} +} \ No newline at end of file diff --git a/src/app/services/shortcut.service.ts b/src/app/services/shortcut.service.ts index 2f7252a..a774034 100644 --- a/src/app/services/shortcut.service.ts +++ b/src/app/services/shortcut.service.ts @@ -1,19 +1,39 @@ import { Injectable, NgZone } from '@angular/core'; -import { register } from '@tauri-apps/api/globalShortcut'; -import { Observable } from 'rxjs'; +import { ShortcutHandler, register, unregister } from '@tauri-apps/api/globalShortcut'; +import { EMPTY, Observable, catchError, empty, from } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class ShortcutService { + bound: Map = new Map(); + constructor(private zone: NgZone) { } - register(shortcut: string) { + register(shortcut: string, handler: ShortcutHandler) { + this.bound.set(handler, shortcut); + + return from(register(shortcut, (s) => { + this.zone.run(() => handler(s)); + })); + } + + unregister(handler: ShortcutHandler) { + const shortcut = this.bound.get(handler); + this.bound.delete(handler); + + return shortcut ? from(unregister(shortcut)) : EMPTY; + } + + rebind(shortcut: string, handler: ShortcutHandler) { + const prevShortcut = this.bound.get(handler)!; + this.register(shortcut, handler).subscribe( + { + error: (_err) => { + this.register(prevShortcut, handler); + console.log("Got error during binding, rebinding previous"); + return EMPTY; - return new Observable((subscriber) => { - register(shortcut, (s) => { - this.zone.run(() => subscriber.next(s)); - }) - }); - + } + }); } }