Announcement

Collapse
No announcement yet.

Tutorial - How to dynamically bind input using C++

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Tutorial - How to dynamically bind input using C++

    Hi Guys ,

    This week I worked on dynamically binding input keyboard and mouse values based on user's choice in keyboard customization section. Here is how I did it.
    First I created an excel table containing the following columns. I only gave two examples of keyboard actions, you will have as many rows as the number of different action event and key binding you want to have in your game.
    Action DefaultInput Input Category
    Primary Attack MouseLeftButton MouseLeftButton Combat
    Move Forward W W Movement

    Next I created a struct for my datatable in my HUD header class in C++. Make sure to add the following namespace
    "Runtime/Engine/Classes/Engine/DataTable.h" in the header class.

    Code:
    USTRUCT(Blueprintable)
    struct FKeyBoardBindingTable : public FTableRowBase
    {
    	GENERATED_USTRUCT_BODY()
    
    	UPROPERTY(BlueprintReadOnly, Category = "KeyBinding")
    	FString Action;
    
    	UPROPERTY(BlueprintReadOnly, Category = "KeyBinding")
    	FString DefaultInput;
    
    	UPROPERTY(BlueprintReadOnly, Category = "KeyBinding")
    	FString Input;
    
    	UPROPERTY(BlueprintReadOnly, Category = "KeyBinding")
    	FString Category;
    
    };
    Now define your datatable in HUD header -
    Code:
    UDataTable* KeyBoardBindingTable;
    and initialize it the HUD constructor class
    Code:
    static ConstructorHelpers::FObjectFinder<UDataTable> KeyBoardBindingTable_BP(TEXT("DataTable'/Game/DataTables/KeyboardConfig.KeyboardConfig'"));
    	KeyBoardBindingTable = KeyBoardBindingTable_BP.Object;
    I imported this excel as datatable in UE4 , inherited from the struct FKeyBoardBindingTable.

    Then , I created userinterface class for keyboard configuration menu. , deriving from SCompounWidget , and wrote the UI in slate architecture. The UI is simple key customization UI that you can see in any game , when user clicks on an input , it asks you to bind it to a new value , then you have to press a key to bind to it. See below.

    Code:
    BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
    void SKeyConfigUI::Construct(const FArguments& InArgs)
    {
    	
    	GameHUD = InArgs._GameHUD;
    	MenuStyle = &FMenuStyles::Get().GetWidgetStyle<FGlobalStyle>("Global");
    	
    	
    	
    	ChildSlot.Padding(50 , 10)
    		[
    			SNew(SOverlay)
    			+ SOverlay::Slot()
    			.HAlign(HAlign_Fill)
    			.VAlign(VAlign_Fill)
    			.Padding(40)
    			[
    				SNew(SBorder)
    				.ColorAndOpacity(FLinearColor::White)
    				.BorderImage(&MenuStyle->BorderBrush1)
    				.Content()
    				[
    					SNew(SOverlay)
    					+ SOverlay::Slot()
    					.HAlign(HAlign_Fill)
    					.VAlign(VAlign_Fill)
    					[
    						SAssignNew(ParentWidget , SScrollBox)
    						+ SScrollBox::Slot()
    						.HAlign(HAlign_Left)
    						.Padding(40, 80, 0, 0)
    						[
    							SNew(STextBlock)
    							.Text(FText::FromString("KeyBoard Configuration"))
    							.Font(FSlateFontInfo(FPaths::EngineContentDir() / TEXT("Slate/Fonts/jancient.ttf"), 30))
    							.ColorAndOpacity(FLinearColor(0.8, 0.7, 0.3, 1))
    							.ShadowColorAndOpacity(FLinearColor(0.16, 0.06, 0.05, 1))
    
    						]
    						+ SScrollBox::Slot()
    							.HAlign(HAlign_Fill)
    							.Padding(40, 60, 40, 0)
    							[
    								SNew(SHorizontalBox)
    								+ SHorizontalBox::Slot()
    								.HAlign(HAlign_Fill)
    								.VAlign(VAlign_Top)
    								[
    									SAssignNew(GeneralButton, SButton)
    									.ButtonStyle(&MenuStyle->KeyConfigHeaderStyle)
    									.ContentPadding(2)
    									.HAlign(HAlign_Center)
    									.VAlign(VAlign_Top)
    									.Content()
    									[
    										SAssignNew(GeneralText, STextBlock)
    										.Text(FText::FromString("General"))
    										.Font(FSlateFontInfo(FPaths::EngineContentDir() / TEXT("Slate/Fonts/Roboto-Bold.ttf"), 15))
    										.ColorAndOpacity(FLinearColor(0.1, 0.1, 0.03, 1))
    										.ShadowColorAndOpacity(FLinearColor(0.93, 1, 0.6, 1))
    										.ShadowOffset(FVector2D(1, 1))
    
    									]
    									.OnClicked(this, &SKeyConfigUI::InputCaterGoryButonClicked, FString("General"))
    								]
    								+ SHorizontalBox::Slot()
    									.HAlign(HAlign_Fill)
    									.VAlign(VAlign_Top)
    									[
    										SAssignNew(MovementButton, SButton)
    										.ButtonStyle(&MenuStyle->KeyConfigNotSelectedStyle)
    										.ContentPadding(2)
    										.HAlign(HAlign_Center)
    										.VAlign(VAlign_Top)
    										.Content()
    										[
    											SAssignNew(MovementText, STextBlock)
    											.Text(FText::FromString("Movement"))
    											.Font(FSlateFontInfo(FPaths::EngineContentDir() / TEXT("Slate/Fonts/Roboto-Bold.ttf"), 15))
    											.ColorAndOpacity(FLinearColor(0.12, 0.1, 0.03, 1))
    											.ShadowColorAndOpacity(FLinearColor(0.93, 1, 0.6, 1))
    											.ShadowOffset(FVector2D(1, 1))
    										]
    										.OnClicked(this, &SKeyConfigUI::InputCaterGoryButonClicked, FString("Movement"))
    									]
    								+ SHorizontalBox::Slot()
    									.HAlign(HAlign_Fill)
    									.VAlign(VAlign_Top)
    									[
    										SAssignNew(CombatButton, SButton)
    										.ButtonStyle(&MenuStyle->KeyConfigNotSelectedStyle)
    										.ContentPadding(2)
    										.HAlign(HAlign_Center)
    										.VAlign(VAlign_Top)
    										.Content()
    										[
    											SAssignNew(CombatText, STextBlock)
    											.Text(FText::FromString("Combat"))
    											.Font(FSlateFontInfo(FPaths::EngineContentDir() / TEXT("Slate/Fonts/Roboto-Bold.ttf"), 15))
    											.ColorAndOpacity(FLinearColor(0.12, 0.1, 0.03, 1))
    											.ShadowColorAndOpacity(FLinearColor(0.93, 1, 0.6, 1))
    											.ShadowOffset(FVector2D(1, 1))
    										]
    										.OnClicked(this, &SKeyConfigUI::InputCaterGoryButonClicked, FString("Combat"))
    									]
    								+ SHorizontalBox::Slot()
    									.HAlign(HAlign_Fill)
    									.VAlign(VAlign_Top)
    									[
    										SAssignNew(MiscellaneousButton, SButton)
    										.ButtonStyle(&MenuStyle->KeyConfigNotSelectedStyle)
    										.ContentPadding(2)
    										.HAlign(HAlign_Center)
    										.VAlign(VAlign_Top)
    										.Content()
    										[
    											SAssignNew(MiscellaneousText, STextBlock)
    											.Text(FText::FromString("Miscellaneous"))
    											.Font(FSlateFontInfo(FPaths::EngineContentDir() / TEXT("Slate/Fonts/Roboto-Bold.ttf"), 15))
    											.ColorAndOpacity(FLinearColor(0.12, 0.1, 0.03, 1))
    											.ShadowColorAndOpacity(FLinearColor(0.93, 1, 0.6, 1))
    											.ShadowOffset(FVector2D(1, 1))
    										]
    										.OnClicked(this, &SKeyConfigUI::InputCaterGoryButonClicked, FString("Miscellaneous"))
    									]
    							]
    				]
    				+ SOverlay::Slot()
    					.HAlign(HAlign_Fill)
    					.VAlign(VAlign_Fill)
    					.Padding(FMargin(100, 250, 0, 50))
    					[
    						SNew(SScrollBox)
    						+ SScrollBox::Slot()
    						.HAlign(HAlign_Fill)
    						[
    							SAssignNew(KeyBindingWidget, SWidgetSwitcher)
    							+ SWidgetSwitcher::Slot()
    							.HAlign(HAlign_Fill)
    							.VAlign(VAlign_Top)
    							[
    								SAssignNew(GeneralWidget, SScrollBox)
    							]
    							+ SWidgetSwitcher::Slot()
    								.HAlign(HAlign_Fill)
    								.VAlign(VAlign_Top)
    								[
    									SAssignNew(MovementWidget, SScrollBox)
    								]
    							+ SWidgetSwitcher::Slot()
    								.HAlign(HAlign_Fill)
    								.VAlign(VAlign_Top)
    								[
    									SAssignNew(CombatWidget, SScrollBox)
    								]
    							+ SWidgetSwitcher::Slot()
    								.HAlign(HAlign_Fill)
    								.VAlign(VAlign_Top)
    								[
    									SAssignNew(MiscellaneousWidget, SScrollBox)
    								]
    						]
    					]
    				+ SOverlay::Slot()
    					.HAlign(HAlign_Center)
    					.VAlign(VAlign_Bottom)
    					.Padding(10)
    					[
    						SNew(SHorizontalBox)
    						+ SHorizontalBox::Slot()
    						.HAlign(HAlign_Fill)
    						.VAlign(VAlign_Fill)
    						.Padding(10, 0)
    					     
    						[
    							SNew(SButton)
    							.ButtonStyle(&MenuStyle->GeneralButtonStyle1)
    							.ContentPadding(2)
    							.HAlign(HAlign_Fill)
    							.VAlign(VAlign_Fill)
    			     			.Content()
    							[
    								SNew(STextBlock)
    								.Text(FText::FromString("  Cancel  "))
    								.Font(FSlateFontInfo(FPaths::EngineContentDir() / TEXT("Slate/Fonts/Roboto-Bold.ttf"), 15))
    								.ColorAndOpacity(FLinearColor(0.7, 0.6, 0.1, 1))
    							]
    							.OnClicked(this, &SKeyConfigUI::CancelButtonClicked)
    
    						]
    						+ SHorizontalBox::Slot()
    							.HAlign(HAlign_Fill)
    							.VAlign(VAlign_Center)
    							.Padding(10, 0)
    							[
    								SNew(SButton)
    								.ButtonStyle(&MenuStyle->GeneralButtonStyle1)
    								.ContentPadding(2)
    								.HAlign(HAlign_Fill)
    								.VAlign(VAlign_Fill)
    								.Content()
    								[
    									SNew(STextBlock)
    									.Text(FText::FromString("  Save  "))
    									.Font(FSlateFontInfo(FPaths::EngineContentDir() / TEXT("Slate/Fonts/Roboto-Bold.ttf"), 15))
    									.ColorAndOpacity(FLinearColor(0.7, 0.6, 0.1, 1))
    								]
    								.OnClicked(this, &SKeyConfigUI::SaveButtonClicked)
    							]
    						+ SHorizontalBox::Slot()
    							.HAlign(HAlign_Fill)
    							.VAlign(VAlign_Center)
    							.Padding(10, 0)
    							[
    								SNew(SButton)
    								.ButtonStyle(&MenuStyle->GeneralButtonStyle1)
    								.ContentPadding(2)
    								.HAlign(HAlign_Center)
    								.VAlign(VAlign_Center)
    								.Content()
    								[
    									SNew(STextBlock)
    									.Text(FText::FromString("  Reset  "))
    									.Font(FSlateFontInfo(FPaths::EngineContentDir() / TEXT("Slate/Fonts/Roboto-Bold.ttf"), 15))
    									.ColorAndOpacity(FLinearColor(0.7, 0.6, 0.1, 1))
    								]
    								.OnClicked(this, &SKeyConfigUI::ResetButtonClicked)
    							]
    
    					]
    			]
    		]
    			
    		];
    	
    		DrawKeyBindingWidget();
    	
    }
    END_SLATE_FUNCTION_BUILD_OPTIMIZATION
    
    void SKeyConfigUI::DrawKeyBindingWidget()
    {
    	int32 rowindex = 1; 
    	GeneralWidget->ClearChildren();
    	MovementWidget->ClearChildren();
    	CombatWidget->ClearChildren();
    	MiscellaneousWidget->ClearChildren();
    
    	while (true)
    	{
    		FKeyBoardBindingTable* LookUpRow = GameHUD->KeyBoardBindingTable->FindRow<FKeyBoardBindingTable>(FName(*FString::FromInt(rowindex)), TEXT("Look Up"));
    		if (LookUpRow)
    		{
    			if (LookUpRow->Category == "General")
    			{
    				GeneralIndex++;
    				GeneralWidget->AddSlot().HAlign(HAlign_Fill).Padding(10)
    					[
    						DrawKeyBindingWidgetRow(LookUpRow->Action, LookUpRow->Input, LookUpRow->Category, rowindex).ToSharedRef()
    					];
    			}
    				
    			else if (LookUpRow->Category == "Movement")
    			{
    
    				MovementIndex++;
    				MovementWidget->AddSlot().HAlign(HAlign_Fill).Padding(10)
    					[
    						DrawKeyBindingWidgetRow(LookUpRow->Action, LookUpRow->Input, LookUpRow->Category, rowindex).ToSharedRef()
    					];
    			}
    			else if (LookUpRow->Category == "Combat")
    			{
    				CombatIndex++;
    				CombatWidget->AddSlot().HAlign(HAlign_Fill).Padding(10)
    					[
    						DrawKeyBindingWidgetRow(LookUpRow->Action, LookUpRow->Input, LookUpRow->Category, rowindex).ToSharedRef()
    					];
    			}
    			else if (LookUpRow->Category == "Miscellaneous")
    			{
    				MiscellaneousIndex++;
    				MiscellaneousWidget->AddSlot().HAlign(HAlign_Fill).Padding(10)
    					[
    						DrawKeyBindingWidgetRow(LookUpRow->Action, LookUpRow->Input, LookUpRow->Category, rowindex).ToSharedRef()
    					];
    			}
    
    			rowindex++;
    		}
    		else
    		{
    			break;
    		}
    	}
    }
    
    TSharedPtr<class SHorizontalBox> SKeyConfigUI::DrawKeyBindingWidgetRow(FString Action, FString Input, FString Category , int32 Index)
    {
    	return
    		 SNew(SHorizontalBox)
    		+ SHorizontalBox::Slot().HAlign(HAlign_Center).VAlign(VAlign_Center)
    		[
    			SAssignNew(BindingText, STextBlock).Text(FText::FromString(Action))
    			.Font(FSlateFontInfo(FPaths::EngineContentDir() / TEXT("Slate/Fonts/jancient.ttf"), 15))
    			.ColorAndOpacity(FLinearColor(0.8, 0.7, 0.3, 1))
    			.ShadowColorAndOpacity(FLinearColor(0.93, 1, 0.6, 1))
    
    		]
    	+ SHorizontalBox::Slot().HAlign(HAlign_Fill).VAlign(VAlign_Fill)
    		[
    			SAssignNew(BindingButton, SButton).ButtonStyle(&MenuStyle->KeyBindingButtonStyle).HAlign(HAlign_Center).VAlign(VAlign_Center)
    			.Content()
    			[
    				SAssignNew(BindingText, STextBlock).Text(FText::FromString(Input))
    				.Font(FSlateFontInfo(FPaths::EngineContentDir() / TEXT("Slate/Fonts/jancient.ttf"), 15))
    				.ColorAndOpacity(FLinearColor(0.8, 0.7, 0.3, 1))
    				.ShadowColorAndOpacity(FLinearColor(0.93, 1, 0.6, 1))
    			]
    			.OnClicked(this, &SKeyConfigUI::KeyCustomizationButtonClicked, FString(Action), FString(Input) , Index)
    		];
    	
    	
    }
    
    
    FReply SKeyConfigUI::SaveButtonClicked()
    {
    	
    	int32 rowindex;
    	for (rowindex = 1; rowindex < TempIndex.Num(); rowindex++)
    	{
    		FKeyBoardBindingTable* LookUpRow = GameHUD->KeyBoardBindingTable->FindRow<FKeyBoardBindingTable>(FName(*TempIndex[rowindex]), TEXT("Look Up"));
    		if (LookUpRow)
    		{
    			LookUpRow->Input = TempInput[rowindex];
    		}
    		else
    		{
    			break;
    		}
    	}
    	return FReply::Handled();
    }
    
    FReply SKeyConfigUI::CancelButtonClicked()
    {
    	DrawKeyBindingWidget();
    	return FReply::Handled();
    }
    
    FReply SKeyConfigUI::ResetButtonClicked()
    {
    	
    	int32 rowindex = 1;
    	while (true)
    	{
    		FKeyBoardBindingTable* LookUpRow = GameHUD->KeyBoardBindingTable->FindRow<FKeyBoardBindingTable>(FName(*FString::FromInt(rowindex)), TEXT("Look Up"));
    		if (LookUpRow)
    		{
    			LookUpRow->Input = LookUpRow->DefaultInput;
    			DrawKeyBindingWidget();
    			rowindex++;
    		}
    		else
    		{
    			break;
    		}
    	}
    	return FReply::Handled();
    }
    
    FReply SKeyConfigUI::InputCaterGoryButonClicked(FString Category)
    {
    	
    	if (Category == "General")
    	{
    		GeneralButton->SetButtonStyle(&MenuStyle->KeyConfigHeaderStyle);
    		MovementButton->SetButtonStyle(&MenuStyle->KeyConfigNotSelectedStyle);
    		CombatButton->SetButtonStyle(&MenuStyle->KeyConfigNotSelectedStyle);
    		MiscellaneousButton->SetButtonStyle(&MenuStyle->KeyConfigNotSelectedStyle);
    		KeyBindingWidget->SetActiveWidgetIndex(0);
    	}
    	else if (Category == "Movement")
    	{
    		GeneralButton->SetButtonStyle(&MenuStyle->KeyConfigNotSelectedStyle);
    		MovementButton->SetButtonStyle(&MenuStyle->KeyConfigHeaderStyle);
    		CombatButton->SetButtonStyle(&MenuStyle->KeyConfigNotSelectedStyle);
    		MiscellaneousButton->SetButtonStyle(&MenuStyle->KeyConfigNotSelectedStyle);
    		KeyBindingWidget->SetActiveWidgetIndex(1);
    	}
    	else if (Category == "Combat")
    	{
    		GeneralButton->SetButtonStyle(&MenuStyle->KeyConfigNotSelectedStyle);
    		MovementButton->SetButtonStyle(&MenuStyle->KeyConfigNotSelectedStyle);
    		CombatButton->SetButtonStyle(&MenuStyle->KeyConfigHeaderStyle);
    		MiscellaneousButton->SetButtonStyle(&MenuStyle->KeyConfigNotSelectedStyle);
    		KeyBindingWidget->SetActiveWidgetIndex(2);
    	}
    	else if (Category == "Miscellaneous")
    	{
    		GeneralButton->SetButtonStyle(&MenuStyle->KeyConfigNotSelectedStyle);
    		MovementButton->SetButtonStyle(&MenuStyle->KeyConfigNotSelectedStyle);
    		CombatButton->SetButtonStyle(&MenuStyle->KeyConfigNotSelectedStyle);
    		MiscellaneousButton->SetButtonStyle(&MenuStyle->KeyConfigHeaderStyle);
    		KeyBindingWidget->SetActiveWidgetIndex(3);
    		TSharedPtr<class SWidget> border = SNew(SCanvas);
    	 
    	}
    		
    	return FReply::Handled();
    }
    
    FReply SKeyConfigUI::KeyCustomizationButtonClicked(FString Key, FString Value , int32 Index)
    {
    	Selectedkey = Key;
    	SelectedOldValue = Value;
    	SelectedIndex = Index-1;
    	CustomKeyWidget = SNew(SOverlay)
    		+ SOverlay::Slot()
    		.HAlign(HAlign_Fill)
    		.VAlign(VAlign_Fill).Padding(400)
    		
    		[
    			SNew(SBorder)
    			.BorderImage(&MenuStyle->BorderBrush2)
    			.VAlign(VAlign_Center)
    			.Content()
    			[
    				SNew(SScrollBox)
    				+ SScrollBox::Slot()
    				.HAlign(HAlign_Center)
    				[
    					SNew(STextBlock)
    					.Text(FText::FromString("Press any key to map to"))
    					.Font(FSlateFontInfo(FPaths::EngineContentDir() / TEXT("Slate/Fonts/Roboto-Bold.ttf"), 15))
    					.ColorAndOpacity(FLinearColor(0.7, 0.6, 0.1, 1))
    				]
    				+ SScrollBox::Slot()
    					.HAlign(HAlign_Center)
    					[
    						SNew(STextBlock)
    						.Text(FText::FromString(Key))
    						.Font(FSlateFontInfo(FPaths::EngineContentDir() / TEXT("Slate/Fonts/Roboto-Bold.ttf"), 17))
    						.ColorAndOpacity(FLinearColor(0.46, 0.77, 0.73, 1))
    					]
    				+ SScrollBox::Slot()
    					.HAlign(HAlign_Center)
    					[
    						SNew(STextBlock)
    						.Text(FText::FromString("Press ESC to cancel"))
    						.Font(FSlateFontInfo(FPaths::EngineContentDir() / TEXT("Slate/Fonts/Roboto-Bold.ttf"), 15))
    						.ColorAndOpacity(FLinearColor(0.46, 0.77, 0.73, 1))
    						.ColorAndOpacity(FLinearColor(0.7, 0.6, 0.1, 1))
    					]
    			]
    
    		];
    	
    	GEngine->GameViewport->AddViewportWidgetContent(CustomKeyWidget.ToSharedRef());
    	KeyBindingWidget->SetEnabled(false);
    	ParentWidget->SetEnabled(false);
    	
        return FReply::Handled();
    }
    
    FReply SKeyConfigUI::OnKeyDown(const FGeometry& MyGeometry, const FKeyboardEvent& InKeyboardEvent)
    {
    	GEngine->GameViewport->RemoveViewportWidgetContent(CustomKeyWidget.ToSharedRef());
    	if (InKeyboardEvent.GetKey() == EKeys::Escape)
    	{
    		KeyBindingWidget->SetEnabled(true);
    		ParentWidget->SetEnabled(true);
    	}
    	else
    	{
    		NewKey = InKeyboardEvent.GetKey();
    	    KeyBindingWidget->SetEnabled(true);
    		ParentWidget->SetEnabled(true);
    		FKeyBoardBindingTable* LookUpRow = GameHUD->KeyBoardBindingTable->FindRow<FKeyBoardBindingTable>(*FString::FromInt(SelectedIndex+1), TEXT("Look Up"));
    		int32 widgetIndex;
    		if (NewKey != FKey(FName(*LookUpRow->Input)))
    		{
    			TempIndex.Add(FString::FromInt(SelectedIndex + 1));
    			TempInput.Add(NewKey.ToString());
    			int index =KeyBindingWidget->GetActiveWidgetIndex();
    			switch (index)
    			{
    			case 0: 
    				GeneralWidget->RemoveSlot(SelectedIndex);
    				GeneralWidget->InsertSlot(SelectedIndex).HAlign(HAlign_Fill).Padding(10)
    					[
    						
    						
    						DrawKeyBindingWidgetRow(LookUpRow->Action, NewKey.ToString(), LookUpRow->Category, SelectedIndex + 1).ToSharedRef()
    					];
    				break;
    			case 1:
    				widgetIndex = SelectedIndex - GeneralIndex;
    				MovementWidget->RemoveSlot(widgetIndex);
    				MovementWidget->InsertSlot(widgetIndex).HAlign(HAlign_Fill).Padding(10)
    					[
    
    						DrawKeyBindingWidgetRow(LookUpRow->Action, NewKey.ToString(), LookUpRow->Category, SelectedIndex + 1).ToSharedRef()
    					];
    				break;
    			case 2:
    				widgetIndex = SelectedIndex - GeneralIndex - MovementIndex;
    				CombatWidget->RemoveSlot(widgetIndex);
    				CombatWidget->InsertSlot(widgetIndex).HAlign(HAlign_Fill).Padding(10)
    					[
    
    						DrawKeyBindingWidgetRow(LookUpRow->Action, NewKey.ToString(), LookUpRow->Category, SelectedIndex + 1).ToSharedRef()
    					];
    				break;
    			case 3:
    				widgetIndex = SelectedIndex - GeneralIndex - MovementIndex  - CombatIndex;
    				MiscellaneousWidget->RemoveSlot(widgetIndex);
    				MiscellaneousWidget->InsertSlot(widgetIndex).HAlign(HAlign_Fill).Padding(10)
    					[
    
    						DrawKeyBindingWidgetRow(LookUpRow->Action, NewKey.ToString(), LookUpRow->Category, SelectedIndex + 1).ToSharedRef()
    					];
    				break;
    			default:
    				break;
    			}
    		}
    	}
    
    	return FReply::Handled();
    }
    OK , and the below is my header class , in case you are confused with the above code.

    Code:
    class FORGOTTENLEGION_API SKeyConfigUI : public SCompoundWidget
    {
    
    	SLATE_BEGIN_ARGS(SKeyConfigUI)
    	{
    	}
    
    	SLATE_ARGUMENT(TWeakObjectPtr<class AGameHUD>, GameHUD);
    	SLATE_END_ARGS()
    
    	
    
    public:
    	/** Constructs this widget with InArgs */
    	void Construct(const FArguments& InArgs);
    	bool FileIO__SaveStringTextToFile(FString SaveDirectory, FString FileName, FString SaveText, bool AllowOverWriting);
    	bool FileIO_ReadFileToString(FString FileDirectory, FString FilePath);
    
    	/** Overridden from SWidget: Called when a key is pressed down - capturing copy */
    	virtual FReply OnKeyDown(const FGeometry& MyGeometry, const FKeyboardEvent& InKeyboardEvent) override;
    private:
    	
    	SScrollBox::FSlot& InsertSlot(int32 Index);
    	FReply InputCaterGoryButonClicked(FString Category);
    	
    	TSharedPtr<class SHorizontalBox> DrawKeyBindingWidgetRow(FString Action, FString Input, FString Category , int32 Index);
    	void DrawKeyBindingWidget();
    
    	const struct FGlobalStyle* MenuStyle;
    	FReply SaveButtonClicked();
    	FReply CancelButtonClicked();
    	FReply ResetButtonClicked();
    	FReply KeyCustomizationButtonClicked(FString Key, FString Value , int32 Index);
    	
    	TWeakObjectPtr<class AGameHUD> GameHUD;
    	TSharedPtr<class SWidgetSwitcher> KeyBindingWidget = SNew(SWidgetSwitcher);
    	TSharedRef<FSlateGameResources> SlateResources = FSlateGameResources::New(FName("BorderBrush1"), "/Game/Blueprints/Widgets/Styles", "/Game/Blueprints/Widgets/Styles");
    	FSlateGameResources& Style = SlateResources.Get();
    	const FSlateBrush* BorderBrush1 = Style.GetBrush("BorderBrush1");
    	FLinearColor SelectedButtonColor = FLinearColor(0.58, 0.74, 0.89, 1);
    
    	FString Selectedkey;
    	FString SelectedOldValue;
    	int32 SelectedIndex;
    	
    	int32 GeneralIndex = 0;;
    	int32 MovementIndex = 0;
    	int32 CombatIndex = 0;
    	int32 MiscellaneousIndex = 0;
    
    	TArray<FString> TempIndex;
    	TArray<FString> TempInput;
    	
    	FKey NewKey;
    	TSharedPtr<class SButton> GeneralButton = SNew(SButton);
    	TSharedPtr<class SButton> MovementButton = SNew(SButton);
    	TSharedPtr<class SButton> CombatButton = SNew(SButton);
    	TSharedPtr<class SButton> MiscellaneousButton = SNew(SButton);
    
    	TSharedPtr<class STextBlock> GeneralText = SNew(STextBlock);
    	TSharedPtr<class STextBlock> MovementText = SNew(STextBlock);
    	TSharedPtr<class STextBlock> CombatText = SNew(STextBlock);
    	TSharedPtr<class STextBlock> MiscellaneousText = SNew(STextBlock);
    	
    	TSharedPtr<class SScrollBox> ParentWidget = SNew(SScrollBox);
    	
    	TSharedPtr<class SScrollBox> GeneralWidget = SNew(SScrollBox);
    	TSharedPtr<class SScrollBox> MovementWidget = SNew(SScrollBox);
    	TSharedPtr<class SScrollBox> CombatWidget = SNew(SScrollBox);
    	TSharedPtr<class SScrollBox> MiscellaneousWidget = SNew(SScrollBox);
    
    	TSharedPtr<class STextBlock> BindingText = SNew(STextBlock);
    	TSharedPtr<class SButton> BindingButton = SNew(SButton);
    	TSharedPtr<class SOverlay> CustomKeyWidget = SNew(SOverlay);
    	
    };
    Now you can easily add this UI in your viewport in your HUD class , whenever required , using the below line

    Code:
    SAssignNew(KeyConfigUI, SKeyConfigUI).GameHUD(this);
    	if (GEngine && GEngine->GameViewport)
    	{
    	     Viewport = GEngine->GameViewport;
    
    		Viewport->AddViewportWidgetContent(
    			SNew(SWeakWidget).PossiblyNullContent(KeyConfigUI.ToSharedRef())
    			);
    		}
    Now our keyconfiguraiton UI is ready(please let me know if you find any bug). SO next I need to tell unreal engine , that whatever current value is present in the Input column of the datatable , I am supposed to use that for desired set of action. So for that I wrote the following code in my playercharacter class. Here , make sure you include the below namespaces

    Code:
    #include "Runtime/Engine/Classes/GameFramework/PlayerInput.h"
    #include "Runtime/Engine/Classes/GameFramework/InputSettings.h"
    #include "Runtime/CoreUObject/Public/UObject/UObjectGlobals.h"
    Code:
    void AForgottenLegionCharacter::SetupPlayerInputComponent(class UInputComponent* InputComponent)
    {
    	// Set up gameplay key bindings
    	check(InputComponent);
    	const UInputSettings* InputSettings = GetDefault<UInputSettings>();
    	int rowindex = 1;
    	while (true)
    	{
    		FKeyBoardBindingTable* LookUpRow = KeyBoardBindingTable->FindRow<FKeyBoardBindingTable>(FName(*FString::FromInt(rowindex)), TEXT("Look Up"));
    		if (LookUpRow)
    		{
    			if (LookUpRow->Action == "Move Forward")
    			{
    				const FInputAxisKeyMapping axismapping(FName("Move Forward"), FKey(FName(*LookUpRow->Input)) , 1);
    		    	((UInputSettings*)InputSettings)->AddAxisMapping(axismapping);
    		}
    			else if (LookUpRow->Action == "Move Backward")
    			{
    				const FInputAxisKeyMapping axismapping(FName("Move Forward"), FKey(FName(*LookUpRow->Input)), -1);
    		    	((UInputSettings*)InputSettings)->AddAxisMapping(axismapping);
    		
    			}
    			else if (LookUpRow->Action == "Move Left")
    			{
    				const FInputAxisKeyMapping axismapping(FName("Move Right"), FKey(FName(*LookUpRow->Input)), -1);
    		    	((UInputSettings*)InputSettings)->AddAxisMapping(axismapping);
    			}
    			else if (LookUpRow->Action == "Move Right")
    			{
    				const FInputAxisKeyMapping axismapping(FName("Move Right"), FKey(FName(*LookUpRow->Input)), 1);
    			 	((UInputSettings*)InputSettings)->AddAxisMapping(axismapping);
    			}
    			
    		   else
    			{
    			   const FInputActionKeyMapping actionmapping(FName(*LookUpRow->Action), FKey(FName(*LookUpRow->Input)), false , false , false , false);
    			   ((UInputSettings*)InputSettings)->AddActionMapping(actionmapping);
    		   }
    			rowindex++;
    		
    		}
    		else
    		{
    			break;
    		}
    	}
    
    	const FInputAxisKeyMapping turnaxismapping(FName("Turn"), FKey(FName("MouseX")), 1);
    	((UInputSettings*)InputSettings)->AddAxisMapping(turnaxismapping);
    	
    	const FInputAxisKeyMapping lookupaxismapping(FName("LookUp"), FKey(FName("MouseY")), 1);
    	((UInputSettings*)InputSettings)->AddAxisMapping(lookupaxismapping);
    
    	((UInputSettings*)InputSettings)->SaveKeyMappings();
    	
    	InputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);
    
    	InputComponent->BindAxis("Move Forward", this, &AForgottenLegionCharacter::MoveForward);
    	InputComponent->BindAxis("Move Right", this, &AForgottenLegionCharacter::MoveRight);
    	InputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput);
    	InputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput);
    
    	
    }
    And thats it, when you hit on play , all this settings will be saved and you can verify by going to the project settings->input section.

    Thanks and Regards ,
    Sameek Kundu
    Last edited by sameek4; 11-24-2014, 02:39 AM.
    DayNight Cycle - https://www.unrealengine.com/marketplace/daynight-cycle
    Jigsaw Puzzle Template - https://www.unrealengine.com/marketp...uzzle-template
    Post Process Blendables Volume 1 - https://www.unrealengine.com/marketp...ndables-volume
    MSSQL Integration for UE4 - https://www.unrealengine.com/marketp...ql-integration
    Radar System with Minimap - https://www.unrealengine.com/marketp...m-with-minimap

    #2
    Use code tag, it's impossible to read anything.
    Alone: The Untold - a story driven horror game

    Comment


      #3
      Done. Didn't know this. Thanks
      DayNight Cycle - https://www.unrealengine.com/marketplace/daynight-cycle
      Jigsaw Puzzle Template - https://www.unrealengine.com/marketp...uzzle-template
      Post Process Blendables Volume 1 - https://www.unrealengine.com/marketp...ndables-volume
      MSSQL Integration for UE4 - https://www.unrealengine.com/marketp...ql-integration
      Radar System with Minimap - https://www.unrealengine.com/marketp...m-with-minimap

      Comment


        #4
        Thanks for the code and the time put into this document! There were a few things not mentioned so just to let you know. Please let me know if the references are incorrect.


        missing from hud
        -----------------------
        #include "Engine\GameViewportClient.h"


        UGameViewportClient* Viewport;
        SKeyConfigUI* KeyConfigUI; <<----- ?





        missing within KeyConfigUI.h
        ------------------------------
        #include "Slate.h"
        #include "SlateGameResources.h"
        #include "GlobalMenuStyle.h"
        #include "MenuStyles.h"



        The creation of the MenuStyles and GlobalStyle classes are not mentioned but the necessary code is @ http://minalien.com/unreal-engine-4-...slatec-part-2/



        Missing within GlobalMenuStyle.h
        ------------------------------------
        FButtonStyle KeyConfigNotSelectedStyle;
        FButtonStyle KeyConfigHeaderStyle;
        FButtonStyle KeyBindingButtonStyle;
        FButtonStyle GeneralButtonStyle1;

        FSlateBrush BorderBrush1;
        FSlateBrush BorderBrush2;




        Missing from Character
        --------------------------
        UDataTable* KeyBoardBindingTable;
        void MoveForward(float Val);
        void MoveRight(float Val)




        AddSlot and RemoveSlot takes type "const TSharedRef<SWidget>& " not an int32 .

        Thank you! I have gotten it to build although I haven't tested it's functionality yet.
        Last edited by Garner; 09-07-2014, 09:24 PM.

        Comment


          #5
          Hi ,

          Sorry for not mentioning this , but insertslot and removeslot are my own functions , which are given as follows :

          SScrollBox.h

          SScrollBox::FSlot& InsertSlot(int32 Index);
          SScrollBox::FSlot& RemoveSlot(int32 Index);

          SScrollBox.cpp

          SScrollBox::FSlot& SScrollBox::InsertSlot(int32 Index)

          {

          SScrollBox::FSlot& NewSlot = SScrollBox::Slot();

          ScrollPanel->Children.Insert(&NewSlot , Index);


          return NewSlot;

          }

          SScrollBox::FSlot& RemoveSlot(int32 Index)
          {
          SScrollBox::FSlot& NewSlot = SScrollBox::Slot();
          ScrollPanel->Children.RemoveAt(Index);
          return NewSlot;
          }
          DayNight Cycle - https://www.unrealengine.com/marketplace/daynight-cycle
          Jigsaw Puzzle Template - https://www.unrealengine.com/marketp...uzzle-template
          Post Process Blendables Volume 1 - https://www.unrealengine.com/marketp...ndables-volume
          MSSQL Integration for UE4 - https://www.unrealengine.com/marketp...ql-integration
          Radar System with Minimap - https://www.unrealengine.com/marketp...m-with-minimap

          Comment


            #6
            Thank you very much!

            Comment

            Working...
            X