Yes, that should be posible with some modification.
Instead of dealying the event, you can stop it before it reaches it's original target, clone it and then refire the clone after the delay.
If you don't know how events work in the displaylist (anything you can see) in flash let me first explain it.
When you click a button a MouseEvent is fired, it begin in the capturing fase where it starts on the stage calling all eventlisteners registered for the "CLICK" event in the order of the priority set when the listeners was registered. If listerners has the same priority (the default is 0), the are called in a random order (properly the order that they where registered).
Once all listeners for the stage has been called the next displayObject in the list of the buttons ancestors is called, and the same thing happens again.
This continue all the way down to inner most displayobject that allow mouse events (could be a textfield label inside the button).
Here the capturing phase ends and the target phase begins.
The all the listeners on the innermost object is called in the target phase.
Then the bubbling phase begin, where all the listernes are called on parents and grandparents all the way up to the stage in the same manner as before (but from the inside out).
It should be noted that in flash the target phase is handled as part of the bubbling phase.
And how can we use this?
Well when you register and event listener you specify the phase and priority. The defaults are bubbling phase and priority 0. So if we register a click event listener on the stage for the capturing phase with priority int.MAX_VALUE, we would get the event before any other listerne except perhaps another identical listener.
The following code would prevent click events to registered by other listeners.
stage.addEventListener(MouseEvent.CLICK, stageClick, true, int.MAX_VALUE);
function stageClick(e:MouseEvent):void
{
e.stopImmediatePropagation();
}
That raises some other problems, firstly you don't want to do it for everything.
- One solution would be be to have a
list of all buttons that should have
their events modified, and checking
against it with e.target.
- Another solution would be to have all
buttons that require a delay
implement an interface (lets call it
IButtonDelay). And then simple check
if e.target is IButtondelay.
- A third solution would be to only
listen for the events on a containg
parent (like a menubar), since it is
unlikely that you would use the event
before it reaches this parent anyway.
For the first two solutions you should prevent mouseinteraction for the children of the buttons to simplify detection (DisplayObjectContainer.mouseChildren = false).
No matter what you choose here, next you would have to delay with a simple Timer. And then fire the event again after the delay.
e.target.dispatchEvent(e.clone());
That raises the problem of not delaying the refired event. My suggestion would be to instead fire an event object that inherits from MouseEvent instead of a simple clone. The MouseEvent is very simple to copy, it only has a few properties. So when you capture it the second time you can check if its a normal mouse click or your duplicated.
Using the solution with the inface on the buttons, it would be something like:
stage.addEventListener(MouseEvent.CLICK, stageClick, true, int.MAX_VALUE);
function stageClick(e:MouseEvent):void
{
if(e.target is IDelayButton && !e is DelayedMouseEvent)
{
e.stopImmediatePropagation();
DelayEvent(e);
}
}
function DelayEvent(e:MouseEvent):void
{
//You code for the delaying, cloning and refiring the event here
}
You might need to listen for more types of events (keyboard events), but most of the code can be made generic enough to include them.
Hope that helps and sorry about the long read.