Look at the following JavaScript file. If you scroll down to line 530 you will find the following class:
var Keyboard = new Class(function (constructor) {
var key = {};
var eventListener = {
keyup: {},
keydown: {},
keypress: {}
};
constructor.overload(["Number"], function (interval) {
setInterval(keypress, interval);
});
window.addEventListener("keyup", keyup, false);
window.addEventListener("keydown", keydown, false);
function keyup(event) {
var keyCode = event.keyCode;
var listener = eventListener.keyup[keyCode];
key[keyCode] = false;
if (listener)
listener();
}
function keydown(event) {
var keyCode = event.keyCode;
var listener = eventListener.keydown[keyCode];
key[keyCode] = true;
if (listener)
listener();
}
function keypress() {
for (var code in key) {
var listener = eventListener.keypress[code];
if (key[code] && listener) listener();
}
}
this.addEventListener = new Dispatcher(["String", "Number", "Function"], function (type, keyCode, listener) {
type = eventListener[type];
if (type) type[keyCode] = listener;
else throw new Error("Unexpected value for type.");
});
});
What the author has done is that he has created a special Keyboard
class for delegating the key events: keyup
, keydown
and keypress
. The class has only one constructor which accepts a single argument - the interval of the keypress
event (which is what you want). You can add event listeners using the addEventListener
method of the instance of the Keyboard
class:
var keyboard = new Keyboard(125); // fire key press 8 times a second.
keypress.addEventListener("keypress", 65, function () {
// do something every time A is pressed
});
Note that the above class depends on the following framework: Lambda JS. You can see a working demo of the above script here. Hope this helps.
Update 1:
Your code does not work in Opera. In addition the second event fires after a extra 500 ms delay in Firefox and consecutive events do not maintain the same interval. Plus it can't handle multiple key events at the same time. Let's rectify this problem:
First we need to create a simple script for Delta Timing so that the key events fire after constant interval. We use the following snippet for creating a DeltaTimer
:
function DeltaTimer(render, interval) {
var timeout;
var lastTime;
this.start = start;
this.stop = stop;
function start() {
timeout = setTimeout(loop, 0);
lastTime = Date.now();
return lastTime;
}
function stop() {
clearTimeout(timeout);
return lastTime;
}
function loop() {
var thisTime = Date.now();
var deltaTime = thisTime - lastTime;
var delay = Math.max(interval - deltaTime, 0);
timeout = setTimeout(loop, delay);
lastTime = thisTime + delay;
render(thisTime);
}
}
Next we write the logic to fire custom keypressed
events. We need custom events since we must be able to handle multiple keys at the same time:
(function (interval) {
var keyboard = {};
window.addEventListener("keyup", keyup, false);
window.addEventListener("keydown", keydown, false);
function keyup(event) {
keyboard[event.keyCode].pressed = false;
}
function keydown(event) {
var keyCode = event.keyCode;
var key = keyboard[keyCode];
if (key) {
if (!key.start)
key.start = key.timer.start();
key.pressed = true;
} else {
var timer = new DeltaTimer(function (time) {
if (key.pressed) {
var event = document.createEvent("Event");
event.initEvent("keypressed", true, true);
event.time = time - key.start;
event.keyCode = keyCode;
window.dispatchEvent(event);
} else {
key.start = 0;
timer.stop();
}
}, interval);
key = keyboard[keyCode] = {
pressed: true,
timer: timer
};
key.start = timer.start();
}
}
})(1000);
The interval
is set at 1000
ms but you may change that. Finally to register an event we do:
window.addEventListener("keypressed", function (event) {
document.body.innerHTML += event.keyCode + " (" + event.time + " ms)<br/>";
}, false);
This is simple and efficient JavaScript. No jQuery required. You can see the live demo here, and see the difference between your script and mine. Cheers.
Update 2:
Looking at the other question on StackOverflow, this is how you would implement it using the above pattern:
window.addEventListener("keypressed", function (event) {
switch (event.keyCode) {
case 37:
Move(-1, 0);
break;
case 38:
Move(0, -1);
break;
case 39:
Move(1, 0);
break;
case 40:
Move(0, 1);
break;
}
}, false);
Using the above code will remove the short delay you're experiencing and also allow multiple events to be fired for different keys at the same time.