From 5171fa32ef6e5d6fb7b26e14703c9e3197938b48 Mon Sep 17 00:00:00 2001 From: tsym77yoshi <67378554+tsym77yoshi@users.noreply.github.com> Date: Sun, 7 Apr 2024 16:13:34 +0900 Subject: [PATCH 01/23] =?UTF-8?q?change:=20HotkeysJS=E3=82=92=E4=BB=A3?= =?UTF-8?q?=E6=9B=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. App.vueでキー入力を受け付ける 2. hotkeyPluginでキー入力に反応する 3. 以前のkeyInputされたときのif文などの判定を(190~200行目あたり)を移動 4. actions内で入力されたものと一致するか検索しあれば実行する hotkeysJsの為に書かれた部分を消す作業はしていませんが一応動作部分はこんな感じで大丈夫だと思います --- src/components/App.vue | 5 +++++ src/plugins/hotkeyPlugin.ts | 42 +++++++++++++++++++++++++++++++++---- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/components/App.vue b/src/components/App.vue index 567e81ad8c..a096fb3cdc 100644 --- a/src/components/App.vue +++ b/src/components/App.vue @@ -139,5 +139,10 @@ onMounted(async () => { } else { isProjectFileLoaded.value = false; } + + // ショートカットキーを動作させる + document.addEventListener("keydown", (e) => { + hotkeyManager.keyInput(e); + }); }); diff --git a/src/plugins/hotkeyPlugin.ts b/src/plugins/hotkeyPlugin.ts index 2efb55295c..82197e88da 100644 --- a/src/plugins/hotkeyPlugin.ts +++ b/src/plugins/hotkeyPlugin.ts @@ -91,6 +91,8 @@ const isNotSameHotkeyTarget = (a: HotkeyTarget) => (b: HotkeyTarget) => { export class HotkeyManager { /** 登録されたHotkeyAction */ private actions: HotkeyAction[] = []; + /** スコープ */ + private scope: Editor = "talk"; /** ユーザーのショートカットキー設定 */ private settings: HotkeySettingType[] | undefined; // ユーザーのショートカットキー設定 /** hotkeys-jsに登録されたショートカットキーの組み合わせ */ @@ -171,7 +173,7 @@ export class HotkeyManager { for (const combination of combinations) { const bindingKey = combinationToBindingKey(combination.combination); this.log("Unbind:", bindingKey, "in", combination.editor); - this.hotkeys.unbind(bindingKey, combination.editor); + /* this.hotkeys.unbind(bindingKey, combination.editor); */ this.registeredCombinations = this.registeredCombinations.filter( isNotSameHotkeyTarget(combination) ); @@ -189,7 +191,7 @@ export class HotkeyManager { "in", action.editor ); - this.hotkeys( + /* this.hotkeys( combinationToBindingKey(setting.combination), { scope: action.editor }, (e) => { @@ -215,7 +217,7 @@ export class HotkeyManager { e.preventDefault(); action.callback(e); } - ); + ); */ this.registeredCombinations = this.registeredCombinations.filter( isNotSameHotkeyTarget(action) ); @@ -267,9 +269,41 @@ export class HotkeyManager { * エディタが変更されたときに呼び出される。 */ onEditorChange(editor: "talk" | "song"): void { - this.hotkeys.setScope(editor); + // this.hotkeys.setScope(editor); + this.scope = editor; this.log("Editor changed to", editor); } + + keyInput(e: KeyboardEvent): void { + const element = e.target; + console.log(element); + // メニュー項目ではショートカットキーを無効化 + if ( + element instanceof HTMLElement && + element.getAttribute("role") == "menu" + ) { + return; + } + + const isInTextbox = + element instanceof HTMLElement && + (element.tagName === "INPUT" || + element.tagName === "SELECT" || + element.tagName === "TEXTAREA" || + element.contentEditable === "true"); + + const combination: HotkeyCombination = eventToCombination(e); + + const action = this.actions + .filter((item) => item.editor == this.scope) + .filter((item) => !isInTextbox || item.enableInTextbox) + .find((item) => this.getSetting(item).combination == combination); + if (action == null) { + return; + } + e.preventDefault(); + action.callback(e); + } } /** hotkeys-js用のキーに変換する */ From 0cb1bc8fbec07baa47c93e7a0cab8485f0e62278 Mon Sep 17 00:00:00 2001 From: tsym77yoshi <67378554+tsym77yoshi@users.noreply.github.com> Date: Sun, 7 Apr 2024 16:26:57 +0900 Subject: [PATCH 02/23] =?UTF-8?q?fix:console.log=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/hotkeyPlugin.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/hotkeyPlugin.ts b/src/plugins/hotkeyPlugin.ts index 82197e88da..afc3099779 100644 --- a/src/plugins/hotkeyPlugin.ts +++ b/src/plugins/hotkeyPlugin.ts @@ -276,7 +276,6 @@ export class HotkeyManager { keyInput(e: KeyboardEvent): void { const element = e.target; - console.log(element); // メニュー項目ではショートカットキーを無効化 if ( element instanceof HTMLElement && From 9915d022b9f76fe5d60e18a75b315dd8cd668dae Mon Sep 17 00:00:00 2001 From: tsym77yoshi <67378554+tsym77yoshi@users.noreply.github.com> Date: Sun, 7 Apr 2024 16:13:34 +0900 Subject: [PATCH 03/23] =?UTF-8?q?change:=20HotkeysJS=E3=82=92=E4=BB=A3?= =?UTF-8?q?=E6=9B=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. App.vueでキー入力を受け付ける 2. hotkeyPluginでキー入力に反応する 3. 以前のkeyInputされたときのif文などの判定を(190~200行目あたり)を移動 4. actions内で入力されたものと一致するか検索しあれば実行する hotkeysJsの為に書かれた部分を消す作業はしていませんが一応動作部分はこんな感じで大丈夫だと思います --- src/components/App.vue | 5 +++++ src/plugins/hotkeyPlugin.ts | 41 +++++++++++++++++++++++++++++++++---- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/components/App.vue b/src/components/App.vue index 567e81ad8c..a096fb3cdc 100644 --- a/src/components/App.vue +++ b/src/components/App.vue @@ -139,5 +139,10 @@ onMounted(async () => { } else { isProjectFileLoaded.value = false; } + + // ショートカットキーを動作させる + document.addEventListener("keydown", (e) => { + hotkeyManager.keyInput(e); + }); }); diff --git a/src/plugins/hotkeyPlugin.ts b/src/plugins/hotkeyPlugin.ts index 2efb55295c..afc3099779 100644 --- a/src/plugins/hotkeyPlugin.ts +++ b/src/plugins/hotkeyPlugin.ts @@ -91,6 +91,8 @@ const isNotSameHotkeyTarget = (a: HotkeyTarget) => (b: HotkeyTarget) => { export class HotkeyManager { /** 登録されたHotkeyAction */ private actions: HotkeyAction[] = []; + /** スコープ */ + private scope: Editor = "talk"; /** ユーザーのショートカットキー設定 */ private settings: HotkeySettingType[] | undefined; // ユーザーのショートカットキー設定 /** hotkeys-jsに登録されたショートカットキーの組み合わせ */ @@ -171,7 +173,7 @@ export class HotkeyManager { for (const combination of combinations) { const bindingKey = combinationToBindingKey(combination.combination); this.log("Unbind:", bindingKey, "in", combination.editor); - this.hotkeys.unbind(bindingKey, combination.editor); + /* this.hotkeys.unbind(bindingKey, combination.editor); */ this.registeredCombinations = this.registeredCombinations.filter( isNotSameHotkeyTarget(combination) ); @@ -189,7 +191,7 @@ export class HotkeyManager { "in", action.editor ); - this.hotkeys( + /* this.hotkeys( combinationToBindingKey(setting.combination), { scope: action.editor }, (e) => { @@ -215,7 +217,7 @@ export class HotkeyManager { e.preventDefault(); action.callback(e); } - ); + ); */ this.registeredCombinations = this.registeredCombinations.filter( isNotSameHotkeyTarget(action) ); @@ -267,9 +269,40 @@ export class HotkeyManager { * エディタが変更されたときに呼び出される。 */ onEditorChange(editor: "talk" | "song"): void { - this.hotkeys.setScope(editor); + // this.hotkeys.setScope(editor); + this.scope = editor; this.log("Editor changed to", editor); } + + keyInput(e: KeyboardEvent): void { + const element = e.target; + // メニュー項目ではショートカットキーを無効化 + if ( + element instanceof HTMLElement && + element.getAttribute("role") == "menu" + ) { + return; + } + + const isInTextbox = + element instanceof HTMLElement && + (element.tagName === "INPUT" || + element.tagName === "SELECT" || + element.tagName === "TEXTAREA" || + element.contentEditable === "true"); + + const combination: HotkeyCombination = eventToCombination(e); + + const action = this.actions + .filter((item) => item.editor == this.scope) + .filter((item) => !isInTextbox || item.enableInTextbox) + .find((item) => this.getSetting(item).combination == combination); + if (action == null) { + return; + } + e.preventDefault(); + action.callback(e); + } } /** hotkeys-js用のキーに変換する */ From 53b5fc84deea8fd9973c44d6460c37a4af5fd029 Mon Sep 17 00:00:00 2001 From: tsym77yoshi <67378554+tsym77yoshi@users.noreply.github.com> Date: Wed, 1 May 2024 00:09:29 +0900 Subject: [PATCH 04/23] =?UTF-8?q?fix:=20=E5=9F=BA=E6=9C=AC=E9=83=A8?= =?UTF-8?q?=E5=88=86=E3=81=AE=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit コメントアウトで消すのをやめる 型を書く不要な処理を削除 filterの順番を一般的に速くなりそうな順番に --- src/plugins/hotkeyPlugin.ts | 36 ++++-------------------------------- 1 file changed, 4 insertions(+), 32 deletions(-) diff --git a/src/plugins/hotkeyPlugin.ts b/src/plugins/hotkeyPlugin.ts index afc3099779..ca9cab63f8 100644 --- a/src/plugins/hotkeyPlugin.ts +++ b/src/plugins/hotkeyPlugin.ts @@ -173,7 +173,6 @@ export class HotkeyManager { for (const combination of combinations) { const bindingKey = combinationToBindingKey(combination.combination); this.log("Unbind:", bindingKey, "in", combination.editor); - /* this.hotkeys.unbind(bindingKey, combination.editor); */ this.registeredCombinations = this.registeredCombinations.filter( isNotSameHotkeyTarget(combination) ); @@ -191,33 +190,6 @@ export class HotkeyManager { "in", action.editor ); - /* this.hotkeys( - combinationToBindingKey(setting.combination), - { scope: action.editor }, - (e) => { - const element = e.target; - // メニュー項目ではショートカットキーを無効化 - if ( - element instanceof HTMLElement && - element.classList.contains("q-item") - ) { - return; - } - if (!action.enableInTextbox) { - if ( - element instanceof HTMLElement && - (element.tagName === "INPUT" || - element.tagName === "SELECT" || - element.tagName === "TEXTAREA" || - element.contentEditable === "true") - ) { - return; - } - } - e.preventDefault(); - action.callback(e); - } - ); */ this.registeredCombinations = this.registeredCombinations.filter( isNotSameHotkeyTarget(action) ); @@ -291,12 +263,12 @@ export class HotkeyManager { element.tagName === "TEXTAREA" || element.contentEditable === "true"); - const combination: HotkeyCombination = eventToCombination(e); + const combination = eventToCombination(e); - const action = this.actions - .filter((item) => item.editor == this.scope) + const action = this.actions .filter((item) => !isInTextbox || item.enableInTextbox) - .find((item) => this.getSetting(item).combination == combination); + .filter((item) => this.getSetting(item).combination == combination) + .find((item) => item.editor == this.scope); if (action == null) { return; } From d5e022fb3339173c79fc0db5639599fd48e9dff2 Mon Sep 17 00:00:00 2001 From: tsym77yoshi <67378554+tsym77yoshi@users.noreply.github.com> Date: Mon, 6 May 2024 18:48:44 +0900 Subject: [PATCH 05/23] =?UTF-8?q?remove:=20test=E4=BB=A5=E5=A4=96=E3=81=AE?= =?UTF-8?q?=E9=83=A8=E5=88=86=E3=81=AEhotkeys-js=E9=96=A2=E9=80=A3?= =?UTF-8?q?=E3=82=92=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 - src/plugins/hotkeyPlugin.ts | 47 ++++++++++--------------------------- 2 files changed, 13 insertions(+), 35 deletions(-) diff --git a/package.json b/package.json index 89b93a1014..7db034a093 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,6 @@ "electron-window-state": "5.0.3", "encoding-japanese": "1.0.30", "glob": "8.0.3", - "hotkeys-js": "3.13.6", "immer": "9.0.21", "markdown-it": "13.0.2", "move-file": "3.0.0", diff --git a/src/plugins/hotkeyPlugin.ts b/src/plugins/hotkeyPlugin.ts index ca9cab63f8..6a0dc6e666 100644 --- a/src/plugins/hotkeyPlugin.ts +++ b/src/plugins/hotkeyPlugin.ts @@ -4,11 +4,10 @@ * HotkeyAction: 実行する処理の名前とコールバックのペア * HotkeySetting: ユーザーが設定できるもの。ActionとCobinationのペア * Combination: ショートカットキーを文字列で表したもの - * binding: hotkeys-js に登録したコールバック - * bindingKey: hotkeys-js で使う、キーの文字列表記 + * binding: 登録したコールバック + * bindingKey: キーの文字列表記 */ import { Plugin, inject, onMounted, onUnmounted } from "vue"; -import hotkeys from "hotkeys-js"; import { HotkeyActionNameType, HotkeyCombination, @@ -50,22 +49,6 @@ export type HotkeyAction = { callback: (e: KeyboardEvent) => void; }; -export type HotkeysJs = { - ( - key: BindingKey, - options: { - scope: string; - }, - callback: (e: KeyboardEvent) => void - ): void; - unbind: (key: BindingKey, scope: string) => void; - setScope: (scope: string) => void; -}; - -// デフォルトはテキストボックス内でショートカットキー無効なので有効にする -hotkeys.filter = () => { - return true; -}; type Log = (message: string, ...args: unknown[]) => void; type RegisteredCombination = { @@ -95,20 +78,17 @@ export class HotkeyManager { private scope: Editor = "talk"; /** ユーザーのショートカットキー設定 */ private settings: HotkeySettingType[] | undefined; // ユーザーのショートカットキー設定 - /** hotkeys-jsに登録されたショートカットキーの組み合わせ */ + /** 登録されたショートカットキーの組み合わせ */ private registeredCombinations: RegisteredCombination[] = []; - private hotkeys: HotkeysJs; private log: Log; constructor( - hotkeys_: HotkeysJs = hotkeys, log: Log = (message: string, ...args: unknown[]) => { window.backend.logInfo(`[HotkeyManager] ${message}`, ...args); } ) { this.log = log; - this.hotkeys = hotkeys_; } /** @@ -263,11 +243,15 @@ export class HotkeyManager { element.tagName === "TEXTAREA" || element.contentEditable === "true"); - const combination = eventToCombination(e); + const combination = combinationToBindingKey(eventToCombination(e)); - const action = this.actions + const action = this.actions .filter((item) => !isInTextbox || item.enableInTextbox) - .filter((item) => this.getSetting(item).combination == combination) + .filter( + (item) => + combinationToBindingKey(this.getSetting(item).combination) == + combination, + ) .find((item) => item.editor == this.scope); if (action == null) { return; @@ -277,19 +261,14 @@ export class HotkeyManager { } } -/** hotkeys-js用のキーに変換する */ +// もし必要になった時の為に残している +/** 判定用のキーに変換する */ const combinationToBindingKey = ( combination: HotkeyCombination ): BindingKey => { // MetaキーはCommandキーとして扱う - // NOTE: hotkeys-jsにはWinキーが無く、Commandキーとして扱われている // NOTE: Metaキーは以前採用していたmousetrapがそうだった名残り - const bindingKey = combination - .toLowerCase() - .split(" ") - .map((key) => (key === "meta" ? "command" : key)) - .join("+"); - return bindingKey as BindingKey; + return combination as unknown as BindingKey; }; export const hotkeyPlugin: Plugin = { From 2cf7f280c6ee86e272493502fe43d1008f42eb8c Mon Sep 17 00:00:00 2001 From: tsym77yoshi <67378554+tsym77yoshi@users.noreply.github.com> Date: Mon, 6 May 2024 19:41:57 +0900 Subject: [PATCH 06/23] =?UTF-8?q?change:=20=E3=82=AD=E3=83=BC=E5=85=A5?= =?UTF-8?q?=E5=8A=9B=E3=81=AE=E3=83=86=E3=82=B9=E3=83=88=E3=81=AE=E5=A4=89?= =?UTF-8?q?=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit キーを押す関数(HotkeyManager.keyInput)があるのでそれを実行して関数の実行回数を検査 keyとcodeの両方を書いているが将来的に統一が決まったら削除する --- tests/unit/lib/hotkeyManager.spec.ts | 136 +++++++++++++-------------- 1 file changed, 63 insertions(+), 73 deletions(-) diff --git a/tests/unit/lib/hotkeyManager.spec.ts b/tests/unit/lib/hotkeyManager.spec.ts index 3e6d743b95..5ff0030d0c 100644 --- a/tests/unit/lib/hotkeyManager.spec.ts +++ b/tests/unit/lib/hotkeyManager.spec.ts @@ -1,54 +1,44 @@ import { describe, it, expect, beforeEach } from "vitest"; -import { HotkeyManager, HotkeysJs, HotkeyAction } from "@/plugins/hotkeyPlugin"; +import { HotkeyManager, HotkeyAction } from "@/plugins/hotkeyPlugin"; import { HotkeyCombination, HotkeySettingType } from "@/type/preload"; -type DummyHotkeysJs = HotkeysJs & { - registeredHotkeys: { - key: string; - scope: string; - // callbackを持たせると比較が面倒になるので持たせない - // callback: (e: KeyboardEvent) => void; - }[]; - currentScope: string; +type DummyKeyboardEvent = { + key: string; + code: string; + target: EventTarget | null; + ctrlKey: boolean; + shiftKey: boolean; + altKey: boolean; + metaKey: boolean; + preventDefault: () => void; }; -const createHotkeyManager = (): { - hotkeyManager: HotkeyManager; - dummyHotkeysJs: DummyHotkeysJs; -} => { - const registeredHotkeys: DummyHotkeysJs["registeredHotkeys"] = []; - const dummyHotkeysJs: DummyHotkeysJs = ( - key: string, - { scope }: { scope: string } - ) => { - if (registeredHotkeys.some((h) => h.key === key && h.scope === scope)) { - throw new Error("assert: duplicate key"); - } - registeredHotkeys.push({ key, scope }); - }; - dummyHotkeysJs.unbind = (key: string) => { - const index = dummyHotkeysJs.registeredHotkeys.findIndex( - (h) => h.key === key - ); - if (index === -1) { - throw new Error("assert: unknown binding"); - } - registeredHotkeys.splice(index, 1); - }; - dummyHotkeysJs.setScope = (scope: string) => { - dummyHotkeysJs.currentScope = scope; - }; - dummyHotkeysJs.registeredHotkeys = registeredHotkeys; - dummyHotkeysJs.currentScope = "talk"; - return { - hotkeyManager: new HotkeyManager(dummyHotkeysJs, () => { +const createDummyInput = ( + combinationKey: string, + combinationCode: string, +): DummyKeyboardEvent => { + const dummyInput: DummyKeyboardEvent = { + key: combinationKey, + code: combinationCode, + target: null, + ctrlKey: false, + shiftKey: false, + altKey: false, + metaKey: false, + preventDefault: () => { /* noop */ - }), - dummyHotkeysJs, + }, }; + return dummyInput; +}; + +const createHotkeyManager = (): HotkeyManager => { + return new HotkeyManager(() => { + /* noop */ + }); }; it("registerできる", () => { - const { hotkeyManager } = createHotkeyManager(); + const hotkeyManager = createHotkeyManager(); hotkeyManager.register({ editor: "talk", name: "音声書き出し", @@ -59,12 +49,13 @@ it("registerできる", () => { }); it("unregisterできる", () => { - const { hotkeyManager, dummyHotkeysJs } = createHotkeyManager(); + const hotkeyManager = createHotkeyManager(); + let testCount = 0; const action = { editor: "talk", name: "音声書き出し", callback: () => { - /* noop */ + testCount++; }, } as const; hotkeyManager.load([ @@ -74,15 +65,17 @@ it("unregisterできる", () => { }, ]); hotkeyManager.register(action); - expect(dummyHotkeysJs.registeredHotkeys).toEqual([ - { key: "1", scope: "talk" }, - ]); + hotkeyManager.keyInput(createDummyInput("1", "Digit1") as KeyboardEvent); + expect(testCount).toBe(1); + hotkeyManager.unregister(action); - expect(dummyHotkeysJs.registeredHotkeys).toEqual([]); + hotkeyManager.keyInput(createDummyInput("1", "Digit1") as KeyboardEvent); + expect(testCount).toBe(1); }); +let testCount = 0; const callback = () => { - /* noop */ + testCount++; }; const dummyAction: HotkeyAction = { editor: "talk", @@ -96,63 +89,60 @@ const createDummySetting = (combination: string): HotkeySettingType => ({ describe("設定変更", () => { let hotkeyManager: HotkeyManager; - let dummyHotkeysJs: DummyHotkeysJs; beforeEach(() => { - const { hotkeyManager: hotkeyManager_, dummyHotkeysJs: dummyHotkeysJs_ } = - createHotkeyManager(); + const hotkeyManager_ = createHotkeyManager(); hotkeyManager = hotkeyManager_; - dummyHotkeysJs = dummyHotkeysJs_; + testCount = 0; }); it("設定を登録するとhotkeysが更新される", () => { hotkeyManager.register(dummyAction); hotkeyManager.load([createDummySetting("1")]); - expect(dummyHotkeysJs.registeredHotkeys).toEqual([ - { key: "1", scope: "talk" }, - ]); + hotkeyManager.keyInput(createDummyInput("1", "Digit1") as KeyboardEvent); + expect(testCount).toBe(1); }); it("設定を更新するとhotkeysが更新される", () => { hotkeyManager.register(dummyAction); hotkeyManager.load([createDummySetting("1")]); - hotkeyManager.replace(createDummySetting("a")); + hotkeyManager.replace(createDummySetting("A")); + hotkeyManager.keyInput(createDummyInput("a", "KeyA") as KeyboardEvent); - expect(dummyHotkeysJs.registeredHotkeys).toEqual([ - { key: "a", scope: "talk" }, - ]); + expect(testCount).toBe(1); }); it("未割り当てにするとhotkeysから削除される", () => { hotkeyManager.register(dummyAction); hotkeyManager.load([createDummySetting("1")]); hotkeyManager.replace(createDummySetting("")); - expect(dummyHotkeysJs.registeredHotkeys).toEqual([]); + hotkeyManager.keyInput(createDummyInput("1", "Digit1") as KeyboardEvent); + expect(testCount).toBe(0); }); it("未割り当てから割り当てるとhotkeysが更新される", () => { hotkeyManager.register(dummyAction); hotkeyManager.load([createDummySetting("")]); - expect(dummyHotkeysJs.registeredHotkeys).toEqual([]); + hotkeyManager.keyInput(createDummyInput("1", "Digit1") as KeyboardEvent); + expect(testCount).toBe(0); + hotkeyManager.replace(createDummySetting("1")); - expect(dummyHotkeysJs.registeredHotkeys).toEqual([ - { key: "1", scope: "talk" }, - ]); + hotkeyManager.keyInput(createDummyInput("1", "Digit1") as KeyboardEvent); + expect(testCount).toBe(1); }); it("割り当て -> 未割り当て -> 割り当てでhotkeysが更新される", () => { hotkeyManager.register(dummyAction); hotkeyManager.load([createDummySetting("1")]); - expect(dummyHotkeysJs.registeredHotkeys).toEqual([ - { key: "1", scope: "talk" }, - ]); + hotkeyManager.keyInput(createDummyInput("1", "Digit1") as KeyboardEvent); + expect(testCount).toBe(1); hotkeyManager.replace(createDummySetting("")); - expect(dummyHotkeysJs.registeredHotkeys).toEqual([]); + hotkeyManager.keyInput(createDummyInput("1", "Digit1") as KeyboardEvent); + expect(testCount).toBe(1); - hotkeyManager.replace(createDummySetting("a")); - expect(dummyHotkeysJs.registeredHotkeys).toEqual([ - { key: "a", scope: "talk" }, - ]); + hotkeyManager.replace(createDummySetting("A")); + hotkeyManager.keyInput(createDummyInput("a", "KeyA") as KeyboardEvent); + expect(testCount).toBe(2); }); }); From 275ca8a0fcd90bde8971b573f72ffe341feb24ee Mon Sep 17 00:00:00 2001 From: tsym77yoshi <67378554+tsym77yoshi@users.noreply.github.com> Date: Mon, 6 May 2024 19:46:43 +0900 Subject: [PATCH 07/23] =?UTF-8?q?remove:=20=E4=BB=A5=E5=89=8D=E3=81=AE?= =?UTF-8?q?=E3=82=B3=E3=83=A1=E3=83=B3=E3=83=88=E3=82=92=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Talk/TalkEditor.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/Talk/TalkEditor.vue b/src/components/Talk/TalkEditor.vue index 2513a06e8c..be914a4117 100644 --- a/src/components/Talk/TalkEditor.vue +++ b/src/components/Talk/TalkEditor.vue @@ -160,7 +160,6 @@ const store = useStore(); const audioKeys = computed(() => store.state.audioKeys); const uiLocked = computed(() => store.getters.UI_LOCKED); -// hotkeys handled by Mousetrap const { registerHotkeyWithCleanup } = useHotkeyManager(); registerHotkeyWithCleanup({ From 9ecd6cfd9db830a543277881cf1837db3ecb4f0a Mon Sep 17 00:00:00 2001 From: tsym77yoshi <67378554+tsym77yoshi@users.noreply.github.com> Date: Mon, 6 May 2024 22:15:00 +0900 Subject: [PATCH 08/23] =?UTF-8?q?fix:=20lint=E3=82=A8=E3=83=A9=E3=83=BC?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/hotkeyPlugin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/hotkeyPlugin.ts b/src/plugins/hotkeyPlugin.ts index 99012ae199..839f081a68 100644 --- a/src/plugins/hotkeyPlugin.ts +++ b/src/plugins/hotkeyPlugin.ts @@ -85,7 +85,7 @@ export class HotkeyManager { private log: Log; constructor( - log: Log = createLogger("HotkeyManager").info, + log: Log = createLogger("HotkeyManager").info ) { this.log = log; } From e9a14fb04ac2b3b5c231526eddb985e7357e4394 Mon Sep 17 00:00:00 2001 From: tsym77yoshi <67378554+tsym77yoshi@users.noreply.github.com> Date: Mon, 6 May 2024 22:18:23 +0900 Subject: [PATCH 09/23] =?UTF-8?q?fix:=20lint=E3=82=A8=E3=83=A9=E3=83=BC?= =?UTF-8?q?=E5=86=8D=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/hotkeyPlugin.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/plugins/hotkeyPlugin.ts b/src/plugins/hotkeyPlugin.ts index 839f081a68..e669f4f34e 100644 --- a/src/plugins/hotkeyPlugin.ts +++ b/src/plugins/hotkeyPlugin.ts @@ -84,9 +84,7 @@ export class HotkeyManager { private log: Log; - constructor( - log: Log = createLogger("HotkeyManager").info - ) { + constructor(log: Log = createLogger("HotkeyManager").info) { this.log = log; } From ddcb089fa990ebaf7cc14501a68cf350d87d5d06 Mon Sep 17 00:00:00 2001 From: tsym77yoshi <67378554+tsym77yoshi@users.noreply.github.com> Date: Tue, 14 May 2024 23:57:13 +0900 Subject: [PATCH 10/23] =?UTF-8?q?FIX:=20=E9=A0=86=E7=95=AA=E3=81=8C?= =?UTF-8?q?=E9=81=95=E3=81=86=E9=9A=9B=E3=81=AB=E5=8B=95=E4=BD=9C=E3=81=97?= =?UTF-8?q?=E3=81=AA=E3=81=84=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/hotkeyPlugin.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/hotkeyPlugin.ts b/src/plugins/hotkeyPlugin.ts index e669f4f34e..2ec221e88f 100644 --- a/src/plugins/hotkeyPlugin.ts +++ b/src/plugins/hotkeyPlugin.ts @@ -265,7 +265,8 @@ const combinationToBindingKey = ( ): BindingKey => { // MetaキーはCommandキーとして扱う // NOTE: Metaキーは以前採用していたmousetrapがそうだった名残り - return combination as unknown as BindingKey; + // 順番が違うものも一致させるために並べ替え + return combination.split(" ").sort().join(" ") as BindingKey; }; export const hotkeyPlugin: Plugin = { From 3b0ed98589d832084f0456b6ee94b9d3f66315de Mon Sep 17 00:00:00 2001 From: tsym77yoshi <67378554+tsym77yoshi@users.noreply.github.com> Date: Wed, 15 May 2024 01:12:48 +0900 Subject: [PATCH 11/23] =?UTF-8?q?refactor:=20=E3=81=A9=E3=81=AE=E3=82=A8?= =?UTF-8?q?=E3=83=87=E3=82=A3=E3=82=BF=E3=83=BC=E3=81=A7=E3=82=82=E5=AE=9F?= =?UTF-8?q?=E8=A1=8C=E3=81=95=E3=82=8C=E3=82=8B=E3=82=B7=E3=83=A7=E3=83=BC?= =?UTF-8?q?=E3=83=88=E3=82=AB=E3=83=83=E3=83=88=E3=82=A2=E3=82=AF=E3=82=B7?= =?UTF-8?q?=E3=83=A7=E3=83=B3=E3=82=92=E7=99=BB=E9=8C=B2=E3=81=A7=E3=81=8D?= =?UTF-8?q?=E3=82=8B=E9=96=A2=E6=95=B0=E3=82=92=E4=BD=9C=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hotkeyPlugin.ts内のEditor型はEditorType型内の要素数が増えてきたら型定義をより一般な形に変更 --- src/components/Menu/MenuBar/MenuBar.vue | 32 +++++++++---------------- src/plugins/hotkeyPlugin.ts | 10 ++++---- 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/src/components/Menu/MenuBar/MenuBar.vue b/src/components/Menu/MenuBar/MenuBar.vue index cd1bf1d60e..2b21b507e2 100644 --- a/src/components/Menu/MenuBar/MenuBar.vue +++ b/src/components/Menu/MenuBar/MenuBar.vue @@ -32,9 +32,10 @@ import { MenuItemData, MenuItemRoot } from "../type"; import MenuButton from "../MenuButton.vue"; import TitleBarButtons from "./TitleBarButtons.vue"; import TitleBarEditorSwitcher from "./TitleBarEditorSwitcher.vue"; +import { EditorType } from "@/type/preload"; import { useStore } from "@/store"; import { base64ImageToUri } from "@/helpers/imageHelper"; -import { HotkeyAction, useHotkeyManager } from "@/plugins/hotkeyPlugin"; +import { useHotkeyManager } from "@/plugins/hotkeyPlugin"; const props = defineProps<{ /** 「ファイル」メニューのサブメニュー */ @@ -42,7 +43,7 @@ const props = defineProps<{ /** 「編集」メニューのサブメニュー */ editSubMenuData: MenuItemData[]; /** エディタの種類 */ - editor: "talk" | "song"; + editor: EditorType; }>(); const store = useStore(); @@ -491,34 +492,23 @@ watch(uiLocked, () => { } }); -/** - * 全エディタに対してホットキーを登録する - * FIXME: hotkeyPlugin側で全エディタに対して登録できるようにする - */ -function registerHotkeyForAllEditors(action: Omit) { - registerHotkeyWithCleanup({ - editor: "talk", - ...action, - }); - registerHotkeyWithCleanup({ - editor: "song", - ...action, - }); -} - -registerHotkeyForAllEditors({ +registerHotkeyWithCleanup({ + editor: "talk&song", callback: createNewProject, name: "新規プロジェクト", }); -registerHotkeyForAllEditors({ +registerHotkeyWithCleanup({ + editor: "talk&song", callback: saveProject, name: "プロジェクトを上書き保存", }); -registerHotkeyForAllEditors({ +registerHotkeyWithCleanup({ + editor: "talk&song", callback: saveProjectAs, name: "プロジェクトを名前を付けて保存", }); -registerHotkeyForAllEditors({ +registerHotkeyWithCleanup({ + editor: "talk&song", callback: importProject, name: "プロジェクトを読み込む", }); diff --git a/src/plugins/hotkeyPlugin.ts b/src/plugins/hotkeyPlugin.ts index 2ec221e88f..e6363d57f8 100644 --- a/src/plugins/hotkeyPlugin.ts +++ b/src/plugins/hotkeyPlugin.ts @@ -12,6 +12,7 @@ import { HotkeyActionNameType, HotkeyCombination, HotkeySettingType, + EditorType, } from "@/type/preload"; import { createLogger } from "@/domain/frontend/log"; @@ -32,7 +33,8 @@ export const useHotkeyManager = () => { return { hotkeyManager, registerHotkeyWithCleanup }; }; -type Editor = "talk" | "song"; +// FIXME: EditorType型内の要素数が増えてきたら型定義をより一般な形に変更 +type Editor = "talk" | "song" | "talk&song"; type BindingKey = string & { __brand: "BindingKey" }; // BindingKey専用のブランド型 @@ -76,7 +78,7 @@ export class HotkeyManager { /** 登録されたHotkeyAction */ private actions: HotkeyAction[] = []; /** スコープ */ - private scope: Editor = "talk"; + private scope: EditorType = "talk"; /** ユーザーのショートカットキー設定 */ private settings: HotkeySettingType[] | undefined; // ユーザーのショートカットキー設定 /** 登録されたショートカットキーの組み合わせ */ @@ -217,7 +219,7 @@ export class HotkeyManager { /** * エディタが変更されたときに呼び出される。 */ - onEditorChange(editor: "talk" | "song"): void { + onEditorChange(editor: EditorType): void { // this.hotkeys.setScope(editor); this.scope = editor; this.log("Editor changed to", editor); @@ -249,7 +251,7 @@ export class HotkeyManager { combinationToBindingKey(this.getSetting(item).combination) == combination, ) - .find((item) => item.editor == this.scope); + .find((item) => item.editor.split("&").includes(this.scope)); if (action == null) { return; } From ccda7f65cbdad9ec3d5966648161c4f0ba12f83b Mon Sep 17 00:00:00 2001 From: tsym77yoshi <67378554+tsym77yoshi@users.noreply.github.com> Date: Wed, 15 May 2024 01:16:17 +0900 Subject: [PATCH 12/23] =?UTF-8?q?FIX:=20=E5=90=8C=E3=81=98=E3=82=B7?= =?UTF-8?q?=E3=83=A7=E3=83=BC=E3=83=88=E3=82=AB=E3=83=83=E3=83=88=E3=82=AD?= =?UTF-8?q?=E3=83=BC=E3=81=AB2=E3=81=A4=E4=BB=A5=E4=B8=8A=E3=81=AE?= =?UTF-8?q?=E6=93=8D=E4=BD=9C=E3=82=92=E5=89=B2=E3=82=8A=E5=BD=93=E3=81=A6?= =?UTF-8?q?=E3=82=89=E3=82=8C=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/hotkeyPlugin.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/hotkeyPlugin.ts b/src/plugins/hotkeyPlugin.ts index e6363d57f8..e3f855c65e 100644 --- a/src/plugins/hotkeyPlugin.ts +++ b/src/plugins/hotkeyPlugin.ts @@ -244,19 +244,19 @@ export class HotkeyManager { const combination = combinationToBindingKey(eventToCombination(e)); - const action = this.actions + const actions = this.actions .filter((item) => !isInTextbox || item.enableInTextbox) .filter( (item) => combinationToBindingKey(this.getSetting(item).combination) == combination, ) - .find((item) => item.editor.split("&").includes(this.scope)); - if (action == null) { + .filter((item) => item.editor.split("&").includes(this.scope)); + if (actions.length == 0) { return; } e.preventDefault(); - action.callback(e); + actions.forEach((action) => action.callback(e)); } } From f9fc14ce5c63e8c17a586e8f7c88e93cc5247333 Mon Sep 17 00:00:00 2001 From: tsym77yoshi <67378554+tsym77yoshi@users.noreply.github.com> Date: Fri, 17 May 2024 01:18:13 +0900 Subject: [PATCH 13/23] =?UTF-8?q?Update=20=E3=83=80=E3=82=A4=E3=82=A2?= =?UTF-8?q?=E3=83=AD=E3=82=B0=E5=86=85=E3=81=A7=E3=83=9B=E3=83=83=E3=83=88?= =?UTF-8?q?=E3=82=AD=E3=83=BC=E3=81=8C=E5=8A=B9=E3=81=8B=E3=81=AA=E3=81=84?= =?UTF-8?q?=E3=82=88=E3=81=86=E3=81=AB=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/hotkeyPlugin.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/plugins/hotkeyPlugin.ts b/src/plugins/hotkeyPlugin.ts index e3f855c65e..b0a626ecd8 100644 --- a/src/plugins/hotkeyPlugin.ts +++ b/src/plugins/hotkeyPlugin.ts @@ -227,10 +227,11 @@ export class HotkeyManager { keyInput(e: KeyboardEvent): void { const element = e.target; - // メニュー項目ではショートカットキーを無効化 + // メニュー項目・ダイアログではショートカットキーを無効化 if ( element instanceof HTMLElement && - element.getAttribute("role") == "menu" + (element.getAttribute("role") == "menu" || + element.classList.contains("q-dialog__inner")) ) { return; } From 78734f1d7ad0bd94c5dc77bbffb031675e4b938e Mon Sep 17 00:00:00 2001 From: tsym77yoshi <67378554+tsym77yoshi@users.noreply.github.com> Date: Mon, 27 May 2024 22:14:40 +0900 Subject: [PATCH 14/23] =?UTF-8?q?add=E3=81=A8remove=E3=82=92=E5=AF=BE?= =?UTF-8?q?=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/App.vue | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/components/App.vue b/src/components/App.vue index 0f22eba2c6..6712656d82 100644 --- a/src/components/App.vue +++ b/src/components/App.vue @@ -20,7 +20,7 @@ From 7bd034ad44071560abe865131312ddd8d0335b45 Mon Sep 17 00:00:00 2001 From: tsym77yoshi <67378554+tsym77yoshi@users.noreply.github.com> Date: Mon, 27 May 2024 23:20:48 +0900 Subject: [PATCH 15/23] =?UTF-8?q?hotkeyPlugin=E5=86=85=E3=81=A7=E5=88=9D?= =?UTF-8?q?=E6=9C=9F=E8=A8=AD=E5=AE=9A=E3=82=92=E6=B6=88=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/hotkeyPlugin.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/plugins/hotkeyPlugin.ts b/src/plugins/hotkeyPlugin.ts index b450a92a3d..11cd093ce3 100644 --- a/src/plugins/hotkeyPlugin.ts +++ b/src/plugins/hotkeyPlugin.ts @@ -78,7 +78,7 @@ export class HotkeyManager { /** 登録されたHotkeyAction */ private actions: HotkeyAction[] = []; /** スコープ */ - private scope: EditorType = "talk"; + private scope: EditorType | undefined; /** ユーザーのショートカットキー設定 */ private settings: HotkeySettingType[] | undefined; // ユーザーのショートカットキー設定 /** 登録されたショートカットキーの組み合わせ */ @@ -227,6 +227,12 @@ export class HotkeyManager { keyInput(e: KeyboardEvent): void { const element = e.target; + + if (this.scope == undefined) { + console.error("hotkeyPluginのスコープが未設定です"); + return; + } + // メニュー項目・ダイアログではショートカットキーを無効化 if ( element instanceof HTMLElement && @@ -252,7 +258,10 @@ export class HotkeyManager { combinationToBindingKey(this.getSetting(item).combination) == combination, ) - .filter((item) => item.editor.split("&").includes(this.scope)); + .filter((item) => + // エラー表記を回避するために三項演算子を利用 + item.editor.split("&").includes(this.scope ? this.scope : ""), + ); if (actions.length == 0) { return; } From 9f62b17da8dcd96258710fa9243fb7d3b5bb1eb5 Mon Sep 17 00:00:00 2001 From: tsym77yoshi <67378554+tsym77yoshi@users.noreply.github.com> Date: Mon, 27 May 2024 23:21:31 +0900 Subject: [PATCH 16/23] =?UTF-8?q?=E6=B6=88=E3=81=97=E5=BF=98=E3=82=8C?= =?UTF-8?q?=E3=82=92=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/hotkeyPlugin.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/hotkeyPlugin.ts b/src/plugins/hotkeyPlugin.ts index 11cd093ce3..9fe4b1b3e1 100644 --- a/src/plugins/hotkeyPlugin.ts +++ b/src/plugins/hotkeyPlugin.ts @@ -220,7 +220,6 @@ export class HotkeyManager { * エディタが変更されたときに呼び出される。 */ onEditorChange(editor: EditorType): void { - // this.hotkeys.setScope(editor); this.scope = editor; this.log("Editor changed to", editor); } From c5c0e89fb6735fafd973d2563e0a8c25a164ba26 Mon Sep 17 00:00:00 2001 From: tsym77yoshi <67378554+tsym77yoshi@users.noreply.github.com> Date: Wed, 29 May 2024 02:05:30 +0900 Subject: [PATCH 17/23] =?UTF-8?q?refactor:=20Editor=E5=9E=8B=E3=82=92?= =?UTF-8?q?=E5=AE=89=E5=85=A8=E3=81=AA=E3=82=82=E3=81=AE=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/hotkeyPlugin.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/plugins/hotkeyPlugin.ts b/src/plugins/hotkeyPlugin.ts index 9fe4b1b3e1..242f98541e 100644 --- a/src/plugins/hotkeyPlugin.ts +++ b/src/plugins/hotkeyPlugin.ts @@ -33,7 +33,6 @@ export const useHotkeyManager = () => { return { hotkeyManager, registerHotkeyWithCleanup }; }; -// FIXME: EditorType型内の要素数が増えてきたら型定義をより一般な形に変更 type Editor = "talk" | "song" | "talk&song"; type BindingKey = string & { __brand: "BindingKey" }; // BindingKey専用のブランド型 @@ -257,10 +256,17 @@ export class HotkeyManager { combinationToBindingKey(this.getSetting(item).combination) == combination, ) - .filter((item) => - // エラー表記を回避するために三項演算子を利用 - item.editor.split("&").includes(this.scope ? this.scope : ""), - ); + .filter((item) => { + if (item.editor === "talk&song") { + return this.scope === "talk" || this.scope === "song"; + } else if (item.editor === "talk") { + return this.scope === "talk"; + } else if (item.editor === "song") { + return this.scope === "song"; + } else { + console.error("scopeに対する処理が設定されていません"); + } + }); if (actions.length == 0) { return; } From 0a82b96cdf3cb0eecba2f156df8ad78361b2985a Mon Sep 17 00:00:00 2001 From: tsym77yoshi <67378554+tsym77yoshi@users.noreply.github.com> Date: Wed, 29 May 2024 02:39:57 +0900 Subject: [PATCH 18/23] =?UTF-8?q?=E3=83=86=E3=82=B9=E3=83=88=E3=82=92vi.fn?= =?UTF-8?q?()=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/unit/lib/hotkeyManager.spec.ts | 36 +++++++++++++--------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/tests/unit/lib/hotkeyManager.spec.ts b/tests/unit/lib/hotkeyManager.spec.ts index 5ff0030d0c..d9737fc6de 100644 --- a/tests/unit/lib/hotkeyManager.spec.ts +++ b/tests/unit/lib/hotkeyManager.spec.ts @@ -50,13 +50,10 @@ it("registerできる", () => { it("unregisterできる", () => { const hotkeyManager = createHotkeyManager(); - let testCount = 0; const action = { editor: "talk", name: "音声書き出し", - callback: () => { - testCount++; - }, + callback: vi.fn(), } as const; hotkeyManager.load([ { @@ -64,23 +61,21 @@ it("unregisterできる", () => { combination: HotkeyCombination("1"), }, ]); + hotkeyManager.onEditorChange("talk"); hotkeyManager.register(action); hotkeyManager.keyInput(createDummyInput("1", "Digit1") as KeyboardEvent); - expect(testCount).toBe(1); + expect(action.callback).toHaveBeenCalledTimes(1); hotkeyManager.unregister(action); hotkeyManager.keyInput(createDummyInput("1", "Digit1") as KeyboardEvent); - expect(testCount).toBe(1); + expect(action.callback).toHaveBeenCalledTimes(1); // 呼び出し回数が増えない }); -let testCount = 0; -const callback = () => { - testCount++; -}; +const callback = vi.fn(); const dummyAction: HotkeyAction = { editor: "talk", name: "音声書き出し", - callback, + callback: callback, }; const createDummySetting = (combination: string): HotkeySettingType => ({ action: "音声書き出し", @@ -92,14 +87,15 @@ describe("設定変更", () => { beforeEach(() => { const hotkeyManager_ = createHotkeyManager(); hotkeyManager = hotkeyManager_; - testCount = 0; + hotkeyManager.onEditorChange("talk"); + callback.mockClear(); }); it("設定を登録するとhotkeysが更新される", () => { hotkeyManager.register(dummyAction); hotkeyManager.load([createDummySetting("1")]); hotkeyManager.keyInput(createDummyInput("1", "Digit1") as KeyboardEvent); - expect(testCount).toBe(1); + expect(callback).toHaveBeenCalledTimes(1); }); it("設定を更新するとhotkeysが更新される", () => { @@ -108,7 +104,7 @@ describe("設定変更", () => { hotkeyManager.replace(createDummySetting("A")); hotkeyManager.keyInput(createDummyInput("a", "KeyA") as KeyboardEvent); - expect(testCount).toBe(1); + expect(callback).toHaveBeenCalledTimes(1); }); it("未割り当てにするとhotkeysから削除される", () => { @@ -116,18 +112,18 @@ describe("設定変更", () => { hotkeyManager.load([createDummySetting("1")]); hotkeyManager.replace(createDummySetting("")); hotkeyManager.keyInput(createDummyInput("1", "Digit1") as KeyboardEvent); - expect(testCount).toBe(0); + expect(callback).toHaveBeenCalledTimes(0); }); it("未割り当てから割り当てるとhotkeysが更新される", () => { hotkeyManager.register(dummyAction); hotkeyManager.load([createDummySetting("")]); hotkeyManager.keyInput(createDummyInput("1", "Digit1") as KeyboardEvent); - expect(testCount).toBe(0); + expect(callback).toHaveBeenCalledTimes(0); hotkeyManager.replace(createDummySetting("1")); hotkeyManager.keyInput(createDummyInput("1", "Digit1") as KeyboardEvent); - expect(testCount).toBe(1); + expect(callback).toHaveBeenCalledTimes(1); }); it("割り当て -> 未割り当て -> 割り当てでhotkeysが更新される", () => { @@ -135,14 +131,14 @@ describe("設定変更", () => { hotkeyManager.load([createDummySetting("1")]); hotkeyManager.keyInput(createDummyInput("1", "Digit1") as KeyboardEvent); - expect(testCount).toBe(1); + expect(callback).toHaveBeenCalledTimes(1); hotkeyManager.replace(createDummySetting("")); hotkeyManager.keyInput(createDummyInput("1", "Digit1") as KeyboardEvent); - expect(testCount).toBe(1); + expect(callback).toHaveBeenCalledTimes(1); hotkeyManager.replace(createDummySetting("A")); hotkeyManager.keyInput(createDummyInput("a", "KeyA") as KeyboardEvent); - expect(testCount).toBe(2); + expect(callback).toHaveBeenCalledTimes(2); }); }); From cfc14333718506ab3eb5b761cdde6e88b47bc7ec Mon Sep 17 00:00:00 2001 From: tsym77yoshi <67378554+tsym77yoshi@users.noreply.github.com> Date: Wed, 29 May 2024 02:42:30 +0900 Subject: [PATCH 19/23] =?UTF-8?q?=E4=B8=8D=E8=A6=81=E3=81=AA=E3=82=B3?= =?UTF-8?q?=E3=83=A1=E3=83=B3=E3=83=88=E3=81=AE=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/hotkeyPlugin.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/hotkeyPlugin.ts b/src/plugins/hotkeyPlugin.ts index 242f98541e..c58699fe0d 100644 --- a/src/plugins/hotkeyPlugin.ts +++ b/src/plugins/hotkeyPlugin.ts @@ -275,7 +275,6 @@ export class HotkeyManager { } } -// もし必要になった時の為に残している /** 判定用のキーに変換する */ const combinationToBindingKey = ( combination: HotkeyCombination, From 008cd8a12a0baa207dbbc1d8602c838f33b2edf5 Mon Sep 17 00:00:00 2001 From: tsym77yoshi <67378554+tsym77yoshi@users.noreply.github.com> Date: Wed, 29 May 2024 08:48:02 +0900 Subject: [PATCH 20/23] =?UTF-8?q?fix:=20unregister=E3=81=AEtest=E3=82=92?= =?UTF-8?q?=E6=AD=A3=E3=81=97=E3=81=84=E6=84=8F=E5=9B=B3=E9=80=9A=E3=82=8A?= =?UTF-8?q?=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/hotkeyPlugin.ts | 7 +++++++ tests/unit/lib/hotkeyManager.spec.ts | 6 ++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/plugins/hotkeyPlugin.ts b/src/plugins/hotkeyPlugin.ts index c58699fe0d..4301cfc7ca 100644 --- a/src/plugins/hotkeyPlugin.ts +++ b/src/plugins/hotkeyPlugin.ts @@ -273,6 +273,13 @@ export class HotkeyManager { e.preventDefault(); actions.forEach((action) => action.callback(e)); } + + /** + * 現在登録されているHotkeyActionをすべて取得する + */ + getAllActions(): HotkeyAction[] { + return this.actions; + } } /** 判定用のキーに変換する */ diff --git a/tests/unit/lib/hotkeyManager.spec.ts b/tests/unit/lib/hotkeyManager.spec.ts index d9737fc6de..d2c0fa7209 100644 --- a/tests/unit/lib/hotkeyManager.spec.ts +++ b/tests/unit/lib/hotkeyManager.spec.ts @@ -63,12 +63,10 @@ it("unregisterできる", () => { ]); hotkeyManager.onEditorChange("talk"); hotkeyManager.register(action); - hotkeyManager.keyInput(createDummyInput("1", "Digit1") as KeyboardEvent); - expect(action.callback).toHaveBeenCalledTimes(1); + expect(hotkeyManager.getAllActions()).toStrictEqual([action]); hotkeyManager.unregister(action); - hotkeyManager.keyInput(createDummyInput("1", "Digit1") as KeyboardEvent); - expect(action.callback).toHaveBeenCalledTimes(1); // 呼び出し回数が増えない + expect(hotkeyManager.getAllActions()).toStrictEqual([]); }); const callback = vi.fn(); From 317c672ab50c8c15584ad9e434970df28c89651e Mon Sep 17 00:00:00 2001 From: tsym77yoshi <67378554+tsym77yoshi@users.noreply.github.com> Date: Wed, 29 May 2024 09:02:15 +0900 Subject: [PATCH 21/23] =?UTF-8?q?add:=20test=E3=81=AE=E6=84=8F=E5=9B=B3?= =?UTF-8?q?=E3=82=92=E3=82=B3=E3=83=A1=E3=83=B3=E3=83=88=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/unit/lib/hotkeyManager.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/lib/hotkeyManager.spec.ts b/tests/unit/lib/hotkeyManager.spec.ts index d2c0fa7209..3538f6a92e 100644 --- a/tests/unit/lib/hotkeyManager.spec.ts +++ b/tests/unit/lib/hotkeyManager.spec.ts @@ -133,7 +133,7 @@ describe("設定変更", () => { hotkeyManager.replace(createDummySetting("")); hotkeyManager.keyInput(createDummyInput("1", "Digit1") as KeyboardEvent); - expect(callback).toHaveBeenCalledTimes(1); + expect(callback).toHaveBeenCalledTimes(1);// 呼び出し回数が増えない hotkeyManager.replace(createDummySetting("A")); hotkeyManager.keyInput(createDummyInput("a", "KeyA") as KeyboardEvent); From 8df31c6001b092fd39dc7278122581f3179864c1 Mon Sep 17 00:00:00 2001 From: tsym77yoshi <67378554+tsym77yoshi@users.noreply.github.com> Date: Wed, 29 May 2024 10:18:38 +0900 Subject: [PATCH 22/23] =?UTF-8?q?fix:=20lint=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/unit/lib/hotkeyManager.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/lib/hotkeyManager.spec.ts b/tests/unit/lib/hotkeyManager.spec.ts index 3538f6a92e..9aefe31927 100644 --- a/tests/unit/lib/hotkeyManager.spec.ts +++ b/tests/unit/lib/hotkeyManager.spec.ts @@ -133,7 +133,7 @@ describe("設定変更", () => { hotkeyManager.replace(createDummySetting("")); hotkeyManager.keyInput(createDummyInput("1", "Digit1") as KeyboardEvent); - expect(callback).toHaveBeenCalledTimes(1);// 呼び出し回数が増えない + expect(callback).toHaveBeenCalledTimes(1); // 呼び出し回数が増えない hotkeyManager.replace(createDummySetting("A")); hotkeyManager.keyInput(createDummyInput("a", "KeyA") as KeyboardEvent); From 7a804fa9a3ec8c9d9a4ed33967ab322d4db2e8cd Mon Sep 17 00:00:00 2001 From: tsym77yoshi <67378554+tsym77yoshi@users.noreply.github.com> Date: Wed, 29 May 2024 10:25:46 +0900 Subject: [PATCH 23/23] Merge branch 'change-hotkey' of https://github.com/tsym77yoshi/voicevox into change-hotkey --- package-lock.json | 6 + package.json | 1 + src/@types/fast-base64.d.ts | 5 + src/backend/electron/electronConfig.ts | 9 +- src/components/CharacterButton.vue | 11 +- src/components/Dialog/EngineManageDialog.vue | 12 +- src/components/Menu/MenuBar/MenuBar.vue | 5 +- .../Sing/CharacterMenuButton/MenuButton.vue | 11 +- src/components/Sing/SequencerNote.vue | 32 +-- src/components/Sing/SequencerPitch.vue | 261 ++++++++---------- src/composables/useEngineIcons.ts | 27 ++ src/helpers/base64Helper.ts | 21 +- src/sing/utility.ts | 7 + src/sing/viewHelper.ts | 21 +- src/store/audio.ts | 21 +- src/store/dictionary.ts | 146 +++++----- src/store/vuex.ts | 235 ++++++++++++++-- 17 files changed, 525 insertions(+), 306 deletions(-) create mode 100644 src/@types/fast-base64.d.ts create mode 100644 src/composables/useEngineIcons.ts diff --git a/package-lock.json b/package-lock.json index b9b4e12bf3..6da39e115c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "electron-window-state": "5.0.3", "encoding-japanese": "1.0.30", "fast-array-diff": "1.1.0", + "fast-base64": "0.1.8", "glob": "8.0.3", "hotkeys-js": "3.13.6", "immer": "9.0.21", @@ -6613,6 +6614,11 @@ "resolved": "https://registry.npmjs.org/fast-array-diff/-/fast-array-diff-1.1.0.tgz", "integrity": "sha512-muSPyZa/yHCoDQhah9th57AmLENB1nekbrUoLAqOpQXdl1Kw8VbH24Syl5XLscaQJlx7KRU95bfTDPvVB5BJvw==" }, + "node_modules/fast-base64": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/fast-base64/-/fast-base64-0.1.8.tgz", + "integrity": "sha512-LICiPjlLyh7/P3gcJYDjKEIX41odzqny1VHSnPsAlBb/zcSJJPYrSNHs54e2TytDRTwHZl7KG5c33IMLdT+9Eg==" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", diff --git a/package.json b/package.json index 6ba653859c..72c281c52b 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "electron-window-state": "5.0.3", "encoding-japanese": "1.0.30", "fast-array-diff": "1.1.0", + "fast-base64": "0.1.8", "glob": "8.0.3", "immer": "9.0.21", "markdown-it": "13.0.2", diff --git a/src/@types/fast-base64.d.ts b/src/@types/fast-base64.d.ts new file mode 100644 index 0000000000..a52a07fa05 --- /dev/null +++ b/src/@types/fast-base64.d.ts @@ -0,0 +1,5 @@ +// fast-base64の型定義が壊れているので、ここで型定義を追加する。 +declare module "fast-base64" { + export function toBytes(base64: string): Promise; + export function toBase64(bytes: Uint8Array): Promise; +} diff --git a/src/backend/electron/electronConfig.ts b/src/backend/electron/electronConfig.ts index 06678ebf93..57219548a4 100644 --- a/src/backend/electron/electronConfig.ts +++ b/src/backend/electron/electronConfig.ts @@ -1,6 +1,7 @@ import { join } from "path"; import fs from "fs"; import { app } from "electron"; +import { moveFile } from "move-file"; import { BaseConfigManager, Metadata } from "@/backend/common/ConfigManager"; import { ConfigType } from "@/type/preload"; @@ -21,10 +22,16 @@ export class ElectronConfigManager extends BaseConfigManager { } protected async save(config: ConfigType & Metadata) { + // ファイル書き込みに失敗したときに設定が消えないように、tempファイル書き込み後上書き移動する + const temp_path = `${this.configPath}.tmp`; await fs.promises.writeFile( - this.configPath, + temp_path, JSON.stringify(config, undefined, 2), ); + + await moveFile(temp_path, this.configPath, { + overwrite: true, + }); } private get configPath(): string { diff --git a/src/components/CharacterButton.vue b/src/components/CharacterButton.vue index 3e49c5f91a..2ca2304b50 100644 --- a/src/components/CharacterButton.vue +++ b/src/components/CharacterButton.vue @@ -196,11 +196,11 @@