[improvement] better comma control for pointer (#2568)

This PR fixes a few bugs with the "comma as pointer" feature.

In tldraw, the `,` key can be used as a replacement for "pointer down"
and "pointer up". This is most useful on laptops with trackpads that
make dragging inconvenient. (See
https://github.com/tldraw/tldraw/issues/2550).

Previously, the canvas had to be focused in order for the comma key to
work. If you clicked on a menu item and then pressed comma, it would not
product a pointer event until you first clicked on the canvas. This is
now fixed by moving the listener out of the `useDocumentEvents` and into
`useKeyboardShortcuts`.

### Change Type

- [x] `minor` — New feature

### Test Plan

1. Click the canvas.
2. Use the comma key to control pointer down / up.
3. Click a shape tool on the toolbar.
4. Move your mouse over the canvas.
5. Press the comma key. It should produce a dot / shape / etc

### Release Notes

- Improve comma key as a replacement for pointer down / pointer up.
pull/2569/head
Steve Ruiz 2024-01-21 14:09:05 +00:00 zatwierdzone przez GitHub
rodzic e848768e18
commit 6fde34fafd
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
2 zmienionych plików z 69 dodań i 51 usunięć

Wyświetl plik

@ -1,6 +1,6 @@
import { useValue } from '@tldraw/state'
import { useEffect } from 'react'
import { TLKeyboardEventInfo, TLPointerEventInfo } from '../editor/types/event-types'
import { TLKeyboardEventInfo } from '../editor/types/event-types'
import { preventDefault } from '../utils/dom'
import { useContainer } from './useContainer'
import { useEditor } from './useEditor'
@ -93,33 +93,12 @@ export function useDocumentEvents() {
break
}
case ',': {
// todo: extract to extension
// This seems very fragile; the comma key here is used to send pointer events,
// but that means it also needs to know about pen mode, hovered ids, etc.
if (!isFocusingInput()) {
preventDefault(e)
if (!editor.inputs.keys.has('Comma')) {
const { x, y, z } = editor.inputs.currentScreenPoint
editor.inputs.keys.add('Comma')
const info: TLPointerEventInfo = {
type: 'pointer',
name: 'pointer_down',
point: { x, y, z },
shiftKey: e.shiftKey,
altKey: e.altKey,
ctrlKey: e.metaKey || e.ctrlKey,
pointerId: 0,
button: 0,
isPen: editor.getInstanceState().isPenMode,
target: 'canvas',
}
editor.dispatch(info)
return
}
}
break
// this was moved to useKeyBoardShortcuts; it's possible
// that the comma key is pressed when the container is not
// focused, for example when the user has just interacted
// with the toolbar. We need to handle it on the window
// (ofc ensuring it's a correct time for a shortcut)
return
}
case 'Escape': {
// In certain browsers, pressing escape while in full screen mode
@ -178,29 +157,8 @@ export function useDocumentEvents() {
return
}
// Use the , key to send pointer events
if (e.key === ',') {
if (document.activeElement?.ELEMENT_NODE) preventDefault(e)
if (editor.inputs.keys.has(e.code)) {
const { x, y, z } = editor.inputs.currentScreenPoint
editor.inputs.keys.delete(e.code)
const info: TLPointerEventInfo = {
type: 'pointer',
name: 'pointer_up',
point: { x, y, z },
shiftKey: e.shiftKey,
altKey: e.altKey,
ctrlKey: e.metaKey || e.ctrlKey,
pointerId: 0,
button: 0,
isPen: editor.getInstanceState().isPenMode,
target: 'canvas',
}
editor.dispatch(info)
return
}
return
}
const info: TLKeyboardEventInfo = {

Wyświetl plik

@ -1,4 +1,4 @@
import { preventDefault, useEditor, useValue } from '@tldraw/editor'
import { TLPointerEventInfo, preventDefault, useEditor, useValue } from '@tldraw/editor'
import hotkeys from 'hotkeys-js'
import { useEffect } from 'react'
import { useActions } from './useActions'
@ -34,6 +34,14 @@ export function useKeyboardShortcuts() {
hotkeys(keys, { element: container, scope: editor.store.id }, callback)
}
const hotUp = (keys: string, callback: (event: KeyboardEvent) => void) => {
hotkeys(
keys,
{ element: container, keyup: true, keydown: false, scope: editor.store.id },
callback
)
}
// Add hotkeys for actions and tools.
// Except those that in SKIP_KBDS!
const areShortcutsDisabled = () =>
@ -65,6 +73,58 @@ export function useKeyboardShortcuts() {
})
}
hot(',', (e) => {
// Skip if shortcuts are disabled
if (areShortcutsDisabled()) return
// Don't press again if already pressed
if (editor.inputs.keys.has('Comma')) return
preventDefault(e) // prevent whatever would normally happen
container.focus() // Focus if not already focused
editor.inputs.keys.add('Comma')
const { x, y, z } = editor.inputs.currentScreenPoint
const info: TLPointerEventInfo = {
type: 'pointer',
name: 'pointer_down',
point: { x, y, z },
shiftKey: e.shiftKey,
altKey: e.altKey,
ctrlKey: e.metaKey || e.ctrlKey,
pointerId: 0,
button: 0,
isPen: editor.getInstanceState().isPenMode,
target: 'canvas',
}
editor.dispatch(info)
})
hotUp(',', (e) => {
if (areShortcutsDisabled()) return
if (!editor.inputs.keys.has('Comma')) return
editor.inputs.keys.delete('Comma')
const { x, y, z } = editor.inputs.currentScreenPoint
const info: TLPointerEventInfo = {
type: 'pointer',
name: 'pointer_up',
point: { x, y, z },
shiftKey: e.shiftKey,
altKey: e.altKey,
ctrlKey: e.metaKey || e.ctrlKey,
pointerId: 0,
button: 0,
isPen: editor.getInstanceState().isPenMode,
target: 'canvas',
}
editor.dispatch(info)
})
return () => {
hotkeys.deleteScope(editor.store.id)
}