@@ -168,7 +172,6 @@ const showSetInstanceModal = ref(false) :show="showShortcutsModal" @update:show="showShortcutsModal = $event" /> - diff --git a/front/src/components/audio/Player.vue b/front/src/components/audio/Player.vue index 23fe2c269..a5ebb1771 100644 --- a/front/src/components/audio/Player.vue +++ b/front/src/components/audio/Player.vue @@ -156,7 +156,7 @@ :title="labels.play" :aria-label="labels.play" class="circular button control" - @click.prevent.stop="resumePlayback" + @click.prevent.stop="playback = true" > @@ -165,7 +165,7 @@ :title="labels.pause" :aria-label="labels.pause" class="circular button control" - @click.prevent.stop="pausePlayback" + @click.prevent.stop="playback = false" > @@ -234,7 +234,7 @@ @@ -316,30 +316,11 @@ - diff --git a/front/src/composables/onKeyboardShortcut.ts b/front/src/composables/onKeyboardShortcut.ts new file mode 100644 index 000000000..49667562c --- /dev/null +++ b/front/src/composables/onKeyboardShortcut.ts @@ -0,0 +1,72 @@ +import { DefaultMagicKeysAliasMap, tryOnScopeDispose, useActiveElement, useEventListener } from '@vueuse/core' +import { computed, reactive } from 'vue' +import { isEqual, isMatch } from 'lodash-es' + +type KeyFilter = string | string[] + +interface Entry { + handler: () => unknown, + prevent: boolean, + __location?: string +} + +const combinations = reactive(new Map()) +const activeElement = useActiveElement() +const bodyIsActive = computed(() => activeElement.value === document.body) + +const current = new Set() +useEventListener(window, 'keydown', (event) => { + if (!bodyIsActive.value) return + current.add(event.key.toLowerCase()) + + const currentArray = [...current] + for (const [requiredKeys, { handler, prevent }] of combinations.entries()) { + if (isEqual(currentArray, requiredKeys)) { + if (prevent) event.preventDefault() + handler() + } + } +}) + +useEventListener(window, 'keyup', (event) => { + current.delete(event.key.toLowerCase()) +}) + +export default (key: KeyFilter, handler: () => unknown, prevent = false) => { + const combination = (Array.isArray(key) ? key : [key as string]).map(key => { + return DefaultMagicKeysAliasMap[key] ?? key + }) + + const entry: Entry = { prevent, handler } + + if (import.meta.env.DEV) { + entry.__location = new Error().stack?.split('\n', 2).pop() + // TODO: Get correct line number somehow? + // Currently $3 is a line number that should work in .ts files, + // though in .vue files we need to get the line of the script plus + // the position of