Simulate button press on gamepad

Godot Version

v4.4.1.stable.mono.official [49a5bc7b6]

Question

	public override void _Input(InputEvent @event)
	{
		if (@event.IsActionPressed("Confirm"))
		{
			var focused = GetViewport().GuiGetFocusOwner();
			if (focused is Button button)
			{
				button.EmitSignal(Button.SignalName.Pressed);
			}
		}
	}

Confirm is an action tied to gamepad button. There is no need to tie it to keyboard, since if you want to press on a button without mouse you can use Enter, this is enforced on OS level and if you try to add your own Enter action, you will get double presses.

This method works, meaning if I press the key on the gamepad the button gets pressed and proper method fires. The issue is that the button doesn’t react on the user interace level - it remains visually static. When you use Enter or mouse, the button is visually pressed.

And here is the question - how to simulate the button getting pressed when you only have access to gamepad (so only to actions).

What I’ve done in my project is slightly different; I want both mouse and gamepad controls to work, so what I do is hook the buttons up with handler functions I can signal, and then (if the gamepad button is pressed) directly call the same function that clicking with the mouse would have called.

This does mean I have something that looks like:

    # Button pressed...
    var focused = GetViewport.GuiGetFocusOwner()
    match focused.name:
        "NewGame":  _handle_new_game()
        "Continue": _handle_continue()
        "Options":  _handle_options()
        "Quit":     _handle_quit()
1 Like

I do have all events registered so it works for mouse and keyboard too, like:

exitButton.Pressed += OnExitButtonPressed;

The issue is that you can’t click on a button with a gamepad. I’m basically calling assigned methods (like OnExitButtonPressed) without clicking on the button. And I need to figure out how to fool the engine into thinking I’m clicking on the buttons without clicking on them.

I will try to do it your way and see if it works.

A focused Button will react to an ui_accept input action so you could use that input action and add the gamepad button to the event list of that action (you’ll need to enable Show built-in actions in the Input Map panel) You don’t need any code in this case.

If you still want to use another input action then you’ll need to fake it like:

func _unhandled_input(event: InputEvent) -> void:
	if event.is_action_pressed(&"test_action"):
		button.toggle_mode = true
		button.set_pressed_no_signal(true)
		button.pressed.emit()
		await get_tree().create_timer(0.2).timeout
		button.set_pressed_no_signal(false)
		button.toggle_mode = false

If the button can only be triggered by an specific input action then you could use the BaseButton.shortcut instead with an InputEventAction. The BaseButton class has built-in BaseButton.shortcut_feedback

1 Like

I have figured it out a few hours ago and wanted to post solution, but I will mark your post as solution since it essentially explains the issue. I was 100% sure that ui_accept etc are hardcoded actions that cannot be edited. The confusion happened because:

  • I have watched some tutorials before, and they were saying to use your own actions instead of built-in ones (which makes sense depending on the context)
  • While searching for solution to my problem I have found a post saying that you should create mouse input events as you press on the gamepad. But to me it sounded quite absurd so I’ve kept digging.