Handling Keyboard Input with JavaScript

WASD

This is the seventh article of an ongoing series about game development for the Web.

In the previous article, we took a look at the inner workings of JavaScript's event system. We talked about the evolution of the DOM event models and demonstrated how to register event handlers or listeners on the element nodes inside a DOM tree.

In this delivery, we will see a practical demonstration of event-driven development in JavaScript. We will use the available KeyEvents in the DOM Level 2 Event Model to handle user input, using the keyboard.

Shall we dance?


Keyboard Input

Every time a key is pressed in a browser window a keyboard event is triggered.

There are three types of keyboard events:

  • keydown
  • keypress
  • keyup

The keydown event occurs when a key is pressed, followed immediately by the keypress event. Then, the keyup event is generated when the pressed key is released.

The registered event handlers receive a subclass of the Event object called KeyboardEvent with relevant information about the activities performed with the keyboard.

The keydown and keyup events keep track of the physical keys pressed on the keyboard. These events allow to identify the pressed or released key using a code, this code can be accessed through the keyCode attribute in the KeyboardEvent object.

On the other hand, keypress is meant for handling the character value tied to the pressed key. Characters do not necessarily match the physical key in the keyboard, hence the special event to handle them. The value of the character produced by a pressed key can be retrieved using the charCode attribute in the KeyboardEvent object.

The rule of thumb is that if you care about the key that was pressed, i.e. player movement controls, you should use keydown, if you care about the character the user typed, i.e. user's character name, you should use keypress.

It is worth mentioning that the DOM Level 2 Event specification does not provide a key event module. This means that the event object values passed per event are not standarized, resulting in some challenges when evaluating them. Libraries like jQuery attempt to provide a homogeneus interface to handle keyboard interaction reliably.

The KeyboardEvent indicates just what's happening on a key. When you need to handle text input, use HTML5 input event instead. For example, if user inputs text from hand-writing system like tablet PC, key events may not be fired.

Keyboard events target the HTML element that has focus. If no element has focus, the event bubbles up to the window object. The <canvas> element is non-focusable by default, therefore, we either have to handle input to the window object directly or add the tabindex global attribute to the <canvas> element itself.

keydown Event

The keydown event is fired when a key is pressed down.

Example:

// Get a reference to the canvas 
//
var canvas = document.getElementById('canvas');

// Create the event listener binding
//
canvas.addEventListener('keydown', handlekeydown, false);

// keydown Event listener definition
//
var handlekeydown = function(event){              
    // Do something with the captured event.keyCode
    return false;
}

keypress Event

The keypress event is fired when a key is pressed down and that key normally produces a character value.

Example:

// Get a reference to the canvas 
//
var canvas = document.getElementById('canvas');

// Create the event listener binding
//
canvas.addEventListener('keypress', handlekeypress, false);

// keydown Event listener definition
//
var handlekeypress = function(event){
    var asciiCode = (event.key) ? event.key : event.charCode;
    var asciiValue = String.fromCharCode(asciiCode);
    // Do something with the captured character (char)
    return false;
}    

keyup Event

The keyup event is fired when a key is released.

Example:

// Get a reference to the canvas 
//
var canvas = document.getElementById('canvas');

// Create the event listener binding
//
canvas.addEventListener('keyup', handlekeyup, false);

// keydown Event listener definition
//
var handlekeyup = function(event){              
    // Do something with the captured event.keyCode
    return false;
}

Let's give it purpose

Say that we have a tile based game where our character moves freely across a grid in four directions: up, left, down, right.

Since we care about the keys that were pressed and not the ASCII values they produce, the keydown event is a good fit.

Here's a naive implementation:

canvas.addEventListener("keydown", function (e) {
    var newPosition = { column:0, row:0 };

    newPosition.column  = currentPosition.column;
    newPosition.row     = currentPosition.row;

    // A
    if(e.keyCode == 65){
        // Let's move left
        newPosition.column -= 1;
    }

    // D
    if(e.keyCode == 68){
        // Let's move right        
        newPosition.column += 1;
    }

    // W
    if( e.keyCode == 87){
       // Let's move up
       newPosition.row -= 1;
    }

    // S
    if(e.keyCode == 83){
       // Let's move down
       newPosition.row += 1;
    }

    // Check if the new position is within the grid
    //
    if(isInsideGrid(newPosition)){
        // New position is valid, update current position
        //
        currentPosition = newPosition;                    
    }

    // Update elements within our game world
    //
    game.update();
}

Code Examples

Working examples of these articles can be accessed through the following link. The source code for these and future examples are hosted in a public repository at Github.

Feel free to fork and submit pull requests.


Conclusion

In this article, we discussed how JavaScript events help us handle user input through the keyboard. We talked about how to create KeyBoardEvent listeners for the <canvas> element and evaluated the different available events and when to use each.

I would recommend looking into this somewhat complete list of key codes and char codes generated by the KeyEvents, put together by Steve Lautenschlager from Cambia Research.

Have you ever implemented an input system in JavaScript? If so, what considerations have you made and what advice would you give?


References

S. Lautenschlager, "JavaScript Char Codes (Key Codes)," Cambia Research, 11 January 2007. [Online]. Available: http://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes. [Accessed 20 May 2014].

M. Pilgrim, HTML5: Up and Running, Sebastopol: O'Riley Media, Inc, 2010.

D. Geary, Core HTML5 Canvas: Graphics, Animation, and Game Development (Core Series), Crawfordsville: Prentice Hall, 2012.

A. Kourbatov, "Keyboard Event Properties," Javascripter, [Online]. Available: http://www.javascripter.net/faq/keyboardeventproperties.htm. [Accessed 20 May 2014].

J. Wolter, "JavaScript Madness: Keyboard Events," 4 November 2012. [Online]. Available: http://unixpapa.com/js/key.html. [Accessed 20 May 2014].

Image source: gamingweapons