听多个keydowns

时间:2011-09-30 18:09:26

标签: javascript keydown addeventlistener

我试图让用户使用箭头键移动页面上的元素。到目前为止,我的运动是上/下/左/右,但不是对角线(同时按下两个箭头键)。

我的听众看起来像这样:

addEventListener('keydown', function(e){
    move = false;
    x = false;
    y = false;
    var keycode;
    if (window.event) keycode = window.event.keyCode;
    else if (e) keycode = e.which;
    switch(keycode){
        case 37:
            move = true;
            x = 'negative';
            //prevent page scroll
            e.preventDefault()
        break;
        case 38:
            move = true;
            y = 'negative'
            //prevent page scroll
            e.preventDefault()
        break;
        case 39:
            move = true;
            x = 'positive'
            //prevent page scroll
            e.preventDefault()
        break;
        case 40:
            move = true;
            y = 'positive'
            //prevent page scroll
            e.preventDefault()
        break;
    }
    if(move){
        animation.move(x,y);
    }
    return false;
})

这个想法是,如果用户按下箭头键,它会将xy设置为negativepositive,并触发move()函数,它将在预期的方向上移动元素预设数量的像素,如果按下两个键,则会触发第二个事件...我也希望能够通过释放和按键让用户无可奈何地改变方向然而,如果用户按下另一个方向键,他们似乎需要等待一个动作才能发生,除非他们完全释放键然后按另一个键,它将不会响应第二个密钥,直到第一个密钥被释放。

3 个答案:

答案 0 :(得分:9)

小提琴:http://jsfiddle.net/ATUEx/

创建一个临时缓存以记住您的击键。

处理两个密钥的实现将遵循以下模式:

  1. <keydown>
    • 清除上一次超时。
    • 检查密钥代码是否已被缓存。
      如果是,则有效组合:
      -删除所有缓存的密钥代码
      -执行此组合的功能
      否则
      -删除所有缓存的密钥代码
      -存储新的密钥代码
      -设置超时以清除密钥代码(见下文),并有合理的延迟
  2. 重复1
  3. 合理的延迟:尝试知道哪个超时足够您。当延迟太短时,下一个启动的事件将找不到先前输入的密钥代码。

    当延迟太长时,如果你不想要它,键击将叠加。

    <小时/>

    代码

    我创建了一个高效的功能,牢记您的代码。你应该能够很容易地实现它。

    (function(){ //Anonymous function, no leaks
        /* Change the next variable if necessary */
        var timeout = 200; /* Timeout in milliseconds*/
    
        var lastKeyCode = -1;
        var timer = null;
        function keyCheck(ev){
            var keyCode = typeof ev.which != "undefined" ? ev.which : event.keyCode;
            /* An alternative way to check keyCodes:
             * if(keyCode >= 37 && keyCode <= 40) ..*/
             /*37=Left  38=Up  39=Right  40=Down */
            if([37, 38, 39, 40].indexOf(keyCode) != -1){
    
                /* lastKeyCode == -1 = no saved key
                   Difference betwene keyCodes == opposite keys = no possible combi*/
                if(lastKeyCode == -1 || Math.abs(lastKeyCode - keyCode) == 2){
                    refresh();
                    lastKeyCode = keyCode;
                } else if(lastKeyCode == keyCode){
                    clear([lastKeyCode]);
                } else {
                    /* lastKeyCode != -1 && keyCode != lastKeyCode
                       and no opposite key = possible combi*/
                    clear([lastKeyCode, keyCode]);
                    lastKeyCode = -1
                }
                ev.preventDefault(); //Stop default behaviour
                ev.stopPropagation(); //Other event listeners won't get the event
            }
    
            /* Functions used above, grouped together for code readability */
            function reset(){
                keyCombi([lastKeyCode]);
                lastKeyCode = -1;
            }
            function clear(array_keys){
                clearTimeout(timer);
                keyCombi(array_keys);
            }
            function refresh(){
                clearTimeout(timer);
                timer = setTimeout(reset, timeout);
            }
        }
    
        var lastX = false;
        var lastY = false;
        function keyCombi(/*Array*/ keys){
            /* Are the following keyCodes in array "keys"?*/
            var left = keys.indexOf(37) != -1;
            var up = keys.indexOf(38) != -1;
            var right = keys.indexOf(39) != -1;
            var down = keys.indexOf(40) != -1;
    
            /* What direction? */
            var x = left ? "negative" : right ? "positive" : false;
            var y = up ? "negative" : down ? "positive" : false;
            /* Are we heading to a different direction?*/
            if(lastX != x || lastY != y) animation.move(x, y);
            lastX = x;
            lastY = y;
        }
    
        //Add event listener
        var eventType = "keydown";window["on"+eventType] = keyCheck;
    })();
    

    在匿名函数结束时,添加了keydown事件侦听器。此事件仅触发一次(按下该键时)。当按下第二个键足够快时,代码会识别出彼此之后的两个击键,并调用keyCombi()

    我设计keyCombi是智能的,只有在值发生变化时才调用animation.move(x,y)。另外,我已经实现了一次处理两个方向的可能性。

    注意:我在匿名函数包装器中包含了这些函数,因此未在全局(window)范围内定义变量。如果您不关心范围界定,请随意删除第一行和最后一行。

答案 1 :(得分:2)

以下是您的代码,稍作修改...... http://jsfiddle.net/w8uNz/它只是工作。在父元素上移动元素。

Rob W是对的,您应该在一段时间内按下动态的密钥缓存。但为了什么?如果你正在制作一个动态游戏 - 必须有更高的抽象。总的来说,如果你想做那样的事情,你需要提高你的编码水平。 (或者它只会给你带来麻烦。)

答案 2 :(得分:1)

从逻辑上讲,这听起来很简单:

  1. 第一个键触发按键事件,将此事件存储在堆栈中
  2. 然后第二个键触发按键事件,将此事件存储在堆栈中
  3. 现在你有两个关键的下降而没有按键
  4. 如果一把钥匙起火你有三种可能性
    1. 你只有一个事件=&gt;走向那个方向
    2. 你有两个事件=&gt;对角线
    3. 您有两个以上的活动或无效的选项(例如左右)=&gt;无所事事,无论你想做什么
  5. 清除堆栈