CFXControl Flex Wiki
English中文

Mod Compatibility

Control Flex is built for mid-to-large modpacks: zero configuration by default, escalating only when a mod's input refuses to behave. This page maps out what each of the five tools can do, when to climb to the next one, and where the result ends up.

1. The escalation ladder

From zero cost to writing code — a ladder you only climb when the rung below does not work. Each step down is more precise, and more expensive to maintain.

Tool What you need What it covers Where the result lives Cost
Auto-discovery Nothing Mods that register their keys through KeyMapping None (registered at runtime) Zero
In-game mod adaptation A controller and a few minutes Key layering, plus stick and cursor behavior for screens and overlays compat/user/<mod_id>.json Low
Compat configs A network connection, or a ready-made file The shareable form of the two rungs above, plus dispatch channels, key suppression and tips compat/{default,mods,user}/ Low
Hand-written compat JSON A text editor and the field reference Fine-grained rules: per-key channels, item suppression, phase persistence, per-screen stick parameters compat/user/<mod_id>.json Medium
Bridge mod Java + Gradle Input systems that bypass KeyMapping, runtime state, custom-drawn UIs Separate JAR + compat/mods/*.json High

Most modpacks stop at rungs 1–3. Only a handful of mods genuinely need a bridge — usually the ones that ship their own input system: EMI, Create's train console, Immersive Vehicles, Epic Fight.

2. When to climb a rung

  1. First check Key Mapping for it — if the key is there, it is a standard KeyMapping mod and rungs 2 / 3 will do.
  2. The key exists but nothing happens in a screen — usually the wrong phase or the wrong dispatch path: add a screen / overlay rule on rung 2, then change the channel on rung 3.
  3. Nothing on press, or the action fires twice — the dispatch channel is wrong (eventBus and keyMapping both firing). Pin it down on rung 4.
  4. The key never shows up at all — the mod keeps bindings in its own config, polls raw key state, or reads the gamepad directly. Only rung 5 can reach it.
  5. The mod has runtime state such as a battle mode — the bridge pushes the state (IPlayerStateRegistry) and JSON consumes it through itemSuppressKeys' playerState condition.

3. One data model underneath all five

Whichever rung you use, what lands on disk is the same compat JSON. The core is three key sections plus one dispatch concept:

Section Active when Typical use
inGameKeys No screen, no overlay Combat keys, skill keys, transformation keys
screenKeys A screen (GUI) is open Inventory, crafting, recipe lookup
overlayKeys An overlay is open (wheels or circles drawn over the HUD) Spell wheels, radial menus, photo HUDs

How a press reaches the mod is decided by the dispatch channel: keyMapping, eventBus, glfwPoll, screenInput, virtualKbm. Different keys in the same file can use different channels — which is also the fix for double-firing keys.

4. Where the result lives: three layers

Compat configs load from three layers, priority user > mods > default; the same mod_id is replaced wholesale, never merged field by field. Which layer to edit — and what can overwrite it — is covered in Editing configs by hand.

5. Where to go next

Still misbehaving? Check in this order

  1. Look at Key Mapping — is the action on the right layer (Main / Screen / Overlay)?
  2. Open Mod Adaptation for that mod — add a screen / overlay rule, or apply a community config.
  3. If the mod only listens for physical keys, bind it through Virtual KBM.
  4. Search the log for [ModCompat] to see whether the config loaded at all, and which gate stopped it.