diff --git a/src/main/java/codechicken/nei/KeyManager.java b/src/main/java/codechicken/nei/KeyManager.java index ff15da80..d8790a42 100644 --- a/src/main/java/codechicken/nei/KeyManager.java +++ b/src/main/java/codechicken/nei/KeyManager.java @@ -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 trackers = new LinkedList<>(); - private static final Map keyBindings = new HashMap<>(); + private static final Map 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(); } } diff --git a/src/main/java/codechicken/nei/NEIClientConfig.java b/src/main/java/codechicken/nei/NEIClientConfig.java index 3cf1de99..743059e5 100644 --- a/src/main/java/codechicken/nei/NEIClientConfig.java +++ b/src/main/java/codechicken/nei/NEIClientConfig.java @@ -987,6 +987,7 @@ public class NEIClientConfig { } }); + KeyManager.requestOptionsReload(); RecipeCatalysts.loadCatalystInfo(); SubsetWidget.loadCustomSubsets(); SubsetWidget.loadHidden(); diff --git a/src/main/java/codechicken/nei/api/API.java b/src/main/java/codechicken/nei/api/API.java index f50ae735..38113916 100644 --- a/src/main/java/codechicken/nei/api/API.java +++ b/src/main/java/codechicken/nei/api/API.java @@ -224,6 +224,7 @@ public class API { KeyManager.registerKeyBinding(ident, defaultKey); } + @Deprecated public static void addHashBind(String ident, int defaultKey) { KeyManager.registerKeyBinding(ident, defaultKey); } diff --git a/src/main/java/codechicken/nei/asm/NEITransformer.java b/src/main/java/codechicken/nei/asm/NEITransformer.java index abbe14d1..485f3178 100644 --- a/src/main/java/codechicken/nei/asm/NEITransformer.java +++ b/src/main/java/codechicken/nei/asm/NEITransformer.java @@ -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"; diff --git a/src/main/java/codechicken/nei/asm/SaveOptionsFixHooks.java b/src/main/java/codechicken/nei/asm/SaveOptionsFixHooks.java new file mode 100644 index 00000000..6e5d3e3c --- /dev/null +++ b/src/main/java/codechicken/nei/asm/SaveOptionsFixHooks.java @@ -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 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 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 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); + } + } +} diff --git a/src/main/java/codechicken/nei/util/NEIKeyboardUtils.java b/src/main/java/codechicken/nei/util/NEIKeyboardUtils.java index a5764dbe..930b5341 100644 --- a/src/main/java/codechicken/nei/util/NEIKeyboardUtils.java +++ b/src/main/java/codechicken/nei/util/NEIKeyboardUtils.java @@ -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(); diff --git a/src/main/resources/assets/nei/asm/blocks.asm b/src/main/resources/assets/nei/asm/blocks.asm index 6c278236..8a5befe1 100644 --- a/src/main/resources/assets/nei/asm/blocks.asm +++ b/src/main/resources/assets/nei/asm/blocks.asm @@ -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