So I’ve finally updated the solution I’ve made earlier for enabling Mac OS X mouse wheel support in Flex applications to a second version. I didn’t want to continue adding stuff into the original post, so I decided to write a separate post just for this new version. As you can see from the title, this version should work in any Flash project you’re writing in ActionScript 3, as opposed to just in Flex projects. This change was contributed by Pavel Fljot, and all the other stuff I’ve added since have been added on top of that. Deployment should now be a lot easier and some features that were missing in the first version have also been added.
First, here is an itemized list of what has changed:
- Flex dependencies have been removed, which makes it possible to use this in pure AS3 projects as well
- States of modifier keys (i.e. ctrl (or command in OS X,) alt, shift) are supported
- An another method of determining which object on the Stage should dispatch the mouse wheel event has been added
- Is enabled for Safari for Windows
- Can be enabled for any number of different Flash objects on the same page
- The initialization state of the mouse wheel support is exposed
- The concept of “registering and unregistering objects” for mouse wheel support within AS3 code has been removed
This changes the way the support is initialized in AS3, but more about that a bit later. Courtesy of Pavel Fljot.
These can be accessed via the ctrlKey, altKey and shiftKey properties in the MouseEvent object, as usual.
Read more about this below. Courtesy of a similar solution from Gabriel Bucknall.
For some mysterious reason the mouse wheel won’t work in Flash when accessed with the Windows version of Safari, so this solution will now enable itself for that browser. Courtesy of Pavel Fljot.
You can read the value of the “initialized” property (or bind to it) to see if the mouse wheel support has been initialized.
This concept is no longer useful, given the new implementation.
Determining the InteractiveObject to dispatch the mouse wheel event
Now, the main difference between these two solutions, I’ve found, is that Gabriel’s is faster but inaccurate in some border cases, while mine is slower but more accurate. The slowness of my solution is very clear if you understand the amount of processing that goes on whenever the user starts rolling the wheel: for each event, the application needs to go through the whole hierarchy of objects on the Stage, find InteractiveObjects that are under the mouse cursor, mouse-enabled and visible, and then find the one of those that is deepest in the display list. Gabriel’s solution doesn’t need to do any of this: it already has the InteractiveObject reference it wants to use at this point. The inaccuracy, on the other hand, stems from the fact that if the user doesn’t move their mouse, the reference won’t get updated. What this means is that if the InteractiveObjects on Stage have moved (in relation to the mouse cursor,) or been added to or removed from the display list while the cursor has stayed put, the reference will not be up to date, and probably incorrect.
As you’ve probably deduced from the last paragraph, there are upsides and downsides to both of these approaches, and I at least would like to be able to choose which one to use, based on the context of what I happen to be doing at the moment. This is why I’ve added this exact feature into the code in the form of a property the value of which you can set at will:
private var _mwSupport:ExternalMouseWheelSupport = ExternalMouseWheelSupport.getInstance(stage); _mwSupport.dispatchingObjectDeterminationMethod = ExternalMouseWheelSupport.COPY_MOUSEMOVE_EVENTS; // or _mwSupport.dispatchingObjectDeterminationMethod = ExternalMouseWheelSupport.TRAVERSE_DISPLAY_LIST;
You can test the differences between these two options with the demo.
Deployment and use
So like I wrote before, the process of deploying and initializing this solution has changed a bit from the last version. This is how you do it now.
- Make sure your embedded Flash objects have a parent div element
- In your AS3 code, get a reference to the singleton instance of ExternalMouseWheelSupport in at least one place
<!-- add Flash object's <object> and <embed> tags here -->
As you can see, the singleton instance accessor is not a property anymore, but a method, so that you can pass a reference to the Stage to it. This change is because of the removal of dependencies to Flex libraries, which could be used to access the Stage instance in the previous version.
import org.hasseg.externalMouseWheel.ExternalMouseWheelSupport; private var _mwSupport:ExternalMouseWheelSupport = ExternalMouseWheelSupport.getInstance(stage);
I generally do this in the applicationComplete event handler, but you can of course call it wherever you want, as long as you make sure the Stage reference you’re using is not null (an Error will be thrown if it is.)
…and that’s it. :)
Downloads and demo
This code is licensed under the MIT License.
I’ve tested this solution with the following browsers (sadly, Opera on the Mac isn’t supported since ExternalInterface doesn’t seem to work in the latest version:)
- On OS X 10.5.2:
- Safari 3.1.1
- Firefox 3 beta 5
- Camino 1.6
- OmniWeb 5.7
- On Windows XP SP2:
- Internet Explorer 7.0
- Firefox 2.0
- Safari 3.1.1
- Opera 9.27
If someone could please test this on the Mac OS version of Firefox 2 and the Windows versions of Firefox 3 beta and IE 6, I’d very much appreciate it.