同时按下的键盘按键

4

我能知道在JavaScript中同时按下的按键数量吗?

如果可以,如何获取它们的keyCode数组?


3
值得注意的是,仅为完整起见,两个按键 同时 按下是不可能的。Javascript 本质上是同步的(这也排除了在 同一时间 进行某些物理操作的极大困难性)。因此,两个 keyPress 事件无法同时触发。这意味着以下建议中的其中一个是正确的方法:跟踪每次按键操作。当您想要按下的两个键按照顺序相继按下,并且在每次按下之间的时间最小化时,就会产生所需的按键组合。 - Jason L.
1
@TravisJ,我刚刚做了这件事,什么都没有发生 - Mac用户。 - Alexandre Khoury
@Mageek - 什么都没有?你试过按Q + ⌘键吗? - Travis J
@TravisJ 这不是由JavaScript处理的,按键也不会在单线程环境中发生,因为两件事情同时发生是不可能的。http://en.wikipedia.org/wiki/Single_threading - Jason L.
1
@TravisJ:你可以同时按住两个键,但是JavaScript无法检测到同时按下两个键。你所指的是像Alt和Ctrl这样的元键。如果按下了这些键,则可以检测到;然而,任意键组合不能直接被检测到。 - Dancrumb
显示剩余2条评论
3个回答

11
你可以监听键盘的按下和释放事件。

你可以监听keydown和keyup事件。

var keys = { length: 0 };

document.onkeydown = function(e){
    if(!keys[e.keyCode])   {
        keys[e.keyCode] = true;
        keys.length++;
    }
}

document.onkeyup = function(e){
    if(keys[e.keyCode])   {
        keys[e.keyCode] = false;
        keys.length--;
    }
}

那么所有当前按下的键中,true 的键都会被记录。

感谢 @Esailija 提供的演示代码:http://jsfiddle.net/maniator/Gc54D/


1
请注意,onkeydown 事件在按键按下时会不断触发,因此它会增加 .length 的值。 - Esailija
如果你按下像 o 这样的键并等待,keys.length 将不断增加,但你仍然只按下一个键。 - Alexandre Khoury
@Neal 非常好,但是我这里有一个错误。如果我按下Command+Shift+Z然后把手指拿开,长度仍旧保持在1。 - Alexandre Khoury
@Mageek 嗯,当您按下按钮然后在释放键之前单击窗口时,似乎会发生这种情况。 - Naftali
1
我在MAC OSX(10.7)上尝试了这个,并分叉(新链接)你的小提琴来看看会发生什么。 因此,cmd-key似乎是某种系统键,它表现得像这样:按下 cmd + anykey,然后释放 anykey 后,JavaScript不会触发。 当按下 cmd + anykey 并释放 cmd-key 然后释放 anykey 时,它可以正常工作。 系统似乎将键从内容锁定,因为它认为您可能想使用浏览器的键命令进行交互。 - insertusernamehere
显示剩余3条评论

1

这应该能解决问题了。它类似于Neal的代码,但应该修复了一些问题,包括离开窗口时的错误和负数键的错误。我还简化了一下消息编写代码。我用按需系统替换了计时器循环来编写按键数量消息,添加了一个安全机制来减少长度索引,并添加了clearKeys以在用户离开窗口时将所有按键切换为“up”状态。代码仍然有两个错误:它无法识别在打开和关闭新窗口后仍然按住的按键(必须释放并重新按下),而且我无法让它识别超过六个按键(我怀疑这与此代码无关,而是与计算机/浏览器有关...)。

var keys = {
    length: 0
};

window.onkeydown = function(e) {
    if (!keys[e.keyCode]) {
        keys[e.keyCode] = true;
        keys.length++;
        document.body.innerHTML = "You are pressing " + keys.length + " keys at the same time.";
    }
}

window.onkeyup = function(e) {
    if (keys[e.keyCode]) {
        keys[e.keyCode] = false;
        if (keys.length) {
            keys.length--;
        }
        document.body.innerHTML = "You are pressing " + keys.length + " keys at the same time.";
    }
}

function clearKeys() {
    for (n in keys) {
        n = false
    };
    keys.length = 0;
    document.body.innerHTML = "You are pressing " + 0 + " keys at the same time.";
}

document.body.innerHTML = "You are pressing 0 keys at the same time.";
window.onblur = clearKeys;

不超过6个按键不是问题,但它存在我在这里描述的错误:https://dev59.com/4WXWa4cB1Zd3GeqPSf87#TlcEoYgBc1ULPQZF4Po8 - Alexandre Khoury

1

既然您想要同时按下的按键数量和它们的键码数组,我建议您使用以下函数:

var getKeys = function () {
    var keys = [];

    window.addEventListener("blur", blur, false);
    window.addEventListener("keyup", keyup, false);
    window.addEventListener("keydown", keydown, false);

    return function () {
        return keys.slice(0);
    };

    function blur() {
        keys.length = 0;
    }

    function keyup(event) {
        var index = keys.indexOf(event.keyCode);
        if (index >= 0) keys.splice(index, 1);
    }

    function keydown(event) {
        var keyCode = event.keyCode;
        if (keys.indexOf(keyCode) < 0)
        keys.push(keyCode);
    }
}();

当您调用getKeys时,它将返回一个同时按下的所有键的数组。您可以使用该数组的length属性来查找同时按下的键数。由于它使用addEventListener,因此它与页面上的其他代码协作工作。
我测试了上述函数,即使在按住一个键的情况下切换到另一个窗口时,它始终返回正确的按键(它会从数组中删除该键)。如果您按住一个键并切换回去,则它会识别出按下了一个键,并将其推入到数组中。因此,我可以证明上述代码没有错误。至少在我测试的浏览器(Opera 12.00)上没有。

我可以同时按下 8 个键 (A, S, D, F, J, K, L;)。这个数字似乎是操作系统特定的,因为我只能同时按下左手的 4 个键和右手的 4 个键。例如,在我按下ASDF之后,再按下另一个左手的键(比如说G),那么它就无法识别最后一个键。这可能是因为操作系统知道人类打字的方式,所以它只允许每个左手和右手键的中断次数为四次。我使用的操作系统是 Ubuntu 12.04。

您可以在此fiddle上查看代码的运行情况。我使用了Delta Timer而不是setInterval来在每50毫秒后显示结果。您可能还希望阅读以下答案


非常好,但还有一个bug :( 当我按住 Command+Shift+ZCommand+Shift+X,然后松开手指时,它仍然显示1个键被按下。(我发现如果在此之后按下并释放一个字母,则结果会返回0)。 - Alexandre Khoury
我看到你在使用Macintosh。嗯,这似乎是一个特定于操作系统的问题。我在Ubuntu上尝试了相同的键组合,它完美地工作了。请注意,在IBM键盘上,Ctrl相当于Command - Aadit M Shah

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接