diff --git a/js/input/DownUpListener.js b/js/input/DownUpListener.js index 62e26aebc..589614e74 100644 --- a/js/input/DownUpListener.js +++ b/js/input/DownUpListener.js @@ -17,6 +17,7 @@ define( function( require ) { var scenery = require( 'SCENERY/scenery' ); require( 'SCENERY/util/Trail' ); var Input = require( 'SCENERY/input/Input' ); + var Trail = require( 'SCENERY/util/Trail' ); /* * The 'trail' parameter passed to down/upInside/upOutside will end with the node to which this DownUpListener has been added. @@ -45,6 +46,7 @@ define( function( require ) { this.downCurrentTarget = null; // 'up' is handled via a pointer lister, which will have null currentTarget, so save the 'down' currentTarget this.downTrail = null; this.pointer = null; + this.interrupted = false; // this listener gets added to the pointer on a 'down' this.downListener = { @@ -109,7 +111,7 @@ define( function( require ) { var trailUnderPointer = event.trail; // TODO: consider changing this so that it just does a hit check and ignores anything in front? - var isInside = trailUnderPointer.isExtensionOf( this.downTrail, true ); + var isInside = trailUnderPointer.isExtensionOf( this.downTrail, true ) && !this.interrupted; if ( isInside && this.options.upInside ) { this.options.upInside( event, this.downTrail ); @@ -134,6 +136,23 @@ define( function( require ) { this.buttonDown( event ); }, + // Called when input is interrupted on this listener, see https://github.com/phetsims/scenery/issues/218 + interrupt: function() { + if ( this.isDown ) { + this.interrupted = true; + + // We create a synthetic event here, as there is no available event here. + this.buttonUp( { + // Empty trail, so that it for-sure isn't under our downTrail (guaranteeing that isInside will be false). + trail: new Trail(), + currentTarget: this.downCurrentTarget, + pointer: this.pointer + } ); + + this.interrupted = false; + } + }, + // When enter/space pressed for this node, trigger a button down keydown: function( event ) { var keyCode = event.domEvent.keyCode; diff --git a/js/input/SimpleDragHandler.js b/js/input/SimpleDragHandler.js index 99c330089..463f8c0db 100644 --- a/js/input/SimpleDragHandler.js +++ b/js/input/SimpleDragHandler.js @@ -43,6 +43,7 @@ define( function( require ) { this.lastDragPoint = null; // the location of the drag at the previous event (so we can calculate a delta) this.startTransformMatrix = null; // the node's transform at the start of the drag, so we can reset on a touch cancel this.mouseButton = undefined; // tracks which mouse button was pressed, so we can handle that specifically + this.interrupted = false; // whether the last input was interrupted (available during endDrag) // TODO: consider mouse buttons as separate pointers? // if an ancestor is transformed, pin our node @@ -98,7 +99,7 @@ define( function( require ) { // mouse/touch move move: function( event ) { if ( !self.dragging ) { return; } - + assert && assert( event.pointer === self.pointer, 'Wrong pointer in move' ); var globalDelta = self.pointer.point.minus( self.lastDragPoint ); @@ -177,6 +178,21 @@ define( function( require ) { this.pointer = null; }, + // Called when input is interrupted on this listener, see https://github.com/phetsims/scenery/issues/218 + interrupt: function() { + if ( this.dragging ) { + this.interrupted = true; + + // We create a synthetic event here, as there is no available event here. + this.endDrag( { + pointer: this.pointer, + currentTarget: this.node + } ); + + this.interrupted = false; + } + }, + tryToSnag: function( event ) { // don't allow drag attempts that use the wrong mouse button (-1 indicates any mouse button works) if ( event.pointer.isMouse && event.domEvent && this.options.mouseButton !== event.domEvent.button && this.options.mouseButton !== -1 ) {