How to detect Event.MOUSE_LEAVE when wmode=opaque or wmode=transparent

感情迁移 提交于 2020-01-16 18:30:13


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?


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


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.