'How can I avoid autorepeated keydown events in JavaScript?

If the user holds down the key, multiple keydown events are fired. For usability reasons I need to use keydown, not keyup, but I want to avoid this situation. My relevant code is the following:

$(document).keydown(function(e) { 
        var key = 0;


        if (e == null) { key = event.keyCode;}  
        else {  key = e.which;} 


        switch(key) {
            case config.keys.left:                
              goLeft();
              break;
            case config.keys.up:                        
              goUp();
              break;
            case config.keys.right:                     
              goRight();
              break;
            case config.keys.down:                
              goDown();
              break;
            case config.keys.action:              
              select();
              break;
        }     
      });

So when the user holds down the down key, for example, goDown() is fired multiple times. I would like it to fire just once even if the user holds the key down.



Solution 1:[1]

Use event.repeat to detect whether or not the event is repeating. You could then wait for "keyup" before allowing the handler to execute a second time.

var allowed = true;

$(document).keydown(function(event) { 
  if (event.repeat != undefined) {
    allowed = !event.repeat;
  }
  if (!allowed) return;
  allowed = false;
  //...
});

$(document).keyup(function(e) { 
  allowed = true;
});
$(document).focus(function(e) { 
  allowed = true;
});

Solution 2:[2]

Another simple adjustment to the accepted answer to allow for the multiple keys scenario:

var keyAllowed = {};

$(document).keydown(function(e) {
  if (keyAllowed [e.which] === false) return;
  keyAllowed [e.which] = false;
  // code to be executed goes here
});

$(document).keyup(function(e) { 
  keyAllowed [e.which] = true;
});

$(document).focus(function(e) { 
  keyAllowed = {};
});

Solution 3:[3]

So, if the existing solution seems dubious (it doesn't consider the case when 2 or more buttons is pressed simultaneously), I suggest another solution that takes it into account.

The _prevKeyDown object is to store keys that are currently pressed.

    _prevKeyDown = {}

    function _downKey( event )
    {
        var wh = event.which;
        var kC = event.keyCode;

        if( _prevKeyDown[ wh ] == null )
        {
            _prevKeyDown[ wh ] = {};
        }

        _prevKeyDown[ wh ][ kC ] = true;
    };

    function _upKey( event )
    {
        var wh = event.which;
        var kC = event.keyCode;

        if( _prevKeyDown[ wh ] != null )
        {
            _prevKeyDown[ wh ][ kC ] = null;
        }               
    };

    function _isKeyDown( event )
    {
        var wh = event.which;
        var kC = event.keyCode;

        var result = false;

        if( this._prevKeyDown[ wh ] != null )
        {
            if( this._prevKeyDown[ wh ][ kC ] == true )
            {
                result = true;
            }
        }

        return result;
    }

    // now your keydown/keyup handlers
    function keydown( event )
    {
        if( !_isKeyDown( event ) )
        {
            // your once-keydown handler here
            _downKey( event );
        }    
    }

    function keyup( event )
    {
        _upKey( event );
    }

Solution 4:[4]

its simple

$(document).keydown(function(e) {
    if (e.repeat) return;
    // ...
});

Solution 5:[5]

(Copied from another question which turned out to be a duplicate of this one.)

dmaurolizer's KeyPress library gives fine control over all keyboard events. You provide callback functions for events. The keydown event sends an optional isRepeat param so you can ignore auto-repeats. Here's a sample using that functionality for the thrust control in a video game:

var my_combos = listener.register_many([
    {
        "keys"          : "up",
        "on_keydown"    : function(e, num, isRepeat) {
            if (isRepeat) return ;
            thrust = 0.1;
        },
        "on_keyup"      : function() {
            thrust = 0;
        }
    }
]);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Ben Davis
Solution 2 mattybrad
Solution 3 sergzach
Solution 4 GiantBooley
Solution 5 Juan Tomas