views:

73

answers:

3

I have a quite large Flex application with a large set of views and I ceratain views I'd like to add shortcuts.

And i'm looking for something like:

<mx:Vbox>

<foo:Shortcut keys="ctrl+s" action="{bar();}"/> 

....

</mx:VBox>

Is there any framwork or component already done that does something like this? I guess it should be too difficult to build? When building this I only want the shortcuts to be active when the view is visible. How do I detect this? What base class is best to inherit from when working with non visual components?

+1  A: 

I don't think this solution answer your question directly but anyway, to help solve your problem here is an example.

For instance, I've extended the TextArea component like so. This is the best I can do so far, it can definitely be improved upon. Like, I don't know how to make the cursor go to the end after the next shortcut is pressed.

public class TextArea extends mx.controls.TextArea
{
   // the keysmap is an example dictionary holding keycodes
   private var keysmap:*={
       112 = "some text for F1"
       ,113 = "the text for F2!"
       //etc, etc
   }

   public var handleKeyDown:Boolean =false;
   public function TextArea(){
       if(handleKeyDown ==true){
            this.addEventListener(KeyboardEvent.KEY_DOWN,this.keydownHandler);
    }
   }
   public  function keydownHandler(e:KeyboardEvent):void{

       if(e.keyCode >= 112 && e.keyCode <= 123){
     e.currentTarget["text"] += String(keysmap[e.keyCode]) +" ";
       }//focusManager.setFocus(this);  
   }
}
joyceschan
+1  A: 

I can't give you a solution using MXML, however my first thought would involve a singleton static class with a Dictionary that contains a list of objects as its keys and dynamically created dictionaries as the value pairing that contain keys denoting the desired key press with a function reference as the value.

So, say you had a Sprite and you wanted to capture ctrl+s for save when focus is on that object, I would get the instance of that Singleton, and call a function such as registerKeyBinding passing in the Sprite, the keyCode you want, and your pre-defined callback:

private var registeredObjects:Dictionary = new Dictionary(true);

public function registerKeyBinding(targetObject:Object, keyCode:int, callback:Function) {   
    if (registeredObjects[targetObject]) {
        Dictionary(registeredObjects[targetObject])[keyCode] = callback;
    }
    else {
        registeredObjects[targetObject] = new Dictionary();
        Dictionary(registeredObjects[targetObject])[keyCode] = callback;
        targetObject.addEventListener(KeyboardEvent.KEY_DOWN, keyDownListener);
    }
}

private function keyDownListener(e:KeyboardEvent):void {
    if (e.ctrlKey == true) {
        //calls the function if that key exists.
        Dictionary(registeredObjects[e.target])[e.keyCode];
    }
}

Can't say I've tested this, but it was just the first thing that popped into my head. You could then setup functions to deregister and delete keys from the dictionaries, check states of the objects in addition to the keyCodes, remove old listeners, and delete entire dictionaries when there is no longer a need for them. Hopefully this is at least a tiny bit helpful.

Tegeril
+2  A: 

I don't know of any framework component that does that already, but the examples above should get you started if you try to build your own.

There's no need to inherit from any component for a non-visual component like the one you've described here (your "foo" class needs no parents.) There's nothing in the Flex framework you need to inherit from for this.

However you architect it, your foo class is going to have to take in and parse keyboard codes to listen for and accept one or more methods to call. All you have to do is figure out when to add and remove the event listeners that will call the passed-in methods.

To handle turning your keyboard events on and off based on visibility, just have your foo component bind to the "visible" property of it's parent and add/remove event listeners accordingly.

You might also consider having the listeners added when the component that foo is nested in is on the display list rather than just visible. To do this, simply added and remove your event listeners in one of the component lifecycle methods - probably commitProperties is the most appropriate.

RJ Owen