Concept: The Chord System

A chord requires modifier keys (Shift / Ctrl / Alt) on an action. Enforcement lives in UInputTriggerCrimsonDynamicChord, an UInputTrigger that sits in an IMC mapping's Triggers array. Because it is per mapping, the same action can carry different chords in different IMCs, and 1 / Shift+1 / Ctrl+1 can be three distinct bindings on one key.

Exact-match semantics

The trigger passes only when the held modifiers exactly equal the requirement. A chord requiring Shift fails if Ctrl is also down; a chord requiring no modifiers fails while any modifier is held. This exactness is what prevents a bare 1 from firing underneath Shift+1.

Gamepad bypass
UpdateState returns Triggered immediately for gamepad input - chords are a keyboard/mouse concern. A chorded keyboard mapping therefore never suppresses the same action on a controller.

Reading modifier state

The trigger prefers the modifier UInputAction assets you configure in UCrimsonInputSettings (Shift/Ctrl/Alt) - reading them via GetActionValue respects your own key mappings. If none are configured it falls back to raw key state (LeftShift/RightShift, etc.). Configure the actions so a player who remaps their modifier keys still chords correctly.

Inline vs rebindable

InlineRebindable
MappingNameempty (None)set to a UCrimsonPlayerMappableKeySettings.Name
Source of the chordDefaultChord on the triggerplayer override in UCrimsonInputUserSettings, else DefaultChord
Player can change itnoyes (persisted, SaveGame)
Who adds the triggeryou, on the IMC mappingauto-injected by AddMappingContextWithChordTriggers (or you, for a default)

Overrides always win over the inline DefaultChord for a rebindable mapping, so a designer default is just the starting value a player can change.

How injection works (originals stay untouched)

UCrimsonInputHelpers::CreateIMCWithChordTriggers returns a transient copy of your IMC. It walks the mappings; for any whose action uses UCrimsonPlayerMappableKeySettings and lacks a chord trigger, it adds one (with MappingName set and an empty DefaultChord). Your asset is never modified, and results are cached per source IMC. AddMappingContextWithChordTriggers is the convenience wrapper that patches then applies. This is why you must add the patched copy in place of the original - never both at once.

FCrimsonChordRequirement lives in CrimsonCommon
The bRequiresShift / bRequiresCtrl / bRequiresAlt struct is defined in CrimsonCommon so both CrimsonInput and CrimsonSettings can share it with no cross-plugin dependency. It also formats its own label via GetDisplayName(FKey).