[UE5.1]Common UI How to set button hovered state when navigating with the keyboard?

I have a Common UI menu. Everything works great except for one thing, keyboard navigation. With the controller, the hovered state is set on the current button automatically. With the keyboard, it seems to activate the mouse and only the mouse can set the hovered state. Is there a way to get the keyboard navigation to set the hovered state? This use a different color and animation when in the hovered state. It’d also have to set the button under the cursor as not hovered.

image

In the image above, you only see the focused button with a blue rectangle around it. Thing is I removed that rectangle because the button already changes color with the mouse and controller. Like this:

image

So is there a way to make keyboard navigation look the same as with mouse or controller (as in the image above)?

Ok, so “On Added to Focus Path” seems to tell me when a button gets focus. And “On Removed from Focus Path” will tell me when a button loses focus. But now what happens is that the keyboard will have a certain focus and the mouse can highlight a different button. So two buttons are highlighted at the same time.

I guess I could keep track of the current hovered/focused button and dynamically highlight them or not. Wish there was an easier way.

you need to add the OnHovered and OnUnhovered Events, too… and link them to the same nodechain as the OnAddedToFocusPath and OnRemovedFromFocusPath…

while on is for the focus… the other is for the bounding interaction…

but yes… all of this is not working right, as it should…

2 Likes

The hovered events work fine for mouse and controller, but they don’t activate for keyboard. That’s the problem. So I’m using the Focus Path events for keyboard. But now I have to manually track which button is active.

yes… and you need both…
the fovus path to react for keyboard…
and the hover for mouse…

I don’t understand why keyboard and controller don’t work the same. Seems like a missing feature.

cause the keyboard and mouse control is legacy from UserWidget… the gamepad is added on top by CommonUI…

again, the system is great… but needs more work, more often updates and better documentation…
I think, making the plugin external… like meta human… to update it f.e. weekly… instead of just with every engine version… would be more precise in problem fixes…

I´ve written a small Subsystem to handle the Selections…

The Header file:

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Components/Widget.h"
#include "Subsystems/GameInstanceSubsystem.h"
#include "CommonUI_HelperSubsystem.generated.h"

/**
 * A helper class to provide Widget informations to CommonUI Navigation.
 */
UCLASS(DisplayName="CommonUI_Helper")
class LOH_THETAVERN_API UCommonUI_HelperSubsystem : public UGameInstanceSubsystem
{
	GENERATED_BODY()

private:
	UPROPERTY()
	TObjectPtr<UWidget> LastSelected;
	UPROPERTY()
	TObjectPtr<UWidget> CurrentSelected;

public:
	UFUNCTION(BlueprintCallable, Category="CommonUI_Helper")
	void SelectNewWidget(UWidget* NewSelectedWidget, bool bOverrideLastSelected, UWidget*& NewCurrent, UWidget*& OldCurrent);
	UFUNCTION(BlueprintCallable, BlueprintPure=true, Category="CommonUI_Helper")
	void GetSelections(UWidget*& Last, UWidget*& Current);
	UFUNCTION(BlueprintCallable, Category="CommonUI_Helper")
	void InvalidateSelections();
};

The Cpp:

// Fill out your copyright notice in the Description page of Project Settings.


#include "CommonUI/CommonUI_HelperSubsystem.h"

void UCommonUI_HelperSubsystem::SelectNewWidget(UWidget* NewSelectedWidget, const bool bOverrideLastSelected, UWidget*& NewCurrent, UWidget*& OldCurrent)
{
	OldCurrent = CurrentSelected;
	CurrentSelected = NewSelectedWidget;
	if(bOverrideLastSelected)
	{
		LastSelected = NewSelectedWidget;
	}
	NewCurrent = CurrentSelected;
}

void UCommonUI_HelperSubsystem::GetSelections(UWidget*& Last, UWidget*& Current)
{
	Last = LastSelected;
	Current = CurrentSelected;
}

void UCommonUI_HelperSubsystem::InvalidateSelections()
{
	LastSelected = nullptr;
	CurrentSelected = nullptr;
}

And this is my code…
The interface calls are for buttons that inherit from this Common Button base…

Works now and never selects two buttons at once…

3 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.