DebugExecBindings

DebugExecBindings

#Overview

name: DebugExecBindings

The value of this variable can be defined or overridden in .ini config files. 25 .ini config files referencing this setting variable.

It is referenced in 9 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of DebugExecBindings is to provide a mechanism for binding keys to debug commands in Unreal Engine. This variable is primarily used for development and debugging purposes, allowing developers to execute specific commands or actions by pressing designated keys during runtime.

DebugExecBindings is primarily used in the Engine module, specifically within the PlayerInput system. It’s also utilized by various developer plugins such as the RenderDoc Plugin and Xcode GPU Debugger Plugin.

The value of this variable is set in multiple ways:

  1. Through configuration files (as seen in the RenderDocPlugin and XcodeGPUDebuggerPlugin modules)
  2. Dynamically at runtime through the SetBind function in PlayerInput

DebugExecBindings interacts with other input-related variables and systems within the PlayerInput class, such as ActionMappings and AxisConfig.

Developers should be aware of the following when using this variable:

  1. It’s intended for development and debugging purposes, not for shipping game features.
  2. The bindings are stored in the config files, so they persist between editor sessions.
  3. These bindings can be modified at runtime, which can be powerful but also potentially confusing if not managed properly.

Best practices when using DebugExecBindings include:

  1. Use clear, descriptive command names to make the purpose of each binding obvious.
  2. Be cautious when adding or modifying bindings to avoid conflicts with existing game controls.
  3. Consider using modifier keys (Shift, Alt, Ctrl) to reduce the likelihood of accidental triggers.
  4. Remove or disable debug bindings before shipping the final product to end-users.
  5. Document any custom debug bindings used in the project for other team members.

#Setting Variables

#References In INI files

<Workspace>/Engine/Config/BaseInput.ini:38, section: [/Script/Engine.PlayerInput]
<Workspace>/Engine/Config/BaseInput.ini:39, section: [/Script/Engine.PlayerInput]
<Workspace>/Engine/Config/BaseInput.ini:40, section: [/Script/Engine.PlayerInput]
<Workspace>/Engine/Config/BaseInput.ini:41, section: [/Script/Engine.PlayerInput]
<Workspace>/Engine/Config/BaseInput.ini:42, section: [/Script/Engine.PlayerInput]
<Workspace>/Engine/Config/BaseInput.ini:43, section: [/Script/Engine.PlayerInput]
<Workspace>/Engine/Config/BaseInput.ini:44, section: [/Script/Engine.PlayerInput]
<Workspace>/Engine/Config/BaseInput.ini:45, section: [/Script/Engine.PlayerInput]
<Workspace>/Engine/Config/BaseInput.ini:46, section: [/Script/Engine.PlayerInput]
<Workspace>/Engine/Config/BaseInput.ini:47, section: [/Script/Engine.PlayerInput]
<Workspace>/Engine/Config/BaseInput.ini:48, section: [/Script/Engine.PlayerInput]
<Workspace>/Engine/Config/BaseInput.ini:49, section: [/Script/Engine.PlayerInput]
<Workspace>/Engine/Config/BaseInput.ini:50, section: [/Script/Engine.PlayerInput]
<Workspace>/Engine/Config/BaseInput.ini:51, section: [/Script/Engine.PlayerInput]
<Workspace>/Engine/Config/BaseInput.ini:52, section: [/Script/Engine.PlayerInput]
<Workspace>/Engine/Config/BaseInput.ini:54, section: [/Script/Engine.PlayerInput]
<Workspace>/Projects/Lyra/Config/DefaultInput.ini:2, section: [/Script/Engine.PlayerInput]
<Workspace>/Projects/Lyra/Config/DefaultInput.ini:3, section: [/Script/Engine.PlayerInput]
<Workspace>/Projects/Lyra/Config/DefaultInput.ini:4, section: [/Script/Engine.PlayerInput]
<Workspace>/Projects/Lyra/Config/DefaultInput.ini:5, section: [/Script/Engine.PlayerInput]
<Workspace>/Projects/Lyra/Config/DefaultInput.ini:6, section: [/Script/Engine.PlayerInput]
<Workspace>/Projects/Lyra/Config/DefaultInput.ini:7, section: [/Script/Engine.PlayerInput]
<Workspace>/Projects/Lyra/Config/DefaultInput.ini:8, section: [/Script/Engine.PlayerInput]
<Workspace>/Projects/Lyra/Config/DefaultInput.ini:9, section: [/Script/Engine.PlayerInput]
<Workspace>/Projects/Lyra/Config/DefaultInput.ini:10, section: [/Script/Engine.PlayerInput]

#References in C++ code

#Callsites

This variable is referenced in the following C++ source code:

#Loc: <Workspace>/Engine/Plugins/Developer/RenderDocPlugin/Source/RenderDocPlugin/Private/RenderDocPluginModule.cpp:375

Scope (from outer to inner):

file
function     void FRenderDocPluginModule::InjectDebugExecKeybind

Source code excerpt:

{
	// Inject our key bind into the debug execs
	GConfig->AddUniqueToSection(TEXT("/Script/Engine.PlayerInput"), TEXT("DebugExecBindings"), TEXT("(Key=F12,Command=\"RenderDoc.CaptureFrame\", Alt=true)"), GInputIni);
}

void FRenderDocPluginModule::EndFrameCapture(void* HWnd, uint32 Flags, const FString& DestFileName)
{
	HWND WindowHandle = (HWnd) ? reinterpret_cast<HWND>(HWnd) : GetActiveWindow();

#Loc: <Workspace>/Engine/Plugins/Developer/XcodeGPUDebuggerPlugin/Source/XcodeGPUDebuggerPlugin/Private/XcodeGPUDebuggerPluginModule.cpp:221

Scope (from outer to inner):

file
function     void FXcodeGPUDebuggerPluginModule::InjectDebugExecKeybind

Source code excerpt:

void FXcodeGPUDebuggerPluginModule::InjectDebugExecKeybind()
{
	GConfig->AddUniqueToSection(TEXT("/Script/Engine.PlayerInput"), TEXT("DebugExecBindings"), TEXT("(Key=E,Command=\"Xcode.CaptureFrame\", Shift=true)"), GInputIni);
}

void FXcodeGPUDebuggerPluginModule::EndFrameCapture(void* HWnd, uint32 Flags, const FString& DestFileName)
{
	ENQUEUE_RENDER_COMMAND(EndXcodeGPUDebuggerCapture)(
		[Plugin = this, Flags, DestFileName](FRHICommandListImmediate& RHICmdList)

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Classes/GameFramework/PlayerInput.h:434

Scope (from outer to inner):

file
class        class UPlayerInput : public UObject

Source code excerpt:

	/** Generic bindings of keys to Exec()-compatible strings for development purposes only */
	UPROPERTY(config)
	TArray<struct FKeyBind> DebugExecBindings;

	/** This player's version of the Axis Properties */
	TArray<struct FInputAxisConfigEntry> AxisConfig;

	/** This player's version of the Action Mappings */
	TArray<struct FInputActionKeyMapping> ActionMappings;

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/UserInterface/PlayerInput.cpp:2237

Scope (from outer to inner):

file
function     bool UPlayerInput::Exec

Source code excerpt:

		if (Key.IsValid())
		{
			for(uint32 BindIndex = 0;BindIndex < (uint32)DebugExecBindings.Num();BindIndex++)
			{
				if (DebugExecBindings[BindIndex].Key == Key)
				{
					Ar.Logf(TEXT("%s"),*DebugExecBindings[BindIndex].Command);
					break;
				}
			}
		}

		return 1;

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/UserInterface/PlayerInput.cpp:2254

Scope (from outer to inner):

file
function     bool UPlayerInput::Exec

Source code excerpt:

		if(Key.IsValid())
		{
			for(int32 BindIndex = DebugExecBindings.Num() - 1; BindIndex >= 0; BindIndex--)
			{
				if(DebugExecBindings[BindIndex].Key == Key)
				{
					bExecutingBindCommand = true;
					bool bResult = ExecInputCommands(GetWorld(), *DebugExecBindings[BindIndex].Command,Ar);
					bExecutingBindCommand = false;
					return bResult;
				}
			}
		}
	}

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/UserInterface/PlayerInput.cpp:2281

Scope (from outer to inner):

file
function     FString UPlayerInput::GetBind

Source code excerpt:

		const bool bCmdPressed = IsCmdPressed();

		for ( int32 BindIndex = DebugExecBindings.Num() - 1; BindIndex >= 0; BindIndex-- )
		{
			const FKeyBind&	Bind = DebugExecBindings[BindIndex];
			if ( Bind.Key == Key && !Bind.bDisabled )
			{
				// if the modifier key pressed [or this key-bind doesn't require that key], and the key-bind isn't
				// configured to ignore they modifier key, we've found a match.
				if ((!Bind.Control || bControlPressed) && (!Bind.Shift || bShiftPressed) && (!Bind.Alt || bAltPressed) && (!Bind.Cmd || bCmdPressed)
					&&	(!Bind.bIgnoreCtrl || !bControlPressed) && (!Bind.bIgnoreShift || !bShiftPressed) && (!Bind.bIgnoreAlt || !bAltPressed) && (!Bind.bIgnoreCmd || !bCmdPressed))
				{
					return DebugExecBindings[BindIndex].Command;
				}
			}
		}
	}

	return TEXT("");

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/UserInterface/PlayerInput.cpp:2303

Scope (from outer to inner):

file
function     FKeyBind UPlayerInput::GetExecBind

Source code excerpt:

{
	FKeyBind Binding;
	for( auto InputBindingIt = DebugExecBindings.CreateConstIterator(); InputBindingIt; ++InputBindingIt )
	{
		if(InputBindingIt->Command == ExecCommand)
		{
			Binding = *InputBindingIt;
			break;
		}

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/UserInterface/PlayerInput.cpp:2327

Scope (from outer to inner):

file
function     void UPlayerInput::SetBind

Source code excerpt:

		}

		for(int32 BindIndex = DebugExecBindings.Num()-1;BindIndex >= 0;BindIndex--)
		{
			if (DebugExecBindings[BindIndex].Key == BindKey)
			{
				DebugExecBindings[BindIndex].Command = CommandMod;
				SaveConfig();
				return;
			}
		}

		FKeyBind NewBind;
		NewBind.Key = BindKey;
		NewBind.Command = CommandMod;
		DebugExecBindings.Add(NewBind);
		SaveConfig();
	}
#endif
}

class UWorld* UPlayerInput::GetWorld() const

#Loc: <Workspace>/Engine/Source/Runtime/GameplayDebugger/Private/GameplayDebuggerLocalController.cpp:568

Scope (from outer to inner):

file
function     void UGameplayDebuggerLocalController::BindInput

Source code excerpt:


		UPlayerInput* Input = CachedReplicator->GetReplicationOwner()->PlayerInput;
		for (int32 Idx = 0; Idx < Input->DebugExecBindings.Num(); Idx++)
		{
			FKeyBind& DebugBinding = Input->DebugExecBindings[Idx];
			const bool bRemoveMask = RemovedMasks.Contains(DebugBinding.Key.GetFName());
			const bool bAddMask = AddedMasks.Contains(DebugBinding.Key.GetFName());

			if (bAddMask || bRemoveMask)
			{
				DebugBinding.bDisabled = bAddMask;