0

I'm writing an input control function for a small javascript game. There seems to be a significantly longer delay between the first and second keydown events than the subsequent events. Consider the following:

let lastPress = 0;

const keydownHandler = (event) => {
  console.log(event.keyCode + ', delta time: ' + (Date.now() - lastPress));
  lastPress = Date.now();
}

document.addEventListener("keydown", keydownHandler, false);

If I run this and hold the right arrow key down I'll see a listing like this (in formatted version):

Keycode Delta time
39 142129
39 492
39 82
39 87
39 82
39 83
39 82
39 84
39 82
39 86

Now, the first delta is obviously huge (since I'm looking at the difference between the previous call to the event handler). What I don't understand is the value 492 ms compared to the 82 - 87 ms on the following calls.

Why is there such a significant gap between the first two events? And is there a way to narrow that gap?

conciliator
  • 6,078
  • 6
  • 41
  • 66
  • Keyboard settings? – py660 May 25 '23 at 20:19
  • 8
    Auto-repeat doesn't start until you've held the key down for a little while. There should be a system setting that controls this delay. – Barmar May 25 '23 at 20:19
  • Have you tried using the `input` event, rather than keyboard events? A keyboard event like `keydown` isn't going to work on a touch device anyway. – Scott Marcus May 25 '23 at 20:48
  • To expand @Barmar 's answer, this first-letter delay is implemented intentionally to decrease the probability of duplicating characters while user types a text. There's indeed a system setting just for that in each OS. You could also consider this answer to simulate continuous keydowns: https://stackoverflow.com/a/29191638/504474 – Kostiantyn Ko May 25 '23 at 21:31

1 Answers1

0

Based on the comments I gathered that this is by design. I ended up with the following (sort of similar to the SO post linked in the comments):

currentKeys = [];

const findKey = (keyCode) => {
  return currentKeys.indexOf(keyCode);
}

const keydownHandler = (event) => {
  if (findKey(event.keyCode) === -1) {
    currentKeys.push(event.keyCode);
  }
}

const keyupHandler = (event) => {
  const index = findKey(event.keyCode);
  if (index >= 0) {
    currentKeys.splice(index, 1);
  }
}

Then, in the game update function I moved the player according to the input.

conciliator
  • 6,078
  • 6
  • 41
  • 66
  • You should use a `Set` to track currently pressed keys. – Darryl Noakes May 29 '23 at 14:46
  • `const currentKeys = new Set(); currentKeys.add(event.keyCode); currentKeys.has(event.keyCode); currentKeys.delete(event.keyCode);` – Darryl Noakes May 29 '23 at 14:49
  • You don't even need the other checks then: you can add the same value again without issues, and attempt to remove a non-present value without issue. – Darryl Noakes May 29 '23 at 14:50
  • `const currentKeys = new Set(); const keydownHandler = (event) => { currentKeys.add(event.keyCode) }; const keyupHandler = (event) => { currentKeys.delete(event.keyCode) }` – Darryl Noakes May 29 '23 at 14:52
  • Your other code can then iterate over the present values using `currentKeys.keys()` or `currentKeys.values()` (they're equivalent with `Set`). – Darryl Noakes May 29 '23 at 14:54