diff --git a/src/main/java/de/siphalor/amecs/api/KeyModifiers.java b/src/main/java/de/siphalor/amecs/api/KeyModifiers.java index 6087a86..09f4f2a 100644 --- a/src/main/java/de/siphalor/amecs/api/KeyModifiers.java +++ b/src/main/java/de/siphalor/amecs/api/KeyModifiers.java @@ -16,18 +16,16 @@ package de.siphalor.amecs.api; -import java.util.Arrays; -import java.util.BitSet; - -import org.apache.commons.lang3.ArrayUtils; -import org.jetbrains.annotations.ApiStatus; - import de.siphalor.amecs.impl.AmecsAPI; import de.siphalor.amecs.impl.duck.IKeyBinding; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.options.KeyBinding; import net.minecraft.client.util.InputUtil; +import org.apache.commons.lang3.ArrayUtils; +import org.jetbrains.annotations.ApiStatus; + +import java.util.Arrays; /** * Defines modifiers for a key binding @@ -61,6 +59,10 @@ public void unset() { } } + public static KeyModifiers getCurrentlyPressed() { + return AmecsAPI.CURRENT_MODIFIERS; + } + // using a boolean array here because it is faster and needs less space private final boolean[] value; @@ -74,10 +76,9 @@ public KeyModifiers() { /** * FOR INTERNAL USE ONLY *

- * Constructs a new modifier object by a raw {@link BitSet} + * Constructs a new modifier object by a raw boolean array * - * @param value - * the raw value with flags set + * @param value the raw value with flags set */ @ApiStatus.Internal public KeyModifiers(boolean[] value) { @@ -90,9 +91,9 @@ public KeyModifiers(boolean[] value) { /** * Constructs a new modifier object by all modifier bits * - * @param alt sets whether the alt flag should be set + * @param alt sets whether the alt flag should be set * @param control sets whether the control flag should be set - * @param shift sets whether the shift flag should be set + * @param shift sets whether the shift flag should be set */ public KeyModifiers(boolean alt, boolean control, boolean shift) { this(); @@ -105,11 +106,28 @@ public KeyModifiers(boolean alt, boolean control, boolean shift) { * Compares this object with the currently pressed keys * * @return whether the modifiers match in the current context + * @deprecated always performs an exact check against {@link #getCurrentlyPressed()}. + * Use {@link AmecsAPI#CURRENT_MODIFIERS} in combination with {@link #contains(KeyModifiers)} or {@link #equals(KeyModifiers)} instead. */ + @Deprecated public boolean isPressed() { return equals(AmecsAPI.CURRENT_MODIFIERS); } + /** + * Returns whether the given modifiers are also set in this object. + * @param other the modifiers to check + * @return whether the given modifiers are also set in this object + */ + public boolean contains(KeyModifiers other) { + for (int i = 0; i < value.length; i++) { + if (other.value[i] && !this.value[i]) { + return false; + } + } + return true; + } + /** * FOR INTERNAL USE ONLY *

@@ -245,6 +263,14 @@ public void cleanup(KeyBinding keyBinding) { set(KeyModifier.fromKey(key), false); } + @Override + public boolean equals(Object obj) { + if (obj instanceof KeyModifiers) { + return equals((KeyModifiers) obj); + } + return false; + } + /** * Returns whether this object equals another one * @@ -262,6 +288,7 @@ public String toString() { // new format even if it needs more characters because it is more user friendly (and simpler to parse). Not everyone knows about bit masks // it could be discussed whether this new is really "better" but i leave it for now. It is backward compatible so nothing breaks + /** * FOR INTERNAL USE ONLY * diff --git a/src/main/java/de/siphalor/amecs/impl/KeyBindingManager.java b/src/main/java/de/siphalor/amecs/impl/KeyBindingManager.java index e1bc03d..6584d4b 100644 --- a/src/main/java/de/siphalor/amecs/impl/KeyBindingManager.java +++ b/src/main/java/de/siphalor/amecs/impl/KeyBindingManager.java @@ -18,6 +18,7 @@ import de.siphalor.amecs.api.KeyBindingUtils; import de.siphalor.amecs.api.KeyModifier; +import de.siphalor.amecs.api.KeyModifiers; import de.siphalor.amecs.api.PriorityKeyBinding; import de.siphalor.amecs.impl.duck.IKeyBinding; import net.fabricmc.api.EnvType; @@ -100,13 +101,17 @@ public static Stream getMatchingKeyBindings(InputUtil.KeyCode keyCod return Stream.empty(); // If there are two key bindings, alt + y and shift + alt + y, and you press shift + alt + y, both will be triggered. // This is intentional. - Stream result = keyBindingList.stream().filter(keyBinding -> ((IKeyBinding) keyBinding).amecs$getKeyModifiers().isPressed()); + Stream result = keyBindingList.stream().filter(KeyBindingManager::areExactModifiersPressed); List keyBindings = result.collect(Collectors.toList()); if (keyBindings.isEmpty()) return keyBindingList.stream().filter(keyBinding -> ((IKeyBinding) keyBinding).amecs$getKeyModifiers().isUnset()); return keyBindings.stream(); } + private static boolean areExactModifiersPressed(KeyBinding keyBinding) { + return KeyBindingUtils.getBoundModifiers(keyBinding).equals(AmecsAPI.CURRENT_MODIFIERS); + } + public static void onKeyPressed(InputUtil.KeyCode keyCode) { getMatchingKeyBindings(keyCode, false).forEach(keyBinding -> ((IKeyBinding) keyBinding).amecs$incrementTimesPressed() @@ -186,14 +191,22 @@ public static boolean onKeyReleasedPriority(InputUtil.KeyCode keyCode) { } public static void setKeyPressed(InputUtil.KeyCode keyCode, boolean pressed) { - AmecsAPI.CURRENT_MODIFIERS.set(KeyModifier.fromKeyCode(keyCode.getKeyCode()), pressed); + KeyModifier modifier = KeyModifier.fromKeyCode(keyCode.getKeyCode()); + AmecsAPI.CURRENT_MODIFIERS.set(modifier, pressed); // Update keybindings with matching modifiers and the same keycode forEachKeyBindingWithKey(keyCode, keyBinding -> setKeyBindingPressed(keyBinding, pressed)); - // Handle the case, that a modifier has been released + if (modifier != null && !pressed) { + handleReleasedModifier(); + } + } + + private static void handleReleasedModifier() { + // Handle the case that a modifier has been released pressedKeyBindings.removeIf(pressedKeyBinding -> { - if (!KeyBindingUtils.getBoundModifiers(pressedKeyBinding).isPressed()) { + KeyModifiers boundModifiers = KeyBindingUtils.getBoundModifiers(pressedKeyBinding); + if (!AmecsAPI.CURRENT_MODIFIERS.contains(boundModifiers)) { pressedKeyBinding.setPressed(false); return true; } diff --git a/src/main/java/de/siphalor/amecs/impl/mixin/MixinKeyBinding.java b/src/main/java/de/siphalor/amecs/impl/mixin/MixinKeyBinding.java index a202e47..7fd770c 100644 --- a/src/main/java/de/siphalor/amecs/impl/mixin/MixinKeyBinding.java +++ b/src/main/java/de/siphalor/amecs/impl/mixin/MixinKeyBinding.java @@ -124,14 +124,14 @@ public void getLocalizedName(CallbackInfoReturnable callbackInfoReturnab @Inject(method = "matchesKey", at = @At("RETURN"), cancellable = true) public void matchesKey(int keyCode, int scanCode, CallbackInfoReturnable callbackInfoReturnable) { - if (!keyModifiers.isUnset() && !keyModifiers.isPressed()) { + if (!keyModifiers.isUnset() && !keyModifiers.equals(KeyModifiers.getCurrentlyPressed())) { callbackInfoReturnable.setReturnValue(false); } } @Inject(method = "matchesMouse", at = @At("RETURN"), cancellable = true) public void matchesMouse(int mouse, CallbackInfoReturnable callbackInfoReturnable) { - if (!keyModifiers.isUnset() && !keyModifiers.isPressed()) { + if (!keyModifiers.isUnset() && !keyModifiers.equals(KeyModifiers.getCurrentlyPressed())) { callbackInfoReturnable.setReturnValue(false); } }