0

I have a customized drag event that works great for most things:

stage.addEventListener( MouseEvent.MOUSE_DOWN, beginDrag );

function beginDrag( e:MouseEvent )
{
  stage.addEventListener( MouseEvent.MOUSE_MOVE, drag );
  stage.addEventListener( MouseEvent.MOUSE_UP, endDrag );
  stage.addEventListener( MouseEvent.DEACTIVATE, endDrag );
  stage.addEventListener( Event.MOUSE_LEAVE, endDrag );
  stage.addEventListener( Event.REMOVED_FROM_STAGE, stageEndDrag );

  //trigger beginDrag event
}
function drag( e:MouseEvent )
{
  //trigger drag event
}
function endDrag( e:Event )
{
  stage.removeEventListener( MouseEvent.MOUSE_MOVE, drag );
  stage.removeEventListener( MouseEvent.MOUSE_UP, endDrag );
  stage.removeEventListener( MouseEvent.DEACTIVATE, endDrag );
  stage.removeEventListener( Event.MOUSE_LEAVE, endDrag );
  stage.removeEventListener( Event.REMOVED_FROM_STAGE, stageEndDrag );

  //trigger endDrag event
}

The issue is that when I use this code with wmode=transparent or wmode=opaque the MOUSE_LEAVE event is not detected when the MOUSE_UP event occurs off the stage.

Is there a way to detect the MOUSE_LEAVE event when wmode is transparent or opaque?

OR

Is there a way to detect that the wmode is set to transparent or opaque so that a work-around may be implemented?

zzzzBov
  • 174,988
  • 54
  • 320
  • 367

1 Answers1

0

By default, MOUSE_LEAVE is not a reliable event. Sometimes it gets fired, at other times it won't. You can find complaints about this all over the web.

There is one thing you can do, though, and that is to manually check if the mouse is over the stage:

var out : Boolean = false;

stage.addEventListener (Event.ENTER_FRAME, checkMouse);

function checkMouse (ev:Event) : void {
    if (
        stage.mouseX < 0 || 
        stage.mouseX > stage.stageWidth || 
        stage.mouseY < 0 || 
        stage.mouseY > stage.stageHeight) 
    {
        if (!out) 
        {
            out = true;
            stage.dispatchEvent (new Event(Event.MOUSE_LEAVE));
        }
    } 
    else if (out) 
    {
        out = false;
        stage.dispatchEvent (new Event("mouseEnter"));
    }
}

This will dispatch the MOUSE_LEAVE event when the cursor is outside of the stage area, and the custom "mouseEnter" event, when it reenters. You can then add event listeners to the stage to reliably react to these events, but you have to keep in mind that more than one MOUSE_LEAVE might be fired at a time (if both the custom one and the built-in one are executed). You can check the out variable to prevent double execution of the event handlers.

P.S. I am not sure this works for all stage.align and stage.scaleMode options. It should work for the combination of StageScaleMode.NO_SCALE and StageAlign.TOP_LEFT, for any other settings you will have to check and possibly find a workaround.

weltraumpirat
  • 22,544
  • 5
  • 40
  • 54
  • @weltraumpirat I'd never found the `MOUSE_LEAVE` event to be unreliable before this. Many people are confused as to *when* the `MOUSE_LEAVE` event gets fired, as it happens when the `MOUSE_UP` event occurs *after* the mouse has left the stage while the user is dragging the mouse. I've discovered that the mouse events aren't handled when the mouse is off of the stage in `wmode=transparent/opaque`, so this method is not likely to work (although I'll still give it a try). – zzzzBov Mar 26 '11 at 18:13
  • If you should run into any trouble with that, you could always use an ENTER_FRAME listener instead. I prefer using MOUSE_MOVE if I can, because it isn't fired as often. – weltraumpirat Mar 26 '11 at 21:36
  • @weltraumpirat, None of the mouse events are fired when the mouse leaves the stage (not even the `MOUSE_OUT` event). If the mouse was released or pressed, the new mouse events don't register the correct value for `buttonDown` either. I don't see how an `ENTER_FRAME` listener could help. – zzzzBov Mar 30 '11 at 19:08
  • My script tests if the mouse is within the stage boundaries. If the mouse is outside of the stage, the MOUSE_LEAVE event is fired manually, regardless of whether the player fires the built-in event, or not. I test on MOUSE_MOVE, but if that doesn't work, ENTER_FRAME will keep testing, even if the player is in the background. – weltraumpirat Mar 30 '11 at 22:24
  • @weltraumpirat, the issue is that the mouse events *aren't being fired* when the mouse is out of the stage (with wmode=transparent), ENTER_FRAME would be getting an inaccurate mouse position. – zzzzBov Mar 30 '11 at 22:43
  • Ok, now I've just set up a test HTML page and *tested* the whole thing with `wmode=transparent` -- it works just fine. Use ENTER_FRAME, I've changed my answer above. – weltraumpirat Mar 31 '11 at 08:14
  • Assuming this method did produce acceptably accurate results, it still doesn't solve my issue. I'd need a way to detect that wmode=transparent so that I can add the fix in dynamically. I don't want changes to affect wmode=window. Unfortunately, this "fix" doesn't accurately report the `stage.mouseX` and `stage.mouseY` coordinates when the viewport is resized (StageScaleMode.NO_SCALE and StageAlign.TOP_LEFT are set). – zzzzBov Mar 31 '11 at 15:34
  • Are you looking for a way to detect the mouse leaving the Flash plugin's stage, or are you looking for a way to detect the mouse leaving the HTML window? Are you going to change wmode settings while the program is running? What exactly are you trying to do with this? – weltraumpirat Mar 31 '11 at 16:28
  • I'm looking for a long-term solution for drag events in an OOP library that I've been making. Some projects can use wmode=window, but others need wmode=transparent. if I start a drag while on the stage, it will ideally end when the MOUSE_UP event fires. When wmode=window, it may happen *after* the mouse has left the stage. When wmode=transparent, mouse events aren't captured when the mouse has left the stage, so I need a work-around so that I can tell it to end the drag event. – zzzzBov Mar 31 '11 at 16:38
  • Have you considered using a JavaScript event listener and call to ExternalInterface? – weltraumpirat Mar 31 '11 at 16:48
  • @weltraumpirat, That's my current-work around, and it works fine. The issue is that it's not portable. If I want to reuse or share my base class, I either need to document its incorrect behavior, or make sure to package it with some JS backup. I'm currently looking into using `ExternalInterface`+`Eval` to internalize the JavaScript fix. – zzzzBov Mar 31 '11 at 16:53