mirror of
https://github.com/scratchfoundation/Gestouch.git
synced 2024-11-27 09:45:38 -05:00
Massive refactoring of input layer
This commit is contained in:
parent
e0a892654d
commit
e9132fec9b
18 changed files with 653 additions and 740 deletions
86
src/org/gestouch/core/Gestouch.as
Normal file
86
src/org/gestouch/core/Gestouch.as
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
package org.gestouch.core
|
||||||
|
{
|
||||||
|
import flash.display.DisplayObject;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Pavel fljot
|
||||||
|
*/
|
||||||
|
public class Gestouch
|
||||||
|
{
|
||||||
|
{
|
||||||
|
initClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** @private */
|
||||||
|
private static var _inputAdapter:IInputAdapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static function get inputAdapter():IInputAdapter
|
||||||
|
{
|
||||||
|
return _inputAdapter;
|
||||||
|
}
|
||||||
|
public static function set inputAdapter(value:IInputAdapter):void
|
||||||
|
{
|
||||||
|
if (_inputAdapter == value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_inputAdapter = value;
|
||||||
|
if (inputAdapter)
|
||||||
|
{
|
||||||
|
inputAdapter.touchesManager = touchesManager;
|
||||||
|
inputAdapter.init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static var _touchesManager:TouchesManager;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static function get touchesManager():TouchesManager
|
||||||
|
{
|
||||||
|
return _touchesManager ||= new TouchesManager(gesturesManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static var _gesturesManager:GesturesManager;
|
||||||
|
public static function get gesturesManager():GesturesManager
|
||||||
|
{
|
||||||
|
return _gesturesManager ||= new GesturesManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static function addDisplayListAdapter(targetClass:Class, adapter:IDisplayListAdapter):void
|
||||||
|
{
|
||||||
|
gesturesManager.gestouch_internal::addDisplayListAdapter(targetClass, adapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static function addTouchHitTester(hitTester:ITouchHitTester, priority:int = 0):void
|
||||||
|
{
|
||||||
|
touchesManager.gestouch_internal::addTouchHitTester(hitTester, priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static function removeTouchHitTester(hitTester:ITouchHitTester):void
|
||||||
|
{
|
||||||
|
touchesManager.gestouch_internal::removeInputAdapter(hitTester);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// public static function getTouches(target:Object = null):Array
|
||||||
|
// {
|
||||||
|
// return touchesManager.getTouches(target);
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
private static function initClass():void
|
||||||
|
{
|
||||||
|
addDisplayListAdapter(DisplayObject, new DisplayListAdapter());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,32 +1,24 @@
|
||||||
package org.gestouch.core
|
package org.gestouch.core
|
||||||
{
|
{
|
||||||
import flash.utils.getQualifiedClassName;
|
|
||||||
import org.gestouch.gestures.Gesture;
|
import org.gestouch.gestures.Gesture;
|
||||||
import org.gestouch.input.MouseInputAdapter;
|
import org.gestouch.input.NativeInputAdapter;
|
||||||
import org.gestouch.input.TouchInputAdapter;
|
|
||||||
|
|
||||||
import flash.display.DisplayObject;
|
import flash.display.DisplayObject;
|
||||||
import flash.display.Shape;
|
import flash.display.Shape;
|
||||||
import flash.display.Stage;
|
import flash.display.Stage;
|
||||||
import flash.events.Event;
|
import flash.events.Event;
|
||||||
import flash.events.IEventDispatcher;
|
import flash.events.IEventDispatcher;
|
||||||
import flash.ui.Multitouch;
|
|
||||||
import flash.utils.Dictionary;
|
import flash.utils.Dictionary;
|
||||||
|
import flash.utils.getQualifiedClassName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Pavel fljot
|
* @author Pavel fljot
|
||||||
*/
|
*/
|
||||||
public class GesturesManager implements IGesturesManager
|
public class GesturesManager
|
||||||
{
|
{
|
||||||
public static var initDefaultInputAdapter:Boolean = true;
|
protected const _displayListAdaptersMap:Dictionary = new Dictionary();
|
||||||
private static var _instance:IGesturesManager;
|
|
||||||
private static var _allowInstantiation:Boolean;
|
|
||||||
|
|
||||||
protected const _touchesManager:ITouchesManager = TouchesManager.getInstance();
|
|
||||||
protected const _frameTickerShape:Shape = new Shape();
|
protected const _frameTickerShape:Shape = new Shape();
|
||||||
protected var _inputAdapters:Vector.<IInputAdapter> = new Vector.<IInputAdapter>();
|
protected var _inputAdapters:Vector.<IInputAdapter> = new Vector.<IInputAdapter>();
|
||||||
protected var _displayListAdaptersMap:Dictionary = new Dictionary();
|
|
||||||
protected var _stage:Stage;
|
|
||||||
protected var _gesturesMap:Dictionary = new Dictionary(true);
|
protected var _gesturesMap:Dictionary = new Dictionary(true);
|
||||||
protected var _gesturesForTouchMap:Dictionary = new Dictionary();
|
protected var _gesturesForTouchMap:Dictionary = new Dictionary();
|
||||||
protected var _gesturesForTargetMap:Dictionary = new Dictionary(true);
|
protected var _gesturesForTargetMap:Dictionary = new Dictionary(true);
|
||||||
|
@ -34,120 +26,36 @@ package org.gestouch.core
|
||||||
protected var _dirtyGesturesLength:uint = 0;
|
protected var _dirtyGesturesLength:uint = 0;
|
||||||
protected var _dirtyGesturesMap:Dictionary = new Dictionary(true);
|
protected var _dirtyGesturesMap:Dictionary = new Dictionary(true);
|
||||||
|
|
||||||
|
use namespace gestouch_internal;
|
||||||
|
|
||||||
|
|
||||||
public function GesturesManager()
|
public function GesturesManager()
|
||||||
{
|
{
|
||||||
if (Object(this).constructor == GesturesManager && !_allowInstantiation)
|
|
||||||
{
|
|
||||||
throw new Error("Do not instantiate GesturesManager directly.");
|
|
||||||
}
|
|
||||||
|
|
||||||
_touchesManager.gesturesManager = this;
|
|
||||||
_displayListAdaptersMap[DisplayObject] = new DisplayListAdapter();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function get inputAdapters():Vector.<IInputAdapter>
|
gestouch_internal function addDisplayListAdapter(targetClass:Class, adapter:IDisplayListAdapter):void
|
||||||
{
|
|
||||||
return _inputAdapters.concat();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static function setImplementation(value:IGesturesManager):void
|
|
||||||
{
|
|
||||||
if (!value)
|
|
||||||
{
|
|
||||||
throw new ArgumentError("value cannot be null.");
|
|
||||||
}
|
|
||||||
if (_instance)
|
|
||||||
{
|
|
||||||
throw new Error("Instance of GesturesManager is already created. If you want to have own implementation of single GesturesManager instace, you should set it earlier.");
|
|
||||||
}
|
|
||||||
_instance = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static function getInstance():IGesturesManager
|
|
||||||
{
|
|
||||||
if (!_instance)
|
|
||||||
{
|
|
||||||
_allowInstantiation = true;
|
|
||||||
_instance = new GesturesManager();
|
|
||||||
_allowInstantiation = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public function addInputAdapter(inputAdapter:IInputAdapter):void
|
|
||||||
{
|
|
||||||
if (!inputAdapter)
|
|
||||||
{
|
|
||||||
throw new Error("Input adapter must be non null.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_inputAdapters.indexOf(inputAdapter) > -1)
|
|
||||||
return;//TODO: throw Error or ignore?
|
|
||||||
|
|
||||||
_inputAdapters.push(inputAdapter);
|
|
||||||
inputAdapter.touchesManager = _touchesManager;
|
|
||||||
inputAdapter.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function removeInputAdapter(inputAdapter:IInputAdapter, dispose:Boolean = true):void
|
|
||||||
{
|
|
||||||
if (!inputAdapter)
|
|
||||||
{
|
|
||||||
throw new Error("Input adapter must be non null.");
|
|
||||||
}
|
|
||||||
var index:int = _inputAdapters.indexOf(inputAdapter);
|
|
||||||
if (index == -1)
|
|
||||||
{
|
|
||||||
throw new Error("This input manager is not registered.");
|
|
||||||
}
|
|
||||||
|
|
||||||
_inputAdapters.splice(index, 1);
|
|
||||||
if (dispose)
|
|
||||||
{
|
|
||||||
inputAdapter.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function addDisplayListAdapter(targetClass:Class, adapter:IDisplayListAdapter):void
|
|
||||||
{
|
{
|
||||||
if (!targetClass || !adapter)
|
if (!targetClass || !adapter)
|
||||||
{
|
{
|
||||||
throw new Error("Argument error: both arguments required.");
|
throw new Error("Argument error: both arguments required.");
|
||||||
}
|
}
|
||||||
|
|
||||||
_displayListAdaptersMap[targetClass] = adapter;
|
_displayListAdaptersMap[targetClass] = adapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// Private methods
|
// Private methods
|
||||||
//
|
//
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
protected function installStage(stage:Stage):void
|
protected function installDefaultInputAdapter(stage:Stage):void
|
||||||
{
|
{
|
||||||
_stage = stage;
|
Gestouch.inputAdapter ||= new NativeInputAdapter(stage);
|
||||||
|
|
||||||
if (Multitouch.supportsTouchEvents)
|
|
||||||
{
|
|
||||||
addInputAdapter(new TouchInputAdapter(stage));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
addInputAdapter(new MouseInputAdapter(stage));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -201,14 +109,14 @@ package org.gestouch.core
|
||||||
|
|
||||||
_gesturesMap[gesture] = true;
|
_gesturesMap[gesture] = true;
|
||||||
|
|
||||||
if (GesturesManager.initDefaultInputAdapter)
|
if (!Gestouch.inputAdapter)
|
||||||
{
|
{
|
||||||
var targetAsDO:DisplayObject = target as DisplayObject;
|
var targetAsDO:DisplayObject = target as DisplayObject;
|
||||||
if (targetAsDO)
|
if (targetAsDO)
|
||||||
{
|
{
|
||||||
if (!_stage && targetAsDO.stage)
|
if (targetAsDO.stage)
|
||||||
{
|
{
|
||||||
installStage(targetAsDO.stage);
|
installDefaultInputAdapter(targetAsDO.stage);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -274,8 +182,8 @@ package org.gestouch.core
|
||||||
otherGesture.state == GestureState.POSSIBLE)
|
otherGesture.state == GestureState.POSSIBLE)
|
||||||
{
|
{
|
||||||
if (otherTarget == target ||
|
if (otherTarget == target ||
|
||||||
gesture.gestouch_internal::targetAdapter.contains(otherTarget) ||
|
gesture.targetAdapter.contains(otherTarget) ||
|
||||||
otherGesture.gestouch_internal::targetAdapter.contains(target)
|
otherGesture.targetAdapter.contains(target)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
var gestureDelegate:IGestureDelegate = gesture.delegate;
|
var gestureDelegate:IGestureDelegate = gesture.delegate;
|
||||||
|
@ -286,7 +194,7 @@ package org.gestouch.core
|
||||||
(!gestureDelegate || !gestureDelegate.gesturesShouldRecognizeSimultaneously(gesture, otherGesture)) &&
|
(!gestureDelegate || !gestureDelegate.gesturesShouldRecognizeSimultaneously(gesture, otherGesture)) &&
|
||||||
(!otherGestureDelegate || !otherGestureDelegate.gesturesShouldRecognizeSimultaneously(otherGesture, gesture)))
|
(!otherGestureDelegate || !otherGestureDelegate.gesturesShouldRecognizeSimultaneously(otherGesture, gesture)))
|
||||||
{
|
{
|
||||||
otherGesture.gestouch_internal::setState_internal(GestureState.FAILED);
|
otherGesture.setState_internal(GestureState.FAILED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -362,7 +270,7 @@ package org.gestouch.core
|
||||||
// Check for state because previous (i+1) gesture may already abort current (i) one
|
// Check for state because previous (i+1) gesture may already abort current (i) one
|
||||||
if (gesture.state != GestureState.FAILED)
|
if (gesture.state != GestureState.FAILED)
|
||||||
{
|
{
|
||||||
gesture.gestouch_internal::touchBeginHandler(touch);
|
gesture.touchBeginHandler(touch);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -388,7 +296,7 @@ package org.gestouch.core
|
||||||
|
|
||||||
if (gesture.state != GestureState.FAILED && gesture.isTrackingTouch(touch.id))
|
if (gesture.state != GestureState.FAILED && gesture.isTrackingTouch(touch.id))
|
||||||
{
|
{
|
||||||
gesture.gestouch_internal::touchMoveHandler(touch);
|
gesture.touchMoveHandler(touch);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -415,7 +323,7 @@ package org.gestouch.core
|
||||||
|
|
||||||
if (gesture.state != GestureState.FAILED && gesture.isTrackingTouch(touch.id))
|
if (gesture.state != GestureState.FAILED && gesture.isTrackingTouch(touch.id))
|
||||||
{
|
{
|
||||||
gesture.gestouch_internal::touchEndHandler(touch);
|
gesture.touchEndHandler(touch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -441,9 +349,9 @@ package org.gestouch.core
|
||||||
{
|
{
|
||||||
var target:DisplayObject = event.target as DisplayObject;
|
var target:DisplayObject = event.target as DisplayObject;
|
||||||
target.removeEventListener(Event.ADDED_TO_STAGE, gestureTarget_addedToStageHandler);
|
target.removeEventListener(Event.ADDED_TO_STAGE, gestureTarget_addedToStageHandler);
|
||||||
if (!_stage && GesturesManager.initDefaultInputAdapter)
|
if (!Gestouch.inputAdapter)
|
||||||
{
|
{
|
||||||
installStage(target.stage);
|
installDefaultInputAdapter(target.stage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
package org.gestouch.core
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The class that implements this interface must also
|
|
||||||
* implement next methods under gestouch_internal namespace:
|
|
||||||
*
|
|
||||||
* function addGesture(gesture:Gesture):void;
|
|
||||||
* function removeGesture(gesture:Gesture):void;
|
|
||||||
* function scheduleGestureStateReset(gesture:Gesture):void;
|
|
||||||
* function onGestureRecognized(gesture:Gesture):void;
|
|
||||||
*/
|
|
||||||
public interface IGesturesManager
|
|
||||||
{
|
|
||||||
function addInputAdapter(inputAdapter:IInputAdapter):void;
|
|
||||||
function removeInputAdapter(inputAdapter:IInputAdapter, dispose:Boolean = true):void;
|
|
||||||
|
|
||||||
function addDisplayListAdapter(targetClass:Class, adapter:IDisplayListAdapter):void;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,9 +5,14 @@ package org.gestouch.core
|
||||||
*/
|
*/
|
||||||
public interface IInputAdapter
|
public interface IInputAdapter
|
||||||
{
|
{
|
||||||
function set touchesManager(value:ITouchesManager):void;
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function set touchesManager(value:TouchesManager):void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when input adapter is set.
|
||||||
|
*/
|
||||||
function init():void;
|
function init():void;
|
||||||
function dispose():void;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
14
src/org/gestouch/core/ITouchHitTester.as
Normal file
14
src/org/gestouch/core/ITouchHitTester.as
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
package org.gestouch.core
|
||||||
|
{
|
||||||
|
import flash.display.InteractiveObject;
|
||||||
|
import flash.geom.Point;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Pavel fljot
|
||||||
|
*/
|
||||||
|
public interface ITouchHitTester
|
||||||
|
{
|
||||||
|
function hitTest(point:Point, nativeTarget:InteractiveObject):Object;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,18 +0,0 @@
|
||||||
package org.gestouch.core
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @author Pavel fljot
|
|
||||||
*/
|
|
||||||
public interface ITouchesManager
|
|
||||||
{
|
|
||||||
function set gesturesManager(value:IGesturesManager):void;
|
|
||||||
|
|
||||||
function get activeTouchesCount():uint;
|
|
||||||
|
|
||||||
function onTouchBegin(inputAdapter:IInputAdapter, touchID:uint, x:Number, y:Number, target:Object):void;
|
|
||||||
function onTouchMove(inputAdapter:IInputAdapter, touchID:uint, x:Number, y:Number):void;
|
|
||||||
function onTouchEnd(inputAdapter:IInputAdapter, touchID:uint, x:Number, y:Number):void;
|
|
||||||
|
|
||||||
function onInputAdapterDispose(inputAdapter:IInputAdapter):void;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -26,6 +26,8 @@ package org.gestouch.core
|
||||||
|
|
||||||
// public var lastMove:Point;
|
// public var lastMove:Point;
|
||||||
|
|
||||||
|
use namespace gestouch_internal;
|
||||||
|
|
||||||
|
|
||||||
public function Touch(id:uint = 0)
|
public function Touch(id:uint = 0)
|
||||||
{
|
{
|
||||||
|
@ -38,9 +40,9 @@ package org.gestouch.core
|
||||||
{
|
{
|
||||||
return _location.clone();
|
return _location.clone();
|
||||||
}
|
}
|
||||||
gestouch_internal function setLocation(value:Point, time:uint):void
|
gestouch_internal function setLocation(x:Number, y:Number, time:uint):void
|
||||||
{
|
{
|
||||||
_location = value;
|
_location = new Point(x, y);
|
||||||
_beginLocation = _location.clone();
|
_beginLocation = _location.clone();
|
||||||
_previousLocation = _location.clone();
|
_previousLocation = _location.clone();
|
||||||
|
|
||||||
|
@ -59,7 +61,7 @@ package org.gestouch.core
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gestouch_internal::setLocation(new Point(x, y), time);
|
setLocation(x, y, time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,32 +1,30 @@
|
||||||
package org.gestouch.core
|
package org.gestouch.core
|
||||||
{
|
{
|
||||||
|
import flash.display.InteractiveObject;
|
||||||
|
import flash.display.Stage;
|
||||||
import flash.geom.Point;
|
import flash.geom.Point;
|
||||||
import flash.utils.Dictionary;
|
import flash.utils.Dictionary;
|
||||||
import flash.utils.getTimer;
|
import flash.utils.getTimer;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Pavel fljot
|
* @author Pavel fljot
|
||||||
*/
|
*/
|
||||||
public class TouchesManager implements ITouchesManager
|
public class TouchesManager
|
||||||
{
|
{
|
||||||
private static var _instance:ITouchesManager;
|
protected var _gesturesManager:GesturesManager;
|
||||||
private static var _allowInstantiation:Boolean;
|
|
||||||
|
|
||||||
protected var _touchesMap:Object = {};
|
protected var _touchesMap:Object = {};
|
||||||
|
protected var _hitTesters:Vector.<ITouchHitTester> = new Vector.<ITouchHitTester>();
|
||||||
|
protected var _hitTesterPrioritiesMap:Dictionary = new Dictionary(true);
|
||||||
|
|
||||||
|
use namespace gestouch_internal;
|
||||||
|
|
||||||
|
|
||||||
public function TouchesManager()
|
public function TouchesManager(gesturesManager:GesturesManager)
|
||||||
{
|
{
|
||||||
if (Object(this).constructor == TouchesManager && !_allowInstantiation)
|
_gesturesManager = gesturesManager;
|
||||||
{
|
|
||||||
throw new Error("Do not instantiate TouchesManager directly.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
addTouchHitTester(new DefaultTouchHitTester());
|
||||||
protected var _gesturesManager:IGesturesManager;
|
|
||||||
public function set gesturesManager(value:IGesturesManager):void
|
|
||||||
{
|
|
||||||
_gesturesManager = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,132 +35,167 @@ package org.gestouch.core
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static function setImplementation(value:ITouchesManager):void
|
public function getTouches(target:Object = null):Array
|
||||||
{
|
{
|
||||||
if (!value)
|
const touches:Array = [];
|
||||||
|
if (!target || target is Stage)
|
||||||
{
|
{
|
||||||
throw new ArgumentError("value cannot be null.");
|
// return all touches
|
||||||
}
|
var i:uint = 0;
|
||||||
if (_instance)
|
for each (var touch:Touch in _touchesMap)
|
||||||
{
|
{
|
||||||
throw new Error("Instance of TouchesManager is already created. If you want to have own implementation of single TouchesManager instace, you should set it earlier.");
|
touches[i++] = touch;
|
||||||
}
|
|
||||||
_instance = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static function getInstance():ITouchesManager
|
|
||||||
{
|
|
||||||
if (!_instance)
|
|
||||||
{
|
|
||||||
_allowInstantiation = true;
|
|
||||||
_instance = new TouchesManager();
|
|
||||||
_allowInstantiation = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function onTouchBegin(inputAdapter:IInputAdapter, touchID:uint, x:Number, y:Number, target:Object):void
|
|
||||||
{
|
|
||||||
var overlappingTouches:Dictionary = _touchesMap[touchID] as Dictionary;
|
|
||||||
if (overlappingTouches)
|
|
||||||
{
|
|
||||||
// In case we listen to both TouchEvents and MouseEvents, one of them will come first
|
|
||||||
// (right now looks like MouseEvent dispatches first, but who know what Adobe will
|
|
||||||
// do tomorrow). This check is to filter out the one comes second.
|
|
||||||
for each (var registeredTouch:Touch in overlappingTouches)
|
|
||||||
{
|
|
||||||
if (registeredTouch.target == target)
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
overlappingTouches = _touchesMap[touchID] = new Dictionary();
|
//TODO
|
||||||
_activeTouchesCount++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var touch:Touch = createTouch();
|
return touches;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gestouch_internal function addTouchHitTester(touchHitTester:ITouchHitTester, priority:int = 0):void
|
||||||
|
{
|
||||||
|
if (!touchHitTester)
|
||||||
|
{
|
||||||
|
throw new ArgumentError("Argument must be non null.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_hitTesters.indexOf(touchHitTester) == -1)
|
||||||
|
{
|
||||||
|
_hitTesters.push(touchHitTester);
|
||||||
|
}
|
||||||
|
|
||||||
|
_hitTesterPrioritiesMap[touchHitTester] = priority;
|
||||||
|
// Sort hit testers using their priorities
|
||||||
|
_hitTesters.sort(hitTestersSorter);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gestouch_internal function removeInputAdapter(touchHitTester:ITouchHitTester):void
|
||||||
|
{
|
||||||
|
if (!touchHitTester)
|
||||||
|
{
|
||||||
|
throw new ArgumentError("Argument must be non null.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var index:int = _hitTesters.indexOf(touchHitTester);
|
||||||
|
if (index == -1)
|
||||||
|
{
|
||||||
|
throw new Error("This touchHitTester is not registered.");
|
||||||
|
}
|
||||||
|
|
||||||
|
_hitTesters.splice(index, 1);
|
||||||
|
delete _hitTesterPrioritiesMap[touchHitTester];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gestouch_internal function onTouchBegin(touchID:uint, x:Number, y:Number, nativeTarget:InteractiveObject = null):Boolean
|
||||||
|
{
|
||||||
|
if (touchID in _touchesMap)
|
||||||
|
return false;// touch with specified ID is already registered and being tracked
|
||||||
|
|
||||||
|
const location:Point = new Point(x, y);
|
||||||
|
|
||||||
|
for each (var registeredTouch:Touch in _touchesMap)
|
||||||
|
{
|
||||||
|
// Check if touch at the same location exists.
|
||||||
|
// In case we listen to both TouchEvents and MouseEvents, one of them will come first
|
||||||
|
// (right now looks like MouseEvent dispatched first, but who know what Adobe will
|
||||||
|
// do tomorrow). This check helps to filter out the one comes after.
|
||||||
|
|
||||||
|
// NB! According to the tests with some IR multitouch frame and Windows computer
|
||||||
|
// TouchEvent comes first, but the following MouseEvent has slightly offset location
|
||||||
|
// (1px both axis). That is why Point#distance() used instead of Point#equals()
|
||||||
|
|
||||||
|
if (Point.distance(registeredTouch.location, location) < 2)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const touch:Touch = createTouch();
|
||||||
touch.id = touchID;
|
touch.id = touchID;
|
||||||
touch.target = target;
|
|
||||||
touch.gestouch_internal::setLocation(new Point(x, y), getTimer());
|
|
||||||
overlappingTouches[inputAdapter] = touch;
|
|
||||||
|
|
||||||
_gesturesManager.gestouch_internal::onTouchBegin(touch);
|
var target:Object;
|
||||||
|
var altTarget:Object;
|
||||||
|
for each (var hitTester:ITouchHitTester in _hitTesters)
|
||||||
|
{
|
||||||
|
target = hitTester.hitTest(location, nativeTarget);
|
||||||
|
if (target)
|
||||||
|
{
|
||||||
|
if ((target is Stage))
|
||||||
|
{
|
||||||
|
// NB! Target is flash.display::Stage is a special case. If it is true, we want
|
||||||
|
// to give a try to a lower-priority (Stage3D) hit-testers.
|
||||||
|
altTarget = target;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
|
||||||
public function onTouchMove(inputAdapter:IInputAdapter, touchID:uint, x:Number, y:Number):void
|
|
||||||
{
|
{
|
||||||
var overlappingTouches:Dictionary = _touchesMap[touchID] as Dictionary;
|
// We found a target.
|
||||||
if (!overlappingTouches)
|
|
||||||
return;//this touch isn't properly registered.. some fake
|
|
||||||
|
|
||||||
var touch:Touch = overlappingTouches[inputAdapter] as Touch;
|
|
||||||
if (!touch)
|
|
||||||
return;//touch with this ID from this inputAdapter is not registered. see workaround reason above
|
|
||||||
|
|
||||||
touch.gestouch_internal::updateLocation(x, y, getTimer());
|
|
||||||
|
|
||||||
_gesturesManager.gestouch_internal::onTouchMove(touch);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function onTouchEnd(inputAdapter:IInputAdapter, touchID:uint, x:Number, y:Number):void
|
|
||||||
{
|
|
||||||
var overlappingTouches:Dictionary = _touchesMap[touchID] as Dictionary;
|
|
||||||
if (!overlappingTouches)
|
|
||||||
return;//this touch isn't properly registered.. some fake
|
|
||||||
|
|
||||||
var touch:Touch = overlappingTouches[inputAdapter] as Touch;
|
|
||||||
if (!touch)
|
|
||||||
return;//touch with this ID from this inputAdapter is not registered. see workaround reason above
|
|
||||||
|
|
||||||
touch.gestouch_internal::updateLocation(x, y, getTimer());
|
|
||||||
|
|
||||||
delete overlappingTouches[inputAdapter];
|
|
||||||
var empty:Boolean = true;
|
|
||||||
for (var key:Object in overlappingTouches)
|
|
||||||
{
|
|
||||||
empty = false;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (empty)
|
}
|
||||||
|
}
|
||||||
|
if (!target && !altTarget)
|
||||||
{
|
{
|
||||||
|
throw new Error("Not touch target found (hit test)." +
|
||||||
|
"Something is wrong, at least flash.display::Stage should be found." +
|
||||||
|
"See Gestouch#addTouchHitTester() and Gestouch#inputAdapter.");
|
||||||
|
}
|
||||||
|
|
||||||
|
touch.target = target || altTarget;
|
||||||
|
touch.setLocation(x, y, getTimer());
|
||||||
|
|
||||||
|
_touchesMap[touchID] = touch;
|
||||||
|
_activeTouchesCount++;
|
||||||
|
|
||||||
|
_gesturesManager.onTouchBegin(touch);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gestouch_internal function onTouchMove(touchID:uint, x:Number, y:Number):void
|
||||||
|
{
|
||||||
|
const touch:Touch = _touchesMap[touchID] as Touch;
|
||||||
|
if (!touch)
|
||||||
|
return;// touch with specified ID isn't registered
|
||||||
|
|
||||||
|
touch.updateLocation(x, y, getTimer());
|
||||||
|
|
||||||
|
_gesturesManager.onTouchMove(touch);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gestouch_internal function onTouchEnd(touchID:uint, x:Number, y:Number):void
|
||||||
|
{
|
||||||
|
const touch:Touch = _touchesMap[touchID] as Touch;
|
||||||
|
if (!touch)
|
||||||
|
return;// touch with specified ID isn't registered
|
||||||
|
|
||||||
|
touch.updateLocation(x, y, getTimer());
|
||||||
|
|
||||||
delete _touchesMap[touchID];
|
delete _touchesMap[touchID];
|
||||||
_activeTouchesCount--;
|
_activeTouchesCount--;
|
||||||
}
|
|
||||||
|
|
||||||
_gesturesManager.gestouch_internal::onTouchEnd(touch);
|
_gesturesManager.onTouchEnd(touch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
gestouch_internal function onTouchCancel(touchID:uint, x:Number, y:Number):void
|
||||||
* Must be called by IInputAdapter#dispose() to remove all the touches invoked by it.
|
|
||||||
*/
|
|
||||||
public function onInputAdapterDispose(inputAdapter:IInputAdapter):void
|
|
||||||
{
|
|
||||||
for (var touchID:Object in _touchesMap)
|
|
||||||
{
|
|
||||||
var overlappingTouches:Dictionary = _touchesMap[touchID] as Dictionary;
|
|
||||||
if (overlappingTouches[inputAdapter])
|
|
||||||
{
|
|
||||||
delete overlappingTouches[inputAdapter];
|
|
||||||
var empty:Boolean = true;
|
|
||||||
for (var key:Object in overlappingTouches)
|
|
||||||
{
|
|
||||||
empty = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (empty)
|
|
||||||
{
|
{
|
||||||
|
const touch:Touch = _touchesMap[touchID] as Touch;
|
||||||
|
if (!touch)
|
||||||
|
return;// touch with specified ID isn't registered
|
||||||
|
|
||||||
|
touch.updateLocation(x, y, getTimer());
|
||||||
|
|
||||||
delete _touchesMap[touchID];
|
delete _touchesMap[touchID];
|
||||||
_activeTouchesCount--;
|
_activeTouchesCount--;
|
||||||
}
|
|
||||||
}
|
_gesturesManager.onTouchCancel(touch);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -171,5 +204,38 @@ package org.gestouch.core
|
||||||
//TODO: pool
|
//TODO: pool
|
||||||
return new Touch();
|
return new Touch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts from higher priority to lower. Items with the same priority keep the order
|
||||||
|
* of addition, e.g.:
|
||||||
|
* add(a), add(b), add(c, -1), add(d, 1) will be ordered to
|
||||||
|
* d, a, b, c
|
||||||
|
*/
|
||||||
|
protected function hitTestersSorter(x:ITouchHitTester, y:ITouchHitTester):Number
|
||||||
|
{
|
||||||
|
const d:int = int(_hitTesterPrioritiesMap[x]) - int(_hitTesterPrioritiesMap[y]);
|
||||||
|
if (d > 0)
|
||||||
|
return -1;
|
||||||
|
else if (d < 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return _hitTesters.indexOf(x) > _hitTesters.indexOf(y) ? 1 : -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
import flash.geom.Point;
|
||||||
|
import flash.display.InteractiveObject;
|
||||||
|
|
||||||
|
import org.gestouch.core.ITouchHitTester;
|
||||||
|
|
||||||
|
|
||||||
|
class DefaultTouchHitTester implements ITouchHitTester
|
||||||
|
{
|
||||||
|
public function hitTest(point:Point, nativeTarget:InteractiveObject):Object
|
||||||
|
{
|
||||||
|
return nativeTarget;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package org.gestouch.extensions.starling
|
package org.gestouch.extensions.starling
|
||||||
{
|
{
|
||||||
|
import starling.core.Starling;
|
||||||
import starling.display.DisplayObject;
|
import starling.display.DisplayObject;
|
||||||
import starling.display.DisplayObjectContainer;
|
import starling.display.DisplayObjectContainer;
|
||||||
|
|
||||||
|
@ -14,22 +15,22 @@ package org.gestouch.extensions.starling
|
||||||
*/
|
*/
|
||||||
final public class StarlingDisplayListAdapter implements IDisplayListAdapter
|
final public class StarlingDisplayListAdapter implements IDisplayListAdapter
|
||||||
{
|
{
|
||||||
private var _targetWeekStorage:Dictionary;
|
private var targetWeekStorage:Dictionary;
|
||||||
|
|
||||||
|
|
||||||
public function StarlingDisplayListAdapter(target:DisplayObject = null)
|
public function StarlingDisplayListAdapter(target:DisplayObject = null)
|
||||||
{
|
{
|
||||||
if (target)
|
if (target)
|
||||||
{
|
{
|
||||||
_targetWeekStorage = new Dictionary(true);
|
targetWeekStorage = new Dictionary(true);
|
||||||
_targetWeekStorage[target] = true;
|
targetWeekStorage[target] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function get target():Object
|
public function get target():Object
|
||||||
{
|
{
|
||||||
for (var key:Object in _targetWeekStorage)
|
for (var key:Object in targetWeekStorage)
|
||||||
{
|
{
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
@ -39,6 +40,7 @@ package org.gestouch.extensions.starling
|
||||||
|
|
||||||
public function globalToLocal(point:Point):Point
|
public function globalToLocal(point:Point):Point
|
||||||
{
|
{
|
||||||
|
point = StarlingUtils.adjustGlobalPoint(Starling.current, point);
|
||||||
return (target as DisplayObject).globalToLocal(point);
|
return (target as DisplayObject).globalToLocal(point);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,180 +0,0 @@
|
||||||
package org.gestouch.extensions.starling
|
|
||||||
{
|
|
||||||
import starling.core.Starling;
|
|
||||||
|
|
||||||
import org.gestouch.input.AbstractInputAdapter;
|
|
||||||
|
|
||||||
import flash.events.EventPhase;
|
|
||||||
import flash.events.MouseEvent;
|
|
||||||
import flash.events.TouchEvent;
|
|
||||||
import flash.geom.Point;
|
|
||||||
import flash.ui.Multitouch;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Pavel fljot
|
|
||||||
*/
|
|
||||||
public class StarlingInputAdapter extends AbstractInputAdapter
|
|
||||||
{
|
|
||||||
private static const PRIMARY_TOUCH_POINT_ID:uint = 0;
|
|
||||||
|
|
||||||
protected var _starling:Starling;
|
|
||||||
|
|
||||||
|
|
||||||
public function StarlingInputAdapter(starling:Starling)
|
|
||||||
{
|
|
||||||
super();
|
|
||||||
|
|
||||||
if (!starling)
|
|
||||||
{
|
|
||||||
throw new Error("Argument error.");
|
|
||||||
}
|
|
||||||
|
|
||||||
_starling = starling;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override public function init():void
|
|
||||||
{
|
|
||||||
// We want to begin tracking only those touches that happen on Stage3D layer,
|
|
||||||
// e.g. event.target == nativeStage. That's we don't listen for touch begin
|
|
||||||
// in capture phase (as we do for native display list).
|
|
||||||
if (Multitouch.supportsTouchEvents)
|
|
||||||
{
|
|
||||||
_starling.nativeStage.addEventListener(TouchEvent.TOUCH_BEGIN, touchBeginHandler);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_starling.nativeStage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override public function dispose():void
|
|
||||||
{
|
|
||||||
_starling.nativeStage.removeEventListener(TouchEvent.TOUCH_BEGIN, touchBeginHandler);
|
|
||||||
_starling.nativeStage.removeEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
|
|
||||||
uninstallStageListeners();
|
|
||||||
_starling = null;
|
|
||||||
_touchesManager.onInputAdapterDispose(this);
|
|
||||||
_touchesManager = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected function installStageListeners():void
|
|
||||||
{
|
|
||||||
// Maximum priority to prevent event hijacking
|
|
||||||
if (Multitouch.supportsTouchEvents)
|
|
||||||
{
|
|
||||||
_starling.nativeStage.addEventListener(TouchEvent.TOUCH_MOVE, touchMoveHandler, true, int.MAX_VALUE);
|
|
||||||
_starling.nativeStage.addEventListener(TouchEvent.TOUCH_MOVE, touchMoveHandler, false, int.MAX_VALUE);
|
|
||||||
_starling.nativeStage.addEventListener(TouchEvent.TOUCH_END, touchEndHandler, true, int.MAX_VALUE);
|
|
||||||
_starling.nativeStage.addEventListener(TouchEvent.TOUCH_END, touchEndHandler, false, int.MAX_VALUE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_starling.nativeStage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler, true, int.MAX_VALUE);
|
|
||||||
_starling.nativeStage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler, false, int.MAX_VALUE);
|
|
||||||
_starling.nativeStage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler, true, int.MAX_VALUE);
|
|
||||||
_starling.nativeStage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler, false, int.MAX_VALUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected function uninstallStageListeners():void
|
|
||||||
{
|
|
||||||
_starling.nativeStage.removeEventListener(TouchEvent.TOUCH_MOVE, touchMoveHandler, true);
|
|
||||||
_starling.nativeStage.removeEventListener(TouchEvent.TOUCH_MOVE, touchMoveHandler, false);
|
|
||||||
_starling.nativeStage.removeEventListener(TouchEvent.TOUCH_END, touchEndHandler, true);
|
|
||||||
_starling.nativeStage.removeEventListener(TouchEvent.TOUCH_END, touchEndHandler, false);
|
|
||||||
_starling.nativeStage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler, true);
|
|
||||||
_starling.nativeStage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler, false);
|
|
||||||
_starling.nativeStage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler, true);
|
|
||||||
_starling.nativeStage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected function mouseDownHandler(event:MouseEvent):void
|
|
||||||
{
|
|
||||||
// We ignore event with bubbling phase because it happened on some native InteractiveObject,
|
|
||||||
// which basically hovers Stage3D layer. So we treat it as if Starling wouldn't recieve any input.
|
|
||||||
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var target:Object = _starling.stage.hitTest(new Point(event.stageX, event.stageY), true);
|
|
||||||
_touchesManager.onTouchBegin(this, PRIMARY_TOUCH_POINT_ID, event.stageX, event.stageY, target);
|
|
||||||
|
|
||||||
if (_touchesManager.activeTouchesCount > 0)
|
|
||||||
{
|
|
||||||
installStageListeners();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected function mouseMoveHandler(event:MouseEvent):void
|
|
||||||
{
|
|
||||||
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
|
||||||
return;//we listen in capture or at_target (to catch on empty stage)
|
|
||||||
|
|
||||||
_touchesManager.onTouchMove(this, PRIMARY_TOUCH_POINT_ID, event.stageX, event.stageY);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected function mouseUpHandler(event:MouseEvent):void
|
|
||||||
{
|
|
||||||
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
|
||||||
return;//we listen in capture or at_target (to catch on empty stage)
|
|
||||||
|
|
||||||
_touchesManager.onTouchEnd(this, PRIMARY_TOUCH_POINT_ID, event.stageX, event.stageY);
|
|
||||||
|
|
||||||
if (_touchesManager.activeTouchesCount == 0)
|
|
||||||
{
|
|
||||||
uninstallStageListeners();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected function touchBeginHandler(event:TouchEvent):void
|
|
||||||
{
|
|
||||||
// We ignore event with bubbling phase because it happened on some native InteractiveObject,
|
|
||||||
// which basically hovers Stage3D layer. So we treat it as if Starling wouldn't recieve any input.
|
|
||||||
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var target:Object = _starling.stage.hitTest(new Point(event.stageX, event.stageY), true);
|
|
||||||
_touchesManager.onTouchBegin(this, event.touchPointID, event.stageX, event.stageY, target);
|
|
||||||
|
|
||||||
if (_touchesManager.activeTouchesCount > 0)
|
|
||||||
{
|
|
||||||
installStageListeners();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected function touchMoveHandler(event:TouchEvent):void
|
|
||||||
{
|
|
||||||
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
|
||||||
return;//we listen in capture or at_target (to catch on empty stage)
|
|
||||||
|
|
||||||
_touchesManager.onTouchMove(this, event.touchPointID, event.stageX, event.stageY);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected function touchEndHandler(event:TouchEvent):void
|
|
||||||
{
|
|
||||||
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
|
||||||
return;//we listen in capture or at_target (to catch on empty stage)
|
|
||||||
|
|
||||||
_touchesManager.onTouchEnd(this, event.touchPointID, event.stageX, event.stageY);
|
|
||||||
|
|
||||||
if (_touchesManager.activeTouchesCount == 0)
|
|
||||||
{
|
|
||||||
uninstallStageListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: handle cancelled touch:
|
|
||||||
// if (event.hasOwnProperty("isTouchPointCanceled") && event["isTouchPointCanceled"] && ...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
package org.gestouch.extensions.starling
|
||||||
|
{
|
||||||
|
import starling.core.Starling;
|
||||||
|
|
||||||
|
import org.gestouch.core.ITouchHitTester;
|
||||||
|
|
||||||
|
import flash.display.InteractiveObject;
|
||||||
|
import flash.geom.Point;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Pavel fljot
|
||||||
|
*/
|
||||||
|
final public class StarlingTouchHitTester implements ITouchHitTester
|
||||||
|
{
|
||||||
|
private var starling:Starling;
|
||||||
|
|
||||||
|
|
||||||
|
public function StarlingTouchHitTester(starling:Starling)
|
||||||
|
{
|
||||||
|
if (!starling)
|
||||||
|
{
|
||||||
|
throw ArgumentError("Missing starling argument.");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.starling = starling;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function hitTest(point:Point, nativeTarget:InteractiveObject):Object
|
||||||
|
{
|
||||||
|
point = StarlingUtils.adjustGlobalPoint(starling, point);
|
||||||
|
return starling.stage.hitTest(point, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
38
src/org/gestouch/extensions/starling/StarlingUtils.as
Normal file
38
src/org/gestouch/extensions/starling/StarlingUtils.as
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
package org.gestouch.extensions.starling
|
||||||
|
{
|
||||||
|
import starling.display.Stage;
|
||||||
|
import starling.core.Starling;
|
||||||
|
|
||||||
|
import flash.geom.Point;
|
||||||
|
import flash.geom.Rectangle;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Pavel fljot
|
||||||
|
*/
|
||||||
|
final public class StarlingUtils
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Transforms real global point (in the scope of flash.display::Stage) into
|
||||||
|
* starling stage "global" coordinates.
|
||||||
|
*/
|
||||||
|
public static function adjustGlobalPoint(starling:Starling, point:Point):Point
|
||||||
|
{
|
||||||
|
const vp:Rectangle = starling.viewPort;
|
||||||
|
const stStage:Stage = starling.stage;
|
||||||
|
|
||||||
|
if (vp.x != 0 || vp.y != 0 ||
|
||||||
|
stStage.stageWidth != vp.width || stStage.stageHeight != vp.height)
|
||||||
|
{
|
||||||
|
point = point.clone();
|
||||||
|
|
||||||
|
// Same transformation they do in Starling
|
||||||
|
// WTF!? https://github.com/PrimaryFeather/Starling-Framework/issues/72
|
||||||
|
point.x = stStage.stageWidth * (point.x - vp.x) / vp.width;
|
||||||
|
point.y = stStage.stageHeight * (point.y - vp.y) / vp.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
return point;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
package org.gestouch.gestures
|
package org.gestouch.gestures
|
||||||
{
|
{
|
||||||
|
import org.gestouch.core.Gestouch;
|
||||||
import org.gestouch.core.GestureState;
|
import org.gestouch.core.GestureState;
|
||||||
import org.gestouch.core.GesturesManager;
|
import org.gestouch.core.GesturesManager;
|
||||||
import org.gestouch.core.IGestureDelegate;
|
import org.gestouch.core.IGestureDelegate;
|
||||||
import org.gestouch.core.IGestureTargetAdapter;
|
import org.gestouch.core.IGestureTargetAdapter;
|
||||||
import org.gestouch.core.IGesturesManager;
|
|
||||||
import org.gestouch.core.Touch;
|
import org.gestouch.core.Touch;
|
||||||
import org.gestouch.core.gestouch_internal;
|
import org.gestouch.core.gestouch_internal;
|
||||||
import org.gestouch.events.GestureStateEvent;
|
import org.gestouch.events.GestureStateEvent;
|
||||||
|
@ -20,9 +20,6 @@ package org.gestouch.gestures
|
||||||
* Base class for all gestures. Gesture is essentially a detector that tracks touch points
|
* Base class for all gestures. Gesture is essentially a detector that tracks touch points
|
||||||
* in order detect specific gesture motion and form gesture event on target.
|
* in order detect specific gesture motion and form gesture event on target.
|
||||||
*
|
*
|
||||||
* TODO:
|
|
||||||
* -
|
|
||||||
*
|
|
||||||
* @author Pavel fljot
|
* @author Pavel fljot
|
||||||
*/
|
*/
|
||||||
public class Gesture extends EventDispatcher
|
public class Gesture extends EventDispatcher
|
||||||
|
@ -35,7 +32,7 @@ package org.gestouch.gestures
|
||||||
public static const DEFAULT_SLOP:uint = Math.round(20 / 252 * flash.system.Capabilities.screenDPI);
|
public static const DEFAULT_SLOP:uint = Math.round(20 / 252 * flash.system.Capabilities.screenDPI);
|
||||||
|
|
||||||
|
|
||||||
protected const _gesturesManager:IGesturesManager = GesturesManager.getInstance();
|
protected const _gesturesManager:GesturesManager = Gestouch.gesturesManager;
|
||||||
/**
|
/**
|
||||||
* Map (generic object) of tracking touch points, where keys are touch points IDs.
|
* Map (generic object) of tracking touch points, where keys are touch points IDs.
|
||||||
*/
|
*/
|
||||||
|
@ -175,7 +172,6 @@ package org.gestouch.gestures
|
||||||
*/
|
*/
|
||||||
public function get location():Point
|
public function get location():Point
|
||||||
{
|
{
|
||||||
//TODO: to clone or not clone? performance & convention or ...
|
|
||||||
return _location.clone();
|
return _location.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
package org.gestouch.input
|
|
||||||
{
|
|
||||||
import org.gestouch.core.IInputAdapter;
|
|
||||||
import org.gestouch.core.ITouchesManager;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Pavel fljot
|
|
||||||
*/
|
|
||||||
public class AbstractInputAdapter implements IInputAdapter
|
|
||||||
{
|
|
||||||
protected var _touchesManager:ITouchesManager;
|
|
||||||
|
|
||||||
|
|
||||||
public function AbstractInputAdapter()
|
|
||||||
{
|
|
||||||
if (Object(this).constructor == AbstractInputAdapter)
|
|
||||||
{
|
|
||||||
throw new Error("This is abstract class and should not be directly instantiated.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function set touchesManager(value:ITouchesManager):void
|
|
||||||
{
|
|
||||||
_touchesManager = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[Abstract]
|
|
||||||
public function init():void
|
|
||||||
{
|
|
||||||
throw new Error("This is abstract method.");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[Abstract]
|
|
||||||
public function dispose():void
|
|
||||||
{
|
|
||||||
throw new Error("This is abstract method.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,103 +0,0 @@
|
||||||
package org.gestouch.input
|
|
||||||
{
|
|
||||||
import flash.display.Stage;
|
|
||||||
import flash.events.EventPhase;
|
|
||||||
import flash.events.MouseEvent;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Pavel fljot
|
|
||||||
*/
|
|
||||||
public class MouseInputAdapter extends AbstractInputAdapter
|
|
||||||
{
|
|
||||||
private static const PRIMARY_TOUCH_POINT_ID:uint = 0;
|
|
||||||
|
|
||||||
protected var _stage:Stage;
|
|
||||||
|
|
||||||
|
|
||||||
public function MouseInputAdapter(stage:Stage)
|
|
||||||
{
|
|
||||||
super();
|
|
||||||
|
|
||||||
if (!stage)
|
|
||||||
{
|
|
||||||
throw new Error("Stage must be not null.");
|
|
||||||
}
|
|
||||||
|
|
||||||
_stage = stage;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override public function init():void
|
|
||||||
{
|
|
||||||
_stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler, true);
|
|
||||||
_stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);// to catch with EventPhase.AT_TARGET
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override public function dispose():void
|
|
||||||
{
|
|
||||||
_stage.removeEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler, true);
|
|
||||||
_stage.removeEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
|
|
||||||
uninstallStageListeners();
|
|
||||||
_touchesManager.onInputAdapterDispose(this);
|
|
||||||
_touchesManager = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected function installStageListeners():void
|
|
||||||
{
|
|
||||||
// Maximum priority to prevent event hijacking
|
|
||||||
_stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler, true, int.MAX_VALUE);
|
|
||||||
_stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler, false, int.MAX_VALUE);
|
|
||||||
_stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler, true, int.MAX_VALUE);
|
|
||||||
_stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler, false, int.MAX_VALUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected function uninstallStageListeners():void
|
|
||||||
{
|
|
||||||
_stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler, true);
|
|
||||||
_stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
|
|
||||||
_stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler, true);
|
|
||||||
_stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected function mouseDownHandler(event:MouseEvent):void
|
|
||||||
{
|
|
||||||
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
|
||||||
return;//we listen in capture or at_target (to catch on empty stage)
|
|
||||||
|
|
||||||
_touchesManager.onTouchBegin(this, PRIMARY_TOUCH_POINT_ID, event.stageX, event.stageY, event.target);
|
|
||||||
|
|
||||||
if (_touchesManager.activeTouchesCount > 0)
|
|
||||||
{
|
|
||||||
installStageListeners();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected function mouseMoveHandler(event:MouseEvent):void
|
|
||||||
{
|
|
||||||
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
|
||||||
return;//we listen in capture or at_target (to catch on empty stage)
|
|
||||||
|
|
||||||
_touchesManager.onTouchMove(this, PRIMARY_TOUCH_POINT_ID, event.stageX, event.stageY);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected function mouseUpHandler(event:MouseEvent):void
|
|
||||||
{
|
|
||||||
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
|
||||||
return;//we listen in capture or at_target (to catch on empty stage)
|
|
||||||
|
|
||||||
_touchesManager.onTouchEnd(this, PRIMARY_TOUCH_POINT_ID, event.stageX, event.stageY);
|
|
||||||
|
|
||||||
if (_touchesManager.activeTouchesCount == 0)
|
|
||||||
{
|
|
||||||
uninstallStageListeners();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
224
src/org/gestouch/input/NativeInputAdapter.as
Normal file
224
src/org/gestouch/input/NativeInputAdapter.as
Normal file
|
@ -0,0 +1,224 @@
|
||||||
|
package org.gestouch.input
|
||||||
|
{
|
||||||
|
import org.gestouch.core.IInputAdapter;
|
||||||
|
import org.gestouch.core.TouchesManager;
|
||||||
|
import org.gestouch.core.gestouch_internal;
|
||||||
|
|
||||||
|
import flash.display.InteractiveObject;
|
||||||
|
import flash.display.Stage;
|
||||||
|
import flash.events.EventPhase;
|
||||||
|
import flash.events.MouseEvent;
|
||||||
|
import flash.events.TouchEvent;
|
||||||
|
import flash.ui.Multitouch;
|
||||||
|
import flash.ui.MultitouchInputMode;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Pavel fljot
|
||||||
|
*/
|
||||||
|
public class NativeInputAdapter implements IInputAdapter
|
||||||
|
{
|
||||||
|
protected static const MOUSE_TOUCH_POINT_ID:uint = 0;
|
||||||
|
|
||||||
|
protected var _stage:Stage;
|
||||||
|
protected var _explicitlyHandleTouchEvents:Boolean;
|
||||||
|
protected var _explicitlyHandleMouseEvents:Boolean;
|
||||||
|
|
||||||
|
use namespace gestouch_internal;
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function NativeInputAdapter(stage:Stage,
|
||||||
|
explicitlyHandleTouchEvents:Boolean = false,
|
||||||
|
explicitlyHandleMouseEvents:Boolean = false)
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
|
||||||
|
if (!stage)
|
||||||
|
{
|
||||||
|
throw new ArgumentError("Stage must be not null.");
|
||||||
|
}
|
||||||
|
|
||||||
|
_stage = stage;
|
||||||
|
|
||||||
|
_explicitlyHandleTouchEvents = explicitlyHandleTouchEvents;
|
||||||
|
_explicitlyHandleMouseEvents = explicitlyHandleMouseEvents;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected var _touchesManager:TouchesManager;
|
||||||
|
public function set touchesManager(value:TouchesManager):void
|
||||||
|
{
|
||||||
|
_touchesManager = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Public methods
|
||||||
|
//
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
public function init():void
|
||||||
|
{
|
||||||
|
if (Multitouch.supportsTouchEvents || _explicitlyHandleTouchEvents)
|
||||||
|
{
|
||||||
|
_stage.addEventListener(TouchEvent.TOUCH_BEGIN, touchBeginHandler, true);
|
||||||
|
_stage.addEventListener(TouchEvent.TOUCH_BEGIN, touchBeginHandler, false);
|
||||||
|
_stage.addEventListener(TouchEvent.TOUCH_MOVE, touchMoveHandler, true);
|
||||||
|
_stage.addEventListener(TouchEvent.TOUCH_MOVE, touchMoveHandler, false);
|
||||||
|
// Maximum priority to prevent event hijacking and loosing the touch
|
||||||
|
_stage.addEventListener(TouchEvent.TOUCH_END, touchEndHandler, true, int.MAX_VALUE);
|
||||||
|
_stage.addEventListener(TouchEvent.TOUCH_END, touchEndHandler, false, int.MAX_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Multitouch.supportsTouchEvents || _explicitlyHandleMouseEvents)
|
||||||
|
{
|
||||||
|
_stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler, true);
|
||||||
|
_stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function onDispose():void
|
||||||
|
{
|
||||||
|
_touchesManager = null;
|
||||||
|
|
||||||
|
_stage.removeEventListener(TouchEvent.TOUCH_BEGIN, touchBeginHandler, true);
|
||||||
|
_stage.removeEventListener(TouchEvent.TOUCH_BEGIN, touchBeginHandler, false);
|
||||||
|
_stage.removeEventListener(TouchEvent.TOUCH_MOVE, touchMoveHandler, true);
|
||||||
|
_stage.removeEventListener(TouchEvent.TOUCH_MOVE, touchMoveHandler, false);
|
||||||
|
_stage.removeEventListener(TouchEvent.TOUCH_END, touchEndHandler, true);
|
||||||
|
_stage.removeEventListener(TouchEvent.TOUCH_END, touchEndHandler, false);
|
||||||
|
|
||||||
|
_stage.removeEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler, true);
|
||||||
|
_stage.removeEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler, false);
|
||||||
|
unstallMouseListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Private methods
|
||||||
|
//
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
protected function installMouseListeners():void
|
||||||
|
{
|
||||||
|
_stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler, true);
|
||||||
|
_stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler, false);
|
||||||
|
// Maximum priority to prevent event hijacking
|
||||||
|
_stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler, true, int.MAX_VALUE);
|
||||||
|
_stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler, false, int.MAX_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected function unstallMouseListeners():void
|
||||||
|
{
|
||||||
|
_stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler, true);
|
||||||
|
_stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler, false);
|
||||||
|
// Maximum priority to prevent event hijacking
|
||||||
|
_stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler, true);
|
||||||
|
_stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Event handlers
|
||||||
|
//
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
protected function touchBeginHandler(event:TouchEvent):void
|
||||||
|
{
|
||||||
|
// We listen in EventPhase.CAPTURE_PHASE or EventPhase.AT_TARGET
|
||||||
|
// (to catch on empty stage) phases only
|
||||||
|
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_touchesManager.onTouchBegin(event.touchPointID, event.stageX, event.stageY, event.target as InteractiveObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected function touchMoveHandler(event:TouchEvent):void
|
||||||
|
{
|
||||||
|
// We listen in EventPhase.CAPTURE_PHASE or EventPhase.AT_TARGET
|
||||||
|
// (to catch on empty stage) phases only
|
||||||
|
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_touchesManager.onTouchMove(event.touchPointID, event.stageX, event.stageY);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected function touchEndHandler(event:TouchEvent):void
|
||||||
|
{
|
||||||
|
// We listen in EventPhase.CAPTURE_PHASE or EventPhase.AT_TARGET
|
||||||
|
// (to catch on empty stage) phases only
|
||||||
|
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (event.hasOwnProperty("isTouchPointCanceled") && event["isTouchPointCanceled"])
|
||||||
|
{
|
||||||
|
_touchesManager.onTouchCancel(event.touchPointID, event.stageX, event.stageY);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_touchesManager.onTouchEnd(event.touchPointID, event.stageX, event.stageY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected function mouseDownHandler(event:MouseEvent):void
|
||||||
|
{
|
||||||
|
// We listen in EventPhase.CAPTURE_PHASE or EventPhase.AT_TARGET
|
||||||
|
// (to catch on empty stage) phases only
|
||||||
|
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const touchAccepted:Boolean = _touchesManager.onTouchBegin(MOUSE_TOUCH_POINT_ID, event.stageX, event.stageY, event.target as InteractiveObject);
|
||||||
|
|
||||||
|
if (touchAccepted)
|
||||||
|
{
|
||||||
|
installMouseListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected function mouseMoveHandler(event:MouseEvent):void
|
||||||
|
{
|
||||||
|
// We listen in EventPhase.CAPTURE_PHASE or EventPhase.AT_TARGET
|
||||||
|
// (to catch on empty stage) phases only
|
||||||
|
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_touchesManager.onTouchMove(MOUSE_TOUCH_POINT_ID, event.stageX, event.stageY);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected function mouseUpHandler(event:MouseEvent):void
|
||||||
|
{
|
||||||
|
// We listen in EventPhase.CAPTURE_PHASE or EventPhase.AT_TARGET
|
||||||
|
// (to catch on empty stage) phases only
|
||||||
|
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_touchesManager.onTouchEnd(MOUSE_TOUCH_POINT_ID, event.stageX, event.stageY);
|
||||||
|
|
||||||
|
if (_touchesManager.activeTouchesCount == 0)
|
||||||
|
{
|
||||||
|
unstallMouseListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,17 +1,33 @@
|
||||||
package org.gestouch.input
|
package org.gestouch.input
|
||||||
{
|
{
|
||||||
import org.gestouch.input.AbstractInputAdapter;
|
import org.gestouch.core.IInputAdapter;
|
||||||
|
import org.gestouch.core.TouchesManager;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* TODO: You can implement your own TUIO Input Adapter (and supply touchesManager with
|
||||||
|
* touch info), but IMHO it is way easier to use NativeInputAdapter and any TUIO library
|
||||||
|
* and manually dispatch native TouchEvents using DisplayObjectContainer#getObjectsUnderPoint()
|
||||||
|
*
|
||||||
|
* @see NativeInputAdapter
|
||||||
|
* @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/DisplayObjectContainer.html#getObjectsUnderPoint() DisplayObjectContainer#getObjectsUnderPoint()
|
||||||
|
*
|
||||||
* @author Pavel fljot
|
* @author Pavel fljot
|
||||||
*/
|
*/
|
||||||
public class TUIOInputAdapter extends AbstractInputAdapter
|
public class TUIOInputAdapter implements IInputAdapter
|
||||||
{
|
{
|
||||||
public function TUIOInputAdapter()
|
public function init():void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function onDispose():void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function set touchesManager(value:TouchesManager):void
|
||||||
{
|
{
|
||||||
super();
|
|
||||||
//TODO
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,117 +0,0 @@
|
||||||
package org.gestouch.input
|
|
||||||
{
|
|
||||||
import flash.display.Stage;
|
|
||||||
import flash.events.EventPhase;
|
|
||||||
import flash.events.TouchEvent;
|
|
||||||
import flash.ui.Multitouch;
|
|
||||||
import flash.ui.MultitouchInputMode;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Pavel fljot
|
|
||||||
*/
|
|
||||||
public class TouchInputAdapter extends AbstractInputAdapter
|
|
||||||
{
|
|
||||||
protected var _stage:Stage;
|
|
||||||
/**
|
|
||||||
* The hash map of touches instantiated via TouchEvent.
|
|
||||||
* Used to avoid collisions (double processing) with MouseInputAdapter.
|
|
||||||
*
|
|
||||||
* TODO: any better way?
|
|
||||||
*/
|
|
||||||
protected var _touchesMap:Object = {};
|
|
||||||
|
|
||||||
{
|
|
||||||
Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function TouchInputAdapter(stage:Stage)
|
|
||||||
{
|
|
||||||
super();
|
|
||||||
|
|
||||||
if (!stage)
|
|
||||||
{
|
|
||||||
throw new Error("Stage must be not null.");
|
|
||||||
}
|
|
||||||
|
|
||||||
_stage = stage;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override public function init():void
|
|
||||||
{
|
|
||||||
_stage.addEventListener(TouchEvent.TOUCH_BEGIN, touchBeginHandler, true);
|
|
||||||
_stage.addEventListener(TouchEvent.TOUCH_BEGIN, touchBeginHandler);// to catch with EventPhase.AT_TARGET
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override public function dispose():void
|
|
||||||
{
|
|
||||||
_stage.removeEventListener(TouchEvent.TOUCH_BEGIN, touchBeginHandler, true);
|
|
||||||
_stage.removeEventListener(TouchEvent.TOUCH_BEGIN, touchBeginHandler);
|
|
||||||
uninstallStageListeners();
|
|
||||||
_touchesManager.onInputAdapterDispose(this);
|
|
||||||
_touchesManager = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected function installStageListeners():void
|
|
||||||
{
|
|
||||||
// Maximum priority to prevent event hijacking
|
|
||||||
_stage.addEventListener(TouchEvent.TOUCH_MOVE, touchMoveHandler, true, int.MAX_VALUE);
|
|
||||||
_stage.addEventListener(TouchEvent.TOUCH_MOVE, touchMoveHandler, false, int.MAX_VALUE);
|
|
||||||
_stage.addEventListener(TouchEvent.TOUCH_END, touchEndHandler, true, int.MAX_VALUE);
|
|
||||||
_stage.addEventListener(TouchEvent.TOUCH_END, touchEndHandler, false, int.MAX_VALUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected function uninstallStageListeners():void
|
|
||||||
{
|
|
||||||
_stage.removeEventListener(TouchEvent.TOUCH_MOVE, touchMoveHandler, true);
|
|
||||||
_stage.removeEventListener(TouchEvent.TOUCH_MOVE, touchMoveHandler);
|
|
||||||
_stage.removeEventListener(TouchEvent.TOUCH_END, touchEndHandler, true);
|
|
||||||
_stage.removeEventListener(TouchEvent.TOUCH_END, touchEndHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected function touchBeginHandler(event:TouchEvent):void
|
|
||||||
{
|
|
||||||
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
|
||||||
return;//we listen in capture or at_target (to catch on empty stage)
|
|
||||||
|
|
||||||
_touchesManager.onTouchBegin(this, event.touchPointID, event.stageX, event.stageY, event.target);
|
|
||||||
|
|
||||||
if (_touchesManager.activeTouchesCount > 0)
|
|
||||||
{
|
|
||||||
installStageListeners();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected function touchMoveHandler(event:TouchEvent):void
|
|
||||||
{
|
|
||||||
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
|
||||||
return;//we listen in capture or at_target (to catch on empty stage)
|
|
||||||
|
|
||||||
_touchesManager.onTouchMove(this, event.touchPointID, event.stageX, event.stageY);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected function touchEndHandler(event:TouchEvent):void
|
|
||||||
{
|
|
||||||
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
|
||||||
return;//we listen in capture or at_target (to catch on empty stage)
|
|
||||||
|
|
||||||
_touchesManager.onTouchEnd(this, event.touchPointID, event.stageX, event.stageY);
|
|
||||||
|
|
||||||
if (_touchesManager.activeTouchesCount == 0)
|
|
||||||
{
|
|
||||||
uninstallStageListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: handle cancelled touch:
|
|
||||||
// if (event.hasOwnProperty("isTouchPointCanceled") && event["isTouchPointCanceled"] && ...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue