Skip to content

Commit

Permalink
fix(fe2): keyboard shortcuts in viewer don't work (#2389)
Browse files Browse the repository at this point in the history
* 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 a508fcf.

* Revert "Revert changes to input.ts"

This reverts commit c47300d.

* Revert "refactor: simplify control shortcuts"

This reverts commit a867d6e.

* Fix broken space

* Refactor Viewer Controls and Keyboard Shortcuts

* Fix keyboard shortcut mapping to handle string keys correctly

* refactor: string enum

* remove filters shortcut
  • Loading branch information
andrewwallacespeckle authored Jul 10, 2024
1 parent 0b2ca9a commit d12e800
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 62 deletions.
95 changes: 61 additions & 34 deletions packages/frontend-2/components/viewer/Controls.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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<HTMLDivElement>)

Expand Down Expand Up @@ -364,28 +374,72 @@ const {
diff: { enabled }
} = useInjectedViewerInterfaceState()

const map: Record<ViewerKeyboardActions, [ModifierKeys[], string]> = {
[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) => {
Expand All @@ -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 })
Expand Down
47 changes: 19 additions & 28 deletions packages/ui-components/src/composables/form/input.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -9,36 +9,27 @@ import type { Ref } from 'vue'
*/
export function onKeyboardShortcut(
modifiers: ModifierKeys[],
...args: Parameters<typeof onKeyDown>
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)
}

/**
Expand Down

0 comments on commit d12e800

Please sign in to comment.