New Input system handles Submit on release rather than Press

After digging around in code I discovered this:

New Input System:

// Process submit and cancel events.
if (!usedSelectionChange && eventSystem.currentSelectedGameObject != null)
{
    // NOTE: Whereas we use callbacks for the other actions, we rely on WasReleasedThisFrame() for
    //       submit and cancel. This makes their behavior consistent with pointer click behavior where
    //       a click will register on button *up*. This nuance in behavior becomes important in
    //       combination with action enable/disable changes in response to submit or cancel. If we
    //       react to button *down* instead of *up*, the button *up* will come in *after* we have
    //       applied the state change.
    var submitAction = m_SubmitAction?.action;
    var cancelAction = m_CancelAction?.action;

    var data = GetBaseEventData();
    if (cancelAction != null && cancelAction.WasReleasedThisFrame())
        ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, data, ExecuteEvents.cancelHandler);
    if (!data.used && submitAction != null && submitAction.WasReleasedThisFrame())
        ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, data, ExecuteEvents.submitHandler);
}

Old Input System:

var data = GetBaseEventData();
if (input.GetButtonDown(m_SubmitButton))
    ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, data, ExecuteEvents.submitHandler);

if (input.GetButtonDown(m_CancelButton))
    ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, data, ExecuteEvents.cancelHandler);
return data.used;

Old input handles the submit on Press, which is what I would expect. And makes it possible to animate a button being pressed before performing an action.

1 Like

ok, bit of a hack, but this seems to work:

using the IUpdateSelectedHandler interface, can process the submit event manually

void IUpdateSelectedHandler.OnUpdateSelected(BaseEventData eventData) {

    if (eventData.used || !EventSystem.current.sendNavigationEvents) {

        return;
    }

    //new input system handles submit on release, we can never animate the button down
    //so, we manually check the submit action and handle ourself

    if (IsActive() && IsInteractable() && eventData.currentInputModule is InputSystemUIInputModule module) {

        var submitAction = module.submit?.action;

        if (submitAction != null && submitAction.WasPressedThisFrame()) {

            //do press animation

            DoStateTransition(SelectionState.Pressed, false);
        }
    }
}
1 Like

Could you explain this one more? Mainly wondering from when to when in the timeline the animation will play given that by triggering “submit” from presses, the button is immediately clicked on press.

For context, we made the conscious choice to move to triggering to release rather than press in order to solve the problem of the release “leaking”. If you click with the mouse, the button will not actually accept the click until you release (over the button). However, submits triggered immediately from presses and thus the release event would go “somewhere else”. In most cases, that doesn’t really matter but was problematic for some cases like rebind UIs. So we ended up settling on making “submit” trigger on release like clicks. But might be we have overlooked something here and this needs more tweaking or a different approach so would like to learn more about your use case.

2 Likes

yeah sorry I should be more clear.
I was overriding the default behaviour on a custom Button class.

basically I wanted “Submit” to be called during the “Press” phase.
I override and play animation only. No click event.
Then start a coroutine listening for submit cancel, then call onClick.

In other words, if you’re holding down the “Enter” key, the button is pressed in. When you release enter key, click is invoked.

I solved by using IUpdateSelectedHandler. So I can play that press animation.
I then don’t need to override any button methods, and the regular submit action calls on release.

I also have this problem.

IMO for a mouse click this is the right behavior.
But I currently use a controller for the input. Here it is a strange behavior to activate a button after release and not by press.
Maybe it should be possible to use the interactions property of the action themself, which is selected e.g. as submit or cancel.
Or there should be an option in the Input System UI Input Module how to handle on click.

Thanks.

2 Likes

I agree that triggering the event on press would be the typical expected behaviour for a console/controller-driven game. It’s true that this is inconsistent with how mouse clicks work, but I think making a distinction in standards here makes sense because button presses in menus aren’t usually overloaded with other functions (e.g. initiating a drag with a cursor) that could make the initial input ambiguous or prone to error.

The “leaking” issue is a real concern, and may create additional complexity for application programmers in situations like returning from pause menus as well as rebinding, but I don’t think trying to prevent this situation at the expense of usability for end users is a good economy. An option that controls when the event is triggered would be very welcome.

This behavior is not typical for keyboard and gamepad input in games, and has a very negative impact on menu-driven games in particular. Navigating menus becomes less responsive, so the entire game feels sluggish. I’ve held off on updating InputSystem in my roleplaying game because the user experience is noticeably worse in the new version.

I would assume that putting the triggering on “down” state isnt the way to go. Even if someone is using a controller, the ui behaviour wouldnt be wrong at triggering in the “up” state.

However, the real issue i found was, that the missing access to the submits “down” state makes ui animations impossible.
In my opinion there are 3 important phases while “submitting”

  1. hover over || select (OnSelect)
  2. mouse click || button down (currently missing on controller)
  3. release mouse over button || button up (OnSubmit)

giving access to those 3 points, might solve any issue due to the fact, that one could implement any logic in any phase.
Pointers already have an exhaustive access to those things, while controller or keypresses are missing some level of complexity.

@Rene-Damm Has any progress been made regarding the customization of the Event System behavior?
I can’t find a built-in option to switch from UI press button “on release” to “on click”, although I may have overlooked something.