Linux/X11下Java keyPress/keyRelease问题

发布于 2024-08-21 05:05:46 字数 677 浏览 4 评论 0原文

我正在用 Java 开发一个小型 2D 游戏引擎,在托管 Ubuntu 的 VirtualBox VM 中玩完我的演示游戏后,我发现了一个奇怪的错误,有时会导致游戏忽略按下按键的事实。所以你向左跑,直到你突然停止移动。

现在在真正的Ubuntu下我找到了问题的原因。当我按住某个键时,始终会发送 keyPress/keyRelease 事件。

我检查按下的按键的系统如下:
- 如果按下某个键,将其添加到“下拉列表”
- 如果释放了某个键,请将其添加到 uplist
- 在游戏的每一帧上从下行列表中删除上行列表中的键
- 如果某个键仍在下拉列表中,则它会被按下

现在,当您按下第二个键时,有时 keyRelease 是另一个键触发的最后一个事件,该键仍被按住但无法以这种方式被识别。

有什么想法如何解决这个问题吗?真的很烦人。

编辑
为了澄清起见,这是我连续按住某个键时得到的结果:
按下:87
已发布:87
已发布:87
按下:87
已发布:87
按下:87
已发布:87
按下:87
已发布:87
等等

EDIT2
好吧,在谷歌搜索了一下之后,我发现这是 X11 服务器的一个“功能”,但我仍然不知道如何检测 java 中的“假”按键事件。

I'm developing a small 2D game engine in Java, after playing around with my demo game in a VirtualBox VM hosting Ubuntu, I found a strange bug that would sometimes cause the game to ignore the fact that a key is pressed. So you're running to the left until you suddenly stop moving.

Now under a real Ubuntu I found the cause of the problem. When I hold a key the keyPress/keyRelease events are send all the time.

My system to check for pressed keys is the following:
- if a key gets pressed add it to the "downlist"
- if a key is released add it to the uplist
- on each frame of the game remove the keys in the uplist from the downlist
- if a key is still in the downlist it's pressed

Now when you press a second key, sometimes keyRelease was the last event fired by the other key which is still held but not recognized in that way.

Any ideas how to fix this? It's really annoying.

EDIT
For clarification this is the result I get when holding down a key continuously:
pressed: 87
released: 87
released: 87
pressed: 87
released: 87
pressed: 87
released: 87
pressed: 87
released: 87
etc.

EDIT2
Ok after googling a bit more I found out that this is a "feature" of the X11 server, but I still have no clue how to detect the "fake" key events in java.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

你是我的挚爱i 2024-08-28 05:05:46

由于每帧解析按键以及在列表之间切换的方式,您可能会遇到一些冲突。为您计划按下的每个键(例如右箭头、左箭头...等)设置一个布尔值可能会更清晰一些。当按下某个键时,将相应的布尔值设置为 true,然后在释放该键时将其设置为 false。这是视频游戏中处理键盘控制的一种非常常见的方法

You may be getting some conflicts because of the way you're resolving keypresses every frame and switching between the lists. It may be a bit cleaner to have a boolean for each of the keys you plan to press (such as right arrow, left arrow...etc). When a key is pressed, set the corresponding boolean to true, then when it's released, set it to false. This is a pretty common way to deal with keyboard control in video games

焚却相思 2024-08-28 05:05:46

好吧...我“修复”了它。

由于 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();
}

由于“真实”keyUp 事件后面没有立即发生keyDown 事件处理正常。理论上,“假”keyUp 和 keyDown 之间不可能出现游戏帧。

Okay... I "fixed" it.

Since X11 keeps firing it's auto repeat key events, there's no way to change the whole thing in a way that those "fake" events are ignored, you can't distinguish between "real" and "fake" events in Java.

So the way to fix it is the following. Since every "fake" keyUp event is followed by an immediate keyDown event, you simply remove the keyUp event from the keyRemoveList if you receive a keyDown event this looks like the following:

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();
}

Since the "real" keyUp event isn't followed by an immediate keyDown event it's processed normally. In theory it should be impossible for a game frame to occur between a "fake" keyUp and keyDown.

当然,X11 中可以配置自动重复。只需看一下 xset 命令选项 r-r
您可以使用以下命令禁用某些键码的自动重复

$ xset -r keycode

Of course autorepeat is configurable in X11. Just take a look at xset command option r or -r.
You can disable autorepeat for some keycodes using

$ xset -r keycode
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文