Annoying bugs with UMG focus (with Is Focusable? on all widgets false)

There are two annoying bugs I am having associated with UMG:

Focusing TextEdit Input sometimes stops character movement
When I press Enter, I focus my chat window TextEdit input control. If I am just moving with WASD, I can focus the control and it doesn’t interrupt my W key from running me forward (this is as InputModeGameAndUI). I have a mouselook feature, where the only way to get it to work properly was to set InputModeGameOnly on RightMouseDown and then revert back to InputModeGameAndUI on RightMouseUp. If I mouselook at all, pressing Enter to focus chat will stop my character dead in its tracks. It stops processing the W key which is down. I’ve thought of a hack in Tick that would poll if W is down and apply movement, but really don’t want to go that route.

Tab and Arrow Keys
I am unable to bind Tab and Arrow Keys in my game, as UMG uses them to steal focus. If I use these keys to run, and press Enter I have the stop dead in tracks bug mentioned above. But then pressing Enter again to lose focus on chat and pressing Up key starts cycling through other TextEdit Widgets on the screen.

I have set “Is Focusable?” to False on every Widget. Things like TextEdit do not have this property, and still steal focus. I have set other properties, such as not drawing the focus dashed borders around selected widgets.

In my tab binding, I tried setting InputMode to focus a nullptr Widget, but it didn’t work as I’d hoped. I read about bEnableKeyboardNavigation or something, and am considering patching the engine to always return false if I have a global setting to disable UI navigation.

Should future versions of the engine have a global runtime setting that will completely disable UMG keyboard navigation (tab, arrow keys)?

1 Like

Movement should always be interrupted if you focus a text edit widget. It’s going to eat all the text keyboard keys until you’ve shifted focus elsewhere. That’s the behavior I would expect on any game.

As for the ‘default navigation’ rules, you can override the behavior by providing a new navigation config.

FSlateApplication::Get().SetNavigationConfig( FNavigationConfig&& Config );

Though it looks like we don’t give you the option to disable Tab for Next/Shift+Tab for Previous. Will make a note to fix that for 4.12.

To get around it now - You could pre-process the input, by registering a FSlateApplication::Get().SetInputPreProcessor(), you can use that to access any key before slate looks at it and do something else with it and prevent further handling of the key if you wish.

Thanks I will look into those two APIs. I hope you do address the Tab in SetNavigationConfig for 4.12, shouldn’t be too big to patch I’d imagine.

As far as movement being interrupted when text widget is focused, I can inform you it does not, it has the inconsistency I mentioned. A lot of games have weird UI quirks though. I know in EverQuest if you run and press / you’ll start autorunning.


Here is code for anyone else that may run into this issue. It works for me in 4.11.0 and doesn’t seem to have broken any of my functionality.

In the Editor, Create New C++ Class -> None, FTabInputProcessor

FTabInputProcessor.h


#pragma once

#include "IInputProcessor.h"

/**
 * 
 */
class ***YOURGAME***_API FTabInputProcessor : virtual public IInputProcessor
{
public:
	FTabInputProcessor();
	virtual ~FTabInputProcessor();

	virtual void Tick(const float DeltaTime, FSlateApplication& SlateApp, TSharedRef<ICursor> Cursor) override;

	virtual bool HandleKeyDownEvent(FSlateApplication& SlateApp, const FKeyEvent& InKeyEvent) override; 
	virtual bool HandleKeyUpEvent(FSlateApplication& SlateApp, const FKeyEvent& InKeyEvent) override; 
	virtual bool HandleAnalogInputEvent(FSlateApplication& SlateApp, const FAnalogInputEvent& InAnalogInputEvent) override; 
	virtual bool HandleMouseMoveEvent(FSlateApplication &, const FPointerEvent &) override;
};

FTabInputProcessor.cpp


#include "***YOURGAME***.h"
#include "FTabInputProcessor.h"
 
FTabInputProcessor::FTabInputProcessor()
{
}

FTabInputProcessor::~FTabInputProcessor()
{
}

void FTabInputProcessor::Tick(const float DeltaTime, FSlateApplication& SlateApp, TSharedRef<ICursor> Cursor)
{
}

bool FTabInputProcessor::HandleKeyDownEvent(FSlateApplication& SlateApp, const FKeyEvent& InKeyEvent)
{
	if (InKeyEvent.GetKey() == EKeys::Tab)
	{
		// pre-process Tab key down
		return true;
	}

	return false;
}

bool FTabInputProcessor::HandleKeyUpEvent(FSlateApplication& SlateApp, const FKeyEvent& InKeyEvent)
{ 
	if (InKeyEvent.GetKey() == EKeys::Tab)
	{
		// pre-process Tab key up
		return true;
	}

	return false;
}

bool FTabInputProcessor::HandleAnalogInputEvent(FSlateApplication& SlateApp, const FAnalogInputEvent& InAnalogInputEvent)
{
	return false;
}

bool FTabInputProcessor::HandleMouseMoveEvent(FSlateApplication &, const FPointerEvent &)
{
	return false;
}

AYOURGAMEPlayerController::BeginPlay(): (#include “FTabInputProcessor.h”)


FNavigationConfig Navigation; 
Navigation.Down.Empty();
Navigation.Up.Empty();
Navigation.Left.Empty();
Navigation.Right.Empty();

FSlateApplication::Get().SetNavigationConfig(std::move(Navigation));

TSharedPtr<FTabInputProcessor> TabInput(new FTabInputProcessor());
FSlateApplication::Get().SetInputPreProcessor(true, TabInput);

Update: in more recent UE versions, you just have to add this to your PlayerController’s BeginPlay:

void AMyPlayerController::BeginPlay()
{
	Super::BeginPlay();

	if (IsLocalPlayerController())
	{
		TSharedRef<FNavigationConfig> Navigation = MakeShared<FNavigationConfig>();
		Navigation->bKeyNavigation = false;
		Navigation->bTabNavigation = false;
		Navigation->bAnalogNavigation = false;
		FSlateApplication::Get().SetNavigationConfig(Navigation);
	}
}

No need to create a new input processor.

10 Likes

How do you actually add this if you primarily work in Blueprints? (C++ novice)

2 Likes

Not possible afaik, for my solution you need C++.

Ever played Lineage-2 ?
you can move and type in chat window at the same time.

in 4.25 (maybe in later versions too:

       TSharedPtr<C_InputProcessor> InputProcessor;  
        ........
	if (!InputProcessor.IsValid()) {
		InputProcessor = MakeShareable(new C_InputProcessor());
		FSlateApplication::Get().RegisterInputPreProcessor(InputProcessor);
	}

derive class from IInputProcessor:
class PROJECT_API C_InputProcessor: public IInputProcessor, public TSharedFromThis<C_InputProcessor> { ... }
then override necessary functions from IInputProcessor

best solution I found:

Has anyone found a way to do this in Blueprints?

Notably, this disables things such as pressing tab to get to the next field in, for example, a login screen. A better solution may be to make UFUNCTIONs to turn navigation on/off from blueprints.

If you tried implementing this and it is giving you errors, try

Including
include “Framework/Application/NavigationConfig.h”

And

inside the
“projname”.build.cs
make sure you have
PrivateDependencyModuleNames.AddRange(new string { “Slate”, “SlateCore” });
(in my case I actually found this commented out in the file and all I had to do was uncomment it out)

This made the code work (im on 5.2)

2 Likes