Files
Cog/Plugins/CogInput/Source/CogInput/Private/CogInputWindow_Actions.cpp
T
Arnaud Jamin 32ca4dc2ba Rename CogWindow plugin to Cog.
Fix Config saving not working
2025-02-12 13:56:06 -05:00

333 lines
12 KiB
C++

#include "CogInputWindow_Actions.h"
#include "CogWidgets.h"
#include "Engine/LocalPlayer.h"
#include "Engine/World.h"
#include "EnhancedInputSubsystems.h"
#include "GameFramework/Pawn.h"
#include "imgui_internal.h"
#include "InputAction.h"
#include "InputMappingContext.h"
//--------------------------------------------------------------------------------------------------------------------------
void FCogInputWindow_Actions::Initialize()
{
Super::Initialize();
bHasMenu = true;
Config = GetConfig<UCogInputConfig_Actions>();
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogInputWindow_Actions::RenderHelp()
{
ImGui::Text(
"This window displays the current state of each Input Action. "
"It can also be used to inject inputs to help debugging.");
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogInputWindow_Actions::RenderContent()
{
Super::RenderContent();
ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();
if (LocalPlayer == nullptr)
{
ImGui::TextDisabled("No Local Player");
return;
}
UEnhancedInputLocalPlayerSubsystem* EnhancedInputSubsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(LocalPlayer);
if (EnhancedInputSubsystem == nullptr)
{
ImGui::TextDisabled("No Enhanced Input Subsystem");
return;
}
UEnhancedPlayerInput* PlayerInput = EnhancedInputSubsystem->GetPlayerInput();
if(PlayerInput == nullptr)
{
ImGui::TextDisabled("No Player Input");
return;
}
const bool IsControlDown = (ImGui::GetCurrentContext()->IO.KeyMods & ImGuiMod_Ctrl) != 0;
if (ImGui::BeginMenuBar())
{
if (ImGui::BeginMenu("Options"))
{
ImGui::Checkbox("Show Header", &Config->ShowHeader);
ImGui::SliderFloat("##Repeat", &Config->RepeatPeriod, 0.1f, 10.0f, "Repeat: %0.1fs");
ImGui::EndMenu();
}
if (ImGui::MenuItem("Reset"))
{
for (FCogInputMappingContextInfo Mapping : Mappings)
{
for (FCogInputActionInfo& Action : Mapping.Actions)
{
Action.Reset();
}
}
}
ImGui::EndMenuBar();
}
//--------------------------------------------------------------------------
// Get all the existing mapping. This is not publicly exposed so we rob it.
//--------------------------------------------------------------------------
TArray<FCogInputMappingContextInfo, TInlineAllocator<8>> AllAppliedMappings;
if (const CogInputMappingContextMap* AppliedMappingContexts = &PRIVATE_ACCESS_PTR(PlayerInput, UEnhancedPlayerInput_AppliedInputContexts))
{
for (auto& kv : *AppliedMappingContexts)
{
FCogInputMappingContextInfo& MappingInfo = AllAppliedMappings.AddDefaulted_GetRef();
MappingInfo.MappingContext = kv.Key;
MappingInfo.Priority = kv.Value;
}
}
//--------------------------------------------------------------------------
// Remove mappings that are not present anymore.
//--------------------------------------------------------------------------
for (int32 i = Mappings.Num() - 1; i >= 0; i--)
{
const FCogInputMappingContextInfo& MappingInfo = Mappings[i];
if (AllAppliedMappings.ContainsByPredicate([&MappingInfo](const FCogInputMappingContextInfo& m)
{
return m.MappingContext == MappingInfo.MappingContext;
}))
{
continue;
}
Mappings.RemoveAt(i);
}
//--------------------------------------------------------------------------
// Add mappings that were not yet added.
//--------------------------------------------------------------------------
for (FCogInputMappingContextInfo& MappingInfo : AllAppliedMappings)
{
//----------------------------------------------------
// The mapping was already added
//----------------------------------------------------
if (Mappings.ContainsByPredicate([&MappingInfo](const FCogInputMappingContextInfo& m) { return m.MappingContext == MappingInfo.MappingContext; }))
{
continue;
}
//----------------------------------------------------
// Add the mapping
//----------------------------------------------------
FCogInputMappingContextInfo& NewMappingInfo = Mappings.AddDefaulted_GetRef();
NewMappingInfo.MappingContext = MappingInfo.MappingContext;
NewMappingInfo.Priority = MappingInfo.Priority;
//----------------------------------------------------
// Add all the mapping actions
//----------------------------------------------------
for (const FEnhancedActionKeyMapping& Mapping : NewMappingInfo.MappingContext->GetMappings())
{
TObjectPtr<const UInputAction> Action = Mapping.Action;
if (Action == nullptr)
{
continue;
}
//----------------------------------------------------
// Actions are present multiple time, as many times
// as they are mapped to key. We only want to display
// the same action once per mapping
//----------------------------------------------------
if (NewMappingInfo.Actions.ContainsByPredicate([&Action](const FCogInputActionInfo& m){ return m.Action == Action; }))
{
continue;
}
FCogInputActionInfo& ActionInfo = NewMappingInfo.Actions.AddDefaulted_GetRef();
ActionInfo.Action = Mapping.Action;
}
Mappings.Sort([](const FCogInputMappingContextInfo& Lhs, const FCogInputMappingContextInfo& Rhs)
{
return Lhs.Priority < Rhs.Priority;
});
}
int Index = 0;
for (FCogInputMappingContextInfo& Mapping : Mappings)
{
const auto MappingName = StringCast<ANSICHAR>(*Mapping.MappingContext.GetName());
const bool Open = ImGui::CollapsingHeader(MappingName.Get(), ImGuiTreeNodeFlags_DefaultOpen);
if (Open && ImGui::BeginTable("Actions", 3, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_NoBordersInBodyUntilResize))
{
ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Current", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableSetupColumn("Inject", ImGuiTableColumnFlags_WidthStretch);
if (Config->ShowHeader)
{
ImGui::TableHeadersRow();
}
for (FCogInputActionInfo& ActionInfo : Mapping.Actions)
{
ImGui::PushID(Index);
const auto ActionName = StringCast<ANSICHAR>(*ActionInfo.Action->GetName());
FInputActionValue ActionValue = PlayerInput->GetActionValue(ActionInfo.Action);
switch (ActionInfo.Action->ValueType)
{
case EInputActionValueType::Boolean:
{
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("%s", ActionName.Get());
ImGui::TableNextColumn();
ImGui::BeginDisabled();
bool Value = ActionValue.Get<bool>();
FCogWidgets::PushBackColor(ImVec4(0.8f, 0.8f, 0.8f, 1));
ImGui::Checkbox("##Current", &Value);
FCogWidgets::PopBackColor();
ImGui::EndDisabled();
ImGui::TableNextColumn();
ECheckBoxState State = ActionInfo.bRepeat ? ECheckBoxState::Undetermined : ActionInfo.bPressed ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
if (FCogWidgets::CheckBoxState("##Inject", State, false))
{
if (IsControlDown)
{
ActionInfo.bRepeat = !ActionInfo.bRepeat;
ActionInfo.bPressed = false;
}
else
{
ActionInfo.bPressed = !ActionInfo.bPressed;
ActionInfo.bRepeat = false;
}
}
if (ImGui::BeginPopupContextItem())
{
ImGui::Checkbox("Repeat", &ActionInfo.bRepeat);
ImGui::EndPopup();
}
if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayShort))
{
ImGui::BeginTooltip();
ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, IsControlDown ? 1.0f : 0.5f), "Repeat [CTRL]");
ImGui::EndTooltip();
}
break;
}
case EInputActionValueType::Axis1D:
{
const float Value = ActionValue.Get<float>();
DrawAxis("%s", ActionName.Get(), Value, &ActionInfo.X);
break;
}
case EInputActionValueType::Axis2D:
{
const FVector2D Value = ActionValue.Get<FVector2D>();
DrawAxis("%s X", ActionName.Get(), Value.X, &ActionInfo.X);
DrawAxis("%s Y", ActionName.Get(), Value.Y, &ActionInfo.Y);
break;
}
case EInputActionValueType::Axis3D:
{
const FVector Value = ActionValue.Get<FVector>();
DrawAxis("%s X", ActionName.Get(), Value.X, &ActionInfo.X);
DrawAxis("%s Y", ActionName.Get(), Value.Y, &ActionInfo.Y);
DrawAxis("%s Z", ActionName.Get(), Value.Z, &ActionInfo.Z);
break;
}
}
ImGui::PopID();
Index++;
}
ImGui::EndTable();
}
}
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogInputWindow_Actions::RenderTick(float DeltaSeconds)
{
Super::RenderTick(DeltaSeconds);
if (GetWorld() == nullptr)
{
return;
}
ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();
if (LocalPlayer == nullptr)
{
return;
}
UEnhancedInputLocalPlayerSubsystem* EnhancedInput = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(LocalPlayer);
if (EnhancedInput == nullptr)
{
return;
}
bool IsTimeToRepeat = false;
float WorldTime = GetWorld()->GetTimeSeconds();
if (RepeatTime < WorldTime)
{
RepeatTime = WorldTime + Config->RepeatPeriod;
IsTimeToRepeat = true;
}
for (FCogInputMappingContextInfo Mapping : Mappings)
{
for (FCogInputActionInfo& ActionInfo : Mapping.Actions)
{
ActionInfo.Inject(*EnhancedInput, IsTimeToRepeat);
}
}
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogInputWindow_Actions::DrawAxis(const char* Format, const char* ActionName, float CurrentValue, float* InjectValue)
{
ImGui::PushID(Format);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text(Format, ActionName);
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(-1);
ImGui::BeginDisabled();
FCogWidgets::PushBackColor(ImVec4(0.8f, 0.8f, 0.8f, 1));
ImGui::SliderFloat("##Value", &CurrentValue, -1.0f, 1.0f, "%0.2f");
FCogWidgets::PopBackColor();
ImGui::EndDisabled();
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(-1);
FCogWidgets::SliderWithReset("##Inject", InjectValue, -1.0f, 1.0f, 0.0f, "%0.2f");
ImGui::PopID();
}