Inconsistent Input Timings in Key Releases on Linux (Wayland)

Godot Version

4.5.1 (Linux)

Question

OS: Fedora Linux Silverblue (GNOME)

I am experiencing inconsistent input behavior in Godot 4 where a key release event is triggered almost instantaneously after a press event (sub-millisecond), or with delays. This leads to unexpected movement in character or almost non existent movement.

Here are some logs

[Pressed] Key: E | Delta: 417745 µs (417.745000 ms)
[Release] Key: E | Delta: 66993 µs (66.993000 ms)

[Pressed] Key: E | Delta: 417965 µs (417.965000 ms)
[Release] Key: E | Delta: 67054 µs (67.054000 ms)

[Pressed] Key: E | Delta: 1548587 µs (1548.587000 ms)
[Release] Key: E | Delta: 77 µs (0.077000 ms)

[Pressed] Key: E | Delta: 462165 µs (462.165000 ms)
[Release] Key: E | Delta: 61965 µs (61.965000 ms)

[Pressed] Key: Alt | Delta: 1210265 µs (1210.265000 ms)
[Release] Key: Alt | Delta: 200000 µs (200.000000 ms)

I tried pressing at fast, consistent intervals, and mostly it sits around 60 ms. However, sometimes it has values of 77 microseconds (too fast for a human hand) or 200 milliseconds.

Thinking it was a hardware or driver issue, I checked these values with a Linux utility called libinput, which I can use to see the time difference between pressing and releasing buttons.

They were normal; those anomalies of < 100 µs or 200 ms were not observed, meaning it is mainly a Godot issue.

I also tried running with –display-driver wayland , but the behavior remained the same. This is the code I used to measure the deltas:

func _unhandled_input(event: InputEvent) -> void:
	if event is InputEventKey and not event.is_echo():
		var current_time = Time.get_ticks_usec()
		var delta_input = current_time - last_event_time
		
		var action_type = "Pressed" if event.pressed else "Release"
		
		print("[%s] Key: %s | Delta: %d µs (%f ms)" % [
			action_type, 
			event.as_text(), 
			delta_input, 
			delta_input / 1000.0
		])

		last_event_time = current_time
1 Like

You’re not measuring the time between the actual events, you’re measuring the time between the event handler being called (they are queued and processed at frame start).

Sadly, it would appear there is no way currently to get what you want, you can find some details / interesting discussion at Add OS time to InputEvent (input timestamp) · Issue #552 · godotengine/godot-proposals · GitHub

1 Like

If this is the case then why if Im pressing a button the event handler throws it before the actual event?
Pressing W for 1 second, the input handler throws a release event instantly before i even releasing
Meaning it false things i released the button.

This behavior is not manifesting only on _unhandled_input

its manifesting everywhere

If i make a player moving, the movement of the player is inconsistent

if i press W for 1 second of half a second and the input system thinks i pressed for 70 microseconds
The player is not moving at all

Or sometimes it thinks i press it longer that i actually did and the player keeps moving even if im no longer press it

This behavior is not happening on windows. I found it only when i switched to linux

for the movement im using

func _physics_process(_delta: float) -> void:
	var ivec := Input.get_vector("left", "right", "up", "down")
	velocity = ivec * speed
	move_and_slide()

Although if the interval is smaller than the frame duration you can’t catch it from a callback that’s bound to the framerate. Ditto for physics tick rate. You can’t get around the time granularity in a game engine.

1 Like