Keybinding Manager
Create keyboard shortcuts with a fluent API: simple keys, combos, double-tap, and context-aware callbacks.
Introduction
The Keybinding Manager lets you create keyboard shortcuts for your mod without
wrestling with Forge's raw keybinding infrastructure. Using a clean fluent API, you can declare
simple keys, multi-key combos (e.g. Ctrl+Shift+X), double-tap shortcuts, and attach
onPress, onRelease, or onHold callbacks to each binding.
Bindings are context-aware: you can restrict a shortcut to be active only in-game, only when a GUI is open, or always. Automatic conflict detection warns you at registration time if two bindings share the same key and context, making debugging painless.
Call EriKeys.create(...).register() inside your ClientProxy.init()
method, during the FMLInitializationEvent. Registering on the server side has no effect
— keybindings are client-only.
EriKeys — Static API
EriKeys is the entry point for the entire Keybinding Manager. Every binding starts
with a call to EriKeys.create(id), which returns a fluent builder. Chain the methods
you need, then finish with .register().
Simple key
The most basic binding: one key, one action.
EriKeys.create("open_menu")
.key(Keyboard.KEY_G)
.category("My Mod")
.onPress(() -> openMenu())
.register();
Combo — Ctrl+Shift+G
Use .combo(KeyCombo) instead of .key(int) to require modifier keys.
Combos are evaluated only when every specified modifier is held at the moment the main key is pressed.
EriKeys.create("debug_mode")
.combo(KeyCombo.of(Keyboard.KEY_G).ctrl().shift())
.category("My Mod")
.context(KeyContext.IN_GAME)
.onPress(() -> toggleDebug())
.register();
Double-tap
Pass a maximum tick window to .doubleTap(maxTicks). The callback fires only when
the key is pressed twice within that window. A value of 10 equals half a second
at 20 ticks/second.
EriKeys.create("dash")
.key(Keyboard.KEY_W)
.doubleTap(10)
.category("My Mod")
.onPress(() -> dash())
.register();
Hold — onHold / onRelease
Use .onHold(Runnable) to run code every tick the key is held, and
.onRelease(Runnable) to react when the key is lifted.
EriKeys.create("sprint")
.key(Keyboard.KEY_R)
.category("My Mod")
.onHold(() -> sprint())
.onRelease(() -> stopSprint())
.register();
Builder method reference
Every method in the builder returns this, so they can be freely chained in any order.
EriKeys.create(String id) // Start a new binding with the given unique ID
.key(int keyCode) // Bind to a single key (Keyboard.KEY_*)
.combo(KeyCombo combo) // Bind to a key combination
.category(String category) // Display category in the vanilla controls screen
.context(KeyContext context) // Restrict activation context (default: ALWAYS)
.doubleTap(int maxTicks) // Require two presses within maxTicks ticks
.onPress(Runnable callback) // Called on key press (or second tap if doubleTap)
.onRelease(Runnable callback) // Called when key is released
.onHold(Runnable callback) // Called every tick while key is held
.register(); // Finalise and register the binding
The string passed to EriKeys.create() must be unique across your entire mod.
A good convention is "modid.action_name" — for example "myrpgmod.ability1".
KeyCombo — Combinations
KeyCombo describes a key together with optional modifier requirements.
Build one with the static factory KeyCombo.of(keyCode), then chain modifiers.
KeyCombo.of(Keyboard.KEY_G) // G only (no modifiers)
KeyCombo.of(Keyboard.KEY_G).ctrl() // Ctrl + G
KeyCombo.of(Keyboard.KEY_G).ctrl().shift() // Ctrl + Shift + G
KeyCombo.of(Keyboard.KEY_G).alt() // Alt + G
Modifier methods available on KeyCombo:
.ctrl()— requires the Control key to be held.shift()— requires the Shift key to be held.alt()— requires the Alt key to be held
You can chain as many modifiers as you like. KeyCombo.of(KEY_G).ctrl().shift().alt()
will only fire when all three modifiers are held simultaneously.
KeyContext — Enum
KeyContext controls when a binding is active. Assign it with
.context(KeyContext.XXX) on the builder. If you omit it, the default is
ALWAYS.
KeyContext.IN_GAME // Active only when no GUI is open (pure gameplay)
KeyContext.IN_GUI // Active only when a GUI screen is open
KeyContext.ALWAYS // Always active, regardless of GUI state (default)
Choosing the right context prevents accidental triggers. For example, a dash ability bound to
W should use IN_GAME so it never fires while you are typing in a chat box.
KeyContext.IN_GUI is useful for shortcuts inside your own menus — for example
pressing Escape or F to trigger a specific action while a custom
EriAPI GUI is open.
KeyConflictDetector
KeyConflictDetector runs automatically every time a binding is registered via
.register(). You do not need to call it manually.
At registration time it checks whether any already-registered binding shares the same effective
key (main key + modifiers) and the same KeyContext. If a conflict is found, a
warning is written to the game log:
[EriAPI/WARN] KeyConflictDetector: binding "mymod.ability2" conflicts with
"mymod.ability1" (same key G + context IN_GAME). Both are registered but
only the first one may fire reliably.
Both conflicting bindings are still registered. The warning is informational — it is up to you to resolve the conflict by changing one of the keys or contexts.
Complete Example
The snippet below registers two ability shortcuts for a hypothetical RPG mod. Both are restricted to in-game context so they never interfere with chat or menus. The second uses a combo to avoid conflicting with the first.
// In ClientProxy.init()
EriKeys.create("mymod.ability1")
.key(Keyboard.KEY_V)
.category("My RPG Mod")
.context(KeyContext.IN_GAME)
.onPress(() -> useAbility(1))
.register();
EriKeys.create("mymod.ability2")
.combo(KeyCombo.of(Keyboard.KEY_V).shift())
.category("My RPG Mod")
.context(KeyContext.IN_GAME)
.onPress(() -> useAbility(2))
.register();
Because ability2 uses Shift+V while ability1 uses plain
V, they do not conflict. KeyConflictDetector will log no warning.
Show the player a visual confirmation when an ability is triggered:
NotificationManager.getInstance().success("Ability 1 activated!");