Input.parse_input_event turns into an infinite loop

Godot Version

v4.7.2.stable.official [ed1daf0bf]

Running on macOS 26.6.2

Context and Goal

I’m prototyping a turn based, player-vs-bots game (not multiplayer).

When a player taps a key, their avatar and all the enemies execute for their turn. The animations for these turn last for a quarter of a second, at which point the player can tap a key again for the next turn to happen. Also, if the player is holding the same key down when the animation finishes, then that action should re-fire.

Code

In _unhandled_input, I check for the action (&Move) and move the position of my avatar via a tween. At the end of the tween I call end_tween with the action that was just animated.

The boolean is_tweening is used to stop this code processing a new action while and existing action is being animated. If I didn’t do this, the avatar would move off the grid spots.

Regardless of whether is_tweening is true or not, I set_input_as_handled for valid actions.

Print calls are for debugging/tracing purposes.

func _unhandled_input(event: InputEvent) -> void:
	
	print( "UNHANDLED INPUT ", event.to_string() )
	
	if event is InputEventAction:
		var e = event as InputEventAction
		print( " ACTION EVENT WITH STRENGTH ", e.strength )
	
	if event.is_action_pressed( &"Move" ):
		
		if not is_tweening:
			
			is_tweening = true
			
			var t : Tween = create_tween()
			
			t.tween_property( avatar, "position", 2.0, 0.250 )
			t.tween_callback( end_tween.bind( &"Move" ) ) 
		
		current_viewport.set_input_as_handled()

The code for end_tween turns is_tweening off and then checks to see if the provided action_name is still being pressed. If so, it creates a new InputEvent and issues it using Input.parse_input_event.

The strength_counter variable starts with a value of 1.0 and is decremented each time I create a new InputEvent. This is purely for debugging purposes so I could check whether I was getting new events or somehow reprocessing the first event over and over.

Print calls are for debugging/tracing purposes.

func end_tween( action_name: StringName ) -> void:
	
	is_tweening = false
	
	print( "TWEEN ENDED FOR ACTION ", action_name )
	
	if Input.is_action_pressed( action_name ):
		
		var event : InputEvent = InputEventAction.new()
		
		event.action   = action_name
		event.pressed  = true
		
		event.strength = str_counter
		
		str_counter -= 0.01
		
		Input.parse_input_event( event )
		
		print( "BUTTON STILL DOWN FOR ACTION ", action_name, ". CREATED NEW ACTION WITH STRENGTH", str_counter )
		
	else:
		
		print( "BUTTON NO LONGER DOWN FOR ACTION ", action_name )

Bug

When I tap the key once. Everything works fine.

UNHANDLED INPUT InputEventKey: keycode=87 (W), mods=none, physical=false, location=unspecified, pressed=true, echo=false
UNHANDLED INPUT InputEventKey: keycode=87 (W), mods=none, physical=false, location=unspecified, pressed=false, echo=false
TWEEN ENDED FOR ACTION Move
BUTTON NO LONGER DOWN FOR ACTION Move

When I tap the key twice, fast enough. Everything works fine.

UNHANDLED INPUT InputEventKey: keycode=87 (W), mods=none, physical=false, location=unspecified, pressed=true, echo=false
UNHANDLED INPUT InputEventKey: keycode=87 (W), mods=none, physical=false, location=unspecified, pressed=false, echo=false
UNHANDLED INPUT InputEventKey: keycode=87 (W), mods=none, physical=false, location=unspecified, pressed=true, echo=false
UNHANDLED INPUT InputEventKey: keycode=87 (W), mods=none, physical=false, location=unspecified, pressed=false, echo=false
TWEEN ENDED FOR ACTION Move
BUTTON NO LONGER DOWN FOR ACTION Move

When I tap the key twice, slow enough. Everything works fine.

UNHANDLED INPUT InputEventKey: keycode=87 (W), mods=none, physical=false, location=unspecified, pressed=true, echo=false
UNHANDLED INPUT InputEventKey: keycode=87 (W), mods=none, physical=false, location=unspecified, pressed=false, echo=false
TWEEN ENDED FOR ACTION Move
BUTTON NO LONGER DOWN FOR ACTION Move
UNHANDLED INPUT InputEventKey: keycode=87 (W), mods=none, physical=false, location=unspecified, pressed=true, echo=false
UNHANDLED INPUT InputEventKey: keycode=87 (W), mods=none, physical=false, location=unspecified, pressed=false, echo=false
TWEEN ENDED FOR ACTION Move
BUTTON NO LONGER DOWN FOR ACTION Move

When I press and hold, and trigger the creation of an InputEvent things go wrong.

UNHANDLED INPUT InputEventKey: keycode=87 (W), mods=none, physical=false, location=unspecified, pressed=true, echo=false
TWEEN ENDED FOR ACTION Move
BUTTON STILL DOWN FOR ACTION Move. CREATED NEW ACTION WITH STRENGTH0.99
UNHANDLED INPUT InputEventAction: action="Move", pressed=true
 ACTION EVENT WITH STRENGTH 1.0
UNHANDLED INPUT InputEventKey: keycode=87 (W), mods=none, physical=false, location=unspecified, pressed=true, echo=true
TWEEN ENDED FOR ACTION Move
BUTTON STILL DOWN FOR ACTION Move. CREATED NEW ACTION WITH STRENGTH0.98
UNHANDLED INPUT InputEventAction: action="Move", pressed=true
 ACTION EVENT WITH STRENGTH 0.99000000953674
UNHANDLED INPUT InputEventKey: keycode=87 (W), mods=none, physical=false, location=unspecified, pressed=false, echo=false
TWEEN ENDED FOR ACTION Move
BUTTON STILL DOWN FOR ACTION Move. CREATED NEW ACTION WITH STRENGTH0.97
UNHANDLED INPUT InputEventAction: action="Move", pressed=true
 ACTION EVENT WITH STRENGTH 0.98000001907349
TWEEN ENDED FOR ACTION Move
BUTTON STILL DOWN FOR ACTION Move. CREATED NEW ACTION WITH STRENGTH0.96
UNHANDLED INPUT InputEventAction: action="Move", pressed=true
 ACTION EVENT WITH STRENGTH 0.97000002861023
TWEEN ENDED FOR ACTION Move
BUTTON STILL DOWN FOR ACTION Move. CREATED NEW ACTION WITH STRENGTH0.95
UNHANDLED INPUT InputEventAction: action="Move", pressed=true
 ACTION EVENT WITH STRENGTH 0.95999997854233
TWEEN ENDED FOR ACTION Move
BUTTON STILL DOWN FOR ACTION Move. CREATED NEW ACTION WITH STRENGTH0.94
UNHANDLED INPUT InputEventAction: action="Move", pressed=true
 ACTION EVENT WITH STRENGTH 0.94999998807907
TWEEN ENDED FOR ACTION Move
BUTTON STILL DOWN FOR ACTION Move. CREATED NEW ACTION WITH STRENGTH0.93
UNHANDLED INPUT InputEventAction: action="Move", pressed=true
 ACTION EVENT WITH STRENGTH 0.93999999761581
TWEEN ENDED FOR ACTION Move
BUTTON STILL DOWN FOR ACTION Move. CREATED NEW ACTION WITH STRENGTH0.92

As you can see, I get a pressed event, an echo event, and a released event, but the code in end_tween continues to see the action as pressed, causing a loop.

Note also, that the strength changes as expected, meaning we really are creating new events.

Also, when I watch it run, I can see that the logs are printed out at quarter second intervals.

Question

What am I misunderstanding about this functionality?

I do have another way of re-writing this code so that I don’t have to use Input.parse_input_event which I’ll try. But I’d still like to know what I’ve done wrong here.

Have you tried

Input.is_action_just_pressed(action_name)

That has the opposite effect. Now holding down the key doesn’t cause the continued forward movement even while the key remains down.

The key taps still work, though.

Parsing the input event marks the event as pressed but you never release it

Oh. Yeah. That is blindingly obvious in retrospect.

:grinning_face:

Thanks.

Now I have two pieces of code that work.

For people who find this, the solution was to add the following after I created the previous InputEvent:

		var event_up : InputEvent = InputEventAction.new()
		
		event_up.action   = action_name
		event_up.pressed  = false
		
		Input.parse_input_event( event_up )