# How Key Bindings Are Configured and Managed in the Undertale-Changer Template

> Discover how Undertale-Changer-Template manages key bindings. Learn about its static repository, runtime selector, and configuration UI for easy key reassignment in your game.

- Repository: [Archived AIk/undertale-changer-template](https://github.com/arch-aik/undertale-changer-template)
- Tags: how-to-guide
- Published: 2026-02-25

---

**The Undertale-Changer Template centralizes key binding management through a static repository in [`KeyBindings.cs`](https://github.com/arch-aik/undertale-changer-template/blob/main/KeyBindings.cs) that stores three default mapping tables, a runtime selector in `SettingsStorage.KeyBindingType` to switch between them, and a configuration UI in [`SettingsController.cs`](https://github.com/arch-aik/undertale-changer-template/blob/main/SettingsController.cs) that enables players to reassign keys without restarting the game.**

The `arch-aik/undertale-changer-template` repository implements a flexible input system for Unity-based Undertale fangames. Understanding how key bindings are configured and managed allows developers to customize default layouts, add new actions, or create custom input handling while maintaining compatibility with the existing settings UI.

## Default Binding Tables in KeyBindings.cs

All default key mappings live in [`Assets/Scripts/UCT/Settings/KeyBindings.cs`](https://github.com/arch-aik/undertale-changer-template/blob/main/Assets/Scripts/UCT/Settings/KeyBindings.cs). This static class defines three distinct `KeyBindingType` tables—**Primary**, **SecondaryA**, and **SecondaryB**—each mapping logical action names (e.g., `MoveDown`, `Confirm`, `Backpack`) to Unity `KeyCode` values.

### The Three KeyBindingType Tables

The `_keyBindings` dictionary initializes the default layouts in static field initializers:

```csharp
private static Dictionary<KeyBindingType, Dictionary<string, KeyCode>> _keyBindings = new()
{
    { KeyBindingType.Primary, new Dictionary<string, KeyCode>
        { { MoveDown, KeyCode.DownArrow }, { Confirm, KeyCode.Z }, … } },
    { KeyBindingType.SecondaryA, new Dictionary<string, KeyCode>
        { { MoveDown, KeyCode.S }, { Confirm, KeyCode.Return }, … } },
    { KeyBindingType.SecondaryB, new Dictionary<string, KeyCode>
        { { MoveDown, KeyCode.None }, { Confirm, KeyCode.None }, … } }
};

```

*Source: [KeyBindings.cs lines 30-84](https://github.com/arch-aik/undertale-changer-template/blob/main/Assets/Scripts/UCT/Settings/KeyBindings.cs#L30-L84)*

## Selecting the Active Binding Table

The template uses [`SettingsStorage.cs`](https://github.com/arch-aik/undertale-changer-template/blob/main/SettingsStorage.cs) to track which binding table is active at runtime. The `KeyBindingType` property defaults to `Primary` but can be switched to `SecondaryA` or `SecondaryB` to instantly change the control scheme.

```csharp
public static KeyBindingType KeyBindingType { get; set; } = KeyBindingType.Primary;

```

*Source: [SettingsStorage.cs line 34](https://github.com/arch-aik/undertale-changer-template/blob/main/Assets/Scripts/UCT/Settings/SettingsStorage.cs#L34)*

To cycle between tables programmatically, the `SettingsController` uses an enum increment helper:

```csharp
SettingsStorage.KeyBindingType = EnumService.IncrementEnum(SettingsStorage.KeyBindingType);

```

*Source: [SettingsController.cs line 411](https://github.com/arch-aik/undertale-changer-template/blob/main/Assets/Scripts/UCT/Settings/SettingsController.cs#L411)*

## Querying Keys During Gameplay

Gameplay code never hardcodes `KeyCode` values. Instead, [`InputService.cs`](https://github.com/arch-aik/undertale-changer-template/blob/main/InputService.cs) provides a centralized wrapper that translates logical actions into the current binding lookup.

When checking for input, `InputService` retrieves the full dictionary from `KeyBindings` and maps specific `KeyCode` queries to their logical indices:

```csharp
public static bool GetKeyDown(KeyCode key)
{
    var keyCodes = KeyBindings.GetDictionary();            // all tables
    return key switch
    {
        KeyCode.DownArrow => GetKeyDownFrom(keyCodes, 0),  // index 0 → MoveDown
        KeyCode.Z => GetKeyDownFrom(keyCodes, 4),          // index 4 → Confirm
        …
        _ => throw new ArgumentNullException($"Unknown {key}")
    };
}

```

*Source: [InputService.cs lines 14-24](https://github.com/arch-aik/undertale-changer-template/blob/main/Assets/Scripts/UCT/Service/InputService.cs#L14-L24)*

The internal `GetKeyDownFrom` method checks the active `KeyBindingType` against the stored `KeyCode` using Unity's `Input.GetKeyDown`:

```csharp
private static bool GetKeyDownFrom(Dictionary<KeyBindingType, Dictionary<string, KeyCode>> keyCodes, int index)
{
    var result = keyCodes.Any(keyBinding
        => KeyBindings.GetInputEveryKeyCodeAtIndex(index, keyBinding, Input.GetKeyDown));
    return result;
}

```

*Source: [InputService.cs lines 36-44](https://github.com/arch-aik/undertale-changer-template/blob/main/Assets/Scripts/UCT/Service/InputService.cs#L36-L44)*

## Runtime Key Reassignment

The [`SettingsController.cs`](https://github.com/arch-aik/undertale-changer-template/blob/main/SettingsController.cs) handles the interactive rebinding UI. When a player selects a `ConfigurableKeyFalse` option, the controller enters a listening state (`_isSettingKey = true`) and waits for the next key press via `GetSettingKeyControl()`.

Upon capturing input, the system performs two critical operations:

1. **Duplicate resolution**: Any other action already using the pressed key has its binding swapped with the target action's previous key.
2. **Storage update**: The new `KeyCode` is committed to the active table via `KeyBindings.SetKeyCode`.

```csharp
var oldKeyCodeStorage = KeyBindings.GetKeyCode(SettingsStorage.KeyBindingType, dataName);
...
KeyBindings.SetKeyCode(SettingsStorage.KeyBindingType, dataName, pressedKeycode);

```

*Source: [SettingsController.cs lines 757-771](https://github.com/arch-aik/undertale-changer-template/blob/main/Assets/Scripts/UCT/Settings/SettingsController.cs#L757-L771)*

Players can also restore factory defaults through a reset handler that invokes `KeyBindings.ResetDictionary()`:

```csharp
private static void GetKeyDownToKeyBindingsReset()
{
    if (InputService.GetKeyDown(KeyCode.Z))
    {
        KeyBindings.ResetDictionary();
    }
}

```

*Source: [SettingsController.cs lines 90-96](https://github.com/arch-aik/undertale-changer-template/blob/main/Assets/Scripts/UCT/Settings/SettingsController.cs#L90-L96)*

## Programmatic API Reference

Developers can manipulate bindings directly through the static `KeyBindings` class without using the UI:

| Operation | Method | Example |
|---|---|---|
| **Get a key** | `KeyBindings.GetKeyCode(type, actionName)` | `KeyCode confirm = KeyBindings.GetKeyCode(KeyBindingType.Primary, "Confirm");` |
| **Set a key** | `KeyBindings.SetKeyCode(type, actionName, key)` | `KeyBindings.SetKeyCode(KeyBindingType.Primary, "Confirm", KeyCode.Space);` |
| **Set by index** (used for UI iteration) | `KeyBindings.SetKeyCodeAtIndex(type, index, key)` | `KeyBindings.SetKeyCodeAtIndex(KeyBindingType.Primary, 4, KeyCode.Space);` |
| **Reset all** | `KeyBindings.ResetDictionary()` | `KeyBindings.ResetDictionary();` |

*Sources: [KeyBindings.cs lines 85-108 (set/get), 98-108 (by index), 139-155 (reset)](https://github.com/arch-aik/undertale-changer-template/blob/main/Assets/Scripts/UCT/Settings/KeyBindings.cs#L85-L108)*

## Practical Code Examples

### Query a Binding in Gameplay

Gameplay scripts should use `InputService` rather than Unity's raw `Input` class to respect the player's chosen layout:

```csharp
using UCT.Service;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    void Update()
    {
        // Move based on the *currently selected* key-binding table
        if (InputService.GetKeyDown(KeyCode.DownArrow))
            MoveDown();

        if (InputService.GetKeyDown(KeyCode.Z))   // "Confirm" action
            ConfirmSelection();
    }
}

```

### Change a Key Programmatically

Switch the active table or modify specific bindings without UI interaction:

```csharp
using UCT.Settings;
using UnityEngine;

// Switch the whole table to the secondary set
SettingsStorage.KeyBindingType = KeyBindingType.SecondaryA;

// Re-assign the "Backpack" button in the primary table
KeyBindings.SetKeyCode(KeyBindingType.Primary, "Backpack", KeyCode.B);

```

### Reset All Bindings to Defaults

Restore factory defaults across all three tables:

```csharp
using UCT.Settings;

// Restores the three default tables (Primary, SecondaryA, SecondaryB)
KeyBindings.ResetDictionary();

```

### Hook into the Configuration UI

Trigger the settings screen from custom scripts:

```csharp
using UCT.Settings;
using UnityEngine;

public class ShortcutOpener : MonoBehaviour
{
    void Update()
    {
        // Press V in overworld to open the Settings UI (the template already does this)
        if (InputService.GetKeyDown(KeyCode.V) && !overworldControl.isSetting)
            SettingsController.Instance.OpenSetting();
    }
}

```

## Summary

- **Centralized storage**: All default mappings reside in [`KeyBindings.cs`](https://github.com/arch-aik/undertale-changer-template/blob/main/KeyBindings.cs) as three static dictionaries (`Primary`, `SecondaryA`, `SecondaryB`).
- **Runtime selection**: `SettingsStorage.KeyBindingType` determines which table is active, allowing instant switching between control schemes.
- **Abstraction layer**: `InputService` routes Unity input checks through the active binding table so gameplay code remains layout-agnostic.
- **Live rebinding**: `SettingsController` provides a UI for capturing new keys, resolving duplicates by swapping conflicting bindings, and persisting changes immediately.
- **Programmatic access**: Static methods `GetKeyCode`, `SetKeyCode`, and `ResetDictionary` allow scripts to manipulate bindings directly without UI interaction.

## Frequently Asked Questions

### Where are the default key bindings defined in the Undertale-Changer Template?

Default key bindings are defined in [`Assets/Scripts/UCT/Settings/KeyBindings.cs`](https://github.com/arch-aik/undertale-changer-template/blob/main/Assets/Scripts/UCT/Settings/KeyBindings.cs) within the static `_keyBindings` dictionary. This field initializes three tables—`Primary`, `SecondaryA`, and `SecondaryB`—that map logical action names like `MoveDown` and `Confirm` to specific Unity `KeyCode` values such as `KeyCode.DownArrow` and `KeyCode.Z`.

### How does the game know which key binding set to use at runtime?

The active binding set is determined by the `SettingsStorage.KeyBindingType` property, which defaults to `KeyBindingType.Primary`. When a player selects a different control scheme in the settings menu, or when code assigns a new value such as `KeyBindingType.SecondaryA`, `InputService` immediately begins querying the corresponding dictionary from [`KeyBindings.cs`](https://github.com/arch-aik/undertale-changer-template/blob/main/KeyBindings.cs) without requiring a scene reload.

### Can players rebind keys without restarting the game?

Yes. The [`SettingsController.cs`](https://github.com/arch-aik/undertale-changer-template/blob/main/SettingsController.cs) handles live rebinding through a listening state triggered by `ConfigurableKeyFalse` options. When activated, the controller captures the next key press via `GetSettingKeyControl()`, resolves duplicate bindings by swapping conflicting keys, and commits the change instantly using `KeyBindings.SetKeyCode`. The new binding is active immediately in the game session.

### How do I reset key bindings to default values programmatically?

To restore all bindings to their original defaults, invoke the static `KeyBindings.ResetDictionary()` method. This routine repopulates the internal dictionaries with the factory defaults defined in the static constructor or field initializers of [`KeyBindings.cs`](https://github.com/arch-aik/undertale-changer-template/blob/main/KeyBindings.cs), affecting all three tables (`Primary`, `SecondaryA`, and `SecondaryB`) simultaneously. This is the same method called when the player presses the reset key in the settings UI.