Improved Keyboard/Gamepad Input & Widget Focus Handling for UMG Menus

@NickDarnell hey, this thread is now more than 2 years old and I didn’t see any improvements in the way the focus is handled.
Did you planned to push something on this or should we stick with custom improvments?
I mainly think about the “onFocus” “onUnfocus” that are pretty easy to push without any side effects but it will helps us a lot.
Having to build the engine just to fix this module is not user friendly.
I hope you can do somehting on this!
thanks,

Something that Just Worked with both keyboard navigation and gamepad navigation would be swell!

Manually wiring up all the navigation graphs and navigation events for gamepad and keyboard and mouse is quite the chore, and so easily breaks when layouts move around :frowning:

I think this is the best suggestion in order to “workaround” this UMG limitation. I do that and actually it simply works like a charm. I don’t suggest to edit the engine things. Through this solution we can have a better behaviour for hover\focus considering the both things as the Same. Using a custom event dispatcher with e custom button. Thanks

Thanks for all your answers! It is really sad to see that even with UE5 we’re forced to such workarounds.

I will also try out these, links.

We are roughly 5 years on since the OP and it looks like none of the issues have been addressed.
I’m working on a small project and recently started trying to put some UI in, and these focus issues are incredibly annoying.

Particularly the “Set Focus” function called on a widget seems to mark the widget as focused enough to trigger the “On Added to Focus Path” event, but when I press the enter key which typically activates the button it doesn’t work until I use the arrow keys or d-pad to navigate to a nearby button and back again, once it has been re-focused in this method the enter key magically starts working again.

There also appears to be issues when pausing the game or attempting to use “Set Input Mode”, many options that look like they should work simply don’t.

1 Like

You can make your own button in c++, based on UButton. Here’s simpl one I use, it becomes Hovered, when it’s in focus, and becomes in focus when it’s hovered:

h:

UCLASS()
class SCENARIOSYSTEM_API UGoodButton : public UButton
{
	GENERATED_BODY()
	
public:
	FButtonStyle FocusedButtonStyle;
protected:
	virtual TSharedRef<SWidget> RebuildWidget() override;


	/** Handle the actual click event from slate and forward it on */
	FReply SlateHandleClicked_Good();
	void SlateHandlePressed_Good();
	void SlateHandleReleased_Good();
	void SlateHandleHovered_Good();
	void SlateHandleUnhovered_Good();


	void OnFocusChange(const FFocusEvent& FocusEvent, const FWeakWidgetPath& WeakWidgetPath, const TSharedPtr<SWidget>& Widget,
		const FWidgetPath& WidgetPath, const TSharedPtr<SWidget>& MyNewWidget);
};

and cpp:

#include "UI/GoodButton.h"
#include "Core/RQ_GameMode.h"
#include "Kismet/GameplayStatics.h"
#include "Components/ButtonSlot.h"

TSharedRef<SWidget> UGoodButton::RebuildWidget()
{
	MyButton = SNew(SButton)
		.OnClicked(BIND_UOBJECT_DELEGATE(FOnClicked, SlateHandleClicked_Good))
		.OnPressed(BIND_UOBJECT_DELEGATE(FSimpleDelegate, SlateHandlePressed_Good))
		.OnReleased(BIND_UOBJECT_DELEGATE(FSimpleDelegate, SlateHandleReleased_Good))
		.OnHovered_UObject(this, &ThisClass::SlateHandleHovered_Good)
		.OnUnhovered_UObject(this, &ThisClass::SlateHandleUnhovered_Good)
		.ButtonStyle(&WidgetStyle)
		.ClickMethod(ClickMethod)
		.TouchMethod(TouchMethod)
		.PressMethod(PressMethod)
		.IsFocusable(IsFocusable)
		;

	if (GetChildrenCount() > 0)
	{
		Cast<UButtonSlot>(GetContentSlot())->BuildSlot(MyButton.ToSharedRef());
	}


	FSlateApplication& SlateApp = FSlateApplication::Get();

	SlateApp.OnFocusChanging().AddUObject(this, &UGoodButton::OnFocusChange);

	return MyButton.ToSharedRef();
}


FReply UGoodButton::SlateHandleClicked_Good()
{


	OnClicked.Broadcast();

	return FReply::Handled();
}

void UGoodButton::SlateHandlePressed_Good()
{
	OnPressed.Broadcast();
}

void UGoodButton::SlateHandleReleased_Good()
{
	OnReleased.Broadcast();
}

void UGoodButton::SlateHandleHovered_Good()
{
	this->SetFocus();
	OnHovered.Broadcast();
}

void UGoodButton::SlateHandleUnhovered_Good()
{
	OnUnhovered.Broadcast();
}

void UGoodButton::OnFocusChange(const FFocusEvent& FocusEvent, const FWeakWidgetPath& WeakWidgetPath, const TSharedPtr<SWidget>& Widget, const FWidgetPath& WidgetPath, const TSharedPtr<SWidget>& MyNewWidget)
{

	if (MyButton.IsValid())
	{
		
		ARQ_GameMode* GameMode = Cast<ARQ_GameMode>(UGameplayStatics::GetGameMode(this->GetOwningPlayer()));
		if (GameMode) {
			if (MyNewWidget == MyButton) {  //GAIN FOCUS

				GameMode->FocusedWidget = this;
				OnHovered.Broadcast();
				FocusedButtonStyle = WidgetStyle;
				FocusedButtonStyle.SetNormal(WidgetStyle.Hovered);
				MyButton->SetButtonStyle(&FocusedButtonStyle);
			}
			else if (Widget == MyButton) {

				if (FocusEvent.GetCause() == EFocusCause::Mouse) {  //do not lose focus to mouse
					this->SetFocus();
				}
				else {
					if (GameMode->FocusedWidget == this) {
						GameMode->FocusedWidget = nullptr;
						OnUnhovered.Broadcast();
					}
					MyButton->SetButtonStyle(&WidgetStyle);
				}
			}
		}
	}
}

I am having that exact problem in UE 5.3.2 right now.

  1. Focusing widgets doesn’t work. Having the same issue. Great job, Epic, as usual.
2 Likes