12.13Tutorial - Multi Touch in AS3 / Flash Player 10.1 - Part 2. TouchEvent & MouseEvent Sequences
Hi Everyone,
In this installment I will cover the TouchEvent and how it is intertwined with MouseEvent. First you need to understand that touches will fire MouseEvent's too. You will get a TouchEvent first, then a MouseEvent. This can prove annoying in some cases, and good in others.
For the complete listing of TouchEvent's as well as some basic description of the information it carries please refer to this page.
First let us register the following events on a target Sprite:
TouchEvent.TOUCH_BEGINTouchEvent.TOUCH_OVERTouchEvent.TOUCH_OUTMouseEvent.MOUSE_DOWNMouseEvent.MOUSE_OVERMouseEvent.MOUSE_OUT
The actual series of events goes like this:
- You apply your finger -- nothing happens
- You start dragging your finger --
TOUCH_BEGIN,TOUCH_OVER,MOUSE_OVER,MOUSE_DOWNget fired, in that order - You move your finger out of the object --
TOUCH_OUT,MOUSE_OUTget fired, in that order - You move your finger back on the object --
TOUCH_OVER,MOUSE_OVERget fired, in that order
Stage Action
Just like with MouseEvent.MOUSE_UP, it is better to listen to TouchEvent.TOUCH_END on the Stage. Just as in the MouseEvent.MOUSE_DOWN handler we add a listener to MouseEvent.MOUSE_UP on the Stage; in the TouchEvent.TOUCH_BEGIN handler we add a listener to TouchEvent.TOUCH_END on the Stage.
Then we get one more action that fires event:
- You remove your finger from the screen --
TOUCH_END,MOUSE_UPget fired, in that order.
Testing it yourself
Try the following code to test it yourself:
-
package
-
{
-
import ascb.drawing.Pen;
-
import flash.display.Sprite;
-
import flash.events.Event;
-
import flash.events.MouseEvent;
-
import flash.events.TouchEvent;
-
import flash.text.TextField;
-
import flash.ui.Multitouch;
-
import flash.ui.MultitouchInputMode;
-
-
/**
-
* ...
-
* @author Martin Legris ( http://blog.martinlegris.com )
-
*/
-
public class Main extends Sprite
-
{
-
protected var _tf:TextField;
-
protected var _object:Sprite;
-
-
public function Main():void
-
{
-
if (stage) init();
-
else addEventListener(Event.ADDED_TO_STAGE, init);
-
}
-
-
private function init(e:Event = null):void
-
{
-
removeEventListener(Event.ADDED_TO_STAGE, init);
-
_tf = new TextField();
-
_tf.width = stage.stageWidth;
-
_tf.height = stage.stageHeight;
-
_tf.mouseEnabled = false;
-
addChild(_tf);
-
-
Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
-
_tf.text = "Input Mode: " + Multitouch.inputMode + "\n";
-
_tf.appendText("Touch Points: " + Multitouch.maxTouchPoints + "\n");
-
_tf.appendText("Supports Touch Events: " + Multitouch.supportsTouchEvents + "\n");
-
-
createChilds();
-
}
-
-
protected function createChilds():void
-
{
-
_object = new Sprite();
-
var p:Pen = new Pen(_object.graphics);
-
p.clear();
-
p.beginFill(0x0033DD, 1);
-
p.drawRect(0, 0, 320, 200);
-
p.endFill();
-
_object.x = 150;
-
_object.y = 250;
-
addChild(_object);
-
-
_object.addEventListener(TouchEvent.TOUCH_BEGIN, doTouchBegin);
-
_object.addEventListener(TouchEvent.TOUCH_OVER, doTouchOver);
-
_object.addEventListener(TouchEvent.TOUCH_OUT, doTouchOut);
-
-
_object.addEventListener(MouseEvent.MOUSE_OVER, doMouseOver);
-
_object.addEventListener(MouseEvent.MOUSE_OUT, doMouseOut);
-
_object.addEventListener(MouseEvent.MOUSE_DOWN, doMouseDown);
-
}
-
-
protected function doTouchBegin(evt:TouchEvent):void
-
{
-
_tf.appendText("touchBegin\n");
-
stage.addEventListener(TouchEvent.TOUCH_END, doTouchEnd);
-
}
-
-
protected function doTouchEnd(evt:TouchEvent):void
-
{
-
_tf.appendText("touchEnd\n");
-
stage.removeEventListener(TouchEvent.TOUCH_END, doTouchEnd);
-
}
-
-
protected function doTouchOver(evt:TouchEvent):void
-
{
-
_tf.appendText("touchOver\n");
-
}
-
-
protected function doTouchOut(evt:TouchEvent):void
-
{
-
_tf.appendText("touchOut\n");
-
}
-
-
protected function doMouseOver(evt:MouseEvent):void
-
{
-
_tf.appendText("doMouseOver\n");
-
}
-
-
protected function doMouseOut(evt:MouseEvent):void
-
{
-
_tf.appendText("doMouseOut\n");
-
}
-
-
protected function doMouseDown(evt:MouseEvent):void
-
{
-
stage.addEventListener(MouseEvent.MOUSE_UP, doMouseUp);
-
_tf.appendText("doMouseDown\n");
-
}
-
-
protected function doMouseUp(evt:MouseEvent):void
-
{
-
_tf.appendText("doMouseUp\n");
-
stage.removeEventListener(MouseEvent.MOUSE_UP, doMouseUp);
-
}
-
}
-
}
TouchEvent.TOUCH_MOVE, MouseEvent.MOUSE_MOVE
This is where, in my opinion, it gets a little strange in my opinion. You cannot expect the TouchEvent to be fired before the MouseEvent; but in any case in common practice you will not listen to both simultaneously. You will either pick one or the other.
To test this yourself, first modify the doTouchBegin and doTouchEnd functions like so:
-
protected function doTouchBegin(evt:TouchEvent):void
-
{
-
_tf.appendText("touchBegin("+evt.touchPointID+")\n");
-
stage.addEventListener(TouchEvent.TOUCH_END, doTouchEnd);
-
stage.addEventListener(TouchEvent.TOUCH_MOVE, doTouchMove);
-
}
-
-
protected function doTouchEnd(evt:TouchEvent):void
-
{
-
_tf.appendText("touchEnd("+evt.touchPointID+")\n");
-
stage.removeEventListener(TouchEvent.TOUCH_END, doTouchEnd);
-
stage.removeEventListener(TouchEvent.TOUCH_MOVE, doTouchMove);
-
}
Next, let's code the doTouchMove function...
-
protected function doTouchMove(evt:TouchEvent):void
-
{
-
_tf.appendText("touchMove("+evt.touchPointID+") [" + evt.stageX + "," + evt.stageY + "]\n");
-
}
You will notice that I "trace" the touchPointID property of the event; to demonstrate that it is a constant in the case of single touch.
Same deal with the MouseEvent.MOUSE_MOVE, first modify doMouseDown and doMouseUp functions:
-
protected function doMouseDown(evt:MouseEvent):void
-
{
-
stage.addEventListener(MouseEvent.MOUSE_UP, doMouseUp);
-
stage.addEventListener(MouseEvent.MOUSE_MOVE, doMouseMove);
-
_tf.appendText("doMouseDown\n");
-
}
-
-
protected function doMouseUp(evt:MouseEvent):void
-
{
-
_tf.appendText("doMouseUp\n");
-
stage.removeEventListener(MouseEvent.MOUSE_UP, doMouseUp);
-
stage.removeEventListener(MouseEvent.MOUSE_MOVE, doMouseMove);
-
}
finally, code the doMouseMove function like so:
-
protected function doMouseMove(evt:MouseEvent):void
-
{
-
_tf.appendText("doMouseMove [" + evt.stageX + "," + evt.stageY + "]\n");
-
}
How to disable this intertwining nightmare
In many cases, you will have a different handler for TouchEvents and MouseEvents, and you will not want BOTH to be triggered. This is because in a multi-touch ideology you will have multiple touches to track, meaning many TouchEvents being fired and with a couple of touchPointID's being referenced. Hence your handler cannot simply copy the logic you use in typical mouse handlers.
The method I have found that works best is to remove the mouse listeners on TOUCH_BEGIN and add them again on TOUCH_END, but making sure you add them only once all touches have ended. In most cases the user will use the Mouse or Touch; but not both simultaneously.
First we will need to track how many touches are active by adding a _activeTouches protected property to the class..
-
protected var _activeTouches:Number = 0;
Then, in the doTouchBegin handler, increment this property; and in the doTouchEnd handler, decrement it. Next, in the doTouchBegin handler, if the value before incrementation is 0, remove mouse listeners; and in the doTouchEnd handler, if the value after decrementation is 0, add the mouse listeners. Like so:
-
protected function registerMouseHandlers():void
-
{
-
_object.addEventListener(MouseEvent.MOUSE_OVER, doMouseOver);
-
_object.addEventListener(MouseEvent.MOUSE_OUT, doMouseOut);
-
_object.addEventListener(MouseEvent.MOUSE_DOWN, doMouseDown);
-
}
-
-
protected function removeMouseHandlers():void
-
{
-
_object.removeEventListener(MouseEvent.MOUSE_OVER, doMouseOver);
-
_object.removeEventListener(MouseEvent.MOUSE_OUT, doMouseOut);
-
_object.removeEventListener(MouseEvent.MOUSE_DOWN, doMouseDown);
-
}
-
-
protected function doTouchBegin(evt:TouchEvent):void
-
{
-
if (_activeTouches == 0)
-
{
-
removeMouseHandlers();
-
stage.addEventListener(TouchEvent.TOUCH_END, doTouchEnd);
-
stage.addEventListener(TouchEvent.TOUCH_MOVE, doTouchMove);
-
}
-
-
_activeTouches++;
-
_tf.appendText("touchBegin("+evt.touchPointID+")\n");
-
}
-
-
protected function doTouchEnd(evt:TouchEvent):void
-
{
-
_activeTouches--;
-
-
if (_activeTouches == 0)
-
{
-
stage.removeEventListener(TouchEvent.TOUCH_END, doTouchEnd);
-
stage.removeEventListener(TouchEvent.TOUCH_MOVE, doTouchMove);
-
registerMouseHandlers();
-
}
-
-
_tf.appendText("touchEnd("+evt.touchPointID+")\n");
-
}
Did you notice that I add and remove TouchEvent's on the Stage only in certain conditions?
Now that this is out of the way, no more intertwining action! You can concentrate on programming your Touch logic separately from your Mouse logic w/o having fears of interference.
TouchEvent.TOUCH_TAP
The last thing to cover is this event. Basically to show you when it is fired.. Basically, they are fired too often. They are fired even if you keep your finger moving on the screen for 2-3-4 seconds. To me, that is not a TAP. If you press your finger, but do not move, the Windows 7 will transform the touch into a right-click, you will see a circle draw itself around your finger, if you wait for it to be completely drawn: it is a right-click AND a touch, but not a TAP. Otherwise whatever you do, with one single finger, is a TAP.
To demonstrate this, add the following property to your Main class:
-
protected var _touchDown:Number;
add this event listener code with the other ones (TouchEvent.TOUCH_BEGIN, TOUCH_OVER, TOUCH_OUT)
-
_object.addEventListener(TouchEvent.TOUCH_TAP, doTouchTap);
Next modify doTouchBegin and doTouchEnd like so:
-
protected function doTouchBegin(evt:TouchEvent):void
-
{
-
if (_activeTouches == 0)
-
{
-
removeMouseHandlers();
-
stage.addEventListener(TouchEvent.TOUCH_END, doTouchEnd);
-
stage.addEventListener(TouchEvent.TOUCH_MOVE, doTouchMove);
-
-
_touchDown = new Date().getTime();
-
}
-
-
_activeTouches++;
-
_tf.appendText("touchBegin("+evt.touchPointID+")\n");
-
}
-
-
protected function doTouchEnd(evt:TouchEvent):void
-
{
-
_activeTouches--;
-
-
if (_activeTouches == 0)
-
{
-
stage.removeEventListener(TouchEvent.TOUCH_END, doTouchEnd);
-
stage.removeEventListener(TouchEvent.TOUCH_MOVE, doTouchMove);
-
registerMouseHandlers();
-
-
_tf.appendText("touch elapsed time:" + (new Date().getTime() - _touchDown) / 1000 + "\n");
-
_touchDown = 0;
-
}
-
-
_tf.appendText("touchEnd("+evt.touchPointID+")\n");
-
}
finally, add a doTouchTap handler:
-
protected function doTouchTap(evt:TouchEvent):void
-
{
-
_tf.appendText("touchTap(" + evt.touchPointID + ")\n");
-
}
If you run this updated code, you will notice that no matter how much your move your finger around once it is done, and how long you keep it down, it will fire a TOUCH_TAP event.. useless in my opinion.
Oki, that's it for today. Hope you enjoyed! I will keep going next week.
Martin
Related posts (automatically generated):

Hello,
great tutorial
can you please also show us how to move a object(image) with touch support?
thx
December 18th, 2009 at 2:27 pm
wow great!!!
thx~
December 27th, 2009 at 5:50 am
Very useful article about this post. I try essay writing services and buy custom essay papers or essays written about this good post.
December 30th, 2009 at 10:11 am
Nice tutorial, but I must disagree. I’m working with a Dell Latitude XT2 and touch events are not always fired in the the same order with mouse events on my machine. Actually it seems to work most of the times but every now and then the order is switched. I’m not quite sure if this may be hardware dependent (or at least caused somehow by the system and not by the Flash Player). I think the better solution by Adobe would have been to implement a switch to simply disable this behaviour when needed.
January 25th, 2010 at 8:52 am
I believe the information covered in the discussion is top notch. I’ve been doing a research on the subject and your blog just cleared up a lot of questions. I am working on a essay help and custom research papers for my English class and currently reading lots of blogs to study.
March 23rd, 2010 at 12:41 am
Nice tutorial, but I must disagree. I’m working with a Dell Latitude XT2 and touch events are not always fired in the the same order with mouse events on my machine. Actually it seems to work most of the times but every now and then the order is switched. I’m not quite sure if this may be hardware dependent (or at least caused somehow by the system and not by the Flash Player). I think the better solution by Adobe would have been to implement a switch to simply disable this behaviour when needed.
June 10th, 2010 at 3:34 am
just a message
June 18th, 2010 at 8:49 am