Showing posts with label easykeyboard. Show all posts
Showing posts with label easykeyboard. Show all posts

Thursday, February 5, 2015

Creating EasyKeyboard class Part 3

Today we will add the ability to add listeners to keyboard by specifying key names instead of keycodes.

This way, well be able to set a key listener to the "A" key, for example, by simply passing "A" as one of the values to one of the methods of EasyKeyboard, instead of sending the key code of the key.

To know which name corresponds to which key, well need to add an array keyLabels in EasyKeyboard.as which contains names for all the keys. The index of each element in this array corresponds to the keys key code:

private var keyLabels:Array = ["0","1","2","3","4","5","6","7","Backspace","Tab","10","11","Center","Enter","14","15","Shift","Control","Alt","Pause","Caps Lock","21","22","23","24","25","26","27","28","29","30","31","Space","Page Up","Page Down","End","Home","Left","Up","Right","Down","41","42","43","44","Insert","Delete","47","0","1","2","3","4","5","6","7","8","9","58","59","60","61","62","63","64","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","Windows","Windows","Menu","94","95","Num 0","Num 1","Num 2","Num 3","Num 4","Num 5","Num 6","Num 7","Num 8","Num 9","Num *","Num +","108","Num -","Num .","Num /","F1","F2","F3","F4","F5","F6","F7","F8","F9","F10","F11","F12","124","125","126","127","128","129","130","131","132","133","134","135","136","137","138","139","140","141","142","143","Num Lock","Scroll Lock","146","147","148","149","150","151","152","153","154","155","156","157","158","159","160","161","162","163","164","165","166","167","168","169","170","171","172","173","174","175","176","177","178","179","180","181","182","183","184","185",";","+",",","-",".","/","~","193","194","195","196","197","198","199","200","201","202","203","204","205","206","207","208","209","210","211","212","213","214","215","216","217","218","[","\","]","","223","224","225","226","227","228","229","230","231","232","233","234","235","236","237","238","239","240","241","242","243","244","245","246","247","248","249","250","251","252","253","254","255"];

Now create a new function called addEasyListener. The parameters are the same as in addListener, except for the first one.

Instead of receiving keyCode, we receive a string keyName value. Then, in the function, we check which key code belongs to the specified key by looping through the array. If no match is found, then throw an error. If everything went smoothly, then simply call addListener() method with all the same parameter values as we received, and keyCode set to what weve calculated:

/**
* Add event listener for a single key using key string value.
* @paramkeyName String name of the key.
* @paramhandlerDown Function to be called when the key is pressed down.
* @paramhandlerUp Function to be called when the key is released.
* @paramalt Used in combination with the alt key.
* @paramctrl Used in combination with the ctrl key.
* @paramshift Used in combination with the shift key.
*/

public function addEasyListener(keyName:String, handlerDown:Function = null, handlerUp:Function = null, alt:Boolean = false, ctrl:Boolean = false, shift:Boolean = false):void {
var code:int = -1;
for (var i:int = 0; i < keyLabels.length; i++) {
if (keyLabels[i] == keyName) {
code = i;
break;
}
}
if (code == -1) {
throw new Error(Incorrect key string value specified - no " + keyName + " key found.);
return;
}
addListener(code, handlerDown, handlerUp, alt, ctrl, shift);
}

Full EasyKeyboard.as code:

package com.kircode.EasyKeyboard 
{
import flash.display.Stage;
import flash.events.Event;
import flash.events.KeyboardEvent;

/**
* Utility for easy keyboard listener management.
* @author Kirill Poletaev
*/
public class EasyKeyboard
{
public var listeners:Array = [];
private var keyLabels:Array = ["0","1","2","3","4","5","6","7","Backspace","Tab","10","11","Center","Enter","14","15","Shift","Control","Alt","Pause","Caps Lock","21","22","23","24","25","26","27","28","29","30","31","Space","Page Up","Page Down","End","Home","Left","Up","Right","Down","41","42","43","44","Insert","Delete","47","0","1","2","3","4","5","6","7","8","9","58","59","60","61","62","63","64","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","Windows","Windows","Menu","94","95","Num 0","Num 1","Num 2","Num 3","Num 4","Num 5","Num 6","Num 7","Num 8","Num 9","Num *","Num +","108","Num -","Num .","Num /","F1","F2","F3","F4","F5","F6","F7","F8","F9","F10","F11","F12","124","125","126","127","128","129","130","131","132","133","134","135","136","137","138","139","140","141","142","143","Num Lock","Scroll Lock","146","147","148","149","150","151","152","153","154","155","156","157","158","159","160","161","162","163","164","165","166","167","168","169","170","171","172","173","174","175","176","177","178","179","180","181","182","183","184","185",";","+",",","-",".","/","~","193","194","195","196","197","198","199","200","201","202","203","204","205","206","207","208","209","210","211","212","213","214","215","216","217","218","[","\","]","","223","224","225","226","227","228","229","230","231","232","233","234","235","236","237","238","239","240","241","242","243","244","245","246","247","248","249","250","251","252","253","254","255"];
private var st:Stage;

public function EasyKeyboard(stage:Stage)
{
stage.addEventListener(KeyboardEvent.KEY_DOWN, kDown);
stage.addEventListener(KeyboardEvent.KEY_UP, kUp);
stage.addEventListener(Event.ENTER_FRAME, frame);
st = stage;
}

private function frame(evt:Event):void {

}

/**
* Add event listener for a single key using a keycode.
* @paramkeyCode Key code of the key.
* @paramhandlerDown Function to be called when the key is pressed down.
* @paramhandlerUp Function to be called when the key is released.
* @paramalt Used in combination with the alt key.
* @paramctrl Used in combination with the ctrl key.
* @paramshift Used in combination with the shift key.
*/

public function addListener(keyCode:int, handlerDown:Function = null, handlerUp:Function = null, alt:Boolean = false, ctrl:Boolean = false, shift:Boolean = false):void {
listeners.push(new KeyListener(keyCode, handlerDown, handlerUp, alt, ctrl, shift));
}

/**
* Add event listener for a single key using key string value.
* @paramkeyName String name of the key.
* @paramhandlerDown Function to be called when the key is pressed down.
* @paramhandlerUp Function to be called when the key is released.
* @paramalt Used in combination with the alt key.
* @paramctrl Used in combination with the ctrl key.
* @paramshift Used in combination with the shift key.
*/

public function addEasyListener(keyName:String, handlerDown:Function = null, handlerUp:Function = null, alt:Boolean = false, ctrl:Boolean = false, shift:Boolean = false):void {
var code:int = -1;
for (var i:int = 0; i < keyLabels.length; i++) {
if (keyLabels[i] == keyName) {
code = i;
break;
}
}
if (code == -1) {
throw new Error(Incorrect key string value specified - no " + keyName + " key found.);
return;
}
addListener(code, handlerDown, handlerUp, alt, ctrl, shift);
}

private function kDown(evt:KeyboardEvent):void {
for (var i:int = 0; i < listeners.length; i++) {
if (evt.keyCode == listeners[i].keyCode && listeners[i] is KeyListener && evt.altKey == listeners[i].alt && evt.ctrlKey == listeners[i].ctrl && evt.shiftKey == listeners[i].shift) {
if (listeners[i].handlerD) listeners[i].handlerD.call();
}
}
}

private function kUp(evt:KeyboardEvent):void {
for (var i:int = 0; i < listeners.length; i++) {
if (evt.keyCode == listeners[i].keyCode && listeners[i] is KeyListener && evt.altKey == listeners[i].alt && evt.ctrlKey == listeners[i].ctrl && evt.shiftKey == listeners[i].shift) {
if (listeners[i].handlerU) listeners[i].handlerU.call();
}
}
}

}

}

If you go to main.as now, you can call the addEasyListener to add keyboard listeners this way:

keyboard = new EasyKeyboard(stage);
keyboard.addEasyListener("A", function() { trace("Down"); }, function() { trace("Up"); } );
// LINE ABOVE EQUALS TO: keyboard.addListener(65, function() { trace("Down"); }, function() { trace("Up"); });

Thats all for today.

Thanks for reading!
Read more »

Monday, January 26, 2015

Creating EasyKeyboard class Part 13

Today well further improve the abilities to remove listeners.

The removeListener() function works fine now, but theres a slight problem with removing TimedListeners. The issue is in the Timer, which doesnt stop working even after the listener was "removed". Aside from just removing it from the listeners array, we also need to reset and nullify the timer inside the listener.

You can witness the bug yourself if you create a timed listener and a key listener which removes the timed listener, then try to hold the key which triggers the timed event. If you remove the listener during the delay, youll see that the code dispatches the timed event one more time before stopping.

keyboard = new EasyKeyboard(stage);
keyboard.addEasyTimedListener("A", 1000, function() { trace("Key A is pressed!!") }, true, "key1");
keyboard.addEasyListener("S", function () { keyboard.removeListener("key1"); trace("Listener for A key removed!"); } );

Lets fix this. Update the removeListener() function:

/**
* Remove a single listener.
* @paramlistenerId Id of the listener, which is specified as String when the listener is created.
*/

public function removeListener(listenerId:String):void {
for (var i:int = listeners.length - 1; i >= 0; i--) {
if (listeners[i].id == listenerId) {
if (listeners[i] is TimedListener) {
listeners[i].delayTimer.reset();
listeners[i].delayTimer = null;
}
listeners.splice(i, 1);
break;
}
}
}

Now well add a function which removes all the listeners at once. Right now we have one called kill(), but it didnt actually remove all the listeners from the array - it just stops listening to the keyboard as a whole.

The removeAllListeners() method will loop through all listeners and remove them one by one, also taking care of timers the same way like in removeListener:

/**
* Remove all listeners. IMPORATNT: If you are removing the EasyKeyboard object as a whole, use the kill() method.
*/

public function removeAllListeners():void {
for (var i:int = listeners.length - 1; i >= 0; i--) {
if (listeners[i] is TimedListener) {
listeners[i].delayTimer.reset();
listeners[i].delayTimer = null;
}
listeners.splice(i, 1);
}
}

We should also call this function in kill():

/**
* Call this before nullifying the class instance to remove all the listeners.
*/

public function kill():void {
removeAllListeners();
st.removeEventListener(KeyboardEvent.KEY_DOWN, kDown);
st.removeEventListener(KeyboardEvent.KEY_UP, kUp);
st.addEventListener(Event.ENTER_FRAME, frame);
}

So, to remove all the listeners, the user simply writes:

keyboard.removeAllListeners();

Full EasyKeyboard.as class code so far:

package com.kircode.EasyKeyboard 
{
import flash.display.Stage;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.utils.Timer;

/**
* Utility for easy keyboard listener management.
* @author Kirill Poletaev
*/
public class EasyKeyboard
{
public var listeners:Array = [];
private var keyLabels:Array = ["0","1","2","3","4","5","6","7","Backspace","Tab","10","11","Center","Enter","14","15","Shift","Control","Alt","Pause","Caps Lock","21","22","23","24","25","26","27","28","29","30","31","Space","Page Up","Page Down","End","Home","Left","Up","Right","Down","41","42","43","44","Insert","Delete","47","0","1","2","3","4","5","6","7","8","9","58","59","60","61","62","63","64","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","Windows","Windows","Menu","94","95","Num 0","Num 1","Num 2","Num 3","Num 4","Num 5","Num 6","Num 7","Num 8","Num 9","Num *","Num +","108","Num -","Num .","Num /","F1","F2","F3","F4","F5","F6","F7","F8","F9","F10","F11","F12","124","125","126","127","128","129","130","131","132","133","134","135","136","137","138","139","140","141","142","143","Num Lock","Scroll Lock","146","147","148","149","150","151","152","153","154","155","156","157","158","159","160","161","162","163","164","165","166","167","168","169","170","171","172","173","174","175","176","177","178","179","180","181","182","183","184","185",";","+",",","-",".","/","~","193","194","195","196","197","198","199","200","201","202","203","204","205","206","207","208","209","210","211","212","213","214","215","216","217","218","[","\","]","","223","224","225","226","227","228","229","230","231","232","233","234","235","236","237","238","239","240","241","242","243","244","245","246","247","248","249","250","251","252","253","254","255"];
private var st:Stage;

public function EasyKeyboard(stage:Stage)
{
stage.addEventListener(KeyboardEvent.KEY_DOWN, kDown);
stage.addEventListener(KeyboardEvent.KEY_UP, kUp);
stage.addEventListener(Event.ENTER_FRAME, frame);
st = stage;
}

private function frame(evt:Event):void {
for (var i:int = 0; i < listeners.length; i++) {
if (listeners[i] is HoldListener && listeners[i].flag) {
if (listeners[i].handler != null) listeners[i].handler.call();
}
}
}

/**
* Call this before nullifying the class instance to remove all the listeners.
*/

public function kill():void {
removeAllListeners();
st.removeEventListener(KeyboardEvent.KEY_DOWN, kDown);
st.removeEventListener(KeyboardEvent.KEY_UP, kUp);
st.addEventListener(Event.ENTER_FRAME, frame);
}

/**
* Add event listener for a single key using a keycode.
* @paramkeyCode Key code of the key.
* @paramhandlerDown Function to be called when the key is pressed down.
* @paramhandlerUp Function to be called when the key is released.
* @paramalt Used in combination with the alt key.
* @paramctrl Used in combination with the ctrl key.
* @paramshift Used in combination with the shift key.
* @paramid ID of the listener. Set this to be able to remove the listener dynamically later using the removeListener() method.
*/

public function addListener(keyCode:int, handlerDown:Function = null, handlerUp:Function = null, alt:Boolean = false, ctrl:Boolean = false, shift:Boolean = false, id:String = ""):void {
listeners.push(new KeyListener(keyCode, handlerDown, handlerUp, alt, ctrl, shift, id));
}

/**
* Add event listener for a single key using a keycode.
* @paramkeyCode Key code of the key.
* @paramhandler Function to execute while the key is held every frame.
* @paramid ID of the listener. Set this to be able to remove the listener dynamically later using the removeListener() method.
*/

public function addHoldListener(keyCode:int, handler:Function, id:String = ""):void {
listeners.push(new HoldListener(keyCode, handler, false, id));
}


/**
* Add event listener for a combination of keys using key codes.
* @paramkeyCodes Array of key codes for the combination.
* @paramhandler Function to execute when the combination is held.
* @paramid ID of the listener. Set this to be able to remove the listener dynamically later using the removeListener() method.
*/

public function addComboListener(keyCodes:Array, handler:Function, id:String = ""):void {
var flags:Array = [];
for (var i:int = 0; i < keyCodes.length; i++) {
if (isNaN(keyCodes[i])) {
throw new Error(Incorrect key code value specified - " + keyCodes[i] + " is not a number.);
return;
}
flags.push(false);
}
listeners.push(new ComboListener(keyCodes, handler, flags, id));
}

/**
* Add event timed listener for a single key using a keycode.
* @paramkeyCode Key code of the key.
* @paramdelay Delay in milliseconds of how long the key needs to be held down for the event to be registered.
* @paramhandler Function to execute when the key has been held for the specified amount of time.
* @paramrepeat Set to true if you want to dispatch the event forever until the key is released. If you only want to dispatch it once, set to false.
* @paramid ID of the listener. Set this to be able to remove the listener dynamically later using the removeListener() method.
*/

public function addTimedListener(keyCode:int, delay:int, handler:Function, repeat:Boolean = true, id:String = ""):void {
var rep:int = 1;
if (repeat == true) rep = 0;
var delayTimer:Timer = new Timer(delay, 1);
listeners.push(new TimedListener(keyCode, delayTimer, handler, rep, id));
}

/**
* Add event listener for a sequence of keys to be pressed.
* @paramkeyCodes Array of key codes in the sequence.
* @paramhandler Function to execute when the keys are pressed in the specific order.
* @paramid ID of the listener. Set this to be able to remove the listener dynamically later using the removeListener() method.
*/

public function addSequenceListener(keyCodes:Array, handler:Function, id:String = ""):void {
for (var i:int = 0; i < keyCodes.length; i++) {
if (isNaN(keyCodes[i])) {
throw new Error(Incorrect key code value specified - " + keyCodes[i] + " is not a number.);
return;
}
}
listeners.push(new SequenceListener(keyCodes, handler, id));
}

/**
* Add event listener for a single key using key string value.
* @paramkeyName String name of the key.
* @paramhandlerDown Function to be called when the key is pressed down.
* @paramhandlerUp Function to be called when the key is released.
* @paramalt Used in combination with the alt key.
* @paramctrl Used in combination with the ctrl key.
* @paramshift Used in combination with the shift key.
* @paramid ID of the listener. Set this to be able to remove the listener dynamically later using the removeListener() method.
*/

public function addEasyListener(keyName:String, handlerDown:Function = null, handlerUp:Function = null, alt:Boolean = false, ctrl:Boolean = false, shift:Boolean = false, id:String = ""):void {
var code:int = -1;
for (var i:int = 0; i < keyLabels.length; i++) {
if (keyLabels[i] == keyName) {
code = i;
break;
}
}
if (code == -1) {
throw new Error(Incorrect key string value specified - no " + keyName + " key found.);
return;
}
addListener(code, handlerDown, handlerUp, alt, ctrl, shift, id);
}

/**
* Add hold listener for a single key using key string value.
* @paramkeyName String name of the key.
* @paramhandler Function to execute while the key is held every frame.
* @paramid ID of the listener. Set this to be able to remove the listener dynamically later using the removeListener() method.
*/

public function addEasyHoldListener(keyName:String, handler:Function, id:String = ""):void {
var code:int = -1;
for (var i:int = 0; i < keyLabels.length; i++) {
if (keyLabels[i] == keyName) {
code = i;
break;
}
}
if (code == -1) {
throw new Error(Incorrect key string value specified - no " + keyName + " key found.);
return;
}
addHoldListener(code, handler, id);
}

/**
* Add event listener for a combination of keys using key names.
* @paramkeyNames Array of key names for the combination.
* @paramhandler Function to execute when the combination is held.
* @paramid ID of the listener. Set this to be able to remove the listener dynamically later using the removeListener() method.
*/

public function addEasyComboListener(keyNames:Array, handler:Function, id:String = ""):void {
var flags:Array = [];
var keyCodes:Array = [];
var u:int;
var i:int;
var code:int = -1;
var keyName:String;

for (u = 0; u < keyNames.length; u++) {
flags.push(false);
code = -1;
keyName = keyNames[u];
for (i = 0; i < keyLabels.length; i++) {
if (keyLabels[i] == keyName) {
code = i;
keyCodes.push(code);
break;
}
}
if (code == -1) {
throw new Error(Incorrect key string value specified - no " + keyName + " key found.);
return;
}
}

listeners.push(new ComboListener(keyCodes, handler, flags, id));
}

/**
* Add event listener for a sequence of keys to be pressed using key names.
* @paramkeyNames Array of key names in the sequence.
* @paramhandler Function to execute when the keys are pressed in the specific order.
* @paramid ID of the listener. Set this to be able to remove the listener dynamically later using the removeListener() method.
*/

public function addEasySequenceListener(keyNames:Array, handler:Function, id:String = ""):void {
var keyCodes:Array = [];
var u:int;
var i:int;
var code:int = -1;
var keyName:String;

for (u = 0; u < keyNames.length; u++) {
code = -1;
keyName = keyNames[u];
for (i = 0; i < keyLabels.length; i++) {
if (keyLabels[i] == keyName) {
code = i;
keyCodes.push(code);
break;
}
}
if (code == -1) {
throw new Error(Incorrect key string value specified - no " + keyName + " key found.);
return;
}
}
listeners.push(new SequenceListener(keyCodes, handler, id));
}

/**
* Add event timed listener for a single key using a keyname.
* @paramkeyName Name of the key.
* @paramdelay Delay in milliseconds of how long the key needs to be held down for the event to be registered.
* @paramhandler Function to execute when the key has been held for the specified amount of time.
* @paramrepeat Set to true if you want to dispatch the event forever until the key is released. If you only want to dispatch it once, set to false.
* @paramid ID of the listener. Set this to be able to remove the listener dynamically later using the removeListener() method.
*/

public function addEasyTimedListener(keyName:String, delay:int, handler:Function, repeat:Boolean = true, id:String = ""):void {
var rep:int = 1;
if (repeat == true) rep = 0;
var delayTimer:Timer = new Timer(delay, 1);
var code:int = -1;
for (var i:int = 0; i < keyLabels.length; i++) {
if (keyLabels[i] == keyName) {
code = i;
break;
}
}
if (code == -1) {
throw new Error(Incorrect key string value specified - no " + keyName + " key found.);
return;
}
listeners.push(new TimedListener(code, delayTimer, handler, rep, id));
}

private function kDown(evt:KeyboardEvent):void {
var u:int = 0;
var comboKeys:int = 0;
for (var i:int = 0; i < listeners.length; i++) {
if (listeners[i] is KeyListener && evt.keyCode == listeners[i].keyCode && evt.altKey == listeners[i].alt && evt.ctrlKey == listeners[i].ctrl && evt.shiftKey == listeners[i].shift) {
if (listeners[i].handlerD) listeners[i].handlerD.call();
}
if (listeners[i] is HoldListener && evt.keyCode == listeners[i].keyCode) {
listeners[i].flag = true;
}
if (listeners[i] is ComboListener) {
comboKeys = 0;
for (u = 0; u < listeners[i].keyCodes.length; u++) {
if (listeners[i].keyCodes[u] == evt.keyCode) {
listeners[i].flags[u] = true;
}
if (listeners[i].flags[u] == true) comboKeys++;
}
if (comboKeys == listeners[i].keyCodes.length) {
if (listeners[i].handler) listeners[i].handler.call();
}
}
if (listeners[i] is TimedListener && evt.keyCode == listeners[i].keyCode) {
if (!listeners[i].delayTimer.running) {
listeners[i].delayTimer.start();
}
}
if (listeners[i] is SequenceListener) {
if (evt.keyCode == listeners[i].keyCodes[listeners[i].sequenceIndex]) {
listeners[i].sequenceIndex++;
if (listeners[i].sequenceIndex == listeners[i].keyCodes.length) {
if (listeners[i].handler) listeners[i].handler.call();
listeners[i].sequenceIndex = 0;
}
}else {
listeners[i].sequenceIndex = 0;
}
}
}
}

private function kUp(evt:KeyboardEvent):void {
var u:int = 0;
for (var i:int = 0; i < listeners.length; i++) {
if (listeners[i] is KeyListener && evt.keyCode == listeners[i].keyCode && evt.altKey == listeners[i].alt && evt.ctrlKey == listeners[i].ctrl && evt.shiftKey == listeners[i].shift) {
if (listeners[i].handlerU) listeners[i].handlerU.call();
}
if (listeners[i] is HoldListener && evt.keyCode == listeners[i].keyCode) {
listeners[i].flag = false;
}
if (listeners[i] is ComboListener) {
for (u = 0; u < listeners[i].keyCodes.length; u++) {
if (listeners[i].keyCodes[u] == evt.keyCode) {
listeners[i].flags[u] = false;
}
}
}
if (listeners[i] is TimedListener && evt.keyCode == listeners[i].keyCode) {
if (listeners[i].delayTimer.running) {
listeners[i].delayTimer.reset();
if (listeners[i].repeat == 2) listeners[i].repeat = 1;
}
}
}
}

/**
* Remove a single listener.
* @paramlistenerId Id of the listener, which is specified as String when the listener is created.
*/

public function removeListener(listenerId:String):void {
for (var i:int = listeners.length - 1; i >= 0; i--) {
if (listeners[i].id == listenerId) {
if (listeners[i] is TimedListener) {
listeners[i].delayTimer.reset();
listeners[i].delayTimer = null;
}
listeners.splice(i, 1);
break;
}
}
}

/**
* Remove all listeners. IMPORATNT: If you are removing the EasyKeyboard object as a whole, use the kill() method.
*/

public function removeAllListeners():void {
for (var i:int = listeners.length - 1; i >= 0; i--) {
if (listeners[i] is TimedListener) {
listeners[i].delayTimer.reset();
listeners[i].delayTimer = null;
}
listeners.splice(i, 1);
}
}

}

}

Thanks for reading!
Read more »