Skip to content

Commit

Permalink
Fix modifier keys not working correctly on their own
Browse files Browse the repository at this point in the history
  • Loading branch information
Siphalor committed Sep 25, 2023
1 parent 7e68e00 commit 749bee4
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 17 deletions.
49 changes: 38 additions & 11 deletions src/main/java/de/siphalor/amecs/api/KeyModifiers.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;

Expand All @@ -74,10 +76,9 @@ public KeyModifiers() {
/**
* FOR INTERNAL USE ONLY
* <p>
* 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) {
Expand All @@ -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();
Expand All @@ -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
* <p>
Expand Down Expand Up @@ -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
*
Expand All @@ -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
*
Expand Down
21 changes: 17 additions & 4 deletions src/main/java/de/siphalor/amecs/impl/KeyBindingManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -100,13 +101,17 @@ public static Stream<KeyBinding> 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<KeyBinding> result = keyBindingList.stream().filter(keyBinding -> ((IKeyBinding) keyBinding).amecs$getKeyModifiers().isPressed());
Stream<KeyBinding> result = keyBindingList.stream().filter(KeyBindingManager::areExactModifiersPressed);
List<KeyBinding> 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()
Expand Down Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,14 @@ public void getLocalizedName(CallbackInfoReturnable<String> callbackInfoReturnab

@Inject(method = "matchesKey", at = @At("RETURN"), cancellable = true)
public void matchesKey(int keyCode, int scanCode, CallbackInfoReturnable<Boolean> 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<Boolean> callbackInfoReturnable) {
if (!keyModifiers.isUnset() && !keyModifiers.isPressed()) {
if (!keyModifiers.isUnset() && !keyModifiers.equals(KeyModifiers.getCurrentlyPressed())) {
callbackInfoReturnable.setReturnValue(false);
}
}
Expand Down

0 comments on commit 749bee4

Please sign in to comment.