Fix Dynamic Keybinding (#972)

This commit is contained in:
slprime authored and GitHub committed 2026-07-11 14:20:03 +03:00
1 parent f8c1f39faf
commit 835c4f7e01
7 files changed
+160 -15

No files matched your search

+54 -12
View File
@@ -5,9 +5,11 @@ import java.util.LinkedList;
import java.util.Map;
import java.util.StringJoiner;
import net.minecraft.client.Minecraft;
import net.minecraft.client.settings.KeyBinding;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import codechicken.nei.util.NEIKeyboardUtils;
import codechicken.nei.util.NEIMouseUtils;
@@ -24,8 +26,16 @@ public class KeyManager {
}
public static LinkedList<IKeyStateTracker> trackers = new LinkedList<>();
private static final Map<String, KeyBinding> keyBindings = new HashMap<>();
private static final Map<String, String> keyAliases = new HashMap<>();
private static volatile boolean pendingOptionsReload = false;
static {
// Aliases for legacy keybinds
keyAliases.put("gui.recipe", "recipe.recipe");
keyAliases.put("gui.usage", "recipe.usage");
keyAliases.put("gui.hide_bookmarks", "bookmark.hide");
}
public static KeyBinding registerKeyBinding(String ident, int defaultKey) {
return keyBindings.computeIfAbsent(ident, id -> {
@@ -39,18 +49,35 @@ public class KeyManager {
}
public static KeyBinding getKeyBinding(String ident) {
return keyBindings.get(ident);
return keyBindings.get(keyAliases.getOrDefault(ident, ident));
}
public static boolean isRegistered(String description) {
for (KeyBinding binding : keyBindings.values()) {
if (binding.getKeyDescription().equals(description)) {
return true;
}
}
return false;
}
public static int getKeyCode(String ident) {
final KeyBinding binding = keyBindings.get(ident);
final KeyBinding binding = getKeyBinding(ident);
return binding == null ? Keyboard.KEY_NONE : binding.getKeyCode();
}
public static boolean isKeyDown(String ident) {
final KeyBinding binding = keyBindings.get(ident);
final int keyCode = binding == null ? Keyboard.KEY_NONE : binding.getKeyCode();
return keyCode > Keyboard.KEY_NONE && keyCode < Keyboard.KEYBOARD_SIZE && Keyboard.isKeyDown(keyCode);
final int keyCode = getKeyCode(ident);
if (keyCode == Keyboard.KEY_NONE) {
return false;
}
if (keyCode < 0) {
return Mouse.isButtonDown(keyCode + 100);
}
return keyCode < Keyboard.KEYBOARD_SIZE && Keyboard.isKeyDown(keyCode);
}
public static boolean isHashDown(String ident) {
@@ -58,13 +85,18 @@ public class KeyManager {
}
public static boolean isHashDown(String ident, int modifierMask) {
if (isKeyDown(ident)) {
return ((modifierMask & NEIKeyboardUtils.CTRL_HASH) != 0) == NEIClientUtils.controlKey()
&& ((modifierMask & NEIKeyboardUtils.SHIFT_HASH) != 0) == NEIClientUtils.shiftKey()
&& ((modifierMask & NEIKeyboardUtils.ALT_HASH) != 0) == NEIClientUtils.altKey();
if (!isKeyDown(ident)) {
return false;
}
return false;
if (NEIKeyboardUtils.isHashKey(getKeyCode(ident))) {
return true;
}
return ((modifierMask & NEIKeyboardUtils.CTRL_HASH) != 0) == NEIClientUtils.controlKey()
&& ((modifierMask & NEIKeyboardUtils.SHIFT_HASH) != 0) == NEIClientUtils.shiftKey()
&& ((modifierMask & NEIKeyboardUtils.ALT_HASH) != 0) == NEIClientUtils.altKey();
}
public static String getKeyName(String ident) {
@@ -99,7 +131,7 @@ public class KeyManager {
}
public static boolean isPressed(String ident) {
final KeyBinding binding = keyBindings.get(ident);
final KeyBinding binding = getKeyBinding(ident);
return binding != null && binding.isPressed();
}
@@ -108,7 +140,17 @@ public class KeyManager {
return dot < 0 ? "nei.options.keys" : "nei.options.keys." + ident.substring(0, dot);
}
public static void requestOptionsReload() {
pendingOptionsReload = true;
}
public static void tickKeyStates() {
if (pendingOptionsReload) {
pendingOptionsReload = false;
Minecraft.getMinecraft().gameSettings.loadOptions();
}
for (IKeyStateTracker tracker : trackers) tracker.tickKeyStates();
}
}
@@ -987,6 +987,7 @@ public class NEIClientConfig {
}
});
KeyManager.requestOptionsReload();
RecipeCatalysts.loadCatalystInfo();
SubsetWidget.loadCustomSubsets();
SubsetWidget.loadHidden();
@@ -224,6 +224,7 @@ public class API {
KeyManager.registerKeyBinding(ident, defaultKey);
}
@Deprecated
public static void addHashBind(String ident, int defaultKey) {
KeyManager.registerKeyBinding(ident, defaultKey);
}
@@ -117,6 +117,19 @@ public class NEITransformer implements IClassTransformer {
ACC_PUBLIC | ACC_STATIC,
new ObfMapping("net/minecraft/client/settings/KeyBinding", "func_74510_a", "(IZ)V"),
asmblocks.get("m_keyBindingSetStateAll")));
transformer.add(
new MethodInjector(
new ObfMapping("net/minecraft/client/settings/GameSettings", "func_74303_b", "()V"),
asmblocks.get("saveOptionsHook"),
true));
transformer.add(
new MethodInjector(
new ObfMapping("net/minecraft/client/settings/GameSettings", "func_74303_b", "()V"),
asmblocks.get("n_saveOptionsSendSettings"),
asmblocks.get("saveOptionsRestoreHook"),
false));
}
String GuiContainer = "net/minecraft/client/gui/inventory/GuiContainer";
@@ -0,0 +1,78 @@
package codechicken.nei.asm;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import codechicken.core.CommonUtils;
import codechicken.nei.KeyManager;
import codechicken.nei.NEIClientConfig;
public final class SaveOptionsFixHooks {
private static final String KEY_PREFIX = "key_nei.options.keys.";
private static List<String> pendingRestoreLines;
private SaveOptionsFixHooks() {}
public static void onBeforeSaveOptions() {
pendingRestoreLines = null;
if (NEIClientConfig.isLoaded()) {
return;
}
final File optionsFile = new File(CommonUtils.getMinecraftDir(), "options.txt");
if (!optionsFile.exists()) {
return;
}
final List<String> missing = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new FileReader(optionsFile))) {
String line;
while ((line = reader.readLine()) != null) {
if (!line.startsWith(KEY_PREFIX)) continue;
final int colon = line.indexOf(':');
if (colon <= 0) continue;
final String description = line.substring(4, colon);
if (!KeyManager.isRegistered(description)) {
missing.add(line);
}
}
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to read key bindings before options save", e);
return;
}
if (!missing.isEmpty()) {
pendingRestoreLines = missing;
}
}
public static void onAfterSaveOptions() {
final List<String> restore = pendingRestoreLines;
pendingRestoreLines = null;
if (restore == null) {
return;
}
final File optionsFile = new File(CommonUtils.getMinecraftDir(), "options.txt");
try (FileWriter writer = new FileWriter(optionsFile, true)) {
for (String line : restore) {
writer.write(line);
writer.write(System.lineSeparator());
}
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to restore NEI key bindings after options save", e);
}
}
}
@@ -23,13 +23,13 @@ public class NEIKeyboardUtils {
keyHashMap.put(Keyboard.KEY_RSHIFT, SHIFT_HASH);
keyHashMap.put(Keyboard.KEY_LCONTROL, CTRL_HASH);
keyHashMap.put(Keyboard.KEY_LCONTROL, CTRL_HASH);
keyHashMap.put(Keyboard.KEY_RCONTROL, CTRL_HASH);
keyHashMap.put(Keyboard.KEY_LMETA, CTRL_HASH);
keyHashMap.put(Keyboard.KEY_RMETA, CTRL_HASH);
keyHashMap.put(Keyboard.KEY_LMENU, ALT_HASH);
keyHashMap.put(Keyboard.KEY_LMENU, ALT_HASH);
keyHashMap.put(Keyboard.KEY_RMENU, ALT_HASH);
}
private NEIKeyboardUtils() {}
@@ -67,7 +67,7 @@ public class NEIKeyboardUtils {
}
if (keyID != Keyboard.CHAR_NONE || hashText.isEmpty()) {
keyText.add(Keyboard.getKeyName(keyID));
keyText.add(keyID < 0 ? NEIMouseUtils.getKeyName(keyID + 100) : Keyboard.getKeyName(keyID));
}
return keyText.toString();
@@ -73,6 +73,16 @@ ILOAD 1
INVOKESTATIC codechicken/nei/asm/KeyBindingFixHooks.setKeyBindStateAll (IZ)V
RETURN
list saveOptionsHook
INVOKESTATIC codechicken/nei/asm/SaveOptionsFixHooks.onBeforeSaveOptions ()V
list n_saveOptionsSendSettings
ALOAD 0
INVOKEVIRTUAL net/minecraft/client/settings/GameSettings.func_82879_c ()V
list saveOptionsRestoreHook
INVOKESTATIC codechicken/nei/asm/SaveOptionsFixHooks.onAfterSaveOptions ()V
#begin GuiContainer patches