# Source: src/input/Key.js

    /**
    * @author       Richard Davey <rich@photonstorm.com>
    * @copyright    2016 Photon Storm Ltd.
    * @license      {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
    */

    /**
    * If you need more fine-grained control over the handling of specific keys you can create and use Phaser.Key objects.
    *
    * @class Phaser.Key
    * @constructor
    * @param {Phaser.Game} game - Current game instance.
    * @param {integer} keycode - The key code this Key is responsible for. See {@link Phaser.KeyCode}.
    */
    Phaser.Key = function (game, keycode) {

        /**
        * @property {Phaser.Game} game - A reference to the currently running game.
        */
        this.game = game;

        /**
        * The enabled state of the key - see `enabled`.
        * @property {boolean} _enabled
        * @private
        */
        this._enabled = true;

        /**
        * @property {object} event - Stores the most recent DOM event.
        * @readonly
        */
        this.event = null;

        /**
        * @property {boolean} isDown - The "down" state of the key. This will remain `true` for as long as the keyboard thinks this key is held down.
        * @default
        */
        this.isDown = false;

        /**
        * @property {boolean} isUp - The "up" state of the key. This will remain `true` for as long as the keyboard thinks this key is up.
        * @default
        */
        this.isUp = true;

        /**
        * @property {boolean} altKey - The down state of the ALT key, if pressed at the same time as this key.
        * @default
        */
        this.altKey = false;

        /**
        * @property {boolean} ctrlKey - The down state of the CTRL key, if pressed at the same time as this key.
        * @default
        */
        this.ctrlKey = false;

        /**
        * @property {boolean} shiftKey - The down state of the SHIFT key, if pressed at the same time as this key.
        * @default
        */
        this.shiftKey = false;

        /**
        * @property {number} timeDown - The timestamp when the key was last pressed down. This is based on Game.time.now.
        */
        this.timeDown = 0;

        /**
        * If the key is down this value holds the duration of that key press and is constantly updated.
        * If the key is up it holds the duration of the previous down session.
        * @property {number} duration - The number of milliseconds this key has been held down for.
        * @default
        */
        this.duration = 0;

        /**
        * @property {number} timeUp - The timestamp when the key was last released. This is based on Game.time.now.
        * @default
        */
        this.timeUp = -2500;

        /**
        * @property {number} repeats - If a key is held down this holds down the number of times the key has 'repeated'.
        * @default
        */
        this.repeats = 0;

        /**
        * @property {number} keyCode - The keycode of this key.
        */
        this.keyCode = keycode;

        /**
        * @property {Phaser.Signal} onDown - This Signal is dispatched every time this Key is pressed down. It is only dispatched once (until the key is released again).
        */
        this.onDown = new Phaser.Signal();

        /**
        * @property {function} onHoldCallback - A callback that is called while this Key is held down. Warning: Depending on refresh rate that could be 60+ times per second.
        */
        this.onHoldCallback = null;

        /**
        * @property {object} onHoldContext - The context under which the onHoldCallback will be called.
        */
        this.onHoldContext = null;

        /**
        * @property {Phaser.Signal} onUp - This Signal is dispatched every time this Key is released. It is only dispatched once (until the key is pressed and released again).
        */
        this.onUp = new Phaser.Signal();

        /**
         * @property {boolean} _justDown - True if the key has just been pressed (NOTE: requires to be reset, see justDown getter)
         * @private
         */
        this._justDown = false;

        /**
         * @property {boolean} _justUp - True if the key has just been pressed (NOTE: requires to be reset, see justDown getter)
         * @private
         */
        this._justUp = false;

    };

    Phaser.Key.prototype = {

        /**
        * Called automatically by Phaser.Keyboard.
        *
        * @method Phaser.Key#update
        * @protected
        */
        update: function () {

            if (!this._enabled) { return; }

            if (this.isDown)
            {
                this.duration = this.game.time.time - this.timeDown;
                this.repeats++;

                if (this.onHoldCallback)
                {
                    this.onHoldCallback.call(this.onHoldContext, this);
                }
            }

        },

        /**
        * Called automatically by Phaser.Keyboard.
        *
        * @method Phaser.Key#processKeyDown
        * @param {KeyboardEvent} event - The DOM event that triggered this.
        * @protected
        */
        processKeyDown: function (event) {

            if (!this._enabled) { return; }

            this.event = event;

            // exit if this key down is from auto-repeat
            if (this.isDown)
            {
                return;
            }

            this.altKey = event.altKey;
            this.ctrlKey = event.ctrlKey;
            this.shiftKey = event.shiftKey;

            this.isDown = true;
            this.isUp = false;
            this.timeDown = this.game.time.time;
            this.duration = 0;
            this.repeats = 0;

            // _justDown will remain true until it is read via the justDown Getter
            // this enables the game to poll for past presses, or reset it at the start of a new game state
            this._justDown = true;

            this.onDown.dispatch(this);

        },

        /**
        * Called automatically by Phaser.Keyboard.
        *
        * @method Phaser.Key#processKeyUp
        * @param {KeyboardEvent} event - The DOM event that triggered this.
        * @protected
        */
        processKeyUp: function (event) {

            if (!this._enabled) { return; }

            this.event = event;

            if (this.isUp)
            {
                return;
            }

            this.isDown = false;
            this.isUp = true;
            this.timeUp = this.game.time.time;
            this.duration = this.game.time.time - this.timeDown;

            // _justUp will remain true until it is read via the justUp Getter
            // this enables the game to poll for past presses, or reset it at the start of a new game state
            this._justUp = true;

            this.onUp.dispatch(this);

        },

        /**
        * Resets the state of this Key.
        *
        * This sets isDown to false, isUp to true, resets the time to be the current time, and _enables_ the key.
        * In addition, if it is a "hard reset", it clears clears any callbacks associated with the onDown and onUp events and removes the onHoldCallback.
        *
        * @method Phaser.Key#reset
        * @param {boolean} [hard=true] - A soft reset won't reset any events or callbacks; a hard reset will.
        */
        reset: function (hard) {

            if (hard === undefined) { hard = true; }

            this.isDown = false;
            this.isUp = true;
            this.timeUp = this.game.time.time;
            this.duration = 0;
            this._enabled = true; // .enabled causes reset(false)
            this._justDown = false;
            this._justUp = false;

            if (hard)
            {
                this.onDown.removeAll();
                this.onUp.removeAll();
                this.onHoldCallback = null;
                this.onHoldContext = null;
            }

        },

        /**
        * Returns `true` if the Key was pressed down within the `duration` value given, or `false` if it either isn't down,
        * or was pressed down longer ago than then given duration.
        *
        * @method Phaser.Key#downDuration
        * @param {number} [duration=50] - The duration within which the key is considered as being just pressed. Given in ms.
        * @return {boolean} True if the key was pressed down within the given duration.
        */
        downDuration: function (duration) {

            if (duration === undefined) { duration = 50; }

            return (this.isDown && this.duration < duration);

        },

        /**
        * Returns `true` if the Key was pressed down within the `duration` value given, or `false` if it either isn't down,
        * or was pressed down longer ago than then given duration.
        *
        * @method Phaser.Key#upDuration
        * @param {number} [duration=50] - The duration within which the key is considered as being just released. Given in ms.
        * @return {boolean} True if the key was released within the given duration.
        */
        upDuration: function (duration) {

            if (duration === undefined) { duration = 50; }

            return (!this.isDown && ((this.game.time.time - this.timeUp) < duration));

        }

    };

    /**
    * The justDown value allows you to test if this Key has just been pressed down or not.
    * When you check this value it will return `true` if the Key is down, otherwise `false`.
    * You can only call justDown once per key press. It will only return `true` once, until the Key is released and pressed down again.
    * This allows you to use it in situations where you want to check if this key is down without using a Signal, such as in a core game loop.
    *
    * @property {boolean} justDown
    * @memberof Phaser.Key
    * @default false
    */
    Object.defineProperty(Phaser.Key.prototype, "justDown", {

        get: function () {

            var current = this._justDown;
            this._justDown = false;
            return current;

        }

    });

    /**
    * The justUp value allows you to test if this Key has just been released or not.
    * When you check this value it will return `true` if the Key is up, otherwise `false`.
    * You can only call justUp once per key release. It will only return `true` once, until the Key is pressed down and released again.
    * This allows you to use it in situations where you want to check if this key is up without using a Signal, such as in a core game loop.
    *
    * @property {boolean} justUp
    * @memberof Phaser.Key
    * @default false
    */
    Object.defineProperty(Phaser.Key.prototype, "justUp", {

        get: function () {

            var current = this._justUp;
            this._justUp = false;
            return current;

        }

    });

    /**
    * An enabled key processes its update and dispatches events.
    * A key can be disabled momentarily at runtime instead of deleting it.
    *
    * @property {boolean} enabled
    * @memberof Phaser.Key
    * @default true
    */
    Object.defineProperty(Phaser.Key.prototype, "enabled", {

        get: function () {

            return this._enabled;

        },

        set: function (value) {

            value = !!value;

            if (value !== this._enabled)
            {
                if (!value)
                {
                    this.reset(false);
                }

                this._enabled = value;
            }
        }

    });

    Phaser.Key.prototype.constructor = Phaser.Key;