0

When holding a single arrow key down the function works correctly.

However, the problem occurs when I then hold a second arrow key and release the second key the first held key is no longer detected.

A simplified version of my functions are as follows:

document.body.onkeyup = function(e){  
  if ([37,38,39,40].indexOf(e.keyCode) > -1){
    var key_pressed = e.keyCode || e.which;
    console.log(key_pressed + " is UP")
  }

  if([32, 37, 38, 39, 40].indexOf(e.keyCode) > -1) {
    e.preventDefault();
  }
};


document.body.onkeydown = function(e){  
  if ([37,38,39,40].indexOf(e.keyCode) > -1){
    var key_pressed = e.keyCode || e.which;
    console.log(key_pressed + " is DOWN")
  }

  if([32, 37, 38, 39, 40].indexOf(e.keyCode) > -1) {
    e.preventDefault();
  }

};

So, if I hold the UP arrow key, it says 38 is DOWN repeatedly whileI am holding the key.
Then if I press the RIGHT arrow key it says 39 is DOWNrepeatedly while I am holding both keys.
Then if I let go of the RIGHT arrow key it says 39 is UP.

My expectation would be for it to then continue to say 38 is DOWN repeatedly again since I am still holding the UP arrow. It does not, however do this.

Why is this happening? What should I do to fix this so that my arrow key is still detected as being held down?

kojow7
  • 10,308
  • 17
  • 80
  • 135
  • Possible duplicate of [How to detect if multiple keys are pressed at once using JavaScript?](https://stackoverflow.com/questions/5203407/how-to-detect-if-multiple-keys-are-pressed-at-once-using-javascript) – J Goble Jun 13 '19 at 21:45

3 Answers3

1

Initialize an interval timer for each arrow key, which runs when they've been pressed.

Clear each arrow's interval timer when they've been released:

var timer = [];
    
document.body.onkeyup = function(e){  
  let key = e.keyCode || e.which;
  if ([37,38,39,40].includes(key)) {
    console.log(key + " is UP");
    clearTimeout(timer[key]);      // stop this key's timer
    timer[key] = null;             // clear it so it can be initialized again
  }

  if ([32, 37, 38, 39, 40].includes(e.keyCode)) {
    e.preventDefault();
  }
};

document.body.onkeydown = function(e) {
  let key = e.keyCode || e.which;
  if ([37,38,39,40].includes(key) && !timer[key]) {
    clearTimeout(timer[key]);
    timer[key] = setInterval(() => {  // create a timer for this key
      console.log(key + " is DOWN")
    }, 100);
  }

  if ([32, 37, 38, 39, 40].includes(key)) {
    e.preventDefault();
  }
};
Rick Hitchcock
  • 35,202
  • 5
  • 48
  • 79
1

Your arrow key is still being detected as held down: its keydown event has fired and its keyup event hasn't. keyup and keydown only fire when something changes, with one exception: the OS-generated keyboard repeat events. (You can filter those out by checking e.repeat.)

If you want an easy way to see what's currently held down, you'll have to maintain that list yourself:

const keysHeld = {};

document.body.addEventListener('keydown', evt => {
  keysHeld[evt.keyCode] = true;
});
document.body.addEventListener('keyup', evt => {
  keysHeld[evt.keyCode] = false;
});

(Note that keyCode is deprecated and you should use code if possible.)

AuxTaco
  • 4,883
  • 1
  • 12
  • 27
  • Hmm, checked into the use of `code` instead. It seems not all browsers currently support it, and most that do support it have only been supporting it for the last 3 years. – kojow7 Jun 14 '19 at 17:49
0

You can workaround this behaviour by keeping track of the pressed keys using an array and watch the array using a timer.

var keysDown = new Array();
document.body.onkeyup = function(e) {
  if ([37, 38, 39, 40].indexOf(e.keyCode) > -1) {
    var key_pressed = e.keyCode || e.which;

    for (var a = 0; a < keysDown.length; a++) {
      if (keysDown[a] == key_pressed) {
        keysDown.splice(a, 1);
      }
    }
  }

};

function update() {
  var message = "";
  for (var a = 0; a < keysDown.length; a++) {
    message += keysDown[a] + " is down ";

  }
  if (message != "") {
    console.log(message);
  }
}
var interval = setInterval(update, 20);

document.body.onkeydown = function(e) {
  if ([37, 38, 39, 40].indexOf(e.keyCode) > -1) {
    var key_pressed = e.keyCode || e.which;
    var found = false;
    for (var a = 0; a < keysDown.length; a++) {
      if (keysDown[a] == key_pressed) {
        found = true;
      }
    }
    if (!found) {
      keysDown.push(key_pressed)
    }
  }
};
obscure
  • 11,916
  • 2
  • 17
  • 36