Thursday, January 22, 2009

Simple solution for MOUSE_WHEEL events on Mac

Flash does not support the MOUSE_WHEEL event for Macs. I was hoping it would be supported in version 9, and again in Flash 10 but I'm still waiting. There have been a number of solutions out there, and the best one I've found is Gabriel Bucknall's MacMouseWheel code. It consists of an actionscript class and some javascript code that will work together to have the browser pass the mouse wheel events to your Flash code.

After reading an awesome article by Peter McBride called JavaScript and VBScript Injection in ActionScript 3, I've put together a single as3 class that fixes the MOUSE_WHEEL problem without the need for any external javascript code. It works on Safari, FireFox and Opera and probably Chrome when it becomes available on the Mac.

The trick was to inject the mouse handling javascript code using ExternalInterface. The code finds the DOM node for itself, intercepts and passes the mouse wheel events which are then disributed to the current InteractiveObject under the cursor.

An example of initialization would be:

class awesomeapp extends Sprite {
public function awesomeapp() {
addEventListener(Event.ADDED_TO_STAGE, stage_init);
}
private function stage_init(e:Event):void {
MacMouseWheelHandler.init(stage);
addEventListener(MouseEvent.MOUSE_WHEEL, wheel_event);
}
}

Download the source (MIT license).

36 comments:

Kim said...

Cool stuff...I'm trying it out.
I just added a ":void" to the function in line 60 since FlexBuilder was bitchin' about your function not having a return value.

Good job man!

JesterXL said...

Dude, frikin' lifesaver, really easy to use, and works out of the box in my Flex project. Thanks a ton for sharing this!

Anonymous said...

Be sure to drop a vote for the bug itself in the Adobe bug tracker:

http://bugs.adobe.com/jira/browse/FP-503

Anonymous said...

This is terrific, but could you write a short example how to use it…i cant get it by my self…this would be nice :c)

zh. said...

Nice class, but it disables page scrolling in browser at all. Not only when mouse is over flash.
I tried to fix it, but no luck.

ed said...

Hi,
I tweaked this code to also allow the wheel to work on pc when wmode is being used in the *object* or *embed* tag.

code is here:
http://code.google.com/p/flex-wmode-mousewheel-handler-example/

Penguin said...

Hi, I am a novice Flash developer. Can someone please explains to me in basic steps (1,2,3) how to make this work on a Mac? Where do I put the MacMouseWheelHandler.as file

I am using this actionsctipt to scroll through my timeline


function scrollTime (event:MouseEvent):void
{
if (event.delta < 0)
{
nextFrame();
timeFrame ++;
trace (timeFrame);
scrollAxial_mc.value = timeFrame;
}
else
{
prevFrame();

timeFrame --;
scrollAxial_mc.value = timeFrame;
if (timeFrame <1 )
{
timeFrame = 1;
}
}
}


Many thanks to whoever answers this question. Help me please.

Pedro said...

Hello,
I´ve noticed that in safari the scrollbars of the browser stopped working is there a solution so that we can switch on/off the flash mousewheel support?

Thanks in advance

groupe de discussion said...

Super çà marche parfaitement pour moi, preuve à l'appuie :

http://www.centre-culturel-de-la-sar de la sarthe.com
allz dans une des rubriques où il y a un scroll !

Great it works for me !
the evidences on http://www.centre-culturel-de-la-sarthe.com

Thank you !

PEZ said...

Lovely!

Robert said...

Crazy easy to implement and works great!

<mx:Application ... creationComplete="init()"

<mx:Script>

import com.earthbrowser.MacMouseWheelHandler;

public function init():void{
      this.addEventListener(Event.ADDED_TO_STAGE, stage_init);

public function stage_init(e:Event):void {
    
MacMouseWheelHandler.init(stage);
}

</mx:Script>
.
.
.

Patrick said...

Hi there,
Can someone post an example? I tried inserting the code into the timeline as well as referencing it via the Document class.

Thank you!

Anonymous said...

ridiculous simply to implement!
Thanks a lot for this one!

For timeline-coders:
put the com folder in the right place and import the class using:

import com.earthbrowser.ebutils.MacMouseWheelHandler;


MacMouseWheelHandler.init(stage)

and there you go

tomek said...

Awesome! Thank you...

tomek

Rob said...

Just out of curiosity, is there any particular reason eb.findSwf iterates through the objects and embeds like it does rather than just using document.getElementById?

Rob said...

I just reread the code and figured out why, though it still seems like there should be a better way to do this.

Anonymous said...

this is by far the best solution on this matter (adobe should fix this) Thank you so much

NotarySojac said...

This is very interesting - the functionality is there if the app is being DEBUGGED from within the Flash IDE - but NOT THERE if just running 'TEST PROJECT' and NOT THERE when I run the app up in an HTML page.

Can anyone suggest what it is I am missing that will not let the MOUSE_WHEEL events be seen when NOT in the Flash DEBUG mode?

Anonymous said...

Hi it works fine for me here :
http://www.vetements-bambous.fr/boutique/index.php?option=com_virtuemart&Itemid=64&lang=fr&var_flexmode=1

but it dosent works on IE (7-8)

Does anybody make it works with IE ?

David Coletta said...

I found that with Safari 4.0.5, there were some problems with the direction of the scroll wheel events. It appeared as if the events were in the same direction no matter whether the wheel was scrolled up or down.

Fixed by adding the following line of code just before calling swf.ExternalMouseEvent():

if (eb.browser.safari && delta > 0.0)
delta += 1.0;

heiko said...

Thanks for sharing this - works a treat in Firefox and Chrome. However I am experiencing issues in Safari 4.05 - scrolling works but then jumps back in same direction. I tried David's fix, but it's not working for me. Would appreciate your feedback on this.

heiko said...

Check my site in Safari 4.0.5 and try using mousewheel over thumbnails. It works but immediately snaps back to start position.

heiko said...

I worked it out! Safari 4.0.5 works perfectly fine now. The weird thing is that it always worked in fullscreen mode.

if(eb.browser.safari) {
if(delta > 0){
delta += 1;
}
if(delta < 0){
delta -= 1;
}
}
swf.externalMouseEvent(delta);

titouille said...

Work perfect with the heiko add. Thanks a lot for sharing

Majakovskij said...

Thanks a TON!

kopfgeist said...

thanks a lot.

great work.

luv it

volker

Robert said...

Hello you lucky bastards.

I say you're a lucky bastard because if you're like me you're about to waste half of your day and lose many years off the duration of your life trying to figure out what the bumpkins above me are praising this solution while you can't get it to work.

This solution WILL NOT work if you are testing/publishing to a local file and testing there. No matter how many ways you try to import a com file, rewrite an event listener, smoke cigarettes, commit murder, it WILL NOT work.

In short for CS Flash timeline coding: delete the stuff after package in your MacMouseWheelHandler.as you dl above and put it local to your .fla file, deploy it to a web page on the net and call MacMouseWheelHandler.init(stage) at the top. All usage of MouseEvent.MOUSE_WHEEL will work as expected after you've done this.

Thank you for the lovely solution, I like having everything in my ActionScript.

Anonymous said...

Tried a few solutions, but this is definitely the best one!
Thanks!

Adam said...

Wow this is awesome, here I was pissed when I found out mouse scrolling didn't work on mac, this just took a huge problem and made it go poof, thanks again for the great class.

VSYO STUDIO | СТУДИЯ "ВСЁ" said...

Thanks! I was looking for those things.

Oliver said...

You are a bloody legend! Thank's for this :)

kittu said...

Its working greate in FF and Chrome, but not working in IE :(

Is there any fix for this ?

Zhongli wangz said...

Its working greate in Flex components except mx.controls.TextArea

Is there any fix for this ?

novus said...

Thank you SOOOOOOO much to Robert for the 'Hello you lucky bastards' comment. I would have groped around for hours if not for him :-( Fortunately Windows 7 has a real implementation of soft/hard links so you can just install Tomcat and link your bin-debug directory:

C:\Program Files\Apache Software Foundation\Tomcat 6.0\webapps\ROOT> mklink /D bin-debug C:\path\to\your\MyFlexApplication\bin-debug

Then go back to FB select the Run/Debug for your application. Set the 'URL or path to launch':
http://localhost:8080/bin-debug/MyFlexApplication.html

... and viola debugging with magically work. Note that you might have to wait 10-15 seconds for the MouseWheelEnabler to actually kick-in (i.e. it takes 10-15 seconds for it to actually start absorbing mouse wheel events). I don't know why this is but I haven't seen the behavior on remote web servers.

Anonymous said...

Hi,
I have a problem with mouse wheel in a flash application which has a function to apply when wheeling is done, but it doesn't work on Safari. I would like to know how to use your solution in my code please? I tried putting import pathTo/MacMouseWheelHandler.as and MacMouseWheelHandler.init(stage); but then, I don't known how to link that with my wheel function.

Thanks!

Anonymous said...

Very good. Thanks for sharing. It works like a charm.