From 22c33d8463513a8a93f480653de84fca7c8cc568 Mon Sep 17 00:00:00 2001 From: Colton Date: Sun, 11 Oct 2026 09:37:18 -0400 Subject: [PATCH 1/2] Implemented momentary keys --- .../aoba/command/commands/CmdClickgui.java | 3 +- .../net/aoba/command/commands/CmdHelp.java | 2 +- src/main/java/net/aoba/gui/GuiManager.java | 8 ++- .../aoba/gui/components/KeybindComponent.java | 34 ++++++++--- .../gui/navigation/windows/MacroWindow.java | 9 ++- .../java/net/aoba/managers/ModuleManager.java | 45 +++++++++++++-- .../net/aoba/managers/SettingManager.java | 17 ++++-- .../java/net/aoba/managers/macros/Macro.java | 9 +-- .../aoba/managers/macros/MacroManager.java | 21 +++---- .../aoba/managers/macros/MacroRecorder.java | 4 +- src/main/java/net/aoba/module/Module.java | 16 +++++- .../net/aoba/module/modules/render/XRay.java | 3 +- .../aoba/module/modules/world/Scaffold.java | 11 +++- .../aoba/settings/types/KeybindSetting.java | 16 ++++-- .../java/net/aoba/utils/input/Keybind.java | 57 +++++++++++++++++++ 15 files changed, 202 insertions(+), 53 deletions(-) create mode 100644 src/main/java/net/aoba/utils/input/Keybind.java diff --git a/src/main/java/net/aoba/command/commands/CmdClickgui.java b/src/main/java/net/aoba/command/commands/CmdClickgui.java index 22e338f7..1970487e 100644 --- a/src/main/java/net/aoba/command/commands/CmdClickgui.java +++ b/src/main/java/net/aoba/command/commands/CmdClickgui.java @@ -12,6 +12,7 @@ import net.aoba.Aoba; import net.aoba.command.Command; import net.aoba.command.InvalidSyntaxException; +import net.aoba.utils.input.Keybind; public class CmdClickgui extends Command { @@ -26,7 +27,7 @@ public void runCommand(String[] parameters) throws InvalidSyntaxException { if (parameters.length != 2) throw new InvalidSyntaxException(this); char keybind = Character.toUpperCase(parameters[1].charAt(0)); - Aoba.getInstance().guiManager.clickGuiButton.setValue(InputConstants.Type.KEYBOARD.getOrCreate((int) keybind)); + Aoba.getInstance().guiManager.clickGuiButton.setValue(Keybind.from(InputConstants.Type.KEYBOARD.getOrCreate((int) keybind))); break; case "open": Aoba.getInstance().guiManager.setClickGuiOpen(true); diff --git a/src/main/java/net/aoba/command/commands/CmdHelp.java b/src/main/java/net/aoba/command/commands/CmdHelp.java index 3c230783..c33fa0b6 100644 --- a/src/main/java/net/aoba/command/commands/CmdHelp.java +++ b/src/main/java/net/aoba/command/commands/CmdHelp.java @@ -43,7 +43,7 @@ public void runCommand(String[] parameters) { CommandManager.sendChatMessage(title); CommandManager.sendChatMessage("Name: " + ChatFormatting.LIGHT_PURPLE + module.getName() + ChatFormatting.RESET); CommandManager.sendChatMessage("Description: " + ChatFormatting.LIGHT_PURPLE + module.getDescription() + ChatFormatting.RESET); - CommandManager.sendChatMessage("Keybind: " + ChatFormatting.LIGHT_PURPLE + module.getBind().getValue().getName() + ChatFormatting.RESET); + CommandManager.sendChatMessage("Keybind: " + ChatFormatting.LIGHT_PURPLE + module.getBind().getValue().getKey().getName() + ChatFormatting.RESET); CommandManager.sendChatMessage("-".repeat(unformatted_title.length() - 2)); // mc font characters are not the same width but eh.. } } diff --git a/src/main/java/net/aoba/gui/GuiManager.java b/src/main/java/net/aoba/gui/GuiManager.java index 597003c9..3b866fff 100644 --- a/src/main/java/net/aoba/gui/GuiManager.java +++ b/src/main/java/net/aoba/gui/GuiManager.java @@ -16,6 +16,8 @@ import com.google.common.collect.Lists; import com.mojang.blaze3d.platform.InputConstants; +import com.mojang.blaze3d.platform.InputConstants.Key; + import net.aoba.Aoba; import net.aoba.AobaClient; import net.aoba.event.events.KeyDownEvent; @@ -83,6 +85,7 @@ import net.aoba.settings.types.KeybindSetting; import net.aoba.utils.input.CursorStyle; import net.aoba.utils.input.Input; +import net.aoba.utils.input.Keybind; import net.aoba.rendering.Renderer2D; import net.aoba.rendering.shaders.Shader; import net.minecraft.client.KeyMapping; @@ -95,7 +98,7 @@ public class GuiManager implements KeyDownListener, TickListener, Render2DListen private static final Minecraft MC = Minecraft.getInstance(); public KeybindSetting clickGuiButton = KeybindSetting.builder().id("key.clickgui").displayName("ClickGUI Key") - .defaultValue(InputConstants.Type.KEYBOARD.getOrCreate(InputConstants.KEY_RSHIFT)).build(); + .defaultValue(Keybind.from(InputConstants.KEY_RSHIFT)).build(); private static CursorStyle currentCursor = CursorStyle.Default; private static String tooltip = null; @@ -403,7 +406,8 @@ public void removeWindow(Window hud, String pageName) { @Override public void onKeyDown(KeyDownEvent event) { - if (clickGuiButton.getValue().getValue() == event.GetKey() && MC.gui.screen() == null && !isKeyboardInputActive) { + Keybind clickguiKeybind = clickGuiButton.getValue(); + if (clickguiKeybind.getKeyCode() == event.GetKey() && MC.gui.screen() == null && !isKeyboardInputActive) { setClickGuiOpen(!clickGuiOpen); toggleMouse(); } diff --git a/src/main/java/net/aoba/gui/components/KeybindComponent.java b/src/main/java/net/aoba/gui/components/KeybindComponent.java index 1c28319e..f1f07627 100644 --- a/src/main/java/net/aoba/gui/components/KeybindComponent.java +++ b/src/main/java/net/aoba/gui/components/KeybindComponent.java @@ -26,17 +26,20 @@ import net.aoba.utils.input.CursorStyle; import net.aoba.utils.types.MouseAction; import net.aoba.utils.types.MouseButton; +import net.aoba.utils.input.Keybind; public class KeybindComponent extends Component implements KeyDownListener { private boolean listeningForKey; private final StringComponent label; private final StringComponent keyTextComponent; + private final CheckboxComponent momentaryCheckbox; - public static UIProperty SelectedKeyProperty = new UIProperty<>("SelectedKey", InputConstants.UNKNOWN, false, true, KeybindComponent::OnSelectedKeyPropertyChanged); + public static UIProperty SelectedKeyProperty = new UIProperty<>("SelectedKey", new Keybind(InputConstants.UNKNOWN, false), false, true, KeybindComponent::OnSelectedKeyPropertyChanged); public static UIProperty HeaderProperty = new UIProperty<>("Header", "", false, true, KeybindComponent::OnHeaderPropertyChanged); - private Consumer onChanged = null; - private static void OnSelectedKeyPropertyChanged(UIElement sender, Key oldValue, Key newValue) { + private Consumer onChanged = null; + + private static void OnSelectedKeyPropertyChanged(UIElement sender, Keybind oldValue, Keybind newValue) { if(sender instanceof KeybindComponent keybind) { keybind.keyTextComponent.setProperty(StringComponent.TextProperty, keybind.getKeyDisplayText()); @@ -57,12 +60,24 @@ public KeybindComponent() { GridComponent grid = new GridComponent(); grid.addColumnDefinition(new GridDefinition(1f, RelativeUnit.Relative)); grid.addColumnDefinition(new GridDefinition(RelativeUnit.Auto)); + grid.addColumnDefinition(new GridDefinition(RelativeUnit.Auto)); + // Label label = new StringComponent(); label.setProperty(StringComponent.TextProperty, getProperty(KeybindComponent.HeaderProperty)); label.setProperty(UIElement.VerticalAlignmentProperty, VerticalAlignment.Center); grid.addChild(label); + // Checkbox + momentaryCheckbox = new CheckboxComponent(); + momentaryCheckbox.setProperty(Component.VerticalAlignmentProperty, VerticalAlignment.Center); + momentaryCheckbox.setOnChanged(e -> { + Keybind keybind = this.getProperty(KeybindComponent.SelectedKeyProperty); + this.setProperty(KeybindComponent.SelectedKeyProperty, new Keybind(keybind.getKey(), e.booleanValue())); + }); + grid.addChild(momentaryCheckbox); + + // Key Button RectangleComponent keyButton = new RectangleComponent(); keyButton.bindProperty(UIElement.BackgroundProperty, GuiManager.componentBackgroundColor); keyButton.bindProperty(UIElement.BorderProperty, GuiManager.componentBorderColor); @@ -89,10 +104,10 @@ public KeybindComponent() { } private String getKeyDisplayText() { - Key keybind = getProperty(SelectedKeyProperty); - if (keybind == null || keybind.equals(InputConstants.UNKNOWN)) + Keybind keybind = getProperty(SelectedKeyProperty); + if (keybind == null || keybind.getKey() == InputConstants.UNKNOWN) return "N/A"; - return keybind.getDisplayName().getString(); + return keybind.getKey().getDisplayName().getString(); } @@ -103,12 +118,13 @@ public void onKeyDown(KeyDownEvent event) { ? InputConstants.UNKNOWN : InputConstants.Type.KEYBOARD.getOrCreate(event.GetKey()); - setProperty(SelectedKeyProperty, key); + boolean isMomentary = momentaryCheckbox.getProperty(CheckboxComponent.IsCheckedProperty); + setProperty(SelectedKeyProperty, new Keybind(key, isMomentary)); setListeningForKey(false); event.cancel(); } } - + private void setListeningForKey(boolean state) { if (listeningForKey == state) return; @@ -131,7 +147,7 @@ protected void onLostFocus() { } } - public void setOnChanged(Consumer consumer) { + public void setOnChanged(Consumer consumer) { this.onChanged = consumer; } } diff --git a/src/main/java/net/aoba/gui/navigation/windows/MacroWindow.java b/src/main/java/net/aoba/gui/navigation/windows/MacroWindow.java index 633d8459..0de39f77 100644 --- a/src/main/java/net/aoba/gui/navigation/windows/MacroWindow.java +++ b/src/main/java/net/aoba/gui/navigation/windows/MacroWindow.java @@ -17,6 +17,7 @@ import net.aoba.gui.components.ButtonComponent; import net.aoba.gui.components.CheckboxComponent; import net.aoba.gui.components.EllipseComponent; +import com.mojang.blaze3d.platform.InputConstants.Key; import net.aoba.gui.components.GridComponent; import net.aoba.gui.components.ItemsComponent; import net.aoba.gui.components.KeybindComponent; @@ -40,6 +41,7 @@ import net.aoba.managers.macros.Macro; import net.aoba.rendering.shaders.Shader; import net.aoba.rendering.utils.PolygonBank; +import net.aoba.utils.input.Keybind; import net.aoba.gui.colors.Color; public class MacroWindow extends Window { private ButtonComponent recordButton; @@ -183,7 +185,7 @@ public MacroWindow() { // Keybind Text keybindComponent = new KeybindComponent(); - keybindComponent.setProperty(KeybindComponent.SelectedKeyProperty, InputConstants.UNKNOWN); + keybindComponent.setProperty(KeybindComponent.SelectedKeyProperty, Keybind.from(InputConstants.UNKNOWN)); keybindComponent.setProperty(KeybindComponent.HeaderProperty, "Macro Keybind"); keybindComponent.setOnChanged((key) -> { if(currentMacro != null) @@ -235,8 +237,9 @@ public MacroWindow() { if(macro.isLooping()) macroNameText += " (Loop)"; - if(macro.getKeybind() != InputConstants.UNKNOWN) - macroNameText += " [" + macro.getKeybind().getDisplayName().getString() + "]"; + Key key = macro.getKeybind().getKey(); + if(key != InputConstants.UNKNOWN) + macroNameText += " [" + key.getDisplayName().getString() + "]"; StringComponent text = new StringComponent(macroNameText); text.setProperty(UIElement.IsHitTestVisibleProperty, true); diff --git a/src/main/java/net/aoba/managers/ModuleManager.java b/src/main/java/net/aoba/managers/ModuleManager.java index 6b11310c..4626d8dd 100644 --- a/src/main/java/net/aoba/managers/ModuleManager.java +++ b/src/main/java/net/aoba/managers/ModuleManager.java @@ -19,7 +19,9 @@ import net.aoba.Aoba; import net.aoba.api.IAddon; import net.aoba.event.events.KeyDownEvent; +import net.aoba.event.events.KeyUpEvent; import net.aoba.event.listeners.KeyDownListener; +import net.aoba.event.listeners.KeyUpListener; import net.aoba.gui.GuiManager; import net.aoba.module.AntiCheat; import net.aoba.module.Module; @@ -84,9 +86,11 @@ import net.aoba.module.modules.world.*; import net.aoba.settings.Setting; import net.aoba.settings.types.EnumSetting; +import net.aoba.settings.types.KeybindSetting; +import net.aoba.utils.input.Keybind; import net.minecraft.client.Minecraft; -public class ModuleManager implements KeyDownListener { +public class ModuleManager implements KeyDownListener, KeyUpListener { private static final Minecraft MC = Minecraft.getInstance(); public ArrayList modules = new ArrayList(); @@ -214,6 +218,7 @@ public ModuleManager(List addons) { } Aoba.getInstance().eventManager.AddListener(KeyDownListener.class, this); + Aoba.getInstance().eventManager.AddListener(KeyUpListener.class, this); } public void addModule(Module module) { @@ -246,12 +251,42 @@ public void onKeyDown(KeyDownEvent event) { for (Module module : modules) { if (module.isDetectable(antiCheat.getValue())) continue; + + KeybindSetting setting = module.getBind(); + Keybind binding = setting.getValue(); + int keyCode = binding.getKeyCode(); + + if (keyCode == InputConstants.UNKNOWN.getValue()) + continue; + + + if (keyCode == event.GetKey()) { + if(binding.getIsMomentary()) + module.enable(); + else + module.toggle(); + } + } + } + } - Key binding = module.getBind().getValue(); - if (binding.getValue() == InputConstants.UNKNOWN.getValue()) + @Override + public void onKeyUp(KeyUpEvent event) { + if (GuiManager.isKeyboardInputActive()) + return; + if (event.GetKey() == InputConstants.UNKNOWN.getValue()) + return; + + if (MC.gui.screen() == null) { + for (Module module : modules) { + KeybindSetting setting = module.getBind(); + Keybind binding = setting.getValue(); + int keyCode = binding.getKeyCode(); + if (keyCode == InputConstants.UNKNOWN.getValue()) continue; - if (binding.getValue() == event.GetKey()) { - module.toggle(); + + if (binding.getIsMomentary() && keyCode == event.GetKey()) { + module.disable(); } } } diff --git a/src/main/java/net/aoba/managers/SettingManager.java b/src/main/java/net/aoba/managers/SettingManager.java index c47939c8..28feef31 100644 --- a/src/main/java/net/aoba/managers/SettingManager.java +++ b/src/main/java/net/aoba/managers/SettingManager.java @@ -24,6 +24,7 @@ import net.aoba.rendering.shaders.Shader; import net.aoba.settings.Setting; import net.aoba.settings.types.*; +import net.aoba.utils.input.Keybind; import net.aoba.utils.types.Range; import net.minecraft.client.Minecraft; import net.minecraft.core.registries.BuiltInRegistries; @@ -161,8 +162,9 @@ private static void fillProperties(Properties properties, HashSet> se properties.setProperty(setting.ID, fontSetting.getFontName()); } case KEYBIND -> { - Key key = ((Key) setting.getValue()); - properties.setProperty(setting.ID, String.valueOf(key.getValue())); + KeybindSetting keybindSetting = (KeybindSetting)setting; + Keybind key = keybindSetting.getValue(); + properties.setProperty(setting.ID, String.valueOf(key.getKeyCode() + "," + key.getIsMomentary())); } case RECTANGLE -> { Rectangle rect = (Rectangle) setting.getValue(); @@ -327,8 +329,15 @@ private static void deserializeSettings(Properties config, HashSet> s fontSetting.setFontName(value); } case KEYBIND -> { - int keyCode = Integer.parseInt(value); - setting.setValue(InputConstants.Type.KEYBOARD.getOrCreate(keyCode)); + KeybindSetting keybindSetting = (KeybindSetting) setting; + String[] keybindValue = value.split(","); + int keyCode = Integer.parseInt(keybindValue[0]); + boolean momentary = false; + if(keybindValue.length > 1) + momentary = Boolean.parseBoolean(keybindValue[1]); + + Key key = InputConstants.Type.KEYBOARD.getOrCreate(keyCode); + keybindSetting.setValue(new Keybind(key, momentary)); } case RECTANGLE -> { String[] dimensions = value.split(","); diff --git a/src/main/java/net/aoba/managers/macros/Macro.java b/src/main/java/net/aoba/managers/macros/Macro.java index 82e50ff0..49a173d6 100644 --- a/src/main/java/net/aoba/managers/macros/Macro.java +++ b/src/main/java/net/aoba/managers/macros/Macro.java @@ -15,6 +15,7 @@ import com.mojang.blaze3d.platform.InputConstants.Key; import net.aoba.managers.macros.actions.MacroEvent; import net.minecraft.client.Minecraft; +import net.aoba.utils.input.Keybind; /** * Represents a Macro that contains a list of events. @@ -24,7 +25,7 @@ public class Macro { private String filePath; private LinkedList events; private boolean looping = false; - private Key keybind = InputConstants.UNKNOWN; + private Keybind keybind = Keybind.from(InputConstants.UNKNOWN); public Macro() { } @@ -39,7 +40,7 @@ public Macro(LinkedList events, boolean looping) { this.looping = looping; } - public Macro(LinkedList events, boolean looping, Key keybind) { + public Macro(LinkedList events, boolean looping, Keybind keybind) { this.events = events; this.looping = looping; this.keybind = keybind; @@ -100,7 +101,7 @@ public void setLooping(boolean looping) { * Getter for the keybind assigned to this Macro. * @return The assigned keybind. */ - public Key getKeybind() { + public Keybind getKeybind() { return this.keybind; } @@ -108,7 +109,7 @@ public Key getKeybind() { * Setter for the keybind assigned to this Macro. * @param keybind The Key to assign. */ - public void setKeybind(Key keybind) { + public void setKeybind(Keybind keybind) { this.keybind = keybind; } diff --git a/src/main/java/net/aoba/managers/macros/MacroManager.java b/src/main/java/net/aoba/managers/macros/MacroManager.java index 2b8522f8..a80c8c35 100644 --- a/src/main/java/net/aoba/managers/macros/MacroManager.java +++ b/src/main/java/net/aoba/managers/macros/MacroManager.java @@ -32,6 +32,7 @@ import net.aoba.managers.macros.actions.MouseClickMacroEvent; import net.aoba.managers.macros.actions.MouseMoveMacroEvent; import net.aoba.managers.macros.actions.MouseScrollMacroEvent; +import net.aoba.utils.input.Keybind; import net.aoba.utils.types.ObservableList; import net.minecraft.client.Minecraft; @@ -97,7 +98,7 @@ private Macro loadMacroFromFile(File file) { String filePath = file.getPath(); LinkedList events = new LinkedList(); boolean looping = false; - Key keybind = InputConstants.UNKNOWN; + Keybind keybind = Keybind.from(InputConstants.UNKNOWN); try (DataInputStream in = new DataInputStream(new FileInputStream(filePath))) { // Read flags until we hit the terminator (0x00). @@ -105,7 +106,7 @@ private Macro loadMacroFromFile(File file) { while ((flag = in.readByte()) != FLAG_TERMINATOR) { switch (flag) { case FLAG_LOOPING -> looping = true; - case FLAG_KEYBIND -> keybind = InputConstants.Type.KEYBOARD.getOrCreate(in.readInt()); + case FLAG_KEYBIND -> keybind = Keybind.from(InputConstants.Type.KEYBOARD.getOrCreate(in.readInt())); default -> {} } } @@ -153,19 +154,19 @@ public void save() { // Write flags. if (macro.isLooping()) out.writeByte(FLAG_LOOPING); - if (macro.getKeybind() != InputConstants.UNKNOWN) { + if (macro.getKeybind().getKey() != InputConstants.UNKNOWN) { out.writeByte(FLAG_KEYBIND); - out.writeInt(macro.getKeybind().getValue()); + out.writeInt(macro.getKeybind().getKeyCode()); } out.writeByte(FLAG_TERMINATOR); // Write events. for (MacroEvent event : macro.getEvents()) { byte id = switch (event) { - case KeyClickMacroEvent e -> EVENT_KEY; - case MouseClickMacroEvent e -> EVENT_CLICK; - case MouseMoveMacroEvent e -> EVENT_MOVE; - case MouseScrollMacroEvent e -> EVENT_SCROLL; + case KeyClickMacroEvent _ -> EVENT_KEY; + case MouseClickMacroEvent _ -> EVENT_CLICK; + case MouseMoveMacroEvent _ -> EVENT_MOVE; + case MouseScrollMacroEvent _ -> EVENT_SCROLL; default -> -1; }; @@ -237,8 +238,8 @@ public void onKeyDown(KeyDownEvent event) { int key = event.GetKey(); for (Macro macro : macros) { - Key bind = macro.getKeybind(); - if (bind != InputConstants.UNKNOWN && bind.getValue() == key) { + Keybind bind = macro.getKeybind(); + if (bind.getKey() != InputConstants.UNKNOWN && bind.getKeyCode() == key) { if (player.isPlaying()) { player.stop(); } else { diff --git a/src/main/java/net/aoba/managers/macros/MacroRecorder.java b/src/main/java/net/aoba/managers/macros/MacroRecorder.java index 36cc0236..9bd2d441 100644 --- a/src/main/java/net/aoba/managers/macros/MacroRecorder.java +++ b/src/main/java/net/aoba/managers/macros/MacroRecorder.java @@ -112,7 +112,7 @@ public Macro constructMacro() { @Override public void onKeyUp(KeyUpEvent event) { - if (event.GetKey() != Aoba.getInstance().guiManager.clickGuiButton.getValue().getValue() + if (event.GetKey() != Aoba.getInstance().guiManager.clickGuiButton.getValue().getKeyCode() && event.GetKey() != 256 && !Aoba.getInstance().guiManager.isClickGuiOpen()) { heldKeys.remove(Integer.valueOf(event.GetKey())); @@ -124,7 +124,7 @@ public void onKeyUp(KeyUpEvent event) { @Override public void onKeyDown(KeyDownEvent event) { - if (event.GetKey() != Aoba.getInstance().guiManager.clickGuiButton.getValue().getValue() + if (event.GetKey() != Aoba.getInstance().guiManager.clickGuiButton.getValue().getKeyCode() && event.GetKey() != 256 && !Aoba.getInstance().guiManager.isClickGuiOpen()) { heldKeys.add(event.GetKey()); diff --git a/src/main/java/net/aoba/module/Module.java b/src/main/java/net/aoba/module/Module.java index b46c4a2d..eccf1c9d 100644 --- a/src/main/java/net/aoba/module/Module.java +++ b/src/main/java/net/aoba/module/Module.java @@ -25,6 +25,7 @@ import net.aoba.settings.types.BooleanSetting; import net.aoba.settings.types.KeybindSetting; import net.aoba.utils.FindItemResult; +import net.aoba.utils.input.Keybind; import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.network.chat.Component; @@ -55,10 +56,10 @@ public abstract class Module { * @param name The name to use for this module. */ public Module(String name) { - this(name, InputConstants.UNKNOWN); + this(name, Keybind.from(InputConstants.UNKNOWN)); } - public Module(String name, Key keybind) { + public Module(String name, Keybind keybind) { this.name = name; keyBind = KeybindSetting.builder().id("key." + name.toLowerCase()).displayName(name + " Key") .defaultValue(keybind).build(); @@ -245,6 +246,17 @@ public void toggle() { state.setValue(!state.getValue()); } + public void enable() { + if (isDetectable(AOBA_CLIENT.moduleManager.antiCheat.getValue())) + state.setValue(false); + else + state.setValue(true); + } + + public void disable() { + state.setValue(false); + } + public boolean isDetectable(AntiCheat anticheat) { return knownDetectable.contains(anticheat); } diff --git a/src/main/java/net/aoba/module/modules/render/XRay.java b/src/main/java/net/aoba/module/modules/render/XRay.java index 757fa735..31069d12 100644 --- a/src/main/java/net/aoba/module/modules/render/XRay.java +++ b/src/main/java/net/aoba/module/modules/render/XRay.java @@ -11,6 +11,7 @@ import java.util.HashSet; import net.aoba.settings.types.BooleanSetting; +import net.aoba.utils.input.Keybind; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; @@ -37,7 +38,7 @@ public class XRay extends Module { .onUpdate(this::ReloadRenderer).build(); public XRay() { - super("XRay", InputConstants.Type.KEYBOARD.getOrCreate(InputConstants.KEY_X)); + super("XRay", Keybind.from(InputConstants.Type.KEYBOARD.getOrCreate(InputConstants.KEY_X))); setCategory(Category.of("Render")); setDescription("Allows the player to see ores."); addSetting(blocks); diff --git a/src/main/java/net/aoba/module/modules/world/Scaffold.java b/src/main/java/net/aoba/module/modules/world/Scaffold.java index 3d6e40ca..41fb56d6 100644 --- a/src/main/java/net/aoba/module/modules/world/Scaffold.java +++ b/src/main/java/net/aoba/module/modules/world/Scaffold.java @@ -22,6 +22,8 @@ import net.aoba.settings.types.KeybindSetting; import com.mojang.blaze3d.platform.InputConstants; import com.mojang.blaze3d.platform.InputConstants.Key; + +import net.aoba.utils.input.Keybind; import net.aoba.utils.player.InteractionUtils; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -40,7 +42,7 @@ public class Scaffold extends Module implements TickListener { private final KeybindSetting descendScaffoldKey = KeybindSetting.builder().id("scaffold_descend_key") .displayName("Descend Key") .description("Hold this key to descend down.") - .defaultValue(InputConstants.Type.KEYBOARD.getOrCreate(InputConstants.KEY_LSHIFT)).build(); + .defaultValue(Keybind.from(InputConstants.Type.KEYBOARD.getOrCreate(InputConstants.KEY_LSHIFT))).build(); private final FloatSetting placeDelay = FloatSetting.builder().id("scaffold_place_delay").displayName("Place Delay") .description("How long (in ticks) until Scaffold will place the next block below the player.") @@ -175,8 +177,11 @@ public void onTick(Post event) { MC.options.keyShift.setDown(false); // Determine the height at which the player will build. - Key descendKey = descendScaffoldKey.getValue(); - if (descendKey.getValue() > 0 && InputConstants.isKeyDown(descendKey.getValue())) { + Keybind descendKeybind = descendScaffoldKey.getValue(); + if (descendKeybind.getKey() == InputConstants.UNKNOWN) + return; + + if (InputConstants.isKeyDown(descendKeybind.getKeyCode())) { yPosition = MC.player.blockPosition().getY() - 2; } else if (MC.player.onGround()) { if (MC.options.keyJump.isDown()) { diff --git a/src/main/java/net/aoba/settings/types/KeybindSetting.java b/src/main/java/net/aoba/settings/types/KeybindSetting.java index 45f6cb70..7416f348 100644 --- a/src/main/java/net/aoba/settings/types/KeybindSetting.java +++ b/src/main/java/net/aoba/settings/types/KeybindSetting.java @@ -9,20 +9,20 @@ package net.aoba.settings.types; import net.aoba.settings.Setting; -import com.mojang.blaze3d.platform.InputConstants.Key; +import net.aoba.utils.input.Keybind; import java.util.function.Consumer; -public class KeybindSetting extends Setting { - protected KeybindSetting(String ID, String displayName, String description, Key default_value, Consumer onUpdate) { +public class KeybindSetting extends Setting { + protected KeybindSetting(String ID, String displayName, String description, Keybind default_value, Consumer onUpdate) { super(ID, displayName, description, default_value, onUpdate); type = TYPE.KEYBIND; } - + /** * Checks whether or not a value is with this setting's valid range. */ @Override - protected boolean isValueValid(Key value) { + protected boolean isValueValid(Keybind value) { return true; } @@ -30,7 +30,7 @@ public static KeybindSetting.BUILDER builder() { return new KeybindSetting.BUILDER(); } - public static class BUILDER extends Setting.BUILDER { + public static class BUILDER extends Setting.BUILDER { protected BUILDER() { } @@ -38,5 +38,9 @@ protected BUILDER() { public KeybindSetting build() { return new KeybindSetting(id, displayName, description, defaultValue, onUpdate); } + + public KeybindSetting.BUILDER setMomentary(boolean value) { + return this; + } } } \ No newline at end of file diff --git a/src/main/java/net/aoba/utils/input/Keybind.java b/src/main/java/net/aoba/utils/input/Keybind.java new file mode 100644 index 00000000..0b74ad49 --- /dev/null +++ b/src/main/java/net/aoba/utils/input/Keybind.java @@ -0,0 +1,57 @@ +package net.aoba.utils.input; + +import com.mojang.blaze3d.platform.InputConstants; +import com.mojang.blaze3d.platform.InputConstants.Key; + +public class Keybind { + private Key key; + private boolean isMomentary = false; + + public Keybind(Key key, boolean isMomentary) { + this.key = key; + this.isMomentary = isMomentary; + } + + public Key getKey() { + return this.key; + } + + public void setKey(Key key) { + this.key = key; + } + + public int getKeyCode() { + return this.key.getValue(); + } + + public void setKeyCode(int code) { + Key key = InputConstants.Type.KEYBOARD.getOrCreate(code); + setKey(key); + } + + public boolean getIsMomentary() { + return this.isMomentary; + } + + public void setIsMomentary(boolean value) { + this.isMomentary = value; + } + + public static Keybind from(Key key) { + return new Keybind(key, false); + } + + public static Keybind from(Key key, boolean momentary) { + return new Keybind(key, momentary); + } + + public static Keybind from(int keyCode) { + Key key = InputConstants.Type.KEYBOARD.getOrCreate(keyCode); + return new Keybind(key, false); + } + + public static Keybind from(int keyCode, boolean momentary) { + Key key = InputConstants.Type.KEYBOARD.getOrCreate(keyCode); + return new Keybind(key, momentary); + } +} From c1f304e867767fab3bff5180116d11207260aa9f Mon Sep 17 00:00:00 2001 From: Colton Date: Sat, 24 Oct 2026 14:57:54 -0400 Subject: [PATCH 2/2] Improved UI of momentary toggle. --- src/main/java/net/aoba/gui/GuiManager.java | 21 ++- .../aoba/gui/components/ButtonComponent.java | 23 ++- .../aoba/gui/components/KeybindComponent.java | 23 ++- .../gui/components/ToggleButtonComponent.java | 132 ++++++++++++++++++ 4 files changed, 183 insertions(+), 16 deletions(-) create mode 100644 src/main/java/net/aoba/gui/components/ToggleButtonComponent.java diff --git a/src/main/java/net/aoba/gui/GuiManager.java b/src/main/java/net/aoba/gui/GuiManager.java index 3b866fff..25fe62e1 100644 --- a/src/main/java/net/aoba/gui/GuiManager.java +++ b/src/main/java/net/aoba/gui/GuiManager.java @@ -144,10 +144,18 @@ public class GuiManager implements KeyDownListener, TickListener, Render2DListen .displayName("UI Panel Border Color").description("Accent color of the background.") .defaultValue(Shader.solid(new Color(100, 100, 100, 100))).build(); + public static ShaderSetting componentBackgroundColor = ShaderSetting.builder().id("ui_component_background_color") + .displayName("UI Component Background Color").description("Background colors of components (i.e TextBox).") + .defaultValue(Shader.solid(new Color(20, 20, 20, 95))).build(); + + public static ShaderSetting componentHoveredBackgroundColor = ShaderSetting.builder().id("ui_component_hover_background_color") + .displayName("UI Component Hovered Background Color").description("Background colors of components (i.e TextBox) when hovered.") + .defaultValue(Shader.solid(new Color(50, 50, 50, 150))).build(); + public static ShaderSetting componentBorderColor = ShaderSetting.builder().id("ui_component_border_color") .displayName("UI Component Border Color").description("Background colors of components (i.e TextBox).") .defaultValue(Shader.solid(new Color(115, 115, 115, 200))).build(); - + public static ShaderSetting windowBackgroundColor = ShaderSetting.builder().id("ui_window_background_color") .displayName("UI Background Color").description("Color of the background.") .defaultValue(Shader.blur(new Color(55, 55, 55, 255), 60f, 5f)).build(); @@ -156,10 +164,6 @@ public class GuiManager implements KeyDownListener, TickListener, Render2DListen .displayName("UI Panel Background Color").description("Accent color of the background.") .defaultValue(Shader.solid(new Color(90, 90, 90, 60))).build(); - public static ShaderSetting componentBackgroundColor = ShaderSetting.builder().id("ui_component_background_color") - .displayName("UI Component Background Color").description("Background colors of components (i.e TextBox).") - .defaultValue(Shader.solid(new Color(20, 20, 20, 95))).build(); - public static ShaderSetting buttonBackgroundColor = ShaderSetting.builder().id("ui_button_background_color") .displayName("UI Button Background Color").description("Background color of buttons.") .defaultValue(Shader.gradient(new Color(180, 50, 220), new Color(100, 20, 160), 90f)).build(); @@ -168,6 +172,11 @@ public class GuiManager implements KeyDownListener, TickListener, Render2DListen .id("ui_button_hover_background_color").displayName("UI Button Hover Background Color") .description("Background color of buttons when hovered.") .defaultValue(Shader.gradient(new Color(210, 80, 255), new Color(130, 40, 190), 90f)).build(); + + public static ShaderSetting buttonPressedBackgroundColor = ShaderSetting.builder() + .id("ui_button_pressed_background_color").displayName("UI Button Pressed Background Color") + .description("Background color of buttons when pressed.") + .defaultValue(Shader.gradient(new Color(150, 20, 195), new Color(70, 0, 130), 90f)).build(); public static ShaderSetting buttonBorderColor = ShaderSetting.builder().id("ui_button_border_color") .displayName("UI Button Border Color").description("Border color of buttons.") @@ -206,11 +215,13 @@ public GuiManager() { SettingManager.registerGlobalSetting(panelBorderColor); SettingManager.registerGlobalSetting(panelBackgroundColor); SettingManager.registerGlobalSetting(componentBackgroundColor); + SettingManager.registerGlobalSetting(componentHoveredBackgroundColor); SettingManager.registerGlobalSetting(foregroundColor); SettingManager.registerGlobalSetting(foregroundHeaderColor); SettingManager.registerGlobalSetting(foregroundAccentColor); SettingManager.registerGlobalSetting(buttonBackgroundColor); SettingManager.registerGlobalSetting(buttonHoverBackgroundColor); + SettingManager.registerGlobalSetting(buttonPressedBackgroundColor); SettingManager.registerGlobalSetting(buttonBorderColor); SettingManager.registerGlobalSetting(roundingRadius); SettingManager.registerGlobalSetting(lineThickness); diff --git a/src/main/java/net/aoba/gui/components/ButtonComponent.java b/src/main/java/net/aoba/gui/components/ButtonComponent.java index 95a8302d..dec242d6 100644 --- a/src/main/java/net/aoba/gui/components/ButtonComponent.java +++ b/src/main/java/net/aoba/gui/components/ButtonComponent.java @@ -20,7 +20,8 @@ public class ButtonComponent extends Component { private Runnable onClick; - + private boolean isPressed = false; + /** * Constructor for button component. * @@ -37,7 +38,8 @@ public ButtonComponent(Runnable onClick) { @Override public void draw(Renderer2D renderer, float partialTicks) { boolean hovered = getProperty(UIElement.IsHoveredProperty); - Shader bgEffect = hovered ? GuiManager.buttonHoverBackgroundColor.getValue() + + Shader bgEffect = isPressed ? GuiManager.buttonPressedBackgroundColor.getValue() : hovered ? GuiManager.buttonHoverBackgroundColor.getValue() : getProperty(BackgroundProperty); Shader bdEffect = getProperty(BorderProperty); Float cornerRadius = getProperty(CornerRadiusProperty); @@ -76,13 +78,24 @@ public void setOnClick(Runnable onClick) { @Override public void onMouseClick(MouseClickEvent event) { super.onMouseClick(event); - if (event.button == MouseButton.LEFT && event.action == MouseAction.DOWN) { + if (event.button == MouseButton.LEFT) { boolean hovered = getProperty(UIElement.IsHoveredProperty); if (hovered) { - if (onClick != null) - onClick.run(); + + if(event.action == MouseAction.DOWN) { + isPressed = true; + }else if(event.action == MouseAction.UP) { + if (onClick != null) { + onClick.run(); + } + isPressed = false; + } event.cancel(); + }else { + isPressed = false; } + }else { + isPressed = false; } } } diff --git a/src/main/java/net/aoba/gui/components/KeybindComponent.java b/src/main/java/net/aoba/gui/components/KeybindComponent.java index f1f07627..d6da89fa 100644 --- a/src/main/java/net/aoba/gui/components/KeybindComponent.java +++ b/src/main/java/net/aoba/gui/components/KeybindComponent.java @@ -19,6 +19,7 @@ import net.aoba.gui.UIProperty; import net.aoba.gui.types.GridDefinition; import net.aoba.gui.types.HorizontalAlignment; +import net.aoba.gui.types.TextAlign; import net.aoba.gui.types.TextWrapping; import net.aoba.gui.types.Thickness; import net.aoba.gui.types.VerticalAlignment; @@ -26,13 +27,14 @@ import net.aoba.utils.input.CursorStyle; import net.aoba.utils.types.MouseAction; import net.aoba.utils.types.MouseButton; +import net.minecraft.client.gui.TextAlignment; import net.aoba.utils.input.Keybind; public class KeybindComponent extends Component implements KeyDownListener { private boolean listeningForKey; private final StringComponent label; private final StringComponent keyTextComponent; - private final CheckboxComponent momentaryCheckbox; + private final ToggleButtonComponent momentaryButton; public static UIProperty SelectedKeyProperty = new UIProperty<>("SelectedKey", new Keybind(InputConstants.UNKNOWN, false), false, true, KeybindComponent::OnSelectedKeyPropertyChanged); public static UIProperty HeaderProperty = new UIProperty<>("Header", "", false, true, KeybindComponent::OnHeaderPropertyChanged); @@ -58,6 +60,7 @@ public KeybindComponent() { setProperty(UIElement.CursorProperty, CursorStyle.Type); GridComponent grid = new GridComponent(); + grid.setProperty(GridComponent.HorizontalSpacingProperty, 4f); grid.addColumnDefinition(new GridDefinition(1f, RelativeUnit.Relative)); grid.addColumnDefinition(new GridDefinition(RelativeUnit.Auto)); grid.addColumnDefinition(new GridDefinition(RelativeUnit.Auto)); @@ -69,13 +72,21 @@ public KeybindComponent() { grid.addChild(label); // Checkbox - momentaryCheckbox = new CheckboxComponent(); - momentaryCheckbox.setProperty(Component.VerticalAlignmentProperty, VerticalAlignment.Center); - momentaryCheckbox.setOnChanged(e -> { + momentaryButton = new ToggleButtonComponent(); + momentaryButton.setProperty(Component.VerticalAlignmentProperty, VerticalAlignment.Center); + momentaryButton.setOnChanged(e -> { Keybind keybind = this.getProperty(KeybindComponent.SelectedKeyProperty); this.setProperty(KeybindComponent.SelectedKeyProperty, new Keybind(keybind.getKey(), e.booleanValue())); }); - grid.addChild(momentaryCheckbox); + + momentaryButton.setProperty(UIElement.PaddingProperty, new Thickness(2f)); + + StringComponent momentaryButtonLabel = new StringComponent(); + momentaryButtonLabel.setProperty(StringComponent.FontSizeProperty, 10f); + momentaryButtonLabel.setProperty(StringComponent.TextProperty, "Hold"); + momentaryButtonLabel.setProperty(StringComponent.TextAlignmentProperty, TextAlign.Center); + momentaryButton.setContent(momentaryButtonLabel); + grid.addChild(momentaryButton); // Key Button RectangleComponent keyButton = new RectangleComponent(); @@ -118,7 +129,7 @@ public void onKeyDown(KeyDownEvent event) { ? InputConstants.UNKNOWN : InputConstants.Type.KEYBOARD.getOrCreate(event.GetKey()); - boolean isMomentary = momentaryCheckbox.getProperty(CheckboxComponent.IsCheckedProperty); + boolean isMomentary = momentaryButton.getProperty(CheckboxComponent.IsCheckedProperty); setProperty(SelectedKeyProperty, new Keybind(key, isMomentary)); setListeningForKey(false); event.cancel(); diff --git a/src/main/java/net/aoba/gui/components/ToggleButtonComponent.java b/src/main/java/net/aoba/gui/components/ToggleButtonComponent.java new file mode 100644 index 00000000..24e0eb29 --- /dev/null +++ b/src/main/java/net/aoba/gui/components/ToggleButtonComponent.java @@ -0,0 +1,132 @@ +/* + * Aoba Hacked Client + * Copyright (C) 2019-2024 coltonk9043 + * + * Licensed under the GNU General Public License, Version 3 or later. + * See . + */ + +package net.aoba.gui.components; + +import java.util.function.Consumer; + +import net.aoba.event.events.MouseClickEvent; +import net.aoba.gui.GuiManager; +import net.aoba.gui.UIElement; +import net.aoba.gui.UIProperty; +import net.aoba.gui.types.Thickness; +import net.aoba.utils.input.CursorStyle; +import net.aoba.rendering.Renderer2D; +import net.aoba.rendering.shaders.Shader; +import net.aoba.utils.types.MouseAction; +import net.aoba.utils.types.MouseButton; + +public class ToggleButtonComponent extends Component { + private Runnable onClick; + private Consumer onChanged; + private boolean isPressed = false; + + public static final UIProperty IsCheckedProperty = new UIProperty<>("IsChecked", false, false, false, ToggleButtonComponent::onIsCheckedChanged); + + private static void onIsCheckedChanged(UIElement sender, Boolean oldValue, Boolean newValue) { + if(sender instanceof ToggleButtonComponent toggleButton) { + if(toggleButton.onChanged != null) + toggleButton.onChanged.accept(newValue); + } + } + + /** + * Constructor for button component. + * + * @param onClick OnClick delegate that will run when the button is pressed. + */ + public ToggleButtonComponent() { + this.setProperty(UIElement.CursorProperty, CursorStyle.Click); + this.setProperty(UIElement.PaddingProperty, new Thickness(4f)); + this.bindProperty(UIElement.BackgroundProperty, GuiManager.componentBackgroundColor); + this.bindProperty(UIElement.BorderProperty, GuiManager.componentBorderColor); + } + + /** + * Constructor for button component. + * + * @param onClick OnClick delegate that will run when the button is pressed. + */ + public ToggleButtonComponent(Runnable onClick) { + this(); + this.onClick = onClick; + } + + @Override + public void draw(Renderer2D renderer, float partialTicks) { + boolean hovered = getProperty(UIElement.IsHoveredProperty); + boolean isChecked = getProperty(IsCheckedProperty); + + Shader bgEffect = (isPressed || isChecked) ? GuiManager.buttonPressedBackgroundColor.getValue() + : hovered ? GuiManager.componentHoveredBackgroundColor.getValue() + : getProperty(BackgroundProperty); + Shader bdEffect = getProperty(BorderProperty); + Float cornerRadius = getProperty(CornerRadiusProperty); + Float borderThickness = getProperty(BorderThicknessProperty); + float radius = cornerRadius != null ? cornerRadius : 0f; + float thickness = borderThickness != null ? borderThickness : 0f; + + if (bgEffect != null || bdEffect != null) { + float actualX = getActualSize().x(); + float actualY = getActualSize().y(); + float actualWidth = getActualSize().width(); + float actualHeight = getActualSize().height(); + + if (bgEffect != null) { + renderer.drawRoundedBox(actualX, actualY, actualWidth, actualHeight, radius, bgEffect); + } + + if (bdEffect != null) { + renderer.drawRoundedBoxOutline(actualX, actualY, actualWidth, actualHeight, radius, thickness, + bdEffect); + } + } + + super.draw(renderer, partialTicks); + } + + /** + * Sets the OnClick delegate of the button. + * + * @param onClick Delegate to set. + */ + public void setOnClick(Runnable onClick) { + this.onClick = onClick; + } + + public void setOnChanged(Consumer onChanged) { + this.onChanged = onChanged; + } + + @Override + public void onMouseClick(MouseClickEvent event) { + + super.onMouseClick(event); + if (event.button == MouseButton.LEFT) { + boolean hovered = getProperty(UIElement.IsHoveredProperty); + if (hovered) { + + if(event.action == MouseAction.DOWN) { + isPressed = true; + }else if(event.action == MouseAction.UP) { + Boolean isChecked = getProperty(IsCheckedProperty); + setProperty(IsCheckedProperty, !Boolean.TRUE.equals(isChecked)); + if (onClick != null) { + onClick.run(); + } + isPressed = false; + } + event.cancel(); + }else { + isPressed = false; + } + }else { + isPressed = false; + } + } +}