Is every MOUSE_DOWN guaranteed a MOUSE_UP? - actionscript-3

Are there any circumstances under which a Flash application could receive two MouseEvent.MOUSE_DOWN without a MouseEvent.MOUSE_UP in between?
In my ActionScript 3 application, I want to track the user dragging a sprite. My plan is to listen for a MouseEvent.MOUSE_DOWN, start an indefinitely repeating timer that records the mouse position, and stop the timer on MouseEvent.MOUSE_UP. Is that a good plan?

Click but do not release the button.
While keeping the button down move the cursor outside.
Release the button outside.
Come back inside and click again.
You will get two down event without an up event.
A better solution to drag-and-drop might be to listen MOUSE_MOVE event and in the event handler check buttonDown property. If the button is down while moving, this will be true, otherwise false.
EDIT: For stage even if you release the button outside the flash window then up event is fired. So for stage this can work, but still instead of timer using MOUSE_MOVE with buttonDown looks better to me. You can check yourself with the following code:
public class StageEventTest extends Sprite
{
public function StageEventTest()
{
stage.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMove);
}
private function onDown(evt:MouseEvent):void {
trace("down");
}
private function onUp(evt:MouseEvent):void {
trace("up");
}
private function onMove(evt:MouseEvent):void {
trace("move", evt.buttonDown);
}
}

it will miss the mouse up event if the mouse is outside of the stage and continue it's mouse tracking when mousing over the stage since the mouse up event was never called. this likely problem can be mitigated by using Event.MOUSE_LEAVE - forward the mouse leave event to the mouse up event handler so that if the user mouses away from the stage the mouse up event will be called.

Yes, but unless you are listening to the stage, I think you can miss the mouseup event if the mouse has gone outside the Flash movie. Nothing beats an experiment though.

Below you can find the code I always use for custom dragging. Normally, it should work fine. I listen to the MOUSE_MOVE-event for repositioning and tracking the sprite, but you can just as well use the Event.ENTER_FRAME-event or use a timer instead.
ObjectToDrag.addEventListener(MouseEvent.MOUSE_DOWN, startCustomDrag);
public function startCustomDrag(e:MouseEvent):void
{
_prevX= e.stageX;
_prevY= e.stageY;
stage.addEventListener(MouseEvent.MOUSE_MOVE, dragObject); //REPLACE BY TIMER OR Event.ENTER_FRAME
stage.addEventListener(MouseEvent.MOUSE_UP, stopCustomDrag);
}
private function dragObject(e:MouseEvent):void
{
ObjectToDrag.x += _prevX - e.stageX; //OR ANY OTHER CALCULATION
ObjectToDrag.y += _prevY - e.stageY; //OR ANY OTHER CALCULATION
_prevX= e.stageX;
_prevY= e.stageY;
}
public function stopCustomDrag(e:MouseEvent):void
{
stage.removeEventListener(MouseEvent.MOUSE_MOVE, dragObject); //REPLACE BY TIMER OR Event.ENTER_FRAME
stage.removeEventListener(MouseEvent.MOUSE_UP, stopCustomDrag);
}

Related

MOUSE_DOWN not firing when expected - AS3, Actionscript

MOUSE_DOWN not firing when expected - AS3, Actionscript
I am not seeing the below code trace in MOUSE_DOWN fired, until I lift the mouse button back up.
This happens even on a new FLA, with only MOUSE_DOWN, MOUSE_UP and CLICK handler code -- nothing else.
Regardless of what I do, I only see MOUSE_DOWN, MOUSE_UP and CLICK traced out AFTER I lift (release) the mouse button..
See code below.
It happens if I attach the handlers to the stage;
or to a sprite.
It happens with/without buttonMode being set.
It happens with/without preventDefault() being called in CLICK..
It happens using event:MouseEvewnt or event:Event as some have suggested.
When I click, I see nothing.
When I release, I see this:
Mouse down
Mouse up
Mouse CLICK
Why don't I see "Mouse down" when clicking (before releasing)?
What the heck am I missing here?
Thank you!
stage.addEventListener(MouseEvent.MOUSE_DOWN, function(event:MouseEvent)
{
// event.preventDefault();
trace("Mouse down");
} );
stage.addEventListener(MouseEvent.MOUSE_UP, function(event:MouseEvent)
{
// event.preventDefault();
trace("Mouse up");
} );
stage.addEventListener(MouseEvent.CLICK, function(event:Event)
{
// event.preventDefault();
trace("Mouse CLICK");
} );

Click after mouse up outside stage

I'am drag game scene in Flash project (mouse down - start drag, mouse up - stop drag). If I mouse up outside stage, click on any object (buttons) don't work once. After one click other click works fine. What's wrong?
update: Trace logs shown that there event as mouseOver, mouseDown, mouseUp, mouseOut are dispatches, but not CLICK.
update: There is silencer of first click after drag in the project. It's necessary to eliminate situation of end drag on some game object (dispath click). Sorry. Thank you all for answers.
You might be losing focus when leaving the stage. Try using (Event.MOUSE_LEAVE) to 'force' a mouse_up.
something like this:
private var _draggedItem:Sprite;
myDisplayObject.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
private function mouseDownHandler(event:MouseEvent):void {
_draggedItem = event.currentTarget as Sprite;
_draggedItem.startDrag();
_draggedItem.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
stage.addEventListener(Event.MOUSE_LEAVE, stageMouseOutHandler);
}
private function stopDragCurrentItem():void {
if (_draggedItem) {
_draggedItem.stopDrag();
_draggedItem.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
if (stage) {
stage.removeEventListener(Event.MOUSE_LEAVE, stageMouseOutHandler);
}
_draggedItem = null;
}
}
private function mouseUpHandler(event:MouseEvent):void {
stopDragCurrentItem();
}
private function stageMouseOutHandler(event:Event):void {
trace("stage out!")
stopDragCurrentItem();
}
update:
And concerning the lost focus, you cold do the following in html where you embed your flash:
<object classid="..." codebase="...." width=550 height=400
name="myMovie" onmouseover="window.document.myMovie.focus();">
though i haven't tested it.

My mouse clicks created and triggered my eventListener at the same time

I tried to achieve the following but failed with the code below:
Click mouse once to appear the box.
Click it again to disappear the box.
What happened is that when I fire the mouse.click event (by clicking), that triggered the "stage.addEventListener(MouseEvent.CLICK, boxGone)" event listener as well. At the screen there is nothing happened because I technically addChild and removeChild the box at the same frame.
I am guessing my initial click created and triggered the event listener at the same time.Is there anyway to avoid this from happening without changing my triggering event(mouse click)? below is the code:
public function ClassConstructor(){
addEventListener(MouseEvent.CLICK, onMouseClickHandler);
}
private function onMouseClickHandler(e:MouseEvent):void{
box.x = stage.mouseX;
box.y = stage.mouseY;
box.gotoAndPlay(1);
stage.addChild(box);
stage.addEventListener(MouseEvent.CLICK, boxGone);
}
private function boxGone(e:MouseEvent):void{
stage.removeChild(box);
stage.removeEventListener(MouseEvent.CLICK, boxGone);
}
Thanks in advance,
Sunny
Modify your first listener with:
stage.addEventListener(MouseEvent.CLICK, onMouseClickHandler);
The event goes from your main class to the stage, and you add the second listener in between, so it is called just after the function's closure. Another solution, to be sure, would be to call
e.stopImmediatePropagation();
This prevents any listener to catch the same event.

Long Touch event with Timer and Confirmation Box for iOS deployment in AS3

I have a project where I have a scrolling list. I would like for my user to be able to "long touch" an item on the list so that they can delete it.
I am developing in Air for iOS using Flash CS6 so I don't really know much about the appropriate MultiTouch gestures for iOS deployment.
In my mind, the animation steps I would like to go like so..
Previously invisible button called btn_delete inside the Item movieclip will appear when Long Touch starts + timer begins
Intermediate step: btn_delete will rotate 90 degrees using TweenMax Rotate (I have this covered)
Final step: when timer reaches it's conclusion, a dialog box / confirmation box will pop up and ask the user if they are sure if they want to delete the item.
So here is some generic code I've written quickly to give you an idea of my structure so far (I've omitted the interlinking listener functions):
function exampleFunction {
_item.addEventListener(TouchEvent.TOUCH_BEGIN, onTouchBegin);
}
//-- Long Press Listener Functions--//
function onTouchBegin(eBegin:TouchEvent) {
trace("start");
}
function onTouchRotate(eEnd:TouchEvent) {
trace("rotation of image");
}
function onTouchEnd(eEnd:TouchEvent) {
trace("end");
}
If anyone has a piece of code they've already written that roughly matches my criteria then please post it!
I would just use MouseEvent for this.
var timer:Timer = new Timer( 500 ); //ms
timer.addEventListener( TimerEvent.TIMER_COMPLETE, timerCompleteHandler );
listItem.addEventListener( MouseEvent.MOUSE_DOWN, mouseDownHandler );
function mouseDownHandler( e:MouseEvent ):void {
timer.start();
stage.addEventListener( MouseEvent.MOUSE_UP, mouseUpHandler );
}
function mouseUpHandler( e:MouseEvent ):void {
//just some clean up to reset the timer and remove the mouse up event listener from the stage
timer.reset();
stage.removeEventListener( MouseEvent.MOUSE_UP, mouseUpHandler );
}
function timerCompleteHandler( e:TimerEvent ):void {
timer.reset();
stage.removeEventListener( MouseEvent.MOUSE_UP, mouseUpHandler );
//do delete actions here
}
So on mouse down, you start your timer and listen for a mouse up event (on the stage and not the component. That is important. If you want to know why, try it on the component and experiment). On mouse up, you reset the timer so the next time you mouse down, it starts at 0 (reset() has the added benefit of stopping the timer). On timer complete, you do the same as in mouse up in addition to your delete code.
I'm using a MouseEvent here just because it behaves identical to TouchEvent (for the most part) in this instance and it could be used on the desktop (meaning you can test in the emulator and you could add this to other projects if you wanted)
UPDATE:
Just reread your question and realized I missed the rotate. For this, just add another timer with a separate complete handler that and in that function, ONLY do the rotation and reset that timer.

Is it possible to SIMULATE a mouse click using a mouse down and up events?

A previous question has gotten me thinking. Is it possible to simulate a MouseEvent.CLICK to get fired by just firing first a MOUSE_DOWN followed by a MOUSE_UP.
As per Adobe's doumentation.
"... For a click event to occur, it must always follow this series of events in the order of occurrence: mouseDown event, then mouseUp. The target object must be identical for both of these events; otherwise the click event does not occur. Any number of other mouse events can occur at any time between the mouseDown or mouseUp events; the click event still occurs." http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/InteractiveObject.html#event:click
From my tests it shows that the CLICK event is NOT constructed from the ActionScript 3 event queue. Or is something wrong with the code?
See:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
[SWF(backgroundColor="0xFFFFFF", frameRate="30", width="800", height="600")]
public class Test extends Sprite
{
private var spr:Sprite = new Sprite();
public function Test()
{
trace("Test()");
this.addEventListener(Event.ADDED_TO_STAGE,init);
}
public function init(e:Event):void
{
trace("init()");
spr.graphics.beginFill(0xFF0000);
spr.graphics.drawRect(0,0,200,80);
spr.graphics.endFill();
addChild(spr);
addEventListener(Event.ENTER_FRAME, onEnterFrame);
spr.addEventListener(MouseEvent.CLICK, onClick);
}
private var tick:int = 0;
private function onEnterFrame(e:Event):void
{
if (tick == 1) spr.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_DOWN,true,false));
if (tick == 2) spr.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_UP,true,false));
if (tick == 3) spr.dispatchEvent(new MouseEvent(MouseEvent.CLICK,true,false));
tick++;
}
private function onClick(e:MouseEvent):void
{
trace("onClick() MouseEvent.CLICK dispatched");
}
}
}
I should get TWO 'onClick()' events instead of one.
The reason you cannot is that all three types are created by the plugin, and are not dependent upon each other.
MouseEvent.MOUSE_DOWN is fired as soon as you press on an interactive object.
MouseEvent.MOUSE_UP is fired as soon as you release the mouse, it does not depend upon the mouse click having started a MOUSE_DOWN within the same InteractiveObject.
MouseEvent.CLICK will only be fired when both events take place in the same object without the cursor leaving the object between the itnerval of mouse down and mouse up.
So you can see that there is a simple case, or two even, in which both MOUSE_DOWN and MOUSE_UP are fired, but CLICK is not called because the event is not a CLICK.
Furthermore, the ability to simply dispatch a MouseEvent.CLICK event makes it unnecesasry to create fake user interaction by firing multiple mouse events, when only one is called for. It would be awkward to have to track each object clicked in the mouse down listener, in order to check that the moue up should also trigger a click. You would also need to remove references when a ROLL_OUT event happened.
In short, the CLICK event is really a lot more than the MOUSE_DOWN and MOUSE_UP events. It is also managing that the events happened in succession and on the same display object without leaving the object. When that happens, and ONLY when that happens flash dispatches a CLICK event.
it's impossible, this code:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
/**
* ...
* #author www0z0k
*/
public class Main extends 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);
stage.addEventListener(MouseEvent.CLICK, onClick);
stage.addEventListener(KeyboardEvent.KEY_DOWN, onStageKeyDown);
}
private function onStageKeyDown(e:KeyboardEvent):void {
trace('pressed');
stage.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_DOWN));
stage.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_UP));
stage.dispatchEvent(new MouseEvent(MouseEvent.CLICK));
}
private function onClick(e:MouseEvent):void{
trace('clicked');
}
}
}
outputs just:
pressed
clicked
after a key is pressed on the keyboard
not sure about this for flash. But when i was learning windows MFC and was clueless. What i did was that I sent WM_MOUSEDOWN followed by WM_MOUSEUP after a short delay. It did work and the button's visual states also changed - without any mouse click!
If I understand what you're asking then the answer is YES.
I am curious if I have over simplified the solution here especially after reading your code attempt. It is very simple to "simulate" a mouse click. The code below outputs two "I have been clicked" statements when the object is clicked and none when you mouse down then move out of the objects boundaries.
This class extended a MovieClip I created on the stage so I didn't have to code a box.
package {
import flash.display.MovieClip;
import flash.events.MouseEvent;
public class clickMe extends MovieClip {
public function clickMe() {
// constructor code
this.addEventListener(MouseEvent.CLICK, clicked);
this.addEventListener(MouseEvent.MOUSE_DOWN, mDown);
}
private function clicked(e:MouseEvent):void{
trace("I have been clicked");
this.removeEventListener(MouseEvent.MOUSE_UP, clicked);
}
private function mDown(e:MouseEvent):void{
this.addEventListener(MouseEvent.MOUSE_UP, clicked);
}
}
}
In your code I believe the problem is that you are trying to run event listener dispatches through an "onEnterFrame" which will only ever fire one event per frame - never two. Also after testing your code I'm not sure what your were trying to accomplish with the "tick" variable because you never reset it. So the the MOUSE_UP event fires once (when tick = 2, unless your holding the mouse down) then none of the other dispatches will ever fire again.
Not quite sure why everybody's making these complex spikes. Or maybe I'm just overseeing something.
Anyway, here's a very easy way to check it:
import flash.events.MouseEvent;
stage.addEventListener(MouseEvent.CLICK, function(){
trace( 'clicked' );
} );
stage.dispatchEvent( new MouseEvent( MouseEvent.MOUSE_DOWN ) );
stage.dispatchEvent( new MouseEvent( MouseEvent.MOUSE_UP ) );
And the answer would be, "no, it's not possible"...
...and probably should be followed by a counter-question: WHY would I want to simulate a click event using a sequence of mousedown and mouseup, when I can dispatch a click event just as well?
Am I a button, having an existential crisis?
Or is it a question out of mere curiosity? But you know what happened to the cat... Right, but maybe it's schrödinger's cat, which means that at the end of this completely irrelevant train of thought, curiosity REALLY did and did NOT kill the cat.
Except if the cat's out of a box.
Then it probably just got wasted.
See, thinking out of the box can get you killed.