skip to Main Content

I was doing tests to detect the keyboard keys, it occurred to me to save it in an array and add the keys in the order in which they are held down. For example, if you keep "w" and "a", the array would be ["w", "a"]. The problem occurs when you hold "w" and then "SHIFT". When you stop holding "w", the key is not removed from the array.

Note: to replicate the problem, first hold down the "w" and while holding it down then press the "SHIFT". Then release the "w" while holding down the "SHIFT".

let keysPressed = [];

document.addEventListener('keydown', (event) => {
  if (!keysPressed.includes(event.key)) {
    keysPressed.push(event.key)
  }
});

document.addEventListener('keyup', (event) => {
  const keyIndex = keysPressed.indexOf(event.key);
  if (keyIndex !== -1) {
    keysPressed.splice(keyIndex, 1)
  }
});

function update() {
  if (keysPressed.length > 0) {
    document.getElementById('status').innerHTML = `Pressed keys: ${keysPressed.join(', ')}<br>Last pressed key: ${keysPressed[keysPressed.length - 1]}`;
  } else {
    document.getElementById('status').textContent = 'No keys pressed'
  }
  requestAnimationFrame(update)
}

requestAnimationFrame(update)
body { 
  font-family: Arial, sans-serif; 
}

.status { 
  font-size: 1.5em; 
  color: green; 
}
<body>
  <h2>Hold a key pressed</h2>
  <p class="status" id="status">No key pressed</p>
</body>

2

Answers


  1. Yes. You pressed ‘w’ and released ‘W’.

    If you want to be transparent to shift, remove also ‘w’.

    If you want to interact at key level, not string level, that is, just register any pressed key (whatever the modifier are when it is pressed), and then unregister any key (whatever the modifiers are when it is released), then you should focus on key code, not key.

    Or you could do both. If you want to give a "string" name to the key for display, while being able to match a release with a previous press, you should keep the key for display, and code for register. That is probably the best thing to do (rather than playing with lower, upper, that would work only if the preconception of what modifier do happen to be true. After all, a user could have mapped "Shift+W" on "Q". Not to mention other modifiers).

    let keysPressed = [];
    let keysCodes = [];
    
    document.addEventListener('keydown', (event) => {
      if (!keysCodes.includes(event.code)) {
        keysPressed.push(event.key);
        keysCodes.push(event.code);
      }
    });
    
    document.addEventListener('keyup', (event) => {
      const keyIndex = keysCodes.indexOf(event.code);
      if (keyIndex !== -1) {
        keysPressed.splice(keyIndex, 1);
        keysCodes.splice(keyIndex, 1);
      }
    });
    
    function update() {
      if (keysPressed.length > 0) {
        document.getElementById('status').innerHTML = `Pressed keys: ${keysPressed.join(', ')}<br>Last pressed key: ${keysPressed[keysPressed.length - 1]}`;
      } else {
        document.getElementById('status').textContent = 'No keys pressed'
      }
      requestAnimationFrame(update)
    }
    
    requestAnimationFrame(update)
    body { 
      font-family: Arial, sans-serif; 
    }
    
    .status { 
      font-size: 1.5em; 
      color: green; 
    }
    <body>
      <h2>Hold a key pressed</h2>
      <p class="status" id="status">No key pressed</p>
    </body>

    Note that the usage of two arrays that are kept synchronous (we add a key code at the end of keysCodes when and only when we add a key at the end of keysPressed. We remove element at position keyIndex from keyCodes when and only when we remove element at position keyIndex of keysPressed is inelegant. That assumption that they will stay synchronous for ever is not abusive, as long as nobody else interact withe neither of those arrays, but if you later try to do something clever with those arrays, well, it is not ideal when you need to trust future coders (even when future coders is you) not to forget that those two arrays must be kept synchronous.
    Generally speaking that is why I prefer "arrays of pairs" than "pairs of arrays".

    So, that should probably be done differently to use objects, classes, arrays of arrays, or something, and search for object by one of the fields when needed. But I wanted to keep as close as possible to your implementation.

    Login or Signup to reply.
  2. this is not a problem this is just how KeyEvent.key works cuz it returns symbol which was pressed or released and in you example you just did:

    pressed  "w"
    pressed  "Shift"
    released "W" not "w" !!!
    released "Shift"
    

    but if you use KeyEvent.code this will look like:

    pressed  "KeyW"
    pressed  "ShiftLeft"
    released "KeyW"
    released "ShiftLeft"
    

    also KeyEvent.key will return symbol according to current selected language on device so you even can switch languages during session and it will return different KeyEvent.key even if you press the same key

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search