强制 keydown 事件仅在每个 keyCode 上触发一次

5

情况: 我有一个 keydown 处理程序,使用了 switch 来检测按下的键,这是相当标准的代码,但是当任何一个键被按住时,keydown 事件会重复触发(而不仅是在实际按下时触发一次)。

问题所在: 我想让 keydown 监听器保持激活状态,即能够检测到同时按下多个键,但只希望每个 keydown 事件触发一次。我将根据按下和松开之间的时间,在 keyup 上执行某些操作,但由于重复触发事件,这个计时被搞砸了。

我尝试过的方法: 我目前正在维护一个已按下的 keyCode 列表,并在我的 keydown 处理程序中对其进行检查,以防止默认行为发生。然而,事件仍然经常触发,我担心这种解决方案的效率/优雅性。

实际问题: 有没有好的方法可以限制 keydown 事件的触发仅在物理按下按键时触发,或仅监听特定的 keyCode?


那是什么意思?即能够检测到同时按下多个键。 - epascarello
例如,按住“y”键,然后再按住“o”键。这不包括删除keydown事件并在keyup之后再添加它的解决方案。 - Piers Mana
4个回答

9
在keydown事件处理程序中,检查按键是否与上次处理的按键相同。如果是,则提前退出。在keyup事件中,忘记上次处理的按键。
例如:
var lastEvent;
var heldKeys = {};

window.onkeydown = function(event) {
    if (lastEvent && lastEvent.keyCode == event.keyCode) {
        return;
    }
    lastEvent = event;
    heldKeys[event.keyCode] = true;
};

window.onkeyup = function(event) {
    lastEvent = null;
    delete heldKeys[event.keyCode];
};​

点击这里查看演示(点击“Result”面板并按下按键)。


0

定义一个布尔值来记录按键是否被按下。在按键按下事件中将其设置为true。让主循环检查该值是否为true并处理事件,然后将按键按下的值设置为false。再定义另一个布尔值来记录按键是否被释放(最初为false)。如果按键松开事件触发,则将其设置为已释放。只有在“released”值也为true时才将按键按下的值设置为true(在按键按下事件中)。


这是一个相当不错的答案。唯一要补充的可能就是,我会定义一个对象数组来存储每个键码在按下时的布尔值,在该对象中将包含 [{ "43": true}, ... ],然后按照上面建议的方式删除该键码。 - LocalPCGuy
这实际上是我现在正在做的,如果不清楚,对不起。我正在保留“向下”键码并在键盘松开时将其删除。我对任何可能比反复检查我的键码列表更有效的替代方法感兴趣。 - Piers Mana

0

这里有一个我认为你想要完成的示例:jsFiddle 示例

目前,组合键 CTRL+B 是唯一被检测到的。只需按下一些数字即可获得活动日志。当按键已经按下时,它会检测到保持操作。


0
这是一个更简洁的版本,会减少错误率。当前按键是否是最后一个按下的并不重要,因为如果keyup事件尚未触发,则它仍处于按下状态。
var heldKeys = {};

window.onkeydown = function(event) {
    if (heldKeys[event.keyCode]) {
        return;
    }
    heldKeys[event.keyCode] = true;
};

window.onkeyup = function(event) {
    heldKeys[event.keyCode] = false;
};​

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