Javascript";";密钥(未注册的密钥更新事件)

Javascript";";密钥(未注册的密钥更新事件),javascript,keyboard,coffeescript,Javascript,Keyboard,Coffeescript,使用HTML5画布和javascript开发一个小游戏。它工作得很好,除了键盘键偶尔会“卡住”,即它会注册一个keydown事件,但有时它不会注册keydup事件。这通常发生在同时按下多个键时,所以这在一定程度上是硬件或操作系统的故障,但我希望有人对如何解决这一问题有想法。我的代码的相关部分(用coffeescript编写): 基本的东西。如果javascript不完全是事件驱动的,这不会是一个问题,但是您可以做什么呢。我目前的想法是为按键添加一个队列,可容纳2或3个键,当超过限制时,第一个键被

使用HTML5画布和javascript开发一个小游戏。它工作得很好,除了键盘键偶尔会“卡住”,即它会注册一个keydown事件,但有时它不会注册keydup事件。这通常发生在同时按下多个键时,所以这在一定程度上是硬件或操作系统的故障,但我希望有人对如何解决这一问题有想法。我的代码的相关部分(用coffeescript编写):

基本的东西。如果javascript不完全是事件驱动的,这不会是一个问题,但是您可以做什么呢。我目前的想法是为按键添加一个队列,可容纳2或3个键,当超过限制时,第一个键被移除并切换到“false”。尽管如此,在本应可以避免的情况下,添加这样的人为限制似乎很奇怪


因此,问题是,有没有一种直接的方法可以确保关键状态得到准确保存,而不必求助于变通办法?最好是一些独立于游戏帧率的东西(无论是以1000 fps还是3 fps的速度运行,都应该同样有效)。

值得指出的是,拥有比
keyup
事件更多的
keydown
事件实际上是预期的行为:当你按下一个键时,操作系统报告说,当有多个
keydown
s时(在正常文本输入中插入一个字符时,每次一个字符,尽管这种情况在Mac OS 10.7中默认的按键保持行为下也会发生)。只有在实际释放钥匙时,您才能获得一个
keyup


当然,您的代码不应该受到此问题的影响。因此,如果在释放
a
键后,您确实处于
game.keys.a
true
的情况下,您应该在浏览器中将遇到的问题报告为bug。我认为不可能找到解决办法。

除了更昂贵的键盘之外,这是所有键盘的常见问题

举个例子,试着玩一个游戏,你有箭头键可以移动,空格键可以开火。你会发现按下两个箭头可能会导致你无法射击


不幸的是,你没有办法解决这个问题,因为很多键盘都是不同的。您应该做的是允许用户在遇到问题时自定义其控件,以便他们可以更改为一组没有此问题的控件。

由于
keydown
事件快速触发,您可以存储一个时间戳,记录您上次听到按键的时间:

when 'A'
    game.keys.A = [true, +newDate()]
然后,运行interval函数检查仍注册为按下但在一段时间内(例如,1秒)未发送
keydown
事件的按键,并将其设置为已释放

我上面的示例可能需要重构大量代码(因为
game.keys.a
现在是数组而不是布尔值)。相反,您可以将时间戳保存在它们自己的对象中:

last_keydown_times = {};
...

when 'A'
    game.keys.A = true
    last_keydown_times['A'] = +new Date();
让间隔功能检查
最后一次按键时间的成员(可能在
循环中)并检查过期值:

setInterval(function() {
    var now = +new Date();
    for(key in last_keydown_times) {
        if(now - last_keydown_times[key] >= 1000) {
            // run the release code for this key
        }
    }
}, 1000);

如果这种情况发生在OSX上,请注意,按住
cmd
键时,您不会得到任何keyup事件


恐怕这个问题没有解决办法。跟踪哪些键当前处于关闭状态的唯一方法是通过keyup/keydown事件,在Mac上,cmd键会剥夺您的这些信息。

您不能在coffeescript中编写
game.keys[direction]=true
?这样可以节省一些打字时间……而且
按String.fromCharCode(evt.keyCode)
我确实可以!谢谢你指出这一点。对于javascript,或者说整个脚本语言来说,我还是个新手,所以我最终错过了很多优化/浓缩东西的好方法。我从来没有听说过解决这个问题的方法。如果将事件绑定到
窗口后没有传递事件,那么您可能认为这是操作系统错误,或者在
键控时窗口没有焦点。即使在本机SDL应用程序中也可以观察到同样的问题。实际上,我认为您正在考虑
keypress
Keydown
仅在用户第一次按下键盘上的键时触发@这可能是对交叉兼容性的让步,以支持不快速启动
keydown
的旧浏览器。根据MDN,
keydown
应该反复发射。当然,MDN不是W3规范,但至少在Firefox中会发生这种情况。@Jivings我刚才提到的,这说明两者(可能)都会重复。是的,你需要一个n键翻转的键盘。大多数键盘只有3或4个,而好的键盘几乎没有限制。这听起来不适合问题中描述的问题。如果我按住键盘上的5个键,则不会报告第6个键的
keydown
;但如果我释放任何键,则会正确报告
keyup
。否则,该键将被有效地“卡住”,直到您再次切换(或重新启动)。谢谢,这是一个很好的解决方案!当然,键控触发的速率取决于系统,因此需要进行一些调整才能找到最佳等待时间。我想我可以让程序在运行时检查一个人键盘的重复率,并相应地调整持续时间。
setInterval(function() {
    var now = +new Date();
    for(key in last_keydown_times) {
        if(now - last_keydown_times[key] >= 1000) {
            // run the release code for this key
        }
    }
}, 1000);