Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

change: HotkeysJSを代替 #1984

Open
wants to merge 28 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
5171fa3
change: HotkeysJSを代替
tsym77yoshi Apr 7, 2024
0cb1bc8
fix:console.log削除
tsym77yoshi Apr 7, 2024
9915d02
change: HotkeysJSを代替
tsym77yoshi Apr 7, 2024
53b5fc8
fix: 基本部分の修正
tsym77yoshi Apr 30, 2024
0b064f2
Merge branch 'change-hotkey' of https://github.com/tsym77yoshi/voicev…
tsym77yoshi Apr 30, 2024
d5e022f
remove: test以外の部分のhotkeys-js関連を削除
tsym77yoshi May 6, 2024
2cf7f28
change: キー入力のテストの変更
tsym77yoshi May 6, 2024
275ca8a
remove: 以前のコメントを削除
tsym77yoshi May 6, 2024
3543da0
Merge branch 'main' into change-hotkey
tsym77yoshi May 6, 2024
9ecd6cf
fix: lintエラー修正
tsym77yoshi May 6, 2024
e9a14fb
fix: lintエラー再修正
tsym77yoshi May 6, 2024
ddcb089
FIX: 順番が違う際に動作しない問題を修正
tsym77yoshi May 14, 2024
3b0ed98
refactor: どのエディターでも実行されるショートカットアクションを登録できる関数を作る
tsym77yoshi May 14, 2024
ccda7f6
FIX: 同じショートカットキーに2つ以上の操作を割り当てられるように
tsym77yoshi May 14, 2024
f9fc14c
Update ダイアログ内でホットキーが効かないように修正
tsym77yoshi May 16, 2024
9f431ef
Merge branch 'main' into change-hotkey
tsym77yoshi May 26, 2024
78734f1
addとremoveを対に
tsym77yoshi May 27, 2024
7bd034a
hotkeyPlugin内で初期設定を消す
tsym77yoshi May 27, 2024
9f62b17
消し忘れを削除
tsym77yoshi May 27, 2024
c5c0e89
refactor: Editor型を安全なものに
tsym77yoshi May 28, 2024
0a82b96
テストをvi.fn()に
tsym77yoshi May 28, 2024
cfc1433
不要なコメントの削除
tsym77yoshi May 28, 2024
008cd8a
fix: unregisterのtestを正しい意図通りに
tsym77yoshi May 28, 2024
317c672
add: testの意図をコメントに
tsym77yoshi May 29, 2024
7ef2b95
Merge branch 'main' into change-hotkey
tsym77yoshi May 29, 2024
8df31c6
fix: lint修正
tsym77yoshi May 29, 2024
7a804fa
Merge branch 'change-hotkey' of https://github.com/tsym77yoshi/voicev…
tsym77yoshi May 29, 2024
ac02817
Merge branch 'change-hotkey' of https://github.com/tsym77yoshi/voicev…
tsym77yoshi May 29, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
"fast-array-diff": "1.1.0",
"fast-base64": "0.1.8",
"glob": "8.0.3",
"hotkeys-js": "3.13.6",
"immer": "9.0.21",
"markdown-it": "13.0.2",
"midi-file": "1.2.4",
Expand Down
19 changes: 18 additions & 1 deletion src/components/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
</template>

<script setup lang="ts">
import { watch, onMounted, ref, computed, toRaw } from "vue";
import { watch, onMounted, onUnmounted, ref, computed, toRaw } from "vue";
import { useGtm } from "@gtm-support/vue-gtm";
import TalkEditor from "@/components/Talk/TalkEditor.vue";
import SingEditor from "@/components/Sing/SingEditor.vue";
Expand Down Expand Up @@ -149,4 +149,21 @@ onMounted(async () => {
isProjectFileLoaded.value = false;
}
});

// ホットキーの監視を開始/終了
const startKeyInputWithCleanup = () => {
const keyInputHandler = (e: KeyboardEvent) => {
hotkeyManager.keyInput(e);
};

onMounted(() => {
document.addEventListener("keydown", keyInputHandler);
});

onUnmounted(() => {
document.removeEventListener("keydown", keyInputHandler);
});
};

startKeyInputWithCleanup();
</script>
32 changes: 11 additions & 21 deletions src/components/Menu/MenuBar/MenuBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ 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 { HotkeyAction, useHotkeyManager } from "@/plugins/hotkeyPlugin";
import { useHotkeyManager } from "@/plugins/hotkeyPlugin";
import { useEngineIcons } from "@/composables/useEngineIcons";

const props = defineProps<{
Expand All @@ -42,7 +43,7 @@ const props = defineProps<{
/** 「編集」メニューのサブメニュー */
editSubMenuData: MenuItemData[];
/** エディタの種類 */
editor: "talk" | "song";
editor: EditorType;
}>();

const store = useStore();
Expand Down Expand Up @@ -499,34 +500,23 @@ watch(uiLocked, () => {
}
});

/**
* 全エディタに対してホットキーを登録する
* FIXME: hotkeyPlugin側で全エディタに対して登録できるようにする
*/
function registerHotkeyForAllEditors(action: Omit<HotkeyAction, "editor">) {
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: "プロジェクトを読み込む",
});
Expand Down
138 changes: 71 additions & 67 deletions src/plugins/hotkeyPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
* 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,
HotkeySettingType,
EditorType,
} from "@/type/preload";
import { createLogger } from "@/domain/frontend/log";

Expand All @@ -33,7 +33,7 @@
return { hotkeyManager, registerHotkeyWithCleanup };
};

type Editor = "talk" | "song";
type Editor = "talk" | "song" | "talk&song";

type BindingKey = string & { __brand: "BindingKey" }; // BindingKey専用のブランド型

Expand All @@ -51,22 +51,6 @@
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 = {
Expand All @@ -92,20 +76,17 @@
export class HotkeyManager {
/** 登録されたHotkeyAction */
private actions: HotkeyAction[] = [];
/** スコープ */
private scope: EditorType | undefined;
/** ユーザーのショートカットキー設定 */
private settings: HotkeySettingType[] | undefined; // ユーザーのショートカットキー設定
/** hotkeys-jsに登録されたショートカットキーの組み合わせ */
/** 登録されたショートカットキーの組み合わせ */
private registeredCombinations: RegisteredCombination[] = [];

private hotkeys: HotkeysJs;
private log: Log;

constructor(
hotkeys_: HotkeysJs = hotkeys,
log: Log = createLogger("HotkeyManager").info,
) {
constructor(log: Log = createLogger("HotkeyManager").info) {
this.log = log;
this.hotkeys = hotkeys_;
}

/**
Expand Down Expand Up @@ -170,7 +151,6 @@
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),
);
Expand All @@ -188,33 +168,6 @@
"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),
);
Expand Down Expand Up @@ -265,27 +218,78 @@
/**
* エディタが変更されたときに呼び出される。
*/
onEditorChange(editor: "talk" | "song"): void {
this.hotkeys.setScope(editor);
onEditorChange(editor: EditorType): void {
this.scope = editor;
this.log("Editor changed to", editor);
}

keyInput(e: KeyboardEvent): void {
const element = e.target;

if (this.scope == undefined) {
console.error("hotkeyPluginのスコープが未設定です");

Check warning on line 230 in src/plugins/hotkeyPlugin.ts

View workflow job for this annotation

GitHub Actions / build-test

Unexpected console statement
return;
}

// メニュー項目・ダイアログではショートカットキーを無効化
if (
element instanceof HTMLElement &&
(element.getAttribute("role") == "menu" ||
element.classList.contains("q-dialog__inner"))
) {
return;
}

const isInTextbox =
element instanceof HTMLElement &&
(element.tagName === "INPUT" ||
element.tagName === "SELECT" ||
element.tagName === "TEXTAREA" ||
element.contentEditable === "true");

const combination = combinationToBindingKey(eventToCombination(e));

const actions = this.actions
.filter((item) => !isInTextbox || item.enableInTextbox)
.filter(
(item) =>
combinationToBindingKey(this.getSetting(item).combination) ==
combination,
)
.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に対する処理が設定されていません");

Check warning on line 267 in src/plugins/hotkeyPlugin.ts

View workflow job for this annotation

GitHub Actions / build-test

Unexpected console statement
}
});
if (actions.length == 0) {
return;
}
e.preventDefault();
actions.forEach((action) => action.callback(e));
}

/**
* 現在登録されているHotkeyActionをすべて取得する
*/
getAllActions(): HotkeyAction[] {
return this.actions;
}
}

/** hotkeys-js用のキーに変換する */
/** 判定用のキーに変換する */
const combinationToBindingKey = (
combination: HotkeyCombination,
): BindingKey => {
// MetaキーはCommandキーとして扱う
// NOTE: hotkeys-jsにはWinキーが無く、Commandキーとして扱われている
// NOTE: Metaキーは以前採用していたmousetrapがそうだった名残り
// NOTE: hotkeys-jsでは方向キーのarrowプレフィックスが不要
const bindingKey = combination
.toLowerCase()
.split(" ")
.map((key) => (key === "meta" ? "command" : key))
.map((key) => key.replace("arrow", ""))
.join("+");
return bindingKey as BindingKey;
// 順番が違うものも一致させるために並べ替え
return combination.split(" ").sort().join(" ") as BindingKey;
};
Comment on lines 289 to 293
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ここコメントと処理が不一致かもです!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.sort()で並べ替える処理をしています!


export const hotkeyPlugin: Plugin = {
Expand Down
Loading
Loading