From 4b8139da66753ad68bfe1bca345cd211433a7e53 Mon Sep 17 00:00:00 2001 From: Braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Wed, 13 Nov 2024 20:10:35 +0100 Subject: [PATCH] fix(core): release key combination presses (#1696) * fix(core): release key combination presses Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com> * chore(changeset): add Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com> --------- Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com> --- .changeset/hot-islands-carry.md | 5 +++ packages/core/src/composables/useKeyPress.ts | 38 ++++++++++---------- 2 files changed, 24 insertions(+), 19 deletions(-) create mode 100644 .changeset/hot-islands-carry.md diff --git a/.changeset/hot-islands-carry.md b/.changeset/hot-islands-carry.md new file mode 100644 index 00000000..fc884afd --- /dev/null +++ b/.changeset/hot-islands-carry.md @@ -0,0 +1,5 @@ +--- +"@vue-flow/core": patch +--- + +Properly release key combinations when one of the keys is unpressed diff --git a/packages/core/src/composables/useKeyPress.ts b/packages/core/src/composables/useKeyPress.ts index e3c7602c..a38afdf7 100644 --- a/packages/core/src/composables/useKeyPress.ts +++ b/packages/core/src/composables/useKeyPress.ts @@ -3,6 +3,9 @@ import { onMounted, ref, toRef, toValue, watch } from 'vue' import type { KeyFilter, KeyPredicate } from '@vueuse/core' import { onKeyStroke, useEventListener } from '@vueuse/core' +type PressedKeys = Set +type KeyOrCode = 'key' | 'code' + export interface UseKeyPressOptions { actInsideInputWithModifier?: MaybeRefOrGetter target?: MaybeRefOrGetter @@ -35,18 +38,23 @@ function isKeyMatch(pressedKey: string, keyToMatch: string, pressedKeys: Set pressedKeys.has(key) && Array.from(pressedKeys.values())[index] === keyCombination[index], ) + + if (isKeyUp) { + pressedKeys.delete(pressedKey.toLowerCase()) + } + + return isMatch } -function createKeyPredicate(keyFilter: string | string[], pressedKeys: Set): KeyPredicate { +function createKeyPredicate(keyFilter: string | string[], pressedKeys: PressedKeys): KeyPredicate { return (event: KeyboardEvent) => { if (!event.code && !event.key) { return false @@ -54,24 +62,17 @@ function createKeyPredicate(keyFilter: string | string[], pressedKeys: Set isKeyMatch(pressedKey, key, pressedKeys, isKeyUp)) + return keyFilter.some((key) => isKeyMatch(event[keyOrCode], key, pressedKeys, event.type === 'keyup')) } // if the keyFilter is a string, we need to check if the key matches the string - return isKeyMatch(pressedKey, keyFilter, pressedKeys, isKeyUp) + return isKeyMatch(event[keyOrCode], keyFilter, pressedKeys, event.type === 'keyup') } } -function useKeyOrCode(code: string, keysToWatch: string | string[]) { - if (typeof keysToWatch === 'string') { - return code === keysToWatch ? 'code' : 'key' - } - +function useKeyOrCode(code: string, keysToWatch: string | string[]): KeyOrCode { return keysToWatch.includes(code) ? 'code' : 'key' } @@ -133,9 +134,7 @@ export function useKeyPress(keyFilter: MaybeRefOrGetter { - return currentFilter(...args) - }, + (...args) => currentFilter(...args), (e) => { if (isPressed.value) { const preventAction = (!modifierPressed || (modifierPressed && !actInsideInputWithModifier.value)) && isInputDOMNode(e) @@ -144,7 +143,8 @@ export function useKeyPress(keyFilter: MaybeRefOrGetter