Как я могу избежать событий автосохранения keydown в JavaScript?

Если пользователь удерживает нажатой клавишу, запускаются несколько событий смены ключа. Для удобства использования мне нужно использовать keydown, а не keyup, но я хочу избежать этой ситуации. Мой соответствующий код следующий:

$(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;
        }     
      });

Итак, когда пользователь удерживает нажатой клавишу вниз, например, goDown() запускается несколько раз. Я бы хотел, чтобы он срабатывал только один раз, даже если пользователь удерживает клавишу нажатой.

Ответ 1

Используйте event.repeat для определения того, повторяется ли событие. Затем вы можете дождаться "keyup", прежде чем позволить обработчику выполнить второй раз.

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;
});

Ответ 2

Еще одна простая настройка для принятого ответа для сценария с несколькими ключами:

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 = {};
});

Ответ 3

Итак, если существующее решение кажется сомнительным (оно не учитывает случай одновременного нажатия двух или более кнопок), я предлагаю другое решение, которое учитывает его.

Объект _prevKeyDown предназначен для хранения нажатых клавиш.

    _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 );
    }

Ответ 4

(Скопирован из другого вопроса, который оказался дубликатом этого.)

dmaurolizer Библиотека KeyPress обеспечивает прекрасный контроль над всеми событиями клавиатуры. Вы предоставляете функции обратного вызова для событий. Событие keydown отправляет необязательный параметр isRepeat, чтобы вы могли игнорировать авто-повторы. Здесь образец, использующий эту функциональность для управления тягой в видеоигре:

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;
        }
    }
]);