From 3e5e687b9506455e9e4f7b86d5285e01e8c63889 Mon Sep 17 00:00:00 2001 From: Jesse Date: Thu, 25 Apr 2024 10:37:10 -0400 Subject: [PATCH] Update usages of KeyboardListener and KeyboardDragListener after changes from https://github.com/phetsims/scenery/issues/1570 --- js/BicyclePumpNode.ts | 4 +- js/ConductivityTesterNode.ts | 6 +-- js/FaucetNode.ts | 2 +- js/MeasuringTapeNode.ts | 2 +- js/accessibility/GrabDragInteraction.js | 49 ++++++++++--------- .../view/GroupSortInteractionView.ts | 6 +-- js/buttons/PlayControlButton.ts | 16 +++--- js/buttons/ResetAllButton.ts | 10 ++-- js/demo/components/demoRichDragListeners.ts | 4 +- js/keypad/Keypad.ts | 30 ++++++++---- js/keypad/KeypadDialog.ts | 4 +- 11 files changed, 71 insertions(+), 62 deletions(-) diff --git a/js/BicyclePumpNode.ts b/js/BicyclePumpNode.ts index a18d9a8e..9bb2b200 100644 --- a/js/BicyclePumpNode.ts +++ b/js/BicyclePumpNode.ts @@ -325,8 +325,8 @@ export default class BicyclePumpNode extends Node { keyboardDragDirection: 'upDown', dragSpeed: 200, shiftDragSpeed: 50, - drag: ( vectorDelta: Vector2 ) => { - const handlePosition = Utils.clamp( this.pumpHandleNode.centerY + vectorDelta.y, minHandleYOffset, maxHandleYOffset ); + drag: ( event, listener ) => { + const handlePosition = Utils.clamp( this.pumpHandleNode.centerY + listener.vectorDelta.y, minHandleYOffset, maxHandleYOffset ); this.dragDelegate.handleDrag( handlePosition ); }, tandem: options.tandem.createTandem( 'keyboardDragListener' ) diff --git a/js/ConductivityTesterNode.ts b/js/ConductivityTesterNode.ts index d11251c0..90ef1456 100644 --- a/js/ConductivityTesterNode.ts +++ b/js/ConductivityTesterNode.ts @@ -230,18 +230,18 @@ export default class ConductivityTesterNode extends Node { // Keyboard drag listener for probes, see https://github.com/phetsims/acid-base-solutions/issues/208 const probeKeyboardDragListener = new KeyboardDragListener( combineOptions( { transform: options.modelViewTransform, - drag: vectorDelta => { + drag: ( event, listener ) => { // probes move together const y = positionProperty.value.y; - const yPositiveProbe = positiveProbePositionProperty.value.y + vectorDelta.y; + const yPositiveProbe = positiveProbePositionProperty.value.y + listener.vectorDelta.y; const yPositiveProbeConstrained = options.probeDragYRange ? Utils.clamp( yPositiveProbe, y + options.probeDragYRange.min, y + options.probeDragYRange.max ) : yPositiveProbe; positiveProbePositionProperty.value = new Vector2( positiveProbePositionProperty.value.x, yPositiveProbeConstrained ); - const yNegativeProbe = negativeProbePositionProperty.value.y + vectorDelta.y; + const yNegativeProbe = negativeProbePositionProperty.value.y + listener.vectorDelta.y; const yNegativeProbeConstrained = options.probeDragYRange ? Utils.clamp( yNegativeProbe, y + options.probeDragYRange.min, y + options.probeDragYRange.max ) : yNegativeProbe; diff --git a/js/FaucetNode.ts b/js/FaucetNode.ts index e117b129..9d5d9688 100644 --- a/js/FaucetNode.ts +++ b/js/FaucetNode.ts @@ -289,7 +289,7 @@ export default class FaucetNode extends AccessibleSlider( Node, 0 ) { // Keyboard support for tap-to-dispense and setting the flow rate to zero. const keyboardListener = new KeyboardListener( { keys: [ 'enter', 'space', '0' ], - callback: ( event, keysPressed ) => { + fire: ( event, keysPressed ) => { if ( options.tapToDispenseEnabled && [ 'enter', 'space' ].includes( keysPressed ) ) { // stop the previous timeout before running a new dispense diff --git a/js/MeasuringTapeNode.ts b/js/MeasuringTapeNode.ts index cc7588c9..1aa24b8c 100644 --- a/js/MeasuringTapeNode.ts +++ b/js/MeasuringTapeNode.ts @@ -399,7 +399,7 @@ class MeasuringTapeNode extends Node { transform: this.modelViewTransformProperty, dragBoundsProperty: this.dragBoundsProperty, start: baseStart, - drag: handleTipOnBaseDrag, + drag: ( event, listener ) => { handleTipOnBaseDrag( listener.vectorDelta ); }, end: baseEnd }, options.baseKeyboardDragListenerOptions ) ); this.baseImage.addInputListener( baseKeyboardDragListener ); diff --git a/js/accessibility/GrabDragInteraction.js b/js/accessibility/GrabDragInteraction.js index dc57d4a6..e8b009ae 100644 --- a/js/accessibility/GrabDragInteraction.js +++ b/js/accessibility/GrabDragInteraction.js @@ -56,7 +56,7 @@ import assertHasProperties from '../../../phet-core/js/assertHasProperties.js'; import getGlobal from '../../../phet-core/js/getGlobal.js'; import merge from '../../../phet-core/js/merge.js'; import StringUtils from '../../../phetcommon/js/util/StringUtils.js'; -import { HighlightFromNode, HighlightPath, KeyboardListener, KeyboardUtils, Node, PDOMPeer, PressListener, Voicing } from '../../../scenery/js/imports.js'; +import { HighlightFromNode, HighlightPath, KeyboardListener, Node, PDOMPeer, PressListener, Voicing } from '../../../scenery/js/imports.js'; import Tandem from '../../../tandem/js/Tandem.js'; import AriaLiveAnnouncer from '../../../utterance-queue/js/AriaLiveAnnouncer.js'; import ResponsePacket from '../../../utterance-queue/js/ResponsePacket.js'; @@ -484,28 +484,28 @@ class GrabDragInteraction extends EnabledComponent { // @private - keep track of all listeners to swap out grab/drag functionalities this.listenersForGrabState = options.listenersForGrabState.concat( grabButtonListener ); - const dragDivListener = new KeyboardListener( { - keys: [ 'enter', 'space', 'escape' ], - listenerFireTrigger: 'both', - callback: ( event, keysPressed, listener ) => { - if ( listener.keysDown && keysPressed === 'enter' ) { + const dragDivDownListener = new KeyboardListener( { + keys: [ 'enter' ], + fire: () => { - // set a guard to make sure the key press from enter doesn't fire future listeners, therefore - // "clicking" the grab button also on this key press. - guardKeyPressFromDraggable = true; - this.releaseDraggable(); - } - else if ( !listener.keysDown && keysPressed === 'space' || keysPressed === 'escape' ) { + // set a guard to make sure the key press from enter doesn't fire future listeners, therefore + // "clicking" the grab button also on this key press. + guardKeyPressFromDraggable = true; + this.releaseDraggable(); + } + } ); - // Release on keyup of spacebar so that we don't pick up the draggable again when we release the spacebar - // and trigger a click event - escape could be added to either keyup or keydown listeners - if ( KeyboardUtils.isAnyKeyEvent( event.domEvent, [ KeyboardUtils.KEY_SPACE, KeyboardUtils.KEY_ESCAPE ] ) ) { - this.releaseDraggable(); - } + const dragDivUpListener = new KeyboardListener( { + keys: [ 'space', 'escape' ], + fireOnDown: false, + fire: () => { - // if successfully dragged, then make the cue node invisible - this.updateVisibilityForCues(); - } + // Release on keyup for spacebar so that we don't pick up the draggable again when we release the spacebar + // and trigger a click event - escape could be added to either keyup or keydown listeners + this.releaseDraggable(); + + // if successfully dragged, then make the cue node invisible + this.updateVisibilityForCues(); }, // release when focus is lost @@ -516,7 +516,11 @@ class GrabDragInteraction extends EnabledComponent { } ); // @private - this.listenersForDragState = options.listenersForDragState.concat( [ dragDivListener, keyboardDragListener ] ); + this.listenersForDragState = options.listenersForDragState.concat( [ + dragDivDownListener, + dragDivUpListener, + keyboardDragListener + ] ); // @private - from non-PDOM pointer events, change representations in the PDOM - necessary for accessible tech that // uses pointer events like iOS VoiceOver. The above listeners manage input from the PDOM. @@ -573,7 +577,8 @@ class GrabDragInteraction extends EnabledComponent { this.removeInputListeners( this.listenersForDragState ); } - dragDivListener.dispose(); + dragDivDownListener.dispose(); + dragDivUpListener.dispose(); this.grabFocusHighlight.highlightChangedEmitter.removeListener( onFocusHighlightChange ); this.grabInteractiveHighlight.highlightChangedEmitter.removeListener( onInteractiveHighlightChange ); diff --git a/js/accessibility/group-sort/view/GroupSortInteractionView.ts b/js/accessibility/group-sort/view/GroupSortInteractionView.ts index 24d474e6..aac03d8c 100644 --- a/js/accessibility/group-sort/view/GroupSortInteractionView.ts +++ b/js/accessibility/group-sort/view/GroupSortInteractionView.ts @@ -269,7 +269,7 @@ export default class GroupSortInteractionView const grabReleaseKeyboardListener = new KeyboardListener( { fireOnHold: true, keys: [ 'enter', 'space', 'escape' ], - callback: ( event, keysPressed ) => { + fire: ( event, keysPressed ) => { if ( this.model.enabled && selectedGroupItemProperty.value !== null ) { // Do the "Grab/release" action to switch to sorting or selecting @@ -290,7 +290,7 @@ export default class GroupSortInteractionView const deltaKeyboardListener = new KeyboardListener( { fireOnHold: true, keys: sortingKeys, - callback: ( event, keysPressed ) => { + fire: ( event, keysPressed ) => { if ( selectedGroupItemProperty.value !== null ) { @@ -329,7 +329,7 @@ export default class GroupSortInteractionView const numbersKeyboardListener = new KeyboardListener( { fireOnHold: true, keys: [ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' ], - callback: ( event, keysPressed ) => { + fire: ( event, keysPressed ) => { if ( selectedGroupItemProperty.value !== null && isGroupItemKeyboardGrabbedProperty.value && isSingleDigit( keysPressed ) ) { diff --git a/js/buttons/PlayControlButton.ts b/js/buttons/PlayControlButton.ts index 393e4916..7c6c63e6 100644 --- a/js/buttons/PlayControlButton.ts +++ b/js/buttons/PlayControlButton.ts @@ -9,7 +9,7 @@ import Property from '../../../axon/js/Property.js'; import optionize from '../../../phet-core/js/optionize.js'; -import { Circle, KeyboardListener, Node, Path, PDOMValueType } from '../../../scenery/js/imports.js'; +import { Circle, KeyboardListener, Node, OneKeyStroke, Path, PDOMValueType } from '../../../scenery/js/imports.js'; import BooleanRoundToggleButton, { BooleanRoundToggleButtonOptions } from '../../../sun/js/buttons/BooleanRoundToggleButton.js'; import TSoundPlayer from '../../../tambo/js/TSoundPlayer.js'; import pauseSoundPlayer from '../../../tambo/js/shared-sound-players/pauseSoundPlayer.js'; @@ -113,20 +113,17 @@ export default class PlayControlButton extends BooleanRoundToggleButton { isPlayingProperty.link( isPlayingListener ); // a listener that toggles the isPlayingProperty with hotkey Alt+K, regardless of where focus is in the document - const keys = [ 'alt+k' ] as const; - let globalKeyboardListener: KeyboardListener | null = null; + let globalKeyboardListener: KeyboardListener | null = null; if ( options.includeGlobalHotkey && phet.chipper.queryParameters.supportsInteractiveDescription ) { - globalKeyboardListener = new KeyboardListener( { - keys: keys, - global: true, - listenerFireTrigger: 'up', - callback: () => { + globalKeyboardListener = KeyboardListener.createGlobal( this, { + keys: [ 'alt+k' ] as const, + fireOnDown: false, + fire: () => { isPlayingProperty.set( !isPlayingProperty.get() ); const soundPlayer = isPlayingProperty.get() ? options.valueOnSoundPlayer : options.valueOffSoundPlayer; if ( soundPlayer ) { soundPlayer.play(); } } } ); - this.addInputListener( globalKeyboardListener ); } this.disposePlayStopButton = () => { @@ -134,7 +131,6 @@ export default class PlayControlButton extends BooleanRoundToggleButton { isPlayingProperty.unlink( isPlayingListener ); } if ( globalKeyboardListener ) { - this.removeInputListener( globalKeyboardListener ); globalKeyboardListener.dispose(); } }; diff --git a/js/buttons/ResetAllButton.ts b/js/buttons/ResetAllButton.ts index 7cea74f3..6573aee8 100644 --- a/js/buttons/ResetAllButton.ts +++ b/js/buttons/ResetAllButton.ts @@ -119,15 +119,13 @@ export default class ResetAllButton extends ResetButton { } ); } ); - const keyboardListener = new KeyboardListener( { + const keyboardListener = KeyboardListener.createGlobal( this, { keys: [ 'alt+r' ], - callback: () => this.pdomClick(), - global: true, + fire: () => this.pdomClick(), // fires on up because the listener will often call interruptSubtreeInput (interrupting this keyboard listener) - listenerFireTrigger: 'up' + fireOnDown: false } ); - this.addInputListener( keyboardListener ); // Add a listener that will set and clear the static flag that signals when a reset all is in progress. const flagSettingListener = ( isFiring : boolean ) => { @@ -136,7 +134,7 @@ export default class ResetAllButton extends ResetButton { this.pushButtonModel.isFiringProperty.lazyLink( flagSettingListener ); this.disposeResetAllButton = () => { - this.removeInputListener( keyboardListener ); + keyboardListener.dispose(); ariaEnabledOnFirePerUtteranceQueueMap.clear(); this.pushButtonModel.isFiringProperty.unlink( flagSettingListener ); }; diff --git a/js/demo/components/demoRichDragListeners.ts b/js/demo/components/demoRichDragListeners.ts index ea137221..90634367 100644 --- a/js/demo/components/demoRichDragListeners.ts +++ b/js/demo/components/demoRichDragListeners.ts @@ -52,8 +52,8 @@ export default function demoRichDragListeners( layoutBounds: Bounds2 ): Node { richKeyboardDragListenerRectangle.addInputListener( new RichKeyboardDragListener( { dragBoundsProperty: dragBoundsProperty, - drag: delta => { - richKeyboardDragListenerRectangle.translate( delta ); + drag: ( event, listener ) => { + richKeyboardDragListenerRectangle.translate( listener.vectorDelta ); } } ) ); diff --git a/js/keypad/Keypad.ts b/js/keypad/Keypad.ts index 44202475..3615555a 100644 --- a/js/keypad/Keypad.ts +++ b/js/keypad/Keypad.ts @@ -8,9 +8,9 @@ */ import merge from '../../../phet-core/js/merge.js'; -import optionize, { combineOptions } from '../../../phet-core/js/optionize.js'; -import type { OneKeyStroke } from '../../../scenery/js/imports.js'; -import { Font, KeyboardListener, KeyboardListenerOptions, Node, NodeOptions, Text, TPaint } from '../../../scenery/js/imports.js'; +import optionize from '../../../phet-core/js/optionize.js'; +import type { KeyboardListenerOptions, OneKeyStroke } from '../../../scenery/js/imports.js'; +import { Font, KeyboardListener, Node, NodeOptions, Text, TPaint } from '../../../scenery/js/imports.js'; import RectangularPushButton from '../../../sun/js/buttons/RectangularPushButton.js'; import Tandem from '../../../tandem/js/Tandem.js'; import BackspaceIcon from '../BackspaceIcon.js'; @@ -22,7 +22,6 @@ import NumberAccumulator, { NumberAccumulatorOptions } from './NumberAccumulator import AbstractKeyAccumulator from './AbstractKeyAccumulator.js'; import ReadOnlyProperty from '../../../axon/js/ReadOnlyProperty.js'; import PickRequired from '../../../phet-core/js/types/PickRequired.js'; -import StrictOmit from '../../../phet-core/js/types/StrictOmit.js'; // constants const DEFAULT_BUTTON_WIDTH = 35; @@ -68,7 +67,10 @@ type SelfOptions = { // Options passed to NumberAccumulator, ignored if options.accumulator is provided accumulatorOptions?: NumberAccumulatorOptions | null; - keyboardListenerOptions?: StrictOmit, 'callback' | 'keys'>; + // If true, the KeyboardListener for this KeyPad will be "global" and key presses will control the Keypad regardless + // of where focus is in the document. Only have one Keypad at a time that can receive global keyboard input + // (an assertion will be thrown). + useGlobalKeyboardListener?: boolean; }; export type KeypadOptions = SelfOptions & NodeOptions; @@ -113,7 +115,7 @@ class Keypad extends Node { tagName: 'div', ariaLabel: 'Keypad', focusable: true, - keyboardListenerOptions: {} + useGlobalKeyboardListener: false }, providedOptions ); super(); @@ -200,18 +202,26 @@ class Keypad extends Node { } } - const keyboardListener = new KeyboardListener( combineOptions>( options.keyboardListenerOptions, { + const keyboardListenerOptions: KeyboardListenerOptions = { // @ts-expect-error - TypeScript doesn't know that keyboardKeys has keys of type OneKeyStroke. Type assertion // works but is incompatible with eslint. keys: Object.keys( keyboardKeys ), - callback: ( sceneryEvent, keysPressed ) => { + fire: ( sceneryEvent, keysPressed ) => { const keyObject = keyboardKeys[ keysPressed ]; this.keyAccumulator.handleKeyPressed( keyObject!.identifier ); } - } ) ); + }; + + let keyboardListener: KeyboardListener; + if ( options.useGlobalKeyboardListener ) { + keyboardListener = KeyboardListener.createGlobal( this, keyboardListenerOptions ); + } + else { + keyboardListener = new KeyboardListener( keyboardListenerOptions ); + this.addInputListener( keyboardListener ); + } - this.addInputListener( keyboardListener ); this.disposeEmitter.addListener( () => keyboardListener.dispose() ); this.stringProperty.link( string => { diff --git a/js/keypad/KeypadDialog.ts b/js/keypad/KeypadDialog.ts index a38e9f20..ac3a5e9f 100644 --- a/js/keypad/KeypadDialog.ts +++ b/js/keypad/KeypadDialog.ts @@ -180,8 +180,8 @@ class KeypadDialog extends Dialog { const submitFromKeypadListener = new KeyboardListener( { keys: [ 'space', 'enter' ], - listenerFireTrigger: 'up', - callback: () => this.submitEdit() + fireOnDown: false, + fire: () => this.submitEdit() } ); this.keypad.addInputListener( submitFromKeypadListener );