views:

4920

answers:

5

I have the bad luck of having to downport some ActionScript 3 code to ActionScript 2 and I have a problem with detecting when the mouse leaves the stage.

In ActionScript 3 there is an event called Event.MOUSE_LEAVE, which can be used to detect when the mouse leaves the stage, but there is no equivalent in ActionScript 2 as far as I can see.

How would you best emulate the same functionality?

Listening for mouse movement and checking the mouse coordinates against the bounds of the stage doesn't work because the mouse coordinates stop updating when the mouse leaves the stage.

+6  A: 

I have not found a reliable way to do this in AS2 (on some browsers you even keep getting mouse updates when the mouse is outside the app). So what I normally do is check if the mouse is outside the outer 10 or 20px border of the application, if so I consider that as a MOUSE_LEAVE. It's probably better to listen for MOUSE_MOVE rather than checking this each frame, since you might miss a few updates if you have a lower framerate.

It is also possible to bring up the context menu, move the mouse outside and then click completely bypassing the whole check above (or even move the mouse very fast past the border), so I often add a timer that fires after the mouse hasn't moved in say 2-3 seconds.

It's not especially robust, but it's the best I have managed.

grapefrukt
I think the timer is the crucial point here as Theo correctly noted that the mouse coordinates stop updating once the mouse leaves the stage..
Polygraf
Works well enough. In my case it's no big deal if I miss the event once or twice, if it works 80-90% of the time, that's good enough.
Theo
+2  A: 

I think I once got round this by putting invisible buttons at the edges of the stage and using their rollout function. think this worked as long as they didn't move the mouse too quickly! distant memories though.

Iain
A: 

There are three categories of solutions to this problem:

  1. Check the mouse position against the stage bounds (for example Mayhew's answer). This is the naive solution and had it worked I would never have asked the question. The problem is that the mouse coordinates stop updating when the mouse leaves the stage, and they will retain their last position, which is always inside the stage.

  2. Create a border around the stage and detect mouse movements inside this border (for example grapefrukt's answer. Works if the border is very wide, but you get a lot of false positives -- and if the mouse stops inside the border and then starts moving again you get a false mouse enter. Also suffers from the same problems as 1, the mouse can always move quickly enough that you will not detect it moving over the border.

  3. Keep track of the direction and velocity of the mouse, so that when you stop receive mouse move events you can calculate where the mouse ought to be and see if that point is outside the stage. Can be fooled in edge cases, but works much better than both 1 and 2. Requires much more code though.

Theo
A: 

Some time ago i have created a class that can help you with this problem. Check this: http://translate.google.com/translate?hl=ru&sl=ru&tl=en&u=http%3A%2F%2Factualwave.com%2Fblog%2F%3Fp%3D24 This post is about easy to use class StageBounds, it can check mouse presence in Fash Player by speed of mouse pointer.

a_w
+3  A: 

Using math to estimate when the mouse will be out of bounds:

(An implementation along the lines of Theo's 3rd option.)

// Stage rollout detection:
private var mouse_dx:Number;
private var mouse_dy:Number;

private function detectMouseOutOfBounds ():Void {
    mouse_dx = _xmouse;
    mouse_dy = _ymouse;

    var mouseListener:Object = { };
    mouseListener.onMouseMove = Delegate.create(this,
        function () {
            mouse_dx = Math.abs(mouse_dx-_xmouse);
            mouse_dy = Math.abs(mouse_dy-_ymouse);
            var speed:Number = Math.max(mouse_dx, mouse_dy) + 5; // Precautionary buffer added.
            var willBeOutOfBounds:Boolean = (
                _xmouse - speed < 0 || 
                _xmouse + speed > Stage.width ||
                _ymouse - speed < 0 ||
                _ymouse + speed > Stage.height
            );
            if (willBeOutOfBounds) {
                _display._alpha = 10;
            } else {
                _display._alpha = 100;
            }
            mouse_dx=_xmouse;
            mouse_dy = _ymouse;
        }
    );
    Mouse.addListener(mouseListener);
}
Pup
I can fool it if I really try, but it's the best I've seen so far. Wish I could give you more than one upvote!
Theo