How to navigate between UMG widgets with Tab key

I have two EditableTextBox widgets on a UMG widget blueprint. I want the tab key to be able to navigate between them, however it doesn’t seem like the is any event that I can bind to to catch the key event. OnKeyChar on the main UMG blueprint graph doesn’t fire presumably because the text box is marking the event as handled.

Sort of figured this out. I extended the SEditableTextBox to override the OnKeyDown method and derived from UEditableTextBox to create the SEditableTextBox in the RebuildWidget. Then I added a method to add the event in blueprint to the event added to the custom SEditableTextBox.

Header

#pragma once

#include "UMG.h"
#include "Components/EditableTextBox.h"

#include "MORPGEditableTextBox.generated.h"

UDELEGATE(BlueprintType, Category = Delegate)
DECLARE_DYNAMIC_DELEGATE(FOnKeyDownResponder);

class MORPG_API SMORPGEditableTextBox : public SEditableTextBox
{
public:
	DECLARE_EVENT(SMORPGEditableTextBox, FKeyDownEvent);
	FKeyDownEvent KeyDown;

	virtual FReply OnKeyDown(const FGeometry& MyGeometry, const FKeyboardEvent& InKeyboardEvent) override;
};

/**
 * 
 */
UCLASS()
class MORPG_API UMORPGEditableTextBox : public UEditableTextBox
{
	GENERATED_UCLASS_BODY()

	UFUNCTION(BlueprintCallable, Category = "MORPG|Widget")
	void Focus();

	UFUNCTION(BlueprintCallable, Category = "MORPG|Widget")
	bool IsFocused();

	virtual TSharedRef<SWidget> RebuildWidget() override;

	UFUNCTION(BlueprintCallable, Category = "MORPG|Event")
	void AddOnKeyDownEvent(FOnKeyDownResponder Responder);
};

Implementation

#include "MORPG.h"
#include "MORPGEditableTextBox.h"

FReply SMORPGEditableTextBox::OnKeyDown(const FGeometry & MyGeometry, const FKeyboardEvent & InKeyboardEvent)
{
	auto reply = SEditableTextBox::OnKeyDown(MyGeometry, InKeyboardEvent);

	if (InKeyboardEvent.GetKey() == EKeys::Tab)
	{
		KeyDown.Broadcast();

		return FReply::Handled();
	}

	return reply;
}

UMORPGEditableTextBox::UMORPGEditableTextBox(const class FPostConstructInitializeProperties& PCIP)
	: Super(PCIP)
{
}

bool UMORPGEditableTextBox::IsFocused()
{
	return MyEditableTextBlock->HasKeyboardFocus();
}

void UMORPGEditableTextBox::Focus()
{
	FSlateApplication::Get().SetKeyboardFocus(MyEditableTextBlock.ToSharedRef());
}

TSharedRef<SWidget> UMORPGEditableTextBox::RebuildWidget()
{
	FString FontPath = FPaths::GameContentDir() / Font.FontName.ToString();

	if (!FPaths::FileExists(FontPath))
	{
		FontPath = FPaths::EngineContentDir() / Font.FontName.ToString();
	}

	MyEditableTextBlock = SNew(SMORPGEditableTextBox)
		.Font(FSlateFontInfo(FontPath, Font.Size))
		.ForegroundColor(ForegroundColor)
		.BackgroundColor(BackgroundColor)
		.ReadOnlyForegroundColor(ReadOnlyForegroundColor)
		.MinDesiredWidth(MinimumDesiredWidth)
		.Padding(Padding)
		.IsCaretMovedWhenGainFocus(IsCaretMovedWhenGainFocus)
		.SelectAllTextWhenFocused(SelectAllTextWhenFocused)
		.RevertTextOnEscape(RevertTextOnEscape)
		.ClearKeyboardFocusOnCommit(ClearKeyboardFocusOnCommit)
		.SelectAllTextOnCommit(SelectAllTextOnCommit)
		.OnTextChanged(BIND_UOBJECT_DELEGATE(FOnTextChanged, HandleOnTextChanged))
		.OnTextCommitted(BIND_UOBJECT_DELEGATE(FOnTextCommitted, HandleOnTextCommitted))
		;

	return MyEditableTextBlock.ToSharedRef();
}

void UMORPGEditableTextBox::AddOnKeyDownEvent(FOnKeyDownResponder Responder)
{
	auto textBlock = MyEditableTextBlock.Get();
	((SMORPGEditableTextBox*)textBlock)->KeyDown.AddUFunction(Responder.GetUObject(), Responder.GetFunctionName());
}

Thank you very much for post this!

for me it’s work when in the YourClassOverUEditableTextBox::RebuildWidget() add a part:

.OnKeyDownHandler(BIND_UOBJECT_DELEGATE(FOnKeyDown, OnKeyDown))