Enlico
Enlico

Reputation: 28520

onkeyup and onkeydown interfering when interleaving presses and releases

The sequence

  1. hold a key other than Shift down (say Alt),
  2. hold Shift down,
  3. release the key held since step 1,
  4. release Shift,

results in leaving the "other key" colored, just like the = 'none' line didn't run for it.

Indeed, here's the GIF showing the behavior corresponding to the 4 actions above:

enter image description here

As you can see, the "Alt up" message is not printed, but trust me that I'm releasing Alt between holding down Shifrt and releasing Shift.


And now that I'm trying on another system Shift is not unique, I can get the same with Ctrl (the other key being for instance one of the 4 arrows).


Why is that? Is it unavoidable?

window.onkeydown = listenKeyDown;
window.onkeyup = listenKeyUp;

function listenKeyDown(e) {
  console.log(e.key + " down")
  if (e.altKey) {
    document.getElementById('alt').style.background = '#00ff00';
  }
  if (e.ctrlKey) {
    document.getElementById('ctrl').style.background = '#00ff00';
  }
  if (e.shiftKey) {
    document.getElementById('shift').style.background = '#00ff00';
  }
  let elem = document.getElementById(e.key);
  if (elem && !e.altKey && !e.ctrlKey && !e.shiftKey) {
    elem.style.background = '#00ff00';
  }
}

function listenKeyUp(e) {
  console.log(e.key + " up")
  if (e.altKey) {
    document.getElementById('alt').style.background = 'none';
  }
  if (e.ctrlKey) {
    document.getElementById('ctrl').style.background = 'none';
  }
  if (e.shiftKey) {
    document.getElementById('shift').style.background = 'none';
  }
  let elem = document.getElementById(e.key);
  if (elem && !e.altKey && !e.ctrlKey && !e.shiftKey) {
    document.getElementById(e.key).style.background = 'none';
  }
}
<div id="alt">Alt</div>
<div id="ctrl">Ctrl</div>
<div id="shift">Shift</div>
<div id="End">End</div>
<div id="Home">Start</div>
<div id="ArrowUp">Up</div>
<div id="ArrowLeft">Left</div>
<div id="ArrowDown">Down</div>
<div id="ArrowRight">Right</div>
<ol>
  <li>Hold down a key (listed above, but other than Shift),</li>
  <li>Hold Shift down</li>
  <li>Release the key of step 1</li>
  <li>Release Shift</li>
</ol>

Upvotes: 0

Views: 31

Answers (1)

Mr. Polywhirl
Mr. Polywhirl

Reputation: 48751

You can simplify which keys are pressed by using a Set.

Also, avoid setting CSS dynamically on the element. Use classes for styling.

const pressedKeys = new Set();

window.addEventListener('keydown', handleKeyDown);
window.addEventListener('keyup', handleKeyUp);

function handleKeyDown(e) {
  e.preventDefault();
  pressedKeys.add(e.key);
  update();
}

function handleKeyUp(e) {
  e.preventDefault();
  pressedKeys.delete(e.key);
  update();
}

function update(e) {
  for (let key of document.querySelectorAll('.key')) {
    key.classList.toggle('pressed', pressedKeys.has(key.dataset.key));
  }
}
.pressed {
  background: limegreen;
}
<div class="key" data-key="Alt">Alt</div>
<div class="key" data-key="Control">Ctrl</div>
<div class="key" data-key="Shift">Shift</div>
<div class="key" data-key="End">End</div>
<div class="key" data-key="Home">Start</div>
<div class="key" data-key="ArrowUp">Up</div>
<div class="key" data-key="ArrowLeft">Left</div>
<div class="key" data-key="ArrowDown">Down</div>
<div class="key" data-key="ArrowRight">Right</div>

Upvotes: 1

Related Questions