Ignore repeated keyboard events when holding down the keys

Viewed 111

My code below, which fires update_doc_text() on pressing Ctrl+Shift+Enter, seems to call the function multiple times for some users (it happens when I hold down on those keys as well). What can I do to make sure the function only executes once?

var ctrlDown = false,
  ctrlKey = 17,
  shiftDown = false,
  shiftKey = 16,
  KeyEnter = 13,

  $(document).keydown(function(e) {
    if (e.keyCode == ctrlKey)
      ctrlDown = true;

    if (e.keyCode == shiftKey)
      shiftDown = true;

    if (ctrlDown && shiftDown && (e.keyCode == KeyEnter))
      update_doc_text();
  }).keyup(function(e) {
    if (e.keyCode == ctrlKey)
      ctrlDown = false;

    if (e.keyCode == shiftKey)
      shiftDown = false;
  });
2 Answers

The problem is due to how you're structured the logic; it's more complicated that it needs to be.

You can achieve what you need by reading the ctrlKey and shiftKey flags from the event to make sure they were held down at the same time as the return key was pressed.

To avoid the repetition when the keys are held down you can use a setTimeout() to set a flag which disables the repeated action for a set amount of time. Try this:

$(document).keydown(function(e) {
  var $doc = $(this);
  if (e.ctrlKey && e.shiftKey && e.which === 13 && !$doc.data('ctrlShiftReturnDisabled')) {
    update_doc_text();
    
    $doc.data('ctrlShiftReturnDisabled', true);
    setTimeout(function() {
      $doc.data('ctrlShiftReturnDisabled', false);
    }, 2000); // 2 seconds, change as needed
  }
});

function update_doc_text() {
  console.log('update_doc_text');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

You can use object to store pressed keys and get key code by e.which property. Also you can use one variable pressed to keep track if the keys are pressed and run your code only if that variable is false.

var keys = {}, pressed = false, codes = [13, 16, 17]
var check = keys => codes.every(k => keys[k]);

$(document).keydown(function(e) {
  keys[e.which] = true;

  if (check(keys) && !pressed) {
    // run your code here
    console.log('pressed')
    pressed = true;
  }

}).keyup(function(e) {
  keys[e.which] = false;

  if (codes.includes(e.which)) {
    pressed = false
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Related