Skip to content

Commit

Permalink
Update usages of KeyboardListener and KeyboardDragListener after chan…
Browse files Browse the repository at this point in the history
  • Loading branch information
jessegreenberg committed Apr 25, 2024
1 parent ae9ceb6 commit 3e5e687
Show file tree
Hide file tree
Showing 11 changed files with 71 additions and 62 deletions.
4 changes: 2 additions & 2 deletions js/BicyclePumpNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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' )
Expand Down
6 changes: 3 additions & 3 deletions js/ConductivityTesterNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<KeyboardDragListenerOptions>( {
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;
Expand Down
2 changes: 1 addition & 1 deletion js/FaucetNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion js/MeasuringTapeNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Expand Down
49 changes: 27 additions & 22 deletions js/accessibility/GrabDragInteraction.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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
Expand All @@ -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.
Expand Down Expand Up @@ -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 );
Expand Down
6 changes: 3 additions & 3 deletions js/accessibility/group-sort/view/GroupSortInteractionView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ export default class GroupSortInteractionView<ItemModel, ItemNode extends Node>
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
Expand All @@ -290,7 +290,7 @@ export default class GroupSortInteractionView<ItemModel, ItemNode extends Node>
const deltaKeyboardListener = new KeyboardListener( {
fireOnHold: true,
keys: sortingKeys,
callback: ( event, keysPressed ) => {
fire: ( event, keysPressed ) => {

if ( selectedGroupItemProperty.value !== null ) {

Expand Down Expand Up @@ -329,7 +329,7 @@ export default class GroupSortInteractionView<ItemModel, ItemNode extends Node>
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 ) ) {

Expand Down
16 changes: 6 additions & 10 deletions js/buttons/PlayControlButton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -113,28 +113,24 @@ 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<typeof keys> | null = null;
let globalKeyboardListener: KeyboardListener<OneKeyStroke[]> | 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 = () => {
if ( isPlayingProperty.hasListener( isPlayingListener ) ) {
isPlayingProperty.unlink( isPlayingListener );
}
if ( globalKeyboardListener ) {
this.removeInputListener( globalKeyboardListener );
globalKeyboardListener.dispose();
}
};
Expand Down
10 changes: 4 additions & 6 deletions js/buttons/ResetAllButton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 ) => {
Expand All @@ -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 );
};
Expand Down
4 changes: 2 additions & 2 deletions js/demo/components/demoRichDragListeners.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
}
} ) );

Expand Down
30 changes: 20 additions & 10 deletions js/keypad/Keypad.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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;
Expand Down Expand Up @@ -68,7 +67,10 @@ type SelfOptions = {
// Options passed to NumberAccumulator, ignored if options.accumulator is provided
accumulatorOptions?: NumberAccumulatorOptions | null;

keyboardListenerOptions?: StrictOmit<KeyboardListenerOptions<OneKeyStroke[]>, '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;
Expand Down Expand Up @@ -113,7 +115,7 @@ class Keypad extends Node {
tagName: 'div',
ariaLabel: 'Keypad',
focusable: true,
keyboardListenerOptions: {}
useGlobalKeyboardListener: false
}, providedOptions );

super();
Expand Down Expand Up @@ -200,18 +202,26 @@ class Keypad extends Node {
}
}

const keyboardListener = new KeyboardListener( combineOptions<KeyboardListenerOptions<OneKeyStroke[]>>( options.keyboardListenerOptions, {
const keyboardListenerOptions: KeyboardListenerOptions<OneKeyStroke[]> = {

// @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<OneKeyStroke[]>;
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 => {
Expand Down
4 changes: 2 additions & 2 deletions js/keypad/KeypadDialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 );

Expand Down

0 comments on commit 3e5e687

Please sign in to comment.