Hold Inputs with CommonUI and Enhanced Input

Hey all,

I am trying to set up some buttons (normal Common Buttons and Bound Action Buttons) to support hold inputs.
If I just put a Common Button in any of my menus and enable Requires Hold, clicking and holding on it does indeed make the progress bar go up. This never works though when the button has an Enhanced Input Action assigned to it and I am trying to trigger it with its assigned input, only through clicking.

Looking at the source code, I feel like the automatic handling of hold inputs is only supported with the legacy input system:

void UCommonButtonBase::BindTriggeringInputActionToClick()
{
	if (CommonUI::IsEnhancedInputSupportEnabled() && TriggeringEnhancedInputAction)
	{
		FBindUIActionArgs BindArgs(TriggeringEnhancedInputAction, false, FSimpleDelegate::CreateUObject(this, &UCommonButtonBase::HandleTriggeringActionCommited));
		BindArgs.OnHoldActionProgressed.BindUObject(this, &UCommonButtonBase::NativeOnActionProgress);
		BindArgs.bIsPersistent = bIsPersistentBinding;

		BindArgs.InputMode = InputModeOverride;

		TriggeringBindingHandle = RegisterUIActionBinding(BindArgs);

		return;
	}

	if (TriggeringInputAction.IsNull() || !TriggeredInputAction.IsNull())
	{
		return;
	}

	if (!TriggeringBindingHandle.IsValid())
	{
		FBindUIActionArgs BindArgs(TriggeringInputAction, false, FSimpleDelegate::CreateUObject(this, &UCommonButtonBase::HandleTriggeringActionCommited));
		BindArgs.OnHoldActionProgressed.BindUObject(this, &UCommonButtonBase::NativeOnActionProgress);
		BindArgs.OnHoldActionPressed.BindUObject(this, &UCommonButtonBase::NativeOnPressed);
		BindArgs.OnHoldActionReleased.BindUObject(this, &UCommonButtonBase::NativeOnReleased);
		BindArgs.bIsPersistent = bIsPersistentBinding;
		BindArgs.bForceHold = GetConvertInputActionToHold();

		BindArgs.InputMode = InputModeOverride;
		
		TriggeringBindingHandle = RegisterUIActionBinding(BindArgs);
	}
}

Has anyone ever managed to figure this out?

1 Like

I just found how to do it.

In FActionRouterBindingCollection::ProcessHoldInput we can see that it need HoldMappings on Bindings.

We can see that FActionRouterBindingCollection::ProcessNormalInput just below support enhanced input. I didn’t found a way to override ProcessHoldInput.

So i just insert my own HoldMapping.

In the OnInputMethodChanged of your UCommonButtonBase child put this :

// Add hold support for enhanced input
if (CommonUI::IsEnhancedInputSupportEnabled() && bRequiresHold && HoldTime > 0)
{
	for (const FUIActionBindingHandle& BindingHandle : GetActionBindings())
	{
		if (TSharedPtr<FUIActionBinding> Binding = FUIActionBinding::FindBinding(BindingHandle); Binding.IsValid() && Binding->InputAction.IsValid())
		{
			if (Binding->InputAction.IsValid())
			{
				if (const UInputAction* InputAction = Binding->InputAction.Get())
				{
					Binding->HoldMappings.Empty();
					
					TArray<FKey> InputActionKeys;
					CommonUI::GetEnhancedInputActionKeys(GetOwningLocalPlayer(), InputAction, InputActionKeys);
					for (const FKey& InputActionKey : InputActionKeys)
					{
						if (!InputActionKey.IsValid())
							return;
						
						const FUIActionKeyMapping KeyMapping(InputActionKey, HoldTime, HoldRollbackTime);
						Binding->HoldMappings.Add(KeyMapping);
					}
				}
			}
		}
	}

I did here because i need mapping context to be set to found every key bound to input action.

You need to add a Hold trigger on your InputAction (I didn’t search why) but value in there are not used. HoldData on your button instead is used (could be changed by overriding UpdateHoldData).

You also need to override NativeOnActionProgress by adding:

CurrentHoldTime = HeldPercent * HoldTime;

To actually have your function call after completion of holding.

1 Like

Hey @Batice77,
It seems that the CommonUI hold issues for Enhanced Input Actions have been resolved in 5.5.
The Hold Pressed and Released events already have bindings in place.