Linux/X11下的Java keyPress/keyRelease问题
我正在用Java开发一个小型2D游戏引擎,在托管Ubuntu的VirtualBox虚拟机上玩了我的演示游戏后,我发现了一个奇怪的错误,它有时会导致游戏忽略按键这一事实。所以你向左跑,直到你突然停止移动 现在在一个真正的Ubuntu下,我找到了问题的原因。当我按住一个键时,按键按下/按键释放事件会一直发送 我的按键检查系统如下:Linux/X11下的Java keyPress/keyRelease问题,java,linux,x11,Java,Linux,X11,我正在用Java开发一个小型2D游戏引擎,在托管Ubuntu的VirtualBox虚拟机上玩了我的演示游戏后,我发现了一个奇怪的错误,它有时会导致游戏忽略按键这一事实。所以你向左跑,直到你突然停止移动 现在在一个真正的Ubuntu下,我找到了问题的原因。当我按住一个键时,按键按下/按键释放事件会一直发送 我的按键检查系统如下: -如果按下某个键,则将其添加到“下行列表” -如果某个键被释放,则将其添加到最上面的 -在游戏的每一帧上,从下列表中移除上列表中的键 -如果某个键仍在下行列表中,则按下该
-如果按下某个键,则将其添加到“下行列表”
-如果某个键被释放,则将其添加到最上面的
-在游戏的每一帧上,从下列表中移除上列表中的键
-如果某个键仍在下行列表中,则按下该键 现在,当您按下第二个键时,有时keyRelease是另一个键触发的最后一个事件,该键仍然保持,但无法以这种方式识别 有没有办法解决这个问题?真烦人 编辑
为了澄清,这是我连续按住一个键时得到的结果:
按下:87
发布:87
发布:87
按下:87
发布:87
按下:87
发布:87
按下:87
发布:87
等等 EDIT2
好的,在谷歌搜索了一段时间后,我发现这是X11服务器的一个“功能”,但我仍然不知道如何检测java中的“假”键事件。由于解决每帧按键和在列表之间切换的方式,您可能会遇到一些冲突。为您计划按下的每个键(如右箭头、左箭头等)设置布尔值可能会更简洁一些。按下某个键时,将相应的布尔值设置为true,然后在释放该键时将其设置为false。这是在视频游戏中处理键盘控制的一种非常常见的方法好的。。。我“修复”了它 由于X11不断触发其自动重复键事件,因此无法以忽略这些“假”事件的方式改变整个事件,您无法区分Java中的“真”和“假”事件 因此,解决方法如下。由于每个“假”keyUp事件之后都会有一个立即的keyDown事件,因此如果收到keyDown事件,只需从keyRemoveList中删除keyUp事件,如下所示:
public final void keyPressed(final KeyEvent e) {
int key = e.getKeyCode();
// Fix AutoKeyRepeat under X11
if (keysRemove.contains(key)) {
keysRemove.remove(Integer.valueOf(key));
}
if (!keysDown.contains(key)) {
keysDown.add(key);
keysPressed.add(key);
lastKeys.add(key);
if (lastKeys.size() > 16) {
lastKeys.remove(0);
}
}
e.consume();
}
由于“真实”键控事件之后没有立即的键控事件,因此正常处理该事件。从理论上讲,在“假”键向上和键向下之间不可能出现游戏帧。当然,自动恢复在X11中是可配置的。只需查看命令选项r或-r。 您可以使用禁用某些键代码的自动重发
$ xset -r keycode
最初我让它像那样工作。但是我需要检查一个键是否只按下了一次(所以如果你按住它,它只会触发一次),所以我想出了处理这个()的新代码,如果没有办法摆脱这个奇怪的GTK行为,我将不得不从头重写整个键盘处理。还有一个问题是,游戏可能会在一个不必要的按键释放事件之后进行检查。将按键动作放在计时器上可能更容易,而不是基于帧计时器。但这并不是真正的“可移植”我不能从Java中禁用它,所以每个玩游戏并遇到这些问题的人都必须自己禁用它。这是一个愚蠢的特性。密钥重复属于应用程序域。。操作系统涉及硬件。是的,但是你如何检测当前的真实情况呢?。。你需要一个该死的计时器来了解是否在此后很快注册了停机。真他妈的丑。Linux让我很生气。