GTNewHorizons / lwjgl3ify

A mod to run Minecraft 1.7.10 using LWJGL3 and Java 17+
GNU Lesser General Public License v3.0
171 stars 37 forks source link

WASD keys sometimes become sticky under the new version 1.2.1/1.2.2 #48

Closed Frefreak closed 1 year ago

Frefreak commented 1 year ago

After #28 the input issue has been fixed, but I notice that sometimes the wasd keys behave like it is kept being pressed, so that the character will keep moving to one direction even without any key pressed. This is relatively easy to trigger once you start walking around for a short distance.

My keyboard should be fine as I haven't noticed similar behavior under other applications.

FYI I tried lwjgl3ify 1.2.1 and 1.2.2 and they both have this annoyance. In 1.1.44 this does not happen (but it has the input issue).

OS: archlinux

EDIT: changed "arrow" key to "wasd" key

Frefreak commented 1 year ago

I played around for a bit with the code locally. It seems to me that sometimes the charCallback for those keys (char window in log) will be called after the release key for them in keyCallback (key window in log).

This is normal when I stop pressing a direction (action = 0 being the last line of this sequence): image

And when it is not normal there will be additional "char window" lines for the same char after the corresponding action = 0 line, and the "sticky" issue is very likely to happen in this case.

I'm not sure what causes this that doesn't make the release event being the last event when player stops pressing the key. The most reliable way I can get to work around this is to append the release event in Keyboard.eventQueue if there are multiple events already (so chances are that we were holding the key). Something like below:

diff --git a/src/main/java/org/lwjglx/opengl/Display.java b/src/main/java/org/lwjglx/opengl/Display.java
index 4c6f132..d862c61 100644
--- a/src/main/java/org/lwjglx/opengl/Display.java
+++ b/src/main/java/org/lwjglx/opengl/Display.java
@@ -6,6 +6,7 @@ import static org.lwjgl.system.MemoryUtil.NULL;
 import java.awt.event.KeyEvent;
 import java.nio.ByteBuffer;
 import java.nio.IntBuffer;
+import java.util.ArrayList;

 import me.eigenraven.lwjgl3ify.Lwjgl3ify;
 import me.eigenraven.lwjgl3ify.core.Config;
@@ -61,6 +62,7 @@ public class Display {
     private static Keyboard.KeyEvent ingredientKeyEvent;
     private static ByteBuffer[] savedIcons;

+    private static ArrayList<Keyboard.KeyEvent> releaseEvents = new ArrayList<>();
     static {
         Sys.initialize(); // init using dummy sys method

@@ -208,9 +210,18 @@ public class Display {
                 if (cancelNextChar) { // Char event being cancelled
                     cancelNextChar = false;
                 } else if (ingredientKeyEvent != null) {
+                    releaseEvents.clear();
+                    if (Keyboard.eventQueue.size() > 1) {
+                        for (Keyboard.KeyEvent evt : Keyboard.eventQueue) {
+                            if (!evt.state.isPressed) {
+                                releaseEvents.add(evt);
+                            }
+                        }
+                    }
                     ingredientKeyEvent.aChar = (char) codepoint; // Send char with ASCII key event here
                     Keyboard.eventQueue.add(ingredientKeyEvent);
                     ingredientKeyEvent = null;
+                    Keyboard.eventQueue.addAll(releaseEvents);
                 } else {
                     Keyboard.addCharEvent(0, (char) codepoint); // Non-ASCII chars
                 }

Using this hacky patch the problem happens a lot less frequently, but it does still happen from time to time. There should be a better way... However with this patch the game has become playable to me so I will use this personally for now.

UPDATE: this one seems to be more reliable (https://github.com/Frefreak/lwjgl3ify/commits/fix_sticky_direction_key)

diff --git a/src/main/java/org/lwjglx/opengl/Display.java b/src/main/java/org/lwjglx/opengl/Display.java
index 4c6f132..e82b187 100644
--- a/src/main/java/org/lwjglx/opengl/Display.java
+++ b/src/main/java/org/lwjglx/opengl/Display.java
@@ -6,6 +6,7 @@ import static org.lwjgl.system.MemoryUtil.NULL;
 import java.awt.event.KeyEvent;
 import java.nio.ByteBuffer;
 import java.nio.IntBuffer;
+import java.util.ArrayList;

 import me.eigenraven.lwjgl3ify.Lwjgl3ify;
 import me.eigenraven.lwjgl3ify.core.Config;
@@ -61,6 +62,7 @@ public class Display {
     private static Keyboard.KeyEvent ingredientKeyEvent;
     private static ByteBuffer[] savedIcons;

+    private static ArrayList<Keyboard.KeyEvent> releaseEvents = new ArrayList<>();
     static {
         Sys.initialize(); // init using dummy sys method

@@ -208,9 +210,20 @@ public class Display {
                 if (cancelNextChar) { // Char event being cancelled
                     cancelNextChar = false;
                 } else if (ingredientKeyEvent != null) {
+                    releaseEvents.clear();
+                    for (Keyboard.KeyEvent evt : Keyboard.eventQueue) {
+                        if (!evt.state.isPressed) {
+                            releaseEvents.add(evt);
+                        }
+                    }
                     ingredientKeyEvent.aChar = (char) codepoint; // Send char with ASCII key event here
                     Keyboard.eventQueue.add(ingredientKeyEvent);
+                    if (ingredientKeyEvent.state == Keyboard.KeyState.PRESS) {
+                        ingredientKeyEvent = null;
+                        return;
+                    }
                     ingredientKeyEvent = null;
+                    Keyboard.eventQueue.addAll(releaseEvents);
                 } else {
                     Keyboard.addCharEvent(0, (char) codepoint); // Non-ASCII chars
                 }
eigenraven commented 1 year ago

Reproduction steps that work for me: