From 307b1bfdbcb7f93c94a40ff80316cf739b3ecdbf Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Mon, 21 Sep 2015 20:09:29 -0700 Subject: [PATCH] Only pointers which are down should be tracked. This change ensures that we only store the results of a hit test on the initial pointer down event. Moreover, we perform new hit tests each time a hovering pointer moves. This is important to ensure correct behavior of input devices which can hover, such as mice. Previously the first hover movement after releasing a mouse button would cause a new pointer state to be recorded along with hit test results for wherever the pointer happened to be which caused the following pointer down event to be delivered to the wrong place. Fixes issue #1189. --- .../lib/src/rendering/sky_binding.dart | 57 +++++++++++-------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/packages/flutter/lib/src/rendering/sky_binding.dart b/packages/flutter/lib/src/rendering/sky_binding.dart index 971de74428..02a89bd6c5 100644 --- a/packages/flutter/lib/src/rendering/sky_binding.dart +++ b/packages/flutter/lib/src/rendering/sky_binding.dart @@ -105,37 +105,44 @@ class SkyBinding extends HitTestTarget { /// A router that routes all pointer events received from the engine final PointerRouter pointerRouter = new PointerRouter(); + /// State for all pointers which are currently down. + /// We do not track the state of hovering pointers because we need + /// to hit-test them on each movement. Map _stateForPointer = new Map(); - _PointerState _createStateForPointer(sky.PointerEvent event, Point position) { - HitTestResult result = hitTest(position); - _PointerState state = new _PointerState(result: result, lastPosition: position); - _stateForPointer[event.pointer] = state; - return state; - } - - _PointerState _getOrCreateStateForPointer(event, position) { - _PointerState state = _stateForPointer[event.pointer]; - if (state == null) - state = _createStateForPointer(event, position); - return state; - } - void _handlePointerEvent(sky.PointerEvent event) { Point position = new Point(event.x, event.y); - _PointerState state = _getOrCreateStateForPointer(event, position); - - if (event.type == 'pointerup' || event.type == 'pointercancel') { - if (_hammingWeight(event.buttons) <= 1) - _stateForPointer.remove(event.pointer); + _PointerState state = _stateForPointer[event.pointer]; + switch (event.type) { + case 'pointerdown': + if (state == null) { + state = new _PointerState(result: hitTest(position), lastPosition: position); + _stateForPointer[event.pointer] = state; + } + break; + case 'pointermove': + if (state == null) { + // The pointer is hovering, ignore it for now since we don't + // know what to do with it yet. + return; + } + event.dx = position.x - state.lastPosition.x; + event.dy = position.y - state.lastPosition.y; + state.lastPosition = position; + break; + case 'pointerup': + case 'pointercancel': + if (state == null) { + // This seems to be a spurious event. Ignore it. + return; + } + // Only remove the pointer state when the last button has been released. + if (_hammingWeight(event.buttons) <= 1) + _stateForPointer.remove(event.pointer); + break; } - - event.dx = position.x - state.lastPosition.x; - event.dy = position.y - state.lastPosition.y; - state.lastPosition = position; - - return dispatchEvent(event, state.result); + dispatchEvent(event, state.result); } /// Determine which [HitTestTarget] objects are located at a given position