1.1.0
Compatibility
Changes
Changelog
Quacky's Better Keybinds — Version 1.1.0
Release Date: August 15, 2026
Type: Bug fix release
Overview
Two fixes: binds now fire on the same tick you press them (no more losing attribute/weapon swaps to a tick of lag), and binds work inside the inventory and every other container screen.
Fixes
Input no longer runs a tick behind
Symptom: every bind fired one tick (50 ms) after the key went down. Anything timing-sensitive — attribute swapping, weapon swap into an attack, hotbar juggling mid-combo — landed a tick late and often missed the window.
Cause: input was polled at END_CLIENT_TICK. The game reads keybinds part-way through Minecraft.tick(), which had already happened by then, so everything the mod set was picked up on the next tick.
Fix: input is now driven from the game's own GLFW callbacks (KeyboardHandler.keyPress, MouseHandler.onButton), the exact place vanilla registers its own presses. Bound actions are resolved and applied the moment the key event arrives, before the game reads keybinds on that same tick — identical timing to a vanilla keybind, zero added latency.
HEADof the callback updates held-key state, so combos are current before anything else sees the eventRETURNruns the binds after vanilla applied its own state, so Override Vanilla can still mute the original action- Per-tick polling is kept, moved to
START_CLIENT_TICK, and demoted to a re-sync for what callbacks can't see (window focus loss, events eaten by a screen) - Releases propagate immediately too — held actions stop on the tick you let go
Keybinds work in the inventory again
Symptom: binds did nothing in the inventory, chests, furnaces or any other container — items could not be swapped to a hotbar slot, moved to the offhand, or dropped with a custom bind.
Cause: two separate blocks. The mod skipped all bind processing whenever a screen was open, and vanilla container screens only ever compare the raw key against their own KeyMappings (checkHotbarKeyPressed), which a remapped or combo bind never matches.
Fix: a new AbstractContainerScreen mixin resolves mod binds itself and performs the matching slot operation before vanilla's check, then cancels so nothing happens twice.
Supported in containers:
| Bound action | Effect on the hovered slot |
|---|---|
| Hotbar 1–9 | Swap with that hotbar slot |
| Swap Offhand | Swap with the offhand |
| Drop | Throw the stack (hold Ctrl for the whole stack) |
| Pick Item | Clone the stack (creative) |
| Inventory | Close the screen |
Details:
- Combo and mouse-button binds work, not just single keys —
mouseClickedis handled alongsidekeyPressed - A bind only fires if the key that was just pressed is part of that combo, so a held modifier can't set an action off on an unrelated keystroke
- Typing is untouched: input aimed at a focused text field (anvil rename, creative search) is left to vanilla
- Vanilla's own preconditions are respected — a slot must be hovered, and the cursor must be empty for a swap
Other changes
- Override Vanilla is now complete. It cleared the suppressed key's held state but not its pending click, so a discrete vanilla action (drop, inventory, hotbar) could still slip through once. Both are cleared now, before mod mappings are driven.
- Actions no longer stick when a screen opens. Anything held is released once on screen open, and re-armed on close without counting as a fresh press.
Technical
New mixins
| Mixin | Target | Purpose |
|---|---|---|
KeyboardHandlerMixin |
KeyboardHandler.keyPress |
Same-tick key edges |
MouseHandlerMixin |
MouseHandler.onButton |
Same-tick mouse edges |
AbstractContainerScreenMixin |
keyPressed, mouseClicked |
Binds inside containers |
KeyMappingAccessor additionally exposes the bound key field, used to find and mute the vanilla action behind a suppressed key.
New class
ContainerBindings— maps an active bind to its container slot operation, matching the game's KeyMappings by identity rather than by name
Changed
InputManager.applyEvent(name, pressed)— single edge from a callback;update()is now a re-sync that reports whether anything movedBindingManager.getActiveBindings()/getMatchingTrigger()— read-only resolution, callable from screensBindingManager.resyncAfterScreen()— re-arm held binds with no press edgeQuackysKeyBinds— tick moved toSTART_CLIENT_TICK;onInputEvent()is the callback path
Compatibility
| Minecraft | 1.21.11 (exact; API drift) |
| Loaders | Fabric 0.19.2+ required |
| Dependencies | Fabric API, ModMenu |
| Config | Unchanged — 1.0.0 configs load as-is, no migration |
Installation
Replace quackys-better-keybinds-1.0.0.jar in mods/ with quackys-better-keybinds-1.1.0.jar. Nothing else changes.
Known Limitations
- Binds still don't fire in non-container screens (chat, pause, options) — that guard is deliberate
- Container support covers slot actions; there is no bind for shift-click quick-move, which vanilla has no keybind for either
- Actions with no registered KeyMapping cannot be bound (nothing to drive)
License
MIT. Quack responsibly.
Author
DeQuackDealer
Build Info
| Gradle | 9.4.0 |
| Loom | 1.16.2 |
| Java | 21 |
Projects on Modrinth are automatically available through a Maven repository for use with JVM build tools such as Gradle. To learn more about the Modrinth Maven API, click here.
Note: When available, you should use the creator's maven repo instead as it will have transitive dependency information that the Modrinth Maven API does not. You may also end up with duplicate dependencies if you use a mix of Modrinth and non-Modrinth Maven repositories for your dependencies, because the group identifier will be different when served through the Modrinth Maven API.
Maven coordinates:
Version ID:
build.gradle:
repositories {
exclusiveContent {
forRepository {
maven {
name = "Modrinth"
url = "https://api.modrinth.com/maven"
}
}
// forRepositories(fg.repository) // Uncomment when using ForgeGradle
filter {
includeGroup "maven.modrinth"
}
}
}
// Standard Gradle dependency
dependencies {
implementation "maven.modrinth:J4Kl3Aag:dRWsivUr"
}
// Legacy Loom dependency
dependencies {
modImplementation "maven.modrinth:J4Kl3Aag:dRWsivUr"
}

