To handle exceptions in your input system for the key used to stop PIE, you can use the FInputProcessor::ProcessKeyEventArgs() function. This function is called whenever a key is pressed or released, and allows you to handle the input event before it is processed by the engine.
Here’s an example that should help you get started
class FMyInputProcessor : public FInputProcessor
{
public:
virtual bool ProcessKeyEventArgs(FKey Key, EInputEvent EventType, float AmountDepressed, bool bGamepad) override
{
// Check if the key is the one used to stop PIE
if (Key == EKeys::Escape && EventType == IE_Pressed)
{
// Do something here to handle the exception
return true; // return true to indicate that the input event has been handled
}
// If the key is not the one used to stop PIE, let the engine handle it
return false;
}
};
// Create an instance of the input processor and register it with the input system
TSharedPtr<FMyInputProcessor> MyInputProcessor = MakeShared<FMyInputProcessor>();
FSlateApplication::Get().RegisterInputPreProcessor(MyInputProcessor);
Here, we create a custom input processor that overrides the ProcessKeyEventArgs() function.
We check if the key pressed is the one used to stop PIE (Escape key), and if it is, we handle the exception and return true to indicate that the input event has been handled.
If the key is not the one used to stop PIE, we return false to let the engine handle it.
Finally, we create an instance of our input processor and register it with the input system using FSlateApplication::Get().RegisterInputPreProcessor().
This will ensure that our input processor is called before the engine processes any input events.
Thanks for the detailed answer . The input preprocessor is a great place to implement this. The part I was stuck on however is pulling the key used to stop PIE from the editor settings, since it’s for a plugin and people can set that key to anything. Is there a library / setting manager class to pull the key from, or do I need to parse some ini through GConfig? That is what I tried to do in my first post, the “numlock” just being a dummy in an attempt to find the context / command for “stop pie” but got no results.
you can use the UEditorPerProjectUserSettings class. This class provides access to the per-project user settings in the editor, including the key binding for stopping PIE. Here’s an example of how you can use it:
#include "Editor/EditorPerProjectUserSettings.h"
// Get the per-project user settings
UEditorPerProjectUserSettings* PerProjUserSettings = GetMutableDefault<UEditorPerProjectUserSettings>();
// Get the key binding for stopping PIE
const FInputChord& StopPIEChord = PerProjUserSettings->PlayWorldStop;
// Use the key binding as needed...
The StopPIEChord variable will contain the key binding for stopping PIE as set by the user in the editor settings. You can then use this information in your input preprocessor to make the necessary exceptions.
I just checked, UE5.1.1 UEditorPerProjectUserSettings does not contain “PlayWorldStop” and does not provide access to the keybindings? My scanners don’t find “PlayWorldStop” in engine source.
It works, it handles the input, but it was a huge facepalm moment because I realized the handled input will now not reach the editor itself. Got to rethink this.
Where I was handling all input, I now made an workaround to return unhandled if the key shares an input chord with a specific editor action. It’s not ideal but this is a very specific case where an input preprocessor also turned out not to be ideal.
#if WITH_EDITOR
// We can't "handle" the situation there as the input would not reach the editor.
auto CanDoInEditor = [&InInputChord](const FName& ContextX, const FName& CommandX) -> bool {
TSharedPtr<FUICommandInfo> InfoX = FInputBindingManager::Get().FindCommandInContext(ContextX, CommandX);
if (InfoX.IsValid() && InfoX->HasActiveChord(InInputChord)) {
CUR_LOG(LogCorePlugin, Verbose, "Processing input which shares an input chord with a specific editor action. Aborting and must return unhandled. UI command: %s, in context: %s", *CommandX.ToString(), *ContextX.ToString());
return false;
}
return true;
};
if (!CanDoInEditor(TEXT("PlayWorld"), TEXT("StopPlaySession"))) {
return FReply::Unhandled();
}
#endif // WITH_EDITOR
I think that we are missing engine functionality here, it would be nice to be able to switch between editor commands and in-game input bindings on a single key so that they don’t conflict. Right now if you handle all input on a widget you will lose all control over the editor (in my case the button to stop PIE). For this reason I’m moving the post to a feature request section.