Keystroke Events

Capturing keystrokes is the most powerful type of interaction you have at your disposal. You can have total control over (almost) any key that has been pressed or released. Note however, Netscape did not include the ability to capture Keystroke events into the Unix versions of Communicator 4.0. If you're planning on using keystrokes in a JavaScript game it will not be playable on any version of Unix including Linux.

The first thing that you have to understand is how to initialize your events. Here is a basic initialization for the "onkeydown" event.

document.onkeydown = keyDown

When this code is read by the browser it will know that whenever a key is pressed, the keyDown() function will be called. It doesn't matter what function you call, and the code does not need the brakets after the funtion name.

To capture what key was pressed works a little bit differently between the browsers. So I'll first show each individually.

Netscape

Netscape is a little more picky than IE is with respect to event handling. You have to put an extra line in to tell Netscape to always check for the keydown event. If you don't have this line, it will mess up when other events like mousedown occur.

document.onkeydown = keyDown
if (ns4) document.captureEvents(Event.KEYDOWN)

Your keyDown() has to pass a hidden variable - I'll use the letter "e" because that is what's commonly used.

function keyDown(e)

This "e" represents the key that was just pressed. To find out out what key that is, you can use the which property:

e.which

This will give the index code for the key - not what letter or number was pressed. To convert the index to the letter or number value, you use:

String.fromCharCode(e.which)

So putting it all together, we can make a function that pops up a message telling the keycode and the real key values of the key that was pressed:

function keyDown(e) {
	var keycode = e.which
	var realkey = String.fromCharCode(e.which)
	alert("keycode: " + keycode + "\nrealkey: " + realkey)
}

document.onkeydown = keyDown
document.captureEvents(Event.KEYDOWN)

View this example (Netscape only)

Internet Explorer

IE works similarly except you don't need to pass the "e" value.

Instead of using e.which, you use window.event.keyCode.

And conversion to the real key value is the same: String.fromCharCode(event.keyCode).

function keyDown() {
	var keycode = event.keyCode
	var realkey = String.fromCharCode(event.keyCode)
	alert("keycode: " + keycode + "\nrealkey: " + realkey)
}

document.onkeydown = keyDown

document.onkeydown = keyDown

View this example (Internet Explorer only)

Combining the Two

Now, if you were to open both browsers and compare the examples, you'll realize the results are not always the same. The keycodes are different because each browser uses a different character set. Because of this you'll always have to make separate code for each browser - there's no way around it.

What I'd suggest is totally forgetting about the real key values entirely, and only work with the keycodes. The following chunk of code will assign nKey to the keycode and ieKey to 0 if you're using Netscape or or it will set ieKey to the keycode and nKey to 0 if you're using Internet Explorer. Then it shows an alert of both values:

function keyDown(e) {
	if (ns4) {var nKey=e.which; var ieKey=0}
	if (ie4) {var ieKey=event.keyCode; var nKey=0}
	alert("nKey:"+nKey+" ieKey:" + ieKey)
}

document.onkeydown = keyDown
if (ns4) document.captureEvents(Event.KEYDOWN)

View this example

Now on to the good stuff....

Moving Elements with the Keyboard

Now you can activate your movement functions from the keyboard. You do a check of which key was pressed, and then call the appropriate function to move your object. For the following example I use the "A" key to initiate a sliding function. For the "A" key, the nKey value is 97, and the ieKey is 65. So I do a check for those values in order to call the "slide" function.

function init() {
	if (ns4) block = document.blockDiv
	if (ie4) block = blockDiv.style
	block.xpos = parseInt(block.left)

	document.onkeydown = keyDown
	if (ns4) document.captureEvents(Event.KEYDOWN)
}

function keyDown(e) {
	if (ns4) {var nKey=e.which; var ieKey=0}
	if (ie4) {var ieKey=event.keyCode; var nKey=0}
	if (nKey==97 || ieKey==65) {   // if "A" key is pressed
		slide()
	}
}

function slide() {
	block.xpos += 5
	block.left = block.xpos
	status = block.xpos       // not needed, just for show
	setTimeout("slide()",30)
}

View this example

Understanding "Active" Variables

That last script is somewhat limited. After the movement is started, there's no way to stop it, and if you hit the key several times it moves faster and faster. So we'll have fix that up.

I've developed a technique of using what I call "active" variables to represent the current state of movement... is it moving? or is it not moving? Once you get used to working with them, they can be very handy. Because most movement functions are recursive, they have no built in way of stopping, and that's where the active variables come into play. By inserting the appropriate "if" statment into the slide function, you can have control of whether that function will repeat or not. Usually you make the function something like this:

function slide() {
	if (myobj.active) {
		myobj.xpos += 5
		myojb.left = myobj.xpos
		setTimeout("slide()",30)
	}
}
In this case, the slide() function will only operate when the myobj.active value is true. Once you set myobj.active to false the movement function will stop. Knowing this, we can insert some code into our script that will give us more control of what's happening.

Using onKeyUp and "Active" Variables

The onkeyup event works exactly the same way the onkeydown did. You can initialize both keydown and keyup with the following:

document.onkeydown = keyDown
document.onkeyup = keyUp
if (ns4) document.captureEvents(Event.KEYDOWN | Event.KEYUP)

And the keyUp() function is the same too. But we want to make so that when a key is released, it will stop whatever movement is currently running. To do that we can set our block's active variable to 0:

function keyUp(e) {
	if (ns4) var nKey = e.which
	if (ie4) var ieKey = window.event.keyCode
	if (nKey==97 || ieKey==65) block.active = false
}

But to totally "error" proof our code, we have to put some more checks into the other functions. Take a look at the code below and see if you can understand what I'm doing. In the keyDown function, the && !block.active is to make sure that we can only call the function if the block is not active. In other words, if the block is moving we do not execute the slide() function again. Then we set the active value to true and move the block. The slide() function has the if (block.active) statement so that it only moves when the block.active value is true - that way when we release a key it will stop executing.

function init() {
	if (ns4) block = document.blockDiv
	if (ie4) block = blockDiv.style
	block.xpos = parseInt(block.left)
	block.active = false

	document.onkeydown = keyDown
	document.onkeyup = keyUp
	if (ns4) document.captureEvents(Event.KEYDOWN | Event.KEYUP)
}

function keyDown(e) {
	if (ns4) {var nKey=e.which; var ieKey=0}
	if (ie4) {var ieKey=event.keyCode; var nKey=0}
	if ((nKey==97 || ieKey==65) && !block.active) {   // if "A" key is pressed
		block.active = true
		slide()
	}
}
function keyUp(e) {
	if (ns4) {var nKey=e.which; var ieKey=0}
	if (ie4) {var ieKey=event.keyCode; var nKey=0}
	if (nKey==97 || ieKey==65) {
		block.active = false   // if "A" key is released
	}
}

function slide() {
	if (block.active) {
		block.xpos += 5
		block.left = block.xpos
		status = block.xpos       // not needed, just for show
		setTimeout("slide()",30)
	}
}

View this example

What Keys can I use?

As I mentioned earlier, the character sets for Netscape and Internet Explorer differ. In general, all letters, numbers, symbols, Space, and Enter will work fine. For a quick way to find out the nKey and ieKey values of particular keys you can view my nKey and ieKey Finder.

Game Controls

Here are a few "bare-bone" demos that show how a gaming environment can be made from these techniques:

Home Next Lesson: Clipping Layers
copyright 1998 Dan Steinman