jQuery Keyer 2.0

Keydown events fire at high frequencies when keys are held down. This is planned to be a rewrite of jQuery Keyer 1.0 jQuery Keyer 2.0 is written as a jQuery UI widget jQuery Keyer allows you to customize your own preferred sensitivity on how keydown events are fired. jQuery Keyer also helps you manage keydown events involving multiple keys.

by Terry Young

HTML

<div class="demo">
    <p>Keydown events fire at high frequencies when keys are held down.</p>
    <p>jQuery Keyer allows you to control sensitivity of keydown events.</p>
    <p>jQuery Keyer also helps you manage simultaneous keydown events.</p>
    <p>Note: Each instance creates a setInterval() timer kept internally.</p>
</div>

<div class="demo">
    <p class="demo-title">Demo 1: Multiple keys</p>
    <p>Click on the plane, then use arrow keys or W/A/S/D keys to control the plane.</p>
    <p>You can hold multiple arrow keys simultaneously.</p>
    <p>This example demonstrates the use of the 'hasKey' method in jQuery Keyer.</p>
    
    <img id="plane" src='http://img13.imageshack.us/img13/3334/planer.png' border='0'/>
</div>
<div class="demo">
    <p class="demo-title">Demo 2: Controlling KeyDown sensitivity</p>
    <p>Click in this textbox, then hold down the UP/DOWN keys.</p>
    <p>Note that in this example, initialDelay is set to 1000 (1 second), and initial interval is set to 100 milliseconds.</p>
    <p>Holding down for more than 3 seconds will speed up the interval to 20 milliseconds.</p>
    <input type="text" id="DEMO_2" value="0" readonly />
</div>
<div class="demo">
    <p class="demo-title">Demo 3: Handling simultaneous multiple keystrokes</p>
    <p>Click in this textbox, press any one or more keys.</p>
    <p>Try holding down multiple keys.</p>
    <p>The textbox below will show which keys are pressed, and for how long.</p>
    <input type="text" id="DEMO_3" value="" readonly />
</div>

CSS

html, body {
    margin:0;
    border:0;
    padding:0;
    width:100%;
    height:100%;
    line-height: 1.8em;
    font-family: Arial;
    font-size: 10pt;
    background-color: #fff;
}
div.demo {
    border: 1px solid #ddd;
    padding: 10px;
    margin: 15px 15px 35px 15px;
}
div.demo input {
    width: 80%;
}

.demo-title {
    font-weight: bold;
}


#plane {
    height: 50px;
    z-index: 2;
    /*
    position:absolute;
    top:40%;
    left:40%;
    */
}

JavaScript

/**
 * Define the KeyEvent object if it does not exist
 * For an exhaustive list, refer to http://mzl.la/Hw2KjT
 */

if (typeof KeyEvent == "undefined") {
    var KeyEvent = {
        // Arrow keys
        DOM_VK_LEFT: 37,
        DOM_VK_UP: 38,
        DOM_VK_RIGHT: 39,
        DOM_VK_DOWN: 40,
        // WASD keys
		DOM_VK_A: 65,
		DOM_VK_D: 68,
		DOM_VK_S: 83,
		DOM_VK_W: 87,
    };
}


$(document).ready(function () {
    
    // jQuery Keyer 2.0
    $.widget("ui.keyer", {
        
        // default options
        options: {
            interval: 50,
            initialDelay: 0,
            keydown: $.noop,
            keyup: $.noop,
            fireKeydownOnMultipleHits: true
        },
        
        // the constructor
        _create: function () {
            // add a class for theming
            this.element.addClass("ui-keyer");

            this.state = {
                event: null,
                pressed: [],
                timer: null,
                elapsed: 0
            };

            this._initializeTimer();            

            var THIS = this;
            
            // Setup event handlers
            this.element
                .on('keydown', function (event) {
                    THIS._keydown.apply(THIS, [event]);
                })
                .on('keyup', function (event) {
                    THIS._keyup.apply(THIS, [event]);
                });

            // Also intially setup .one('keydown',...)
            this._keydownOnce();
        },

        _initializeTimer: function () {
            var THIS = this;

            if (this.state.timer) {
                clearInterval(this.state.timer);
                this.state.timer = null;
            }
            
            this.state.timer = setInterval(function () {
                THIS._keydownProxy.apply(THIS, [THIS.state.event]);
            }, this.options.interval);
        },

        // called when created, and later when changing options
        _refresh:...