Source: input/keyboard/Keyboard.js

//------------------------------------------------------------------------------
// Constructor scope
//------------------------------------------------------------------------------

/** 
 * Creates a new instance of the Keyboard class.
 * 
 * @constructor
 *
 * @param {Object} [options] Keyboard settings.
 *
 * @class
 * @classdesc
 * 
 * The Keyboard class represents a physical keyboard with associated keys. 
 * With class instances, it is possible to read the state (pressed, released, 
 * etc.) for each individual key on the keyboard.
 */
rune.input.Keyboard = function(options) {
    
    //--------------------------------------------------------------------------
    // Private properties
    //--------------------------------------------------------------------------
    
    /**
     * Whether the keyboard should be activated or not. An inactive keyboard, 
     * registers no input.
     *
     * @type {boolean}
     * @private
     */
    this.m_enabled = Boolean(options.enable);
    
    /**
     * List of keyboard keys.
     *
     * @type {Array.<rune.input.KeyboardKey>}
     * @private
     */
    this.m_keys = new Array(rune.input.Keyboard.NUM_KEYS);
    
    /**
     * Lookup table for the keyboard keys.
     *
     * @type {Object}
     * @private
     */
    this.m_LUT = {};
    
    /**
     * Reference to event handler (keydown).
     *
     * @type {Function}
     * @private
     */
    this.m_onKeyDownHandler = null;
    
    /**
     * Reference to event handler (keyup).
     *
     * @type {Function}
     * @private
     */
    this.m_onKeyUpHandler = null;
    
    /**
     * Settings for the current keyboard.
     *
     * @type {rune.input.KeyboardOptions}
     * @private
     */
    this.m_options = new rune.input.KeyboardOptions(options);
    
    //--------------------------------------------------------------------------
    // Constructor call
    //--------------------------------------------------------------------------
    
    /**
     * Invokes secondary class constructor.
     */
    this.m_construct();
};

//------------------------------------------------------------------------------
// Public static constants
//------------------------------------------------------------------------------

/**
 * Number of keys.
 * 
 * @constant {number}
 */
rune.input.Keyboard.NUM_KEYS = 256;

//------------------------------------------------------------------------------
// Public prototype getter and setter methods
//------------------------------------------------------------------------------

/**
 * Whether the keyboard should be activated or not. An inactive (false) 
 * keyboard, registers no input.
 *
 * @member {boolean} enabled
 * @memberof rune.input.Keyboard
 * @instance
 */
Object.defineProperty(rune.input.Keyboard.prototype, "enabled", {
    /**
     * @this rune.input.Keyboard
     * @ignore
     */
    get : function() {
        return this.m_enabled;
    },

    /**
     * @this rune.input.Keyboard
     * @ignore
     */
    set : function(value) {
        if (this.m_enabled != value) {
            this.m_enabled  = value;
            
            if (this.m_enabled == true) {
                this.m_constructEvent();
            } else {
                this.m_disposeEvent();
                this.reset();
            }
        }
    }
});

//------------------------------------------------------------------------------
// Public prototype methods (API)
//------------------------------------------------------------------------------

/**
 * Checks if the specified key was just pressed.
 *
 * @param {string} key A valid key, such as "SPACE".
 * 
 * @returns {boolean}
 */
rune.input.Keyboard.prototype.justPressed = function(key) {
    key = key.toUpperCase();
    if (this.m_keys[this.m_LUT[key]] != null) return this.m_keys[this.m_LUT[key]].isJustPressed();
    else return false;
};

/**
 * Checks if the specified key has just been released.
 *
 * @param {string} key A valid key, such as "SPACE".
 * 
 * @returns {boolean}
 */
rune.input.Keyboard.prototype.justReleased = function(key) {
    key = key.toUpperCase();
    if (this.m_keys[this.m_LUT[key]] != null) return this.m_keys[this.m_LUT[key]].isJustReleased();
    else return false;
};

/**
 * Checks if the specified key is pressed.
 *
 * @param {string} key A valid key, such as "SPACE".
 * 
 * @returns {boolean}
 */
rune.input.Keyboard.prototype.pressed = function(key) {
    key = key.toUpperCase();
    if (this.m_keys[this.m_LUT[key]] != null) return this.m_keys[this.m_LUT[key]].isPressed();
    else return false;
};

/**
 * Resets the state of all keyboard keys.
 *
 * @returns {undefined}
 */
rune.input.Keyboard.prototype.reset = function() {
    var i = this.m_keys.length;
    while (i--) {
        var key = this.m_keys[i];
        if (key != null) {
            key.reset();
        }
    }
};

//------------------------------------------------------------------------------
// Public prototype methods (ENGINE)
//------------------------------------------------------------------------------

/**
 * Updating the keyboard.
 *
 * @returns {undefined}
 * @ignore
 */
rune.input.Keyboard.prototype.update = function() {
    if (this.m_enabled == true) {
        this.m_updateKeys();
    }
};

/**
 * Removes memory allocated by the keyboard.
 * 
 * @returns {undefined}
 * @ignore
 */
rune.input.Keyboard.prototype.dispose = function() {
    this.m_disposeEvent();
    this.m_disposeKeys();
};

//------------------------------------------------------------------------------
// Protected prototype methods
//------------------------------------------------------------------------------

/**
 * The class constructor.
 * 
 * @returns {undefined}
 * @protected
 * @ignore
 */
rune.input.Keyboard.prototype.m_construct = function() {
    this.m_constructKeys();
    if (this.m_options.enable == true) {
        this.m_constructEvent();
    }
};

//------------------------------------------------------------------------------
// Private prototype methods
//------------------------------------------------------------------------------

/**
 * Creates a KeyboardKey object for each key (keycode) on the keyboard.
 *
 * @returns {undefined}
 * @private
 */
rune.input.Keyboard.prototype.m_constructKeys = function() {
    var i = 0;

    i = 1;
    while(i <= 12) {
        this.m_constructKey("F"+i, 111+(i++));
    }
            
    i = 65;
    while (i <= 90) {
        this.m_constructKey(String.fromCharCode(i), i++);
    }

    i = 48;
    this.m_constructKey("ZERO",         i++);
    this.m_constructKey("ONE",          i++);
    this.m_constructKey("TWO",          i++);
    this.m_constructKey("THREE",        i++);
    this.m_constructKey("FOUR",         i++);
    this.m_constructKey("FIVE",         i++);
    this.m_constructKey("SIX",          i++);
    this.m_constructKey("SEVEN",        i++);
    this.m_constructKey("EIGHT",        i++);
    this.m_constructKey("NINE",         i++);

    i = 96;
    this.m_constructKey("NUMPADZERO",   i++);
    this.m_constructKey("NUMPADONE",    i++);
    this.m_constructKey("NUMPADTWO",    i++);
    this.m_constructKey("NUMPADTHREE",  i++);
    this.m_constructKey("NUMPADFOUR",   i++);
    this.m_constructKey("NUMPADFIVE",   i++);
    this.m_constructKey("NUMPADSIX",    i++);
    this.m_constructKey("NUMPADSEVEN",  i++);
    this.m_constructKey("NUMPADEIGHT",  i++);
    this.m_constructKey("NUMPADNINE",   i++);
    this.m_constructKey("PAGEUP",        33);
    this.m_constructKey("PAGEDOWN",      34);
    this.m_constructKey("HOME",          36);
    this.m_constructKey("END",           35);
    this.m_constructKey("INSERT",        45);

    this.m_constructKey("ESCAPE",        27);
    this.m_constructKey("MINUS",        189);
    this.m_constructKey("NUMPADMINUS",  109);
    this.m_constructKey("PLUS",         187);
    this.m_constructKey("NUMPADPLUS",   107);
    this.m_constructKey("DELETE",        46);
    this.m_constructKey("BACKSPACE",      8);
    this.m_constructKey("LBRACKET",     219);
    this.m_constructKey("RBRACKET",     221);
    this.m_constructKey("BACKSLASH",    220);
    this.m_constructKey("CAPSLOCK",      20);
    this.m_constructKey("SEMICOLON",    186);
    this.m_constructKey("QUOTE",        222);
    this.m_constructKey("ENTER",         13);
    this.m_constructKey("SHIFT",         16);
    this.m_constructKey("COMMA",        188);
    this.m_constructKey("PERIOD",       190);
    this.m_constructKey("NUMPADPERIOD", 110);
    this.m_constructKey("SLASH",        191);
    this.m_constructKey("NUMPADSLASH",  191);
    this.m_constructKey("CONTROL",       17);
    this.m_constructKey("ALT",           18);
    this.m_constructKey("SPACE",         32);
    this.m_constructKey("UP",            38);
    this.m_constructKey("DOWN",          40);
    this.m_constructKey("LEFT",          37);
    this.m_constructKey("RIGHT",         39);
    this.m_constructKey("TAB",            9);
    this.m_constructKey("BACKQUOTE",    192);
};

/**
 * Creates a KeyboardKey object for a specific keyboard key.
 *
 * @param {string} keyName Name of key.
 * @param {number} keyCode Key code of key.
 *
 * @returns {undefined}
 * @private
 */
rune.input.Keyboard.prototype.m_constructKey = function(keyName, keyCode) {
    this.m_LUT[keyName]  = keyCode;
    this.m_keys[keyCode] = new rune.input.KeyboardKey();
};

/**
 * Creates necessary event listeners.
 *
 * @returns {undefined}
 * @private
 */
rune.input.Keyboard.prototype.m_constructEvent = function() {
    this.m_constructEventKeyDown();
    this.m_constructEventKeyUp();
};

/**
 * Create event listeners for KEY_DOWN.
 *
 * @returns {undefined}
 * @private
 */
rune.input.Keyboard.prototype.m_constructEventKeyDown = function() {
    var m_this = this;
    this.m_options.target.addEventListener(
        "keydown",
        this.m_onKeyDownHandler = function(event) {
            m_this.m_onKeyDown(event.keyCode);
        }
    );
};

/**
 * Create event listeners for KEY_UP.
 *
 * @returns {undefined}
 * @private
 */
rune.input.Keyboard.prototype.m_constructEventKeyUp = function() {
    var m_this = this;
    this.m_options.target.addEventListener(
        "keyup",
        this.m_onKeyUpHandler = function(event) {
            m_this.m_onKeyUp(event.keyCode);
        }
    );
};

/**
 * Updates the state of all keys.
 *
 * @returns {undefined}
 * @private
 */
rune.input.Keyboard.prototype.m_updateKeys = function() {
    var i = this.m_keys.length;
    while (i--) {
        var key = this.m_keys[i];
        if (key != null) {
            key.update();
        }
    }
};

/**
 * Deletes registered event listeners.
 *
 * @returns {undefined}
 * @private
 */
rune.input.Keyboard.prototype.m_disposeEvent = function() {
    this.reset();
    this.m_disposeEventKeyUp();
    this.m_disposeEventKeyDown();
};

/**
 * Create event listeners for KEY_DOWN.
 *
 * @returns {undefined}
 * @private
 */
rune.input.Keyboard.prototype.m_disposeEventKeyUp = function() {
    var m_this = this;
    this.m_options.target.removeEventListener(
        "keydown",
        this.m_onKeyDownHandler
    );
};

/**
 * Create event listeners for KEY_DOWN.
 *
 * @returns {undefined}
 * @private
 */
rune.input.Keyboard.prototype.m_disposeEventKeyDown = function() {
    var m_this = this;
    this.m_options.target.removeEventListener(
        "keyup",
        this.m_onKeyUpHandler
    );
};

/**
 * Clears memory used to store information about available keys.
 *
 * @returns {undefined}
 * @private
 */
rune.input.Keyboard.prototype.m_disposeKeys = function() {
    this.m_LUT = null;
    this.m_keys.length = 0;
    this.m_keys = null;
};

/**
 * Event handler for KEY_DOWN.
 *
 * @param {number} keyCode Current key code.
 * 
 * @returns {undefined}
 * @private
 */
rune.input.Keyboard.prototype.m_onKeyDown = function(keyCode) {
    var key = this.m_keys[keyCode];
    if (key != null) key.onKeyDown();
};

/**
 * Event handler for KEY_DOWN.
 *
 * @param {number} keyCode Current key code.
 * 
 * @returns {undefined}
 * @private
 */
rune.input.Keyboard.prototype.m_onKeyUp = function(keyCode) {
    var key = this.m_keys[keyCode];
    if (key != null) key.onKeyUp();
};