Preventing scrolling and mouse events on out of focus AIR application

This has been a little bit of annoyance for me for some time. When an AIR application (like any Twitter application) is out of focus and you click on the application activate it, you inadvertently click a link or button within the application. You are also able to scroll the application when the application has no focus, which may or may not be your desired behavior.

I wanted a way to prevent mouse events and scrolling until the application has focus. I tried to find away around this annoyance by capturing if the application has focus by listening for Event.ACTIVATE or Event.DEACTIVATE events on the NativeApplication.nativeApplication:

 NativeApplication.nativeApplication.addEventListener(Event.ACTIVATE, handleAppActivate);
 NativeApplication.nativeApplication.addEventListener(Event.DEACTIVATE, handleAppDiactivate);

private function handleAppActivate(event:Event):void
 {
 // set a flag that application has focus so now links and buttons work
 }

private function handleAppDiactivate(event:Event):void
 {
 // set some flag to let the application has no focus so disable links and buttons
 }
 

This solution has a couple of problems. First the application has focus the instance you click on any link within the application window. So fine, the way around that is to use some kind of timer so that your flag that says application is now active is not set until some time after the application receives focus. This leads to the second problem, at least for larger scale applications. You have to pipe the flag that says the application has no focus to every button and link through the entire application, this is a huge pain.

Today I just happened to be playing with the new FramerateThrottler class created by Grant Skinner to reduce CPU usage for AIR applications running on Mac (this is yet another gripe of mine). So on his bog there are some comments about using mouseChildren and mouseEnabled on all open AIR windows to reduce CPU. Anyways, when I was messing around with this suggestion, I happened to notice my application no longer scrolled when the application was in the background, but mouse events were still active.

So I then thought of combining my previous attempt at preventing links and buttons from being clicked on with mouseChildren and mouseEnabled. I ended up only setting mouseChildren and mouseEnabled to true if the application has focus, and after a small timer dalay of 500 miliseconds. That gives me just enough time to click on the application any where without also clicking on a link or button and activating it. So now I can click on the application to give it focus any place I like without firing off click events:

 NativeApplication.nativeApplication.addEventListener(Event.ACTIVATE, handleAppActivate);
 NativeApplication.nativeApplication.addEventListener(Event.DEACTIVATE, handleAppDiactivate);

private var timer:Timer;
 private function handleAppActivate(event:Event):void
 {
 // set timer to enable mouse events after short delay on app activation
 timer = new Timer(500);
 timer.addEventListener(TimerEvent.COMPLETE, enableAppEvents);
 timer.start();
 }

private function handleAppDiactivate(event:Event):void
 {
 this.mouseChildren = false;
 this.mouseEnabled = false;
 }

private function enableAppEvents(event:TimerEvent):void
 {
 timer.stop();
 timer.removeEventListener(TimerEvent.COMPLETE, enableAppEvents);

// now scrolling and mouse events work
 this.mouseChildren = true;
 this.mouseEnabled = true;
 }
 

That’s it, a simple solution that was probably sitting under my nose the whole time but I never thought of it.

UPDATE

Jonnie Hallman from Adobe posted a great article that expands the idea of handling throttling and events (mouse wheel for example).

http://www.adobe.com/devnet/air/flex/articles/framerate_throttling.html

– Mr

One Comment

Comments are closed.