Create a gist now

Instantly share code, notes, and snippets.

example of fast keyboard events delegation with callbacks & the "supported key" concept
/*
* KeyboardHandler
*
* example of fast keyboard events delegation with callbacks & the "supported key"
* concept. a basic keyboard state machine.
*
* usage e.g.:
*
* var kh:KeyboardHandler = new KeyboardHandler(nativeStage);
* kh.addKey(Keyboard.LEFT, leftKeyHandler);
* kh.addKey(Keyboard.SHIFT, leftKeyHandler);
*
* ...
* private leftKeyHandler(keyCode:uint, isDown:uint):void
* {
* // LAZY way to see if a key is already down; SHIFT + LEFT combination
* trace(kh.keyIsDown(Keyboard.SHIFT) && keyCode == Keyboard.LEFT && isDown);
* }
*
* source code is released in the public domain without warranty of any kind
* Lubomir I. Ivanov, 2014
*
*/
package
{
import flash.display.Stage;
import flash.events.KeyboardEvent;
/* this is the worker safe variant, but perhaps the class should be a singleton
* as you can imagine...you may need only one of it.
*/
public final class KeyboardHandler /* implements IDispose */
{
public var enabled:Boolean;
private var stage:Stage;
private var supportedKeys:Vector.<SupportedKey>;
private var disposed:Boolean;
public function KeyboardHandler(_stage:Stage):void
{
disposed = false;
enabled = true;
stage = _stage;
supportedKeys = Vector.<SupportedKey>([]);
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
}
// public: add a keyCode (flash.ui.Keyboard)
public function addKey(keyCode:uint, callback:Function):void
{
if (callback == null)
throw Error("callback cannot be null");
removeKey(keyCode);
supportedKeys[supportedKeys.length] = new SupportedKey(keyCode, callback);
}
// public: remove a keyCode (flash.ui.Keyboard)
public function removeKey(keyCode:uint):void
{
for (var i:uint = 0, len:uint = supportedKeys.length; i < len; i++) {
const sk:SupportedKey = supportedKeys[i];
if (sk.keyCode == keyCode) {
sk.callback = null;
supportedKeys[i] = null;
supportedKeys.splice(i, 1);
return;
}
}
}
// public: check if a supported key is down
public function keyIsDown(keyCode:uint):Boolean
{
const sk:SupportedKey = getSupportedKey(keyCode);
if (!sk)
return false;
return sk.isDown;
}
// private
private function getSupportedKey(keyCode:uint):SupportedKey
{
for (var i:uint = 0, len:uint = supportedKeys.length; i < len; i++) {
const sk:SupportedKey = supportedKeys[i];
if (sk.keyCode == keyCode)
return sk;
}
return null;
}
// private
private function keyDownHandler(e:KeyboardEvent):void
{
if (!enabled)
return;
e.preventDefault();
e.stopImmediatePropagation();
const keyCode:uint = e.keyCode;
const sk:SupportedKey = getSupportedKey(keyCode);
if (!sk || (sk && sk.isDown))
return;
sk.isDown = true;
sk.callback(keyCode, true);
}
// private
private function keyUpHandler(e:KeyboardEvent):void
{
if (!enabled)
return;
e.preventDefault();
e.stopImmediatePropagation();
const keyCode:uint = e.keyCode;
const sk:SupportedKey = getSupportedKey(keyCode);
if (!sk || (sk && !sk.isDown))
return;
sk.isDown = false;
sk.callback(keyCode, false);
}
public function dispose():void
{
if (disposed)
return;
for (var i:uint = 0, len:uint = supportedKeys.length; i < len; i++) {
supportedKeys[i].callback = null;
supportedKeys[i] = null;
}
supportedKeys.length = 0;
supportedKeys = null;
stage.removeEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
stage.removeEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
stage = null;
disposed = true;
}
}
}
/* a helper static class for local use */
final internal class SupportedKey
{
/* get / set modifiers are great for APIs changes, but are rather slow.
* you should rather use them *if* and *only if* the API changes or if
* you really want a read-only property.
*/
public var keyCode:uint;
public var isDown:Boolean;
public var callback:Function;
public function SupportedKey(_keyCode:uint, _callback:Function):void
{
isDown = false;
keyCode = _keyCode;
callback = _callback;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment