In my game, I use the event listeners keyup
and keydown
to track which keys are pressed (this.input
is a reference to the Input
function below):
$(document.body).on('keydown', this.input.keyPress.bind(this.input));
$(document.body).on('keyup', this.input.keyPress.bind(this.input));
Everything works as expected, until I press 2 keys at once. The left key moves the player left, the shift key fires a weapon. Separately, they work fine. If both are pressed at once, however, and held, the player shoots twice.
Here is the code I am using to handle the inputs (removed other key events for brevity)
shootSpecial
should only be called once since keyMap.shift
is only true
on keydown
. Once keyup
is triggered, it is set to false
:
keyMap[key] = e.type === 'keydown';
var Input = function () {
var keyMap = {};
this.handleKeyPress = function () {
if (keyMap.arrowleft === true) {
game.player.moving.left = true;
} else if (keyMap.shift === true) {
game.player.shootSpecial();
}
};
this.keyPress = function (e) {
var key = e.key.toLowerCase();
if (key === ' ') {
key = 'space';
}
keyMap[key] = e.type === 'keydown';
console.log(key, keyMap[key]);
this.handleKeyPress();
};
};
The console.log
reports that left and shift are true
on keydown
and then both false
on keyup
so I'm not too sure why it would be triggering the shootSpecial
event twice.
var keyMap = {};
var handleKeyPress = function () {
if (keyMap.arrowleft === true) {
console.log('left');
} else if (keyMap.shift === true) {
console.log('shift');
}
};
var keyPress = function (e) {
var key = e.key.toLowerCase();
keyMap[key] = e.type === 'keydown';
if (document.getElementById(key))
document.getElementById(key).innerText = e.type === 'keydown';
handleKeyPress();
}
document.addEventListener('keydown', keyPress);
document.addEventListener('keyup', keyPress);
LEFT:<div id="arrowleft">false</div>
SHIFT:<div id="shift">false</div>
As you can see by the fiddle, one event gets called twice.
If you press two keys, you'll fire two events, whether you press them at the same time or not. The same for the keyup
event. So in total the handleKeypress function is called four times.
The order might well happen to be:
key | event | keyMap.arrowleft | keyMap.shift | effect
-----------+---------+------------------+--------------+----------
shift | keydown | false | true | shoot
arrowleft | keydown | true | true | moving.left=true
arrowleft | keyup | false | true | shoot
shift | keyup | false | false | nothing
So in that scenario you shoot twice. Of course, this will not always be the case, as the order might be different.
Pass the key as argument to the handleKeyPress function to make sure you only execute an action that corresponds to that key.
var Input = function () {
var keyMap = {};
this.handleKeyPress = function (key) {
switch (key) {
case 'arrowleft':
game.player.moving.left = keyMap[key]; // also sets back to false
break;
case 'shift':
if (keyMap.shift) game.player.shootSpecial();
break;
}
};
this.keyPress = function (e) {
var key = e.key.toLowerCase();
if (key === ' ') {
key = 'space';
}
keyMap[key] = e.type === 'keydown';
this.handleKeyPress(key); // pass key
};
};