Create a new Key Command via C++ and bind it to the Editor

I’m trying to create custom Input Chord to execute custom functionality. It shows up in the Editor Settings, but it does not trigger. I tried different key combinations without any luck.

.h



#pragma once

#include "CoreMinimal.h"
#include "Framework/Commands/Commands.h"
#include "UICommandList.h"

class BLUEPRINTNODEPREFABS_API FBlueprintNodePrefabCommands : public TCommands<FBlueprintNodePrefabCommands>
{
public:
    FBlueprintNodePrefabCommands();

    virtual void RegisterCommands() override;

    /** List of all the Blueprint Node Prefab commands */
    static TSharedRef<FUICommandList> actionList;

    // Spawn a Popup-Menu that list the NodePrefabs created in a GraphEditor
    TSharedPtr<FUICommandInfo> SpawnNodePrefabList;

    class Callbacks
    {
    public:
        static void SpawnNodePrefabList();

        static bool CanSpawnNodePrefabList();
    };
};



.cpp


#include "BlueprintNodePrefabCommands.h"
#include "UIAction.h"
#include "EditorStyleSet.h"
#include "GlobalEditorCommonCommands.h"

#define LOCTEXT_NAMESPACE "BlueprintNodePrefabCommands"

TSharedRef<FUICommandList> FBlueprintNodePrefabCommands::actionList(new FUICommandList());

FBlueprintNodePrefabCommands::FBlueprintNodePrefabCommands()
    : TCommands<FBlueprintNodePrefabCommands>(
    TEXT("NodePrefabs"), // Context name for fast lookup
    LOCTEXT("NodePrefabs", "Blueprint Node Prefabs"), // Localized context name for displaying
    NAME_None,     // No parent context
    FEditorStyle::GetStyleSetName()) // Icon Style Set
{

}

void FBlueprintNodePrefabCommands::RegisterCommands()
{
    UI_COMMAND(SpawnNodePrefabList, "Spawn Node Prefab List", "Opens a list with Blueprint Node Prefabs to select from", EUserInterfaceActionType::Button, FInputChord(EKeys::RightMouseButton, true, false, false, false));
    actionList->MapAction(SpawnNodePrefabList, FExecuteAction::CreateStatic(&FBlueprintNodePrefabCommands::Callbacks::SpawnNodePrefabList), FCanExecuteAction::CreateStatic(&FBlueprintNodePrefabCommands::Callbacks::CanSpawnNodePrefabList));

}

void FBlueprintNodePrefabCommands::Callbacks::SpawnNodePrefabList()
{
    GEngine->AddOnScreenDebugMessage(INDEX_NONE, 4.f, FColor::Red, FString(TEXT("SpawnNodePrefabList")), true);
    UE_LOG(LogTemp, Error, TEXT("SpawnNodePrefabList"));
}

bool FBlueprintNodePrefabCommands::Callbacks::CanSpawnNodePrefabList()
{
    return true;
}



#undef LOCTEXT_NAMESPACE



module


    //~ IModuleInterface interface
    virtual void StartupModule() override
    {
        FBlueprintNodePrefabCommands::Register();
    }


    virtual void ShutdownModule() override
    {
        FBlueprintNodePrefabCommands::Unregister();
    }


Input seems to be routed through FSlateApplication::ProcessKeyDownEvent. In there the input seems to get routed through the focused widgets. In case the widgets did not handle the Event, there is FSlateApplication::UnhandledKeyDownEventHandler that takes over. This is bound to FMainFrameActionCallbacks::OnUnhandledKeyDownEvent which routes the Key Event trough the MainFrame bindings (SaveAll, …).

So yea, seems it is never ever called cause the engine does not consider my binding when routing the input.

In the end I want the input only to be considered by a SPanelWidget, but widgets do not seem to have a CommandList I can add the commands to.

So how to do it?

ok, managed to register it to the MainFrame and triggers :rolleyes:


void FBlueprintNodePrefabCommands::RegisterCommands()
{
    UI_COMMAND(SpawnNodePrefabList, "Spawn Node Prefab List", "Opens a list with Blueprint Node Prefabs to select from", EUserInterfaceActionType::Button, FInputChord(EKeys::RightMouseButton, true, false, false, false));
    actionList->MapAction(SpawnNodePrefabList, FExecuteAction::CreateStatic(&FBlueprintNodePrefabCommands::Callbacks::SpawnNodePrefabList), FCanExecuteAction::CreateStatic(&FBlueprintNodePrefabCommands::Callbacks::CanSpawnNodePrefabList));

    IMainFrameModule& mainFrame = FModuleManager::Get().LoadModuleChecked<IMainFrameModule>("MainFrame");
    mainFrame.GetMainFrameCommandBindings()->Append(actionList);
}

How to register the command now to SGraphPanel?

3 Likes

Im interested in this too.
I have been trying to wrangle my way into the Graph Editor so I can add a custom UI_COMMAND to the right-click context menu.

I noticed that there is a list of InputPreProcessor that gets the change on the input before it is passed to slate. I make use of that and check if the window below the cursor is a GraphEditor.


bool FSlateApplication::RegisterInputPreProcessor(TSharedPtr<IInputProcessor> InputProcessor, const int32 Index /*= INDEX_NONE*/)
void FSlateApplication::UnregisterInputPreProcessor(TSharedPtr<IInputProcessor> InputProcessor)