How-To: Find and Fix Input Clashes

Goal: find every Input Action that a higher-priority Input Mapping Context silently hides, every key two contexts fight over, and every chord that can never fire - and repair them from one Review page - without pressing Play once. This page walks the whole tool, button by button. It is longer than most How-To pages on purpose: the analyzer models something the editor never shows you, so the first run is confusing without a guide.

Prerequisites
The plugin enabled (Quick Start). bEnableInputClashAnalyzer is on by default in Project Settings -> Crimson -> Crimson Input Settings Clash Analyzer. Your Input Mapping Contexts and Input Actions are ordinary Enhanced Input assets; nothing in the analyzer needs a Crimson type.
Editor tool, both audiences
Steps 1 to 8 are pure editor UI and read the same whichever audience you chose at the top of the window. Step 9 is where Blueprint and C++ differ.

What the tool is checking, in one paragraph

When a player's control mappings are rebuilt, Enhanced Input sorts every applied context by priority (highest first) and walks their mappings. A mapping whose action has Consume Lower Priority Enhanced Input Mappings ticked claims its key: every mapping on that key in a lower-priority context is dropped, before the game runs a single frame. Two contexts at the same priority are ordered by whichever was added first, which no asset records. Chorded mappings are exempt from claiming, but only the engine's own Chorded Action trigger gets that exemption. The analyzer replays exactly that rebuild over a scenario - the contexts you say are applied together, at what priority, in which input mode - and reports every place the outcome is not what a designer would expect.

A scenario is a moment, not the whole game
Do not put every context in the project into one scenario. A scenario is what is applied at one moment: the pawn's contexts during gameplay, or the pawn's contexts plus the inventory screen's context while the inventory is open. One scenario per situation; save each.

1. Open the analyzer

Tools -> Crimson Input -> Input Clash Analyzer (1), or the Input Clashes button in the Level Editor play toolbar (2). The tab is a normal dockable tab; it opens floating the first time and remembers where you dock it. The console command Crimson.InputClash.Open opens it too, and Crimson.InputClash.Open <ScenarioName> opens it with a saved scenario already analyzed.

The Tools menu: the entry lives in the Crimson Input section near the bottom (1).
The same tool from the play toolbar (2).
Verify
An empty Input Clash Analyzer tab appears with a fresh scenario named Scenario N (numbered after the saved ones) and the status line reads Add contexts and press Analyze. If the menu entry is missing, the plugin is disabled or bEnableInputClashAnalyzer is off; both need an editor restart.

2. Discover what the project applies

Press Discover (1). The scan takes a few seconds on a large project and shows a progress bar. It finds every UInputMappingContext and UInputAction asset, plus every place a context is applied with a priority that can be read from assets: the engine's Default Mapping Contexts project setting, AddMappingContext nodes in Blueprint graphs (literal pins only), and any asset, class default, or component template that stores a context next to an integer property whose name contains Priority. Lyra-style InputMapping + Priority structs on a game feature action, a hero component's default mappings, CommonUI's InputMapping + InputMappingPriority on a screen widget, a data asset with its own MappingContextPriority - all of these count.

The whole tab: Discover (1), Add from discovery (2), the Priority column (3), the input mode tags (4), Analyze (5), Save (6).
C++ is invisible to discovery
A context added from C++ (Subsystem->AddMappingContext(IMC, Priority)) leaves no trace in any asset. Discovery cannot see it, so you add it by hand in step 3 and type the priority your code passes. If a scenario's results look too good to be true, a hand-added context is usually what is missing.
Verify
The Output Log prints Input clash discovery: N contexts, M actions, K application sites in J assets. Open Add from discovery... and you see one submenu per asset that applies a context.

3. Build a scenario

A scenario is the list in the Applied contexts panel. Fill it three ways, and mix them freely:

  • Add from discovery... (1) lists every asset that applies a context, as a submenu. Open the asset you care about and pick Add all from this source (2) to add its contexts with the priorities it uses, or pick contexts one at a time. Add everything discovered adds every application site at once; Add every context in the project adds every context asset at priority 0 whether or not anything applies it.
  • Add context... opens an asset picker filtered to Input Mapping Contexts. Use it for contexts your C++ applies. They arrive at priority 0; set the real value in the Priority column.
  • Remove drops the selected rows; Clear empties the list; the On checkbox keeps a context in the scenario without analyzing it, handy for comparing with and without a screen open.
Add from discovery (1) with one source asset expanded; Add all from this source (2) adds its contexts with their real priorities.
Add context (1) opens the ordinary asset picker (2) for contexts that discovery cannot see.

Then set each Priority (3) to what the game passes to AddMappingContext. Discovery fills this in; hand-added contexts start at 0. Double-click a row to open the context asset.

Verify
Every context row shows a mapping count in the Mappings column. A count of - means the asset failed to load; check the path. Press Discover before analyzing if you want the Fix column on Same priority ambiguity rows: the priority fixer writes to the asset that applies the context, so it needs the discovered sources.

4. Tell it which input mode the player is in

The Input mode tags field (4) holds the gameplay tags the player is assumed to be in - typically InputMode.Game during play and InputMode.Menu (or both) while a screen is open. Enhanced Input only consults these when Enable Input Mode Filtering is on in Project Settings -> Engine -> Enhanced Input -> Input Modes; then every context whose Input Mode Query does not match is dropped from the rebuild, exactly as at runtime, and the analyzer shows it as Filtered by input mode in the Status column. With filtering off in the project, the field does nothing and you can leave it empty.

Two more knobs on the same row: Key profile analyzes a mappable key profile's override mappings instead of the defaults (the list is built from the profiles the selected contexts define). Apply context processor runs each context through FCrimsonInputContextProcessor (Input/CrimsonInputContextProcessor.h) first. When a plugin has registered a processor - typically one that injects chord triggers so rebindable chords are enforced - that duplicate is what the runtime actually applies, so leave it on. With no processor registered it is a no-op.

Menu scenarios look alarming at first
With input mode filtering on and a Menu tag set, every gameplay context is filtered out and the report lists each of their actions as inactive. That is the input mode doing its job, and the analyzer only raises Action unreachable when consumption hid something, never when the mode filtered a whole context. Read the Status column before reading the findings.
Verify
Set InputMode.Menu, press Analyze, and every gameplay context's Status flips from Active to Filtered by input mode; clear the tag and they flip back.

5. Analyze and read the Clashes view

Press Analyze (5). With Auto analyze ticked the report also refreshes every time you change a priority, a checkbox, or a tag. The Clashes view lists one row per finding, most severe first. Filter with the three severity toggles (1), review the certain fixes with Fix all Auto (2), or type in the filter box (3) to match a key, an action, a context, or any word of the explanation. The Fix column (4) is step 7. Double-click a row to open the context it names; right-click for the action, the other context, or to copy the row as text. Copy Report puts the whole report on the clipboard.

The Clashes view: severity toggles (1), Fix all Auto (2), the text filter (3), and the Fix column (4).
SeverityCategoryWhat it meansWhat usually fixes it
ErrorHidden by higher priorityA higher-priority context consumes the key, so this mapping is dropped at rebuild. The action never sees the key.Rebind the lower mapping, untick Consume on the higher action if both should fire, remove whichever is the duplicate, or accept it when the higher context is a screen meant to own the key while open.
ErrorAction unreachableEvery mapping of an action in the scenario is hidden. The action can never fire here.Fix the individual Hidden rows.
ErrorChord action unmappedA Chorded Action trigger names an action nothing active maps; the chord can never fire.Map the chord action in an active context.
ErrorInvalid mappingNull action, invalid key, or a null trigger or modifier entry.Repair the entry in the context asset.
WarningSame priority ambiguityTwo contexts at equal priority map a key and at least one consumes it. Add order decides, and nothing records it.Give them different priorities: screens above always-on contexts, gameplay layers one step apart.
WarningChorded mapping consumesA mapping with a chord gate has Consume ticked, so it claims the key for every lower context whether or not the chord is held.Untick Consume on the chorded action (Auto fix).
WarningConsumed by gated mappingThe same situation, seen from a mapping it already hid.Same fix.
WarningGate blocks without siblingAn exact-match gate requiring no modifiers blocks whenever any modifier is held, and no chorded mapping on the key benefits.Switch the trigger to yield-to-sibling semantics, or remove it.
WarningSame context shared key / Cross context both fire / Gate overlapTwo different actions fire on one press.Accept it if intended; otherwise rebind or remove one side.
WarningValue type mismatch / Reserved action overlap / Duplicate mappingThe issues the engine's own QueryMapKeyInContextSet reports.Add modifiers, move the other action, remove the duplicate.
InfoChord family, Chord blocker caveat, Unevaluated gate, Context filtered, Context redirected, Rebindable gate defaultContext for reading the rest; nothing is wrong by itself.None. Unevaluated gate: see step 9.
Verify
The status line at the bottom counts contexts (active), mappings, keys, and errors / warnings / info / accepted. Give two contexts the same priority with a shared key and a Same priority ambiguity row appears; change one priority and it goes away on its own.

6. Read the Key Map view

Switch to Key Map (1) to see the same analysis from the key's point of view: one row per key, its receivers listed in the engine's evaluation order (2). An active receiver is white; a hidden one is dimmed with [HIDDEN by ...] after it; (consumes) marks the mapping that claims the key; gate: Shift+ shows a chord condition; gate: ? marks a custom trigger the analyzer could not evaluate (step 9). This is the view to use when someone reports key X does nothing - find the key and read down.

Key Map (1): every key with its receivers in evaluation order (2).
Verify
Find a key you know is bound in two contexts; both receivers appear, and the lower one is dimmed if the higher one consumes.

7. Fix what it found

Every finding the tool can repair shows a button in the Fix column. There are four kinds:

ButtonTierWhat it means
FixAutoAlways correct: a chorded mapping that consumes, a duplicate mapping, a screen context tied with a gameplay context. Safe to apply in bulk with Fix all Auto.
Options...ProposeA concrete edit you should look at first, usually one of several: rebind the hidden mapping to a free key on the same device (the list only offers keys nothing active uses), stop the higher action consuming so both fire, remove the mapping, raise one of two tied contexts.
Accept...AcceptNo asset change. Two actions firing on one press, or a screen's action hiding a gameplay action while the screen is open, is a design choice; accepting records the pair on the scenario so it stops being reported. Save the scenario to keep it.
Why?ManualExplanation only: a chord action nobody maps, an invalid mapping, a reserved key. Needs a design decision.

Every button opens the same Review window. Tick the fixes to apply (1), read the tier (2) and the exact edits listed under each fix - asset, property, old value, new value (3) - then press Apply (4). Everything applies in one Undo step; packages are marked dirty, not saved, so you can still look at the assets before committing. The scenario updates when a context priority changed, and the analysis re-runs so the fixed rows disappear.

Fix all Auto on the Gameplay scenario: the checkbox (1), the tier badge (2), the edit with old and new value (3), and Apply (4).

A Propose fix shows a dropdown (1) with every option the tool could find; the first is its best guess. For a hidden mapping the list is Rebind to <free key> entries, then Untick Consume on <the hider> (2), then Remove the mapping, and finally Remove the higher mapping instead for the case where the higher one is the duplicate (a screen that rebinds a global navigation action on the same key), and Accept when the hiding is the design: a screen owns the key while it is open and the gameplay action underneath is meant to wait. Accepting records the pair on the scenario like any other accept and also retires the Action unreachable row it caused. When the hidden mapping is itself a chord, the untick option comes first: moving a chorded mapping defeats the chord.

An Options review: the dropdown of alternatives (1), including letting the higher action stop consuming (2).
Consumption is decided at rebuild time
The Auto fix for a chorded mapping unticks Consume Lower Priority Enhanced Input Mappings on its action. Only the engine's own Chorded Action trigger is exempt from consumption; a custom chord that consumes drops every lower mapping on the key before the chord is ever evaluated. This is the single most common cause of my chord works but the plain key died.
Verify
Press Fix all Auto, apply, and the Auto rows disappear from the Clashes view while the touched assets show as dirty in the Content Browser. Edit -> Undo reverts all of them at once.

8. Save the scenario

Type a name in the box next to the scenario dropdown and press Save (6). The scenario - contexts, priorities, input mode tags, key profile, processor toggle, and the accepted pairs - is written to Config/DefaultEditor.ini under UCrimsonInputClashSettings::InputClashScenarios, so it travels with the project and the team shares it. New starts an empty one; Delete removes the saved one. A * after the name in the dropdown means unsaved changes.

Scripting
Crimson.InputClash.Report <Name> prints a saved scenario's full report to the log, Crimson.InputClash.Fixes <Name> prints the numbered fixes it would propose, Crimson.InputClash.Open <Name> opens the tab on it, and Crimson.InputClash.Apply <Name> [auto] [accept] [<fix>[=<option>] ...] [save] applies fixes by number (auto takes every Auto fix, accept every Accept fix, 3=1 takes option 1 of fix #3) through the same applier as the Review page, writes the scenario back to the config, and with save saves the touched packages. All four work from -ExecCmds in a commandlet-style editor run, which is how to gate a build on zero input errors.

9. Teach it your custom chord trigger (optional)

The analyzer understands the engine's Chorded Action trigger by itself. Any other Implicit or Blocker trigger is opaque: its mapping shows gate: ? in the Key Map and an Unevaluated gate info row, and the analyzer treats it as unconditional. To make it precise, the trigger describes the condition it enforces: one or more alternatives (keys, modifier tags, or actions that must be held) and how they match - Exact (the held set must equal the condition; an empty condition means nothing may be held), AtLeast (extras are ignored, like the engine chord), or YieldToChordedSibling (fires unless another mapping on the same key claims the held set exactly).

Open your trigger Blueprint (parent class Input Trigger). In Class Settings -> Interfaces add Crimson Input Trigger Gate Descriptor, then implement Describe Input Gate: Make Crimson Input Trigger Gate -> Return Node, with Alternatives holding one Make Crimson Input Gate Condition whose Held Keys (or Held Modifier Tags) lists what your trigger requires, and Match set to Exact, At Least, or Yield To Chorded Sibling. Leave Statically Known ticked. The Mapping Key input tells you which mapping the trigger instance sits on, for triggers whose condition depends on the key.

Choosing a match mode
A trigger that hard-blocks its mapping whenever its chord is not held describes Exact - an empty condition then means nothing may be held, which is what lets plain Y stand down while RT+Y fires. A trigger that only stands aside for a more specific sibling on the same key describes YieldToChordedSibling. AtLeast is how the engine's own Chorded Action behaves: extras held are ignored. If the player can rebind the chord, set bAuthoredDefaultOnly so reports note that an override may change the outcome.

Use HeldModifierTags rather than raw keys when your chord is authored as an Input.Modifier.* tag: tags resolve through ICrimsonInputModifierRegistry (Input/ICrimsonInputModifierRegistry.h) when a registry is present, so a tag-based chord and an engine Chorded Action on the same physical modifier read as one held identity. With no registry the tags stay opaque but still compare against each other.
Verify
Analyze a context that uses your trigger. The gate: ? in the Key Map becomes gate: <your description>, and the Unevaluated gate row for it is gone.

10. Propose your own fixes (optional, C++)

The fix layer has the same hook as the analysis. Register an ICrimsonInputClashFixer and it runs before the built-in fixers, so it can claim a finding first and offer repairs that only make sense for your conventions - for a chord trigger of your own, set its Block When Unchorded flag to false as the alternative to unticking Consume. The edit builders in CrimsonInputClashEdits (consume flag, rebind, remove mapping, priority on a discovered source) cover the common asset writes; anything else is an FCrimsonInputClashEdit with your own Apply lambda. For restructuring a context, UCrimsonInputClashEditLibrary::MoveActionMappings(From, Action, To) moves every mapping of an action with its triggers, modifiers, and per-mapping settings; it is Blueprint-callable and reachable from editor Python as unreal.CrimsonInputClashEditLibrary.move_action_mappings.

cpp
// MyProjectEditorModule.cpp - propose repairs for your own conventions
#include "InputClash/CrimsonInputClashFixTypes.h" // CrimsonInputEditor
class FMyChordFixer : public ICrimsonInputClashFixer
{
public:
virtual FName GetName() const override { return TEXT("MyChord"); }
virtual void Propose(const FCrimsonInputClashFixContext& Context, TArray<FCrimsonInputClashFix>& OutFixes) const override
{
const FCrimsonInputClashReport& Report = *Context.Report;
for (int32 Index = 0; Index < Report.Findings.Num(); ++Index)
{
const FCrimsonInputClashFinding& Finding = Report.Findings[Index];
if (Finding.Category != ECrimsonInputClashCategory::GateBlocksWithoutSibling)
{
continue;
}
FCrimsonInputClashFix Fix;
Fix.FindingIndex = Index;
Fix.Tier = ECrimsonInputClashFixTier::Propose;
Fix.Title = FText::FromString(TEXT("Loosen the chord on this mapping"));
Fix.Rationale = FText::FromString(TEXT("Switch the trigger to yield-to-sibling semantics."));
FCrimsonInputClashFixOption& Option = Fix.Options.AddDefaulted_GetRef();
Option.Label = FText::FromString(TEXT("Set Block When Unchorded = false"));
// Build an FCrimsonInputClashEdit: Asset, Description, OldValue, NewValue, and an Apply lambda
// that calls Modify(), writes the property, PostEditChange(), and MarkPackageDirty().
OutFixes.Add(MoveTemp(Fix));
}
}
};
void FMyProjectEditorModule::StartupModule()
{
FCrimsonInputClashFixerRegistry::Get().Register(MakeShared<FMyChordFixer>());
}

Troubleshooting

SymptomCauseWhat to do
Discover finds contexts but no application sitesThe project applies contexts from C++ only, or through a struct whose priority field is not named with Priority.Add contexts by hand with Add context... and type the priorities. Rename the field if you own it.
A screen's actions are all Hidden by higher priority by an always-on contextThe screen shares a priority with the always-on context, or sits below it.Raise the screen's Input Mapping Priority; the Auto fix does exactly this.
Everything is filtered and nothing is analyzedA Menu tag is set and the project's default input mode query is NONE(InputMode.Menu).Expected for gameplay contexts. Add the screen's context to the scenario; it is Do Not Filter and stays active.
A Same priority ambiguity row has no Fix buttonThe tab has no discovery data, so the fixer does not know which asset applies the context.Press Discover (or open with Crimson.InputClash.Open <Name> discover). Fixes are proposed again as soon as discovery finishes.
The Fix button is missing on a rowNo fixer claims that category (Info rows, chord action unmapped), or the mapping's context could not be resolved.Read the Details column; Info rows never have fixes.
Apply reports could not be appliedThe asset changed since the analysis (someone edited it, or a previous fix moved the mapping).Press Analyze and apply again from the fresh report.
gate: ? on a mappingA custom Implicit or Blocker trigger without a descriptor.Step 9.
A context you just edited still analyzes with its old mappingsA context processor served a cached processed copy. Any processor that caches its processed form has to drop that copy when the source asset changes.Re-run Analyze. If a project processor caches, invalidate on OnObjectPropertyChanged and OnObjectTransacted.

See also

  • API Reference