Thursday, October 25, 2012

Creating EasyKeyboard class: Part 7

In this tutorial we will add the ability to add key combination listeners using key names, as well as add a validation check for addComboListener's keyCodes.

Go to EasyKeyboard.as class and add a new function called addEasyComboListener. Add 2 parameters - keyNames array and handler function.

Declare 6 variables inside - flags array, keyCodes array, i integer, u integer, code integer and keyName string.

The flags and keyCodes arrays will be filled with values in the next piece of code, and then passed to a ComboListener object, which is hen added to listeners. The u and i variables play a role in the two for loops that I'm about to add. The code variable holds the value of the current key's keyCode. The keyName variable holds the value of the current key's name.

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

Add a for loop that goes through all keyNames values. In each cycle push a "false" value to flags, set code to -1 and keyName to keyNames[u]. Then add a new loop, and this time check the current keyName with each keyLabel to check its validity and find out what keyCode that key has. If code value remains -1 after the loop, that means no keyCode was found and an error is thrown.

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;
break;
}
}
if (code == -1) {
throw new Error('Incorrect key string value specified - no "' + keyName + '" key found.');
return;
}
}

And then we add the values together to create a ComboListener object that is then passed to the listeners array:

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

Full function:

/**
 * 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.
 */

public function addEasyComboListener(keyNames:Array, handler:Function):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;
break;
}
}
if (code == -1) {
throw new Error('Incorrect key string value specified - no "' + keyName + '" key found.');
return;
}
}

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

Now you can go to main.as and add key combination listeners this way:

keyboard = new EasyKeyboard(stage);
keyboard.addEasyComboListener(["A", "S"], function() { trace("A+S combo is being held!"); } );

Return back to EasyKeyboard.as and find the addComboListener() function. Here, we'll add an if...statement inside the loop, which checks each element in keyCode for validity. If the value is not a number - throw out an error:

/**
 * 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.
 */

public function addComboListener(keyCodes:Array, handler:Function):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));
}

Therefore, if you go back to main.as and write this:

keyboard.addComboListener([1, "a"], null);

You'll receive the following error:

Error: Incorrect key code value specified - "a" is not a number.
at com.kircode.EasyKeyboard::EasyKeyboard/addComboListener()
at main/init()

Full EasyKeyboard class code so far:

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 {
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 {
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.
 */

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 a keycode.
 * @paramkeyCode Key code of the key.
 * @paramhandler Function to execute while the key is held every frame.
 */

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


/**
 * 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.
 */

public function addComboListener(keyCodes:Array, handler:Function):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));
}

/**
 * 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);
}

/**
 * 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.
 */

public function addEasyHoldListener(keyName:String, handler:Function):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);
}

/**
 * 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.
 */

public function addEasyComboListener(keyNames:Array, handler:Function):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;
break;
}
}
if (code == -1) {
throw new Error('Incorrect key string value specified - no "' + keyName + '" key found.');
return;
}
}

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

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();
}
}
}
}

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;
}
}
}
}
}

}

}

Thanks for reading!

No comments:

Post a Comment