Tuesday, October 02, 2007

ActionScript: Key Press Routing

The Disclaimer

I recently needed some fairly obvious functionality in ActionScript, but for the life of me, I couldn't find an obvious way to access it. So, with a sinking feeling, I went ahead and implemented my own code to solve the problem. What follows, is this code - if I've reinvented the wheel, definitely let me know. If I haven't, then hopefully I can save someone else so time.

The Problem

I was working in Flash MX 2004 with a series of movie clips. These clips represented different UI windows. What I wanted to do, was to add keyboard shortcuts to these movie clips.

The obvious thing to do is to make use of Key.addListener and do something like:

  Key.addListener({
     onKeyUp: function() {
         if(Key.getCode() == Key.UP) {
            volume_mc.increase();
         }
         ...
     }
  });

The problem with this code is that it will handle every Key.UP press the same way, regardless of the movie clip in focus. This is annoying - I might want Key.UP to raise the volume when I'm hovering over the volume component, and go to the next song when I'm hovering over the album graphic.

Naturally, this can be done by adding more code to the condition that checks to see if the Flash player should invoke volume_mc.increase(). But this is oh so ugly. Especially, because the different clips that want different handlers may not be centrally created. And what about modal windows? Suppose I pop-up a dialog window, the key strokes shouldn't get through to the windows below it.

The Solution

My solution was to create an object called the KeyPressRouter. It allows you to register movie clips and a corresponding handler to invoke. When the user presses a key, the appropriate movie clip (meaning: visible, with the highest depth and within the bounds of _xmouse,_ymouse) will have its handler invoked. If no movie clips match this criteria, nothing happens.

A sample snippet of code might be:

 // In some shared part of your code
 keyRouter = new KeyPressRouter();
 ...

 // In volume component
 keyRouter.register(this, function(target) {
     if(Key.getCode() == Key.UP) { target.increase(); }
     if(Key.getCode() == Key.DOWN) { target.decrease(); }
 });

 // In modal dialog window
 keyRouter.register(this, function(target) {
     if(Key.getCode() == Key.UP) { target.scrollMessageUp(); }
     if(Key.getCode() == Key.DOWN) { target.scrollMessageDown(); }
 });

Note: in the above code, the handler takes in target, which is a convenient way to get a hold of the original movie clip that the handler was associated with.

The Code

Grab the code here: key-press-router.tar.gz. It's still very rough around the edges. But, as I said, maybe it'll save someone some time in solving this same problem.

3 comments:

  1. Thanks for your script, but do you know if is it possible to simulate a keypress event in actionscript 2 ? I want to make a virtual keyboard.
    Thanks in advance,
    Yann

    ReplyDelete
  2. Yann -

    I'm sorry, but I don't know the answer to your question.

    If you find out, I'd love it if you shared it with everyone here!

    -Ben

    ReplyDelete
  3. Anonymous4:39 AM

    Hello Ben,

    Thanks for your reply.

    I have a way on this site, I need to try it :
    http://www.ultrashock.com/forums/actionscript/simulate-a-keypress-121111.html

    Regards,

    Yann

    ReplyDelete