forked from VOICEVOX/voicevox
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor: 修飾キーのcomposableを追加 (VOICEVOX#1711)
* Refactor: 修飾キーのcomposableを追加 * Dlete: 不要なexportを削除 Co-authored-by: Hiroshiba <[email protected]> * #1711のテスト書いてみた (#1) --------- Co-authored-by: Hiroshiba <[email protected]>
- Loading branch information
1 parent
06e8721
commit e100dc9
Showing
4 changed files
with
133 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import { Ref, ref, onUnmounted, onMounted, unref } from "vue"; | ||
import { isMac } from "@/type/preload"; | ||
|
||
// FIXME: Vue3.3以上では定義済みなので削除する | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
type AnyFn = (...args: any[]) => any; | ||
type MaybeRef<T> = T | Ref<T>; | ||
type MaybeRefOrGetter<T> = MaybeRef<T> | (() => T); | ||
function toValue<T>(r: MaybeRefOrGetter<T>): T { | ||
return typeof r === "function" ? (r as AnyFn)() : unref(r); | ||
} | ||
|
||
type Target = EventTarget & GlobalEventHandlers; | ||
|
||
const useCreateUseKey = ( | ||
key: string, | ||
_target: MaybeRefOrGetter<Target> = window | ||
): Ref<boolean> => { | ||
const target = toValue(_target); | ||
|
||
const isActive = ref(false); | ||
|
||
const onKeydown = (e: KeyboardEvent) => { | ||
if (e.key === key) { | ||
isActive.value = true; | ||
} | ||
}; | ||
const onKeyup = (e: KeyboardEvent) => { | ||
if (e.key === key) { | ||
isActive.value = false; | ||
} | ||
}; | ||
const onBlur = () => { | ||
isActive.value = false; | ||
}; | ||
|
||
onMounted(() => { | ||
target.addEventListener("keydown", onKeydown); | ||
target.addEventListener("keyup", onKeyup); | ||
target.addEventListener("blur", onBlur); | ||
}); | ||
|
||
onUnmounted(() => { | ||
target.removeEventListener("keydown", onKeydown); | ||
target.removeEventListener("keyup", onKeyup); | ||
target.removeEventListener("blur", onBlur); | ||
}); | ||
|
||
return isActive; | ||
}; | ||
|
||
/** Shiftキーが押されているかどうかを返す */ | ||
export const useShiftKey = (target: Target = window) => | ||
useCreateUseKey("Shift", target); | ||
|
||
/** Altキー(MacではOptionキー)が押されているかどうかを返す */ | ||
export const useAltKey = (target: Target = window) => | ||
useCreateUseKey("Alt", target); | ||
|
||
const useMetaKey = (target: Target = window) => useCreateUseKey("Meta", target); | ||
const useControlKey = (target: Target = window) => | ||
useCreateUseKey("Control", target); | ||
|
||
/** Ctrlキー(MacではCommandキー)が押されているかどうかを返す */ | ||
export const useCommandOrControlKey = (target: Target = window) => { | ||
if (isMac) { | ||
return useMetaKey(target); | ||
} | ||
return useControlKey(target); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import { mount } from "@vue/test-utils"; | ||
import { Ref } from "vue"; | ||
import { | ||
useCommandOrControlKey, | ||
useShiftKey, | ||
} from "@/composables/useModifierKey"; | ||
|
||
import { isMac } from "@/type/preload"; | ||
|
||
describe("useModifierKey", () => { | ||
// テスト用のコンポーネント | ||
const mountWrapper = (func: (elem: HTMLElement) => Ref<boolean>) => | ||
mount({ | ||
setup: () => { | ||
const elem = document.createElement("div"); | ||
return { elem, isActive: func(elem) }; | ||
}, | ||
render: () => null, // 警告防止 | ||
}); | ||
|
||
it("Shiftキーが押されている状態になる", async () => { | ||
const wrapper = mountWrapper(useShiftKey); | ||
|
||
// 押す | ||
wrapper.vm.elem.dispatchEvent( | ||
new KeyboardEvent("keydown", { key: "Shift" }) | ||
); | ||
expect(wrapper.vm.isActive).toBe(true); | ||
|
||
// 離す | ||
wrapper.vm.elem.dispatchEvent(new KeyboardEvent("keyup", { key: "Shift" })); | ||
expect(wrapper.vm.isActive).toBe(false); | ||
|
||
// もう一度押したあとblurさせる | ||
wrapper.vm.elem.dispatchEvent( | ||
new KeyboardEvent("keydown", { key: "Shift" }) | ||
); | ||
wrapper.vm.elem.dispatchEvent(new Event("blur")); | ||
expect(wrapper.vm.isActive).toBe(false); | ||
}); | ||
|
||
it("isMacに従ったキーが押されている状態になる", async () => { | ||
const wrapper = mountWrapper(useCommandOrControlKey); | ||
const key = isMac ? "Meta" : "Control"; | ||
wrapper.vm.elem.dispatchEvent(new KeyboardEvent("keydown", { key })); | ||
expect(wrapper.vm.isActive).toBe(true); | ||
}); | ||
}); |