From d12e80035daa8c723e06d2e9750f869bfcd14ba5 Mon Sep 17 00:00:00 2001 From: andrewwallacespeckle <139135120+andrewwallacespeckle@users.noreply.github.com> Date: Wed, 10 Jul 2024 11:11:20 +0100 Subject: [PATCH] fix(fe2): keyboard shortcuts in viewer don't work (#2389) * feat: use shift for shortcuts. Swap onKeyStroke for useMagicKeys * refactor: simplify control shortcuts * Revert changes to input.ts * refactor: Make more DRY * Revert "refactor: Make more DRY" This reverts commit a508fcfb9d2fef0cd2635911bc57410989166a50. * Revert "Revert changes to input.ts" This reverts commit c47300d0104d09f9fa0ae9bc9e86e994f0a46206. * Revert "refactor: simplify control shortcuts" This reverts commit a867d6e34d06a7a6436ff4bdb6c4a7db94d3ca21. * Fix broken space * Refactor Viewer Controls and Keyboard Shortcuts * Fix keyboard shortcut mapping to handle string keys correctly * refactor: string enum * remove filters shortcut --- .../frontend-2/components/viewer/Controls.vue | 95 ++++++++++++------- .../src/composables/form/input.ts | 47 ++++----- 2 files changed, 80 insertions(+), 62 deletions(-) diff --git a/packages/frontend-2/components/viewer/Controls.vue b/packages/frontend-2/components/viewer/Controls.vue index 4fc8098a75..46a9155614 100644 --- a/packages/frontend-2/components/viewer/Controls.vue +++ b/packages/frontend-2/components/viewer/Controls.vue @@ -275,6 +275,16 @@ import { useFunctionRunsStatusSummary } from '~/lib/automate/composables/runStat const isGendoEnabled = useIsGendoModuleEnabled() +enum ViewerKeyboardActions { + ToggleModels = 'ToggleModels', + ToggleExplorer = 'ToggleExplorer', + ToggleDiscussions = 'ToggleDiscussions', + ToggleMeasurements = 'ToggleMeasurements', + ToggleProjection = 'ToggleProjection', + ToggleSectionBox = 'ToggleSectionBox', + ZoomExtentsOrSelection = 'ZoomExtentsOrSelection' +} + const width = ref(360) const scrollableControlsContainer = ref(null as Nullable) @@ -364,28 +374,72 @@ const { diff: { enabled } } = useInjectedViewerInterfaceState() +const map: Record = { + [ViewerKeyboardActions.ToggleModels]: [[ModifierKeys.Shift], 'm'], + [ViewerKeyboardActions.ToggleExplorer]: [[ModifierKeys.Shift], 'e'], + [ViewerKeyboardActions.ToggleDiscussions]: [[ModifierKeys.Shift], 't'], + [ViewerKeyboardActions.ToggleMeasurements]: [[ModifierKeys.Shift], 'r'], + [ViewerKeyboardActions.ToggleProjection]: [[ModifierKeys.Shift], 'p'], + [ViewerKeyboardActions.ToggleSectionBox]: [[ModifierKeys.Shift], 'b'], + [ViewerKeyboardActions.ZoomExtentsOrSelection]: [[ModifierKeys.Shift], 'space'] +} + +const getShortcutTitle = (action: ViewerKeyboardActions) => + `(${getKeyboardShortcutTitle([...map[action][0], map[action][1]])})` + const modelsShortcut = ref( - `Models (${getKeyboardShortcutTitle([ModifierKeys.AltOrOpt, 'm'])})` + `Models ${getShortcutTitle(ViewerKeyboardActions.ToggleModels)}` ) const explorerShortcut = ref( - `Scene Explorer (${getKeyboardShortcutTitle([ModifierKeys.AltOrOpt, 'e'])})` + `Scene Explorer ${getShortcutTitle(ViewerKeyboardActions.ToggleExplorer)}` ) const discussionsShortcut = ref( - `Discussions (${getKeyboardShortcutTitle([ModifierKeys.AltOrOpt, 't'])})` + `Discussions ${getShortcutTitle(ViewerKeyboardActions.ToggleDiscussions)}` ) const zoomExtentsShortcut = ref( - `Fit to screen (${getKeyboardShortcutTitle([ModifierKeys.AltOrOpt, 'Space'])})` + `Fit to screen ${getShortcutTitle(ViewerKeyboardActions.ZoomExtentsOrSelection)}` ) const projectionShortcut = ref( - `Projection (${getKeyboardShortcutTitle([ModifierKeys.AltOrOpt, 'p'])})` + `Projection ${getShortcutTitle(ViewerKeyboardActions.ToggleProjection)}` ) const sectionBoxShortcut = ref( - `Section Box (${getKeyboardShortcutTitle([ModifierKeys.AltOrOpt, 'b'])})` + `Section Box ${getShortcutTitle(ViewerKeyboardActions.ToggleSectionBox)}` ) const measureShortcut = ref( - `Measure Mode (${getKeyboardShortcutTitle([ModifierKeys.AltOrOpt, 'd'])})` + `Measure Mode ${getShortcutTitle(ViewerKeyboardActions.ToggleMeasurements)}` ) +const handleKeyboardAction = (action: ViewerKeyboardActions) => { + switch (action) { + case ViewerKeyboardActions.ToggleModels: + toggleActiveControl('models') + break + case ViewerKeyboardActions.ToggleExplorer: + toggleActiveControl('explorer') + break + case ViewerKeyboardActions.ToggleDiscussions: + toggleActiveControl('discussions') + break + case ViewerKeyboardActions.ToggleMeasurements: + toggleMeasurements() + break + case ViewerKeyboardActions.ToggleProjection: + trackAndtoggleProjection() + break + case ViewerKeyboardActions.ToggleSectionBox: + toggleSectionBox() + break + case ViewerKeyboardActions.ZoomExtentsOrSelection: + trackAndzoomExtentsOrSelection() + break + } +} + +Object.entries(map).forEach(([actionKey, [modifiers, key]]) => { + const action = actionKey as ViewerKeyboardActions + onKeyboardShortcut(modifiers, key, () => handleKeyboardAction(action)) +}) + const { isSmallerOrEqualSm } = useIsSmallerOrEqualThanBreakpoint() const toggleActiveControl = (control: ActiveControl) => { @@ -396,33 +450,6 @@ const toggleActiveControl = (control: ActiveControl) => { activeControl.value = activeControl.value === control ? 'none' : control } -onKeyboardShortcut([ModifierKeys.AltOrOpt], 'm', () => { - toggleActiveControl('models') -}) -onKeyboardShortcut([ModifierKeys.AltOrOpt], 'e', () => { - toggleActiveControl('explorer') -}) -onKeyboardShortcut([ModifierKeys.AltOrOpt], 'f', () => { - toggleActiveControl('filters') -}) -onKeyboardShortcut([ModifierKeys.AltOrOpt], ['t'], () => { - toggleActiveControl('discussions') -}) -onKeyboardShortcut([ModifierKeys.AltOrOpt], 'd', () => { - toggleActiveControl('measurements') -}) - -// Viewer actions kbd shortcuts -onKeyboardShortcut([ModifierKeys.AltOrOpt], ' ', () => { - trackAndzoomExtentsOrSelection() -}) -onKeyboardShortcut([ModifierKeys.AltOrOpt], 'p', () => { - toggleProjection() -}) -onKeyboardShortcut([ModifierKeys.AltOrOpt], 'b', () => { - toggleSectionBox() -}) - const mp = useMixpanel() watch(activeControl, (newVal) => { mp.track('Viewer Action', { type: 'action', name: 'controls-toggle', action: newVal }) diff --git a/packages/ui-components/src/composables/form/input.ts b/packages/ui-components/src/composables/form/input.ts index c479ac82b2..e6cad18f77 100644 --- a/packages/ui-components/src/composables/form/input.ts +++ b/packages/ui-components/src/composables/form/input.ts @@ -1,4 +1,4 @@ -import { onKeyDown } from '@vueuse/core' +import { useMagicKeys, whenever } from '@vueuse/core' import { OperatingSystem } from '@speckle/shared' import { clientOs, ModifierKeys } from '~~/src/helpers/form/input' import { computed, ref } from 'vue' @@ -9,36 +9,27 @@ import type { Ref } from 'vue' */ export function onKeyboardShortcut( modifiers: ModifierKeys[], - ...args: Parameters + key: string, + callback: () => void ) { - onKeyDown( - args[0], - (e) => { - const isAltOrOpt = e.getModifierState('Alt') - const isCtrlOrCmd = - clientOs === OperatingSystem.Mac - ? e.getModifierState('Meta') - : e.getModifierState('Control') - const isShift = e.getModifierState('Shift') + const keys = useMagicKeys() - for (const modifier of modifiers) { - switch (modifier) { - case ModifierKeys.CtrlOrCmd: - if (!isCtrlOrCmd) return - break - case ModifierKeys.AltOrOpt: - if (!isAltOrOpt) return - break - case ModifierKeys.Shift: - if (!isShift) return - break - } - } + const modifierKeys = modifiers.map((modifier) => { + switch (modifier) { + case ModifierKeys.CtrlOrCmd: + return clientOs === OperatingSystem.Mac ? 'Meta' : 'Control' + case ModifierKeys.AltOrOpt: + return 'Alt' + case ModifierKeys.Shift: + return 'Shift' + default: + return '' + } + }) + + const keyCombination = `${modifierKeys.join('+')}+${key}` - args[1](e) - }, - args[2] - ) + whenever(keys[keyCombination], callback) } /**