mirror of
https://github.com/scratchfoundation/Gestouch.git
synced 2024-11-23 07:47:59 -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
|
||||
{
|
||||
import flash.utils.getQualifiedClassName;
|
||||
import org.gestouch.gestures.Gesture;
|
||||
import org.gestouch.input.MouseInputAdapter;
|
||||
import org.gestouch.input.TouchInputAdapter;
|
||||
import org.gestouch.input.NativeInputAdapter;
|
||||
|
||||
import flash.display.DisplayObject;
|
||||
import flash.display.Shape;
|
||||
import flash.display.Stage;
|
||||
import flash.events.Event;
|
||||
import flash.events.IEventDispatcher;
|
||||
import flash.ui.Multitouch;
|
||||
import flash.utils.Dictionary;
|
||||
import flash.utils.getQualifiedClassName;
|
||||
|
||||
/**
|
||||
* @author Pavel fljot
|
||||
*/
|
||||
public class GesturesManager implements IGesturesManager
|
||||
public class GesturesManager
|
||||
{
|
||||
public static var initDefaultInputAdapter:Boolean = true;
|
||||
private static var _instance:IGesturesManager;
|
||||
private static var _allowInstantiation:Boolean;
|
||||
|
||||
protected const _touchesManager:ITouchesManager = TouchesManager.getInstance();
|
||||
protected const _displayListAdaptersMap:Dictionary = new Dictionary();
|
||||
protected const _frameTickerShape:Shape = new Shape();
|
||||
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 _gesturesForTouchMap:Dictionary = new Dictionary();
|
||||
protected var _gesturesForTargetMap:Dictionary = new Dictionary(true);
|
||||
|
@ -34,120 +26,36 @@ package org.gestouch.core
|
|||
protected var _dirtyGesturesLength:uint = 0;
|
||||
protected var _dirtyGesturesMap:Dictionary = new Dictionary(true);
|
||||
|
||||
use namespace gestouch_internal;
|
||||
|
||||
|
||||
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>
|
||||
{
|
||||
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
|
||||
gestouch_internal function addDisplayListAdapter(targetClass:Class, adapter:IDisplayListAdapter):void
|
||||
{
|
||||
if (!targetClass || !adapter)
|
||||
{
|
||||
throw new Error("Argument error: both arguments required.");
|
||||
}
|
||||
|
||||
_displayListAdaptersMap[targetClass] = adapter;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Private methods
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
protected function installStage(stage:Stage):void
|
||||
protected function installDefaultInputAdapter(stage:Stage):void
|
||||
{
|
||||
_stage = stage;
|
||||
|
||||
if (Multitouch.supportsTouchEvents)
|
||||
{
|
||||
addInputAdapter(new TouchInputAdapter(stage));
|
||||
}
|
||||
else
|
||||
{
|
||||
addInputAdapter(new MouseInputAdapter(stage));
|
||||
}
|
||||
Gestouch.inputAdapter ||= new NativeInputAdapter(stage);
|
||||
}
|
||||
|
||||
|
||||
|
@ -201,14 +109,14 @@ package org.gestouch.core
|
|||
|
||||
_gesturesMap[gesture] = true;
|
||||
|
||||
if (GesturesManager.initDefaultInputAdapter)
|
||||
if (!Gestouch.inputAdapter)
|
||||
{
|
||||
var targetAsDO:DisplayObject = target as DisplayObject;
|
||||
if (targetAsDO)
|
||||
{
|
||||
if (!_stage && targetAsDO.stage)
|
||||
if (targetAsDO.stage)
|
||||
{
|
||||
installStage(targetAsDO.stage);
|
||||
installDefaultInputAdapter(targetAsDO.stage);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -274,8 +182,8 @@ package org.gestouch.core
|
|||
otherGesture.state == GestureState.POSSIBLE)
|
||||
{
|
||||
if (otherTarget == target ||
|
||||
gesture.gestouch_internal::targetAdapter.contains(otherTarget) ||
|
||||
otherGesture.gestouch_internal::targetAdapter.contains(target)
|
||||
gesture.targetAdapter.contains(otherTarget) ||
|
||||
otherGesture.targetAdapter.contains(target)
|
||||
)
|
||||
{
|
||||
var gestureDelegate:IGestureDelegate = gesture.delegate;
|
||||
|
@ -286,7 +194,7 @@ package org.gestouch.core
|
|||
(!gestureDelegate || !gestureDelegate.gesturesShouldRecognizeSimultaneously(gesture, otherGesture)) &&
|
||||
(!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
|
||||
if (gesture.state != GestureState.FAILED)
|
||||
{
|
||||
gesture.gestouch_internal::touchBeginHandler(touch);
|
||||
gesture.touchBeginHandler(touch);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -388,7 +296,7 @@ package org.gestouch.core
|
|||
|
||||
if (gesture.state != GestureState.FAILED && gesture.isTrackingTouch(touch.id))
|
||||
{
|
||||
gesture.gestouch_internal::touchMoveHandler(touch);
|
||||
gesture.touchMoveHandler(touch);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -415,7 +323,7 @@ package org.gestouch.core
|
|||
|
||||
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;
|
||||
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
|
||||
{
|
||||
function set touchesManager(value:ITouchesManager):void;
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
function set touchesManager(value:TouchesManager):void;
|
||||
|
||||
/**
|
||||
* Called when input adapter is set.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -25,6 +25,8 @@ package org.gestouch.core
|
|||
public var pressure:Number;
|
||||
|
||||
// public var lastMove:Point;
|
||||
|
||||
use namespace gestouch_internal;
|
||||
|
||||
|
||||
public function Touch(id:uint = 0)
|
||||
|
@ -38,9 +40,9 @@ package org.gestouch.core
|
|||
{
|
||||
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();
|
||||
_previousLocation = _location.clone();
|
||||
|
||||
|
@ -59,7 +61,7 @@ package org.gestouch.core
|
|||
}
|
||||
else
|
||||
{
|
||||
gestouch_internal::setLocation(new Point(x, y), time);
|
||||
setLocation(x, y, time);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,32 +1,30 @@
|
|||
package org.gestouch.core
|
||||
{
|
||||
import flash.display.InteractiveObject;
|
||||
import flash.display.Stage;
|
||||
import flash.geom.Point;
|
||||
import flash.utils.Dictionary;
|
||||
import flash.utils.getTimer;
|
||||
|
||||
|
||||
/**
|
||||
* @author Pavel fljot
|
||||
*/
|
||||
public class TouchesManager implements ITouchesManager
|
||||
public class TouchesManager
|
||||
{
|
||||
private static var _instance:ITouchesManager;
|
||||
private static var _allowInstantiation:Boolean;
|
||||
|
||||
protected var _gesturesManager:GesturesManager;
|
||||
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)
|
||||
{
|
||||
throw new Error("Do not instantiate TouchesManager directly.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected var _gesturesManager:IGesturesManager;
|
||||
public function set gesturesManager(value:IGesturesManager):void
|
||||
{
|
||||
_gesturesManager = value;
|
||||
_gesturesManager = gesturesManager;
|
||||
|
||||
addTouchHitTester(new DefaultTouchHitTester());
|
||||
}
|
||||
|
||||
|
||||
|
@ -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.");
|
||||
}
|
||||
if (_instance)
|
||||
{
|
||||
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.");
|
||||
}
|
||||
_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)
|
||||
// return all touches
|
||||
var i:uint = 0;
|
||||
for each (var touch:Touch in _touchesMap)
|
||||
{
|
||||
if (registeredTouch.target == target)
|
||||
return;
|
||||
touches[i++] = touch;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
overlappingTouches = _touchesMap[touchID] = new Dictionary();
|
||||
_activeTouchesCount++;
|
||||
//TODO
|
||||
}
|
||||
|
||||
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.target = target;
|
||||
touch.gestouch_internal::setLocation(new Point(x, y), getTimer());
|
||||
overlappingTouches[inputAdapter] = touch;
|
||||
|
||||
_gesturesManager.gestouch_internal::onTouchBegin(touch);
|
||||
}
|
||||
|
||||
|
||||
public function onTouchMove(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());
|
||||
|
||||
_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)
|
||||
var target:Object;
|
||||
var altTarget:Object;
|
||||
for each (var hitTester:ITouchHitTester in _hitTesters)
|
||||
{
|
||||
empty = false;
|
||||
break;
|
||||
}
|
||||
if (empty)
|
||||
{
|
||||
delete _touchesMap[touchID];
|
||||
_activeTouchesCount--;
|
||||
}
|
||||
|
||||
_gesturesManager.gestouch_internal::onTouchEnd(touch);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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])
|
||||
target = hitTester.hitTest(location, nativeTarget);
|
||||
if (target)
|
||||
{
|
||||
delete overlappingTouches[inputAdapter];
|
||||
var empty:Boolean = true;
|
||||
for (var key:Object in overlappingTouches)
|
||||
if ((target is Stage))
|
||||
{
|
||||
empty = false;
|
||||
break;
|
||||
// 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;
|
||||
}
|
||||
if (empty)
|
||||
else
|
||||
{
|
||||
delete _touchesMap[touchID];
|
||||
_activeTouchesCount--;
|
||||
// We found a target.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
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];
|
||||
_activeTouchesCount--;
|
||||
|
||||
_gesturesManager.onTouchEnd(touch);
|
||||
}
|
||||
|
||||
|
||||
gestouch_internal function onTouchCancel(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];
|
||||
_activeTouchesCount--;
|
||||
|
||||
_gesturesManager.onTouchCancel(touch);
|
||||
}
|
||||
|
||||
|
||||
|
@ -171,5 +204,38 @@ package org.gestouch.core
|
|||
//TODO: pool
|
||||
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
|
||||
{
|
||||
import starling.core.Starling;
|
||||
import starling.display.DisplayObject;
|
||||
import starling.display.DisplayObjectContainer;
|
||||
|
||||
|
@ -14,22 +15,22 @@ package org.gestouch.extensions.starling
|
|||
*/
|
||||
final public class StarlingDisplayListAdapter implements IDisplayListAdapter
|
||||
{
|
||||
private var _targetWeekStorage:Dictionary;
|
||||
private var targetWeekStorage:Dictionary;
|
||||
|
||||
|
||||
public function StarlingDisplayListAdapter(target:DisplayObject = null)
|
||||
{
|
||||
if (target)
|
||||
{
|
||||
_targetWeekStorage = new Dictionary(true);
|
||||
_targetWeekStorage[target] = true;
|
||||
targetWeekStorage = new Dictionary(true);
|
||||
targetWeekStorage[target] = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function get target():Object
|
||||
{
|
||||
for (var key:Object in _targetWeekStorage)
|
||||
for (var key:Object in targetWeekStorage)
|
||||
{
|
||||
return key;
|
||||
}
|
||||
|
@ -39,6 +40,7 @@ package org.gestouch.extensions.starling
|
|||
|
||||
public function globalToLocal(point:Point):Point
|
||||
{
|
||||
point = StarlingUtils.adjustGlobalPoint(Starling.current, 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
|
||||
{
|
||||
import org.gestouch.core.Gestouch;
|
||||
import org.gestouch.core.GestureState;
|
||||
import org.gestouch.core.GesturesManager;
|
||||
import org.gestouch.core.IGestureDelegate;
|
||||
import org.gestouch.core.IGestureTargetAdapter;
|
||||
import org.gestouch.core.IGesturesManager;
|
||||
import org.gestouch.core.Touch;
|
||||
import org.gestouch.core.gestouch_internal;
|
||||
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
|
||||
* in order detect specific gesture motion and form gesture event on target.
|
||||
*
|
||||
* TODO:
|
||||
* -
|
||||
*
|
||||
* @author Pavel fljot
|
||||
*/
|
||||
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);
|
||||
|
||||
|
||||
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.
|
||||
*/
|
||||
|
@ -175,7 +172,6 @@ package org.gestouch.gestures
|
|||
*/
|
||||
public function get location():Point
|
||||
{
|
||||
//TODO: to clone or not clone? performance & convention or ...
|
||||
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
|
||||
{
|
||||
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
|
||||
*/
|
||||
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