Context Stack
The context stack is the core of InputForge’s runtime flexibility. It lets the same physical key mean different things depending on what the player is currently doing.
How the Stack Works
Section titled “How the Stack Works”EnhancedInputSystem maintains an ordered list of active InputMappingContext resources. When a Godot input event arrives, contexts are evaluated in reverse order — the most recently added context has the highest priority.
When a context successfully handles an event (at least one mapping matches and passes its triggers), the event is consumed via GetViewport().SetInputAsHandled() and no lower-priority context sees it.
Mouse motion events are never consumed because multiple systems may need to react to them simultaneously.
Stack (bottom → top): [0] BaseContext ← lowest priority [1] VehicleContext [2] MenuContext ← highest priority (last added)Pushing and Popping Contexts
Section titled “Pushing and Popping Contexts”var system = EnhancedInputSystem.GetInstance();
// Push when entering a statesystem.AddContext(vehicleContext);
// Pop when leavingsystem.RemoveContext(vehicleContext);There is no strict push/pop ordering enforced — you can remove any context at any time regardless of insertion order. This means you can layer contexts arbitrarily:
// Gameplay + vehicle simultaneouslysystem.AddContext(gameplayContext);system.AddContext(vehicleContext);
// Only vehicle input reaches the vehicle; gameplay input still works for// actions not handled by vehicleContext (e.g. pause, map)PreventFallbackContext
Section titled “PreventFallbackContext”By default, an event that the topmost context doesn’t handle falls through to lower-priority contexts. Set PreventFallbackContext = true to stop that — only the topmost context is evaluated, regardless of whether it matched. Useful for modal states like a pause menu, where nothing underneath should react.
system.AddContext(menuContext);system.PreventFallbackContext = true; // gameplay beneath the menu goes silent// ... on close:system.RemoveContext(menuContext);system.PreventFallbackContext = false;Checking the active context
Section titled “Checking the active context”GetCurrentContext() returns the topmost active context, and InputMappingContext compares by ContextName, so you can check which context is on top without holding the exact resource instance:
if (system.GetCurrentContext() == drivingContext){ // driving is the active context right now}Binding and Unbinding Callbacks
Section titled “Binding and Unbinding Callbacks”Callbacks are registered on the context, not the system. This means the same context resource can be shared across multiple objects, each with their own callbacks:
// Player A and Player B share the same GameplayContext resource// but bind different callbacksplayerA.GameplayContext.BindAction(jumpAction, playerA.OnJump);playerB.GameplayContext.BindAction(jumpAction, playerB.OnJump);Always unbind callbacks when the subscriber is removed from the scene to avoid dangling references:
public override void _ExitTree(){ EnhancedInputSystem.GetInstance().RemoveContext(GameplayContext); GameplayContext.UnbindAction(JumpAction, OnJump); GameplayContext.UnbindAction(MoveAction, OnMove);}Callback Overloads
Section titled “Callback Overloads”BindAction accepts five callback signatures. Choose the one that matches what you actually need from the value:
// Boolean — pressed or releasedcontext.BindAction(jumpAction, (bool pressed) => { });
// Float — single axis value (X component)context.BindAction(scrollAction, (float delta) => { });
// Vector2 — two-axis value (XY components)context.BindAction(moveAction, (Vector2 dir) => { });
// Vector3 — full raw value, all three componentscontext.BindAction(rawAction, (Vector3 raw) => { });
// ContextualInputEvent — value plus the InputKey Source that firedcontext.BindAction(moveAction, (ContextualInputEvent e) => { });The last overload is for source-aware handling — when one action is fed by multiple mappings and the callback needs to know which physical source produced the value. The other four are unchanged; reach for the contextual one only when you need the source.