From 28facc430ec61e82257c8b698890ac1eb852dda9 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Fri, 6 Nov 2020 14:10:26 +0100 Subject: [PATCH] Allow raw key handlers to cancel keybindings (required for #305) So that when you press e.g. Ctrl+Z, it doesn't trigger the keybinding bound to Z (currently full brightness). --- .../replaymod/core/KeyBindingRegistry.java | 39 +++++++------------ .../core/events/KeyBindingEventCallback.java | 2 - .../core/events/KeyEventCallback.java | 17 ++++++-- .../core/mixin/MixinKeyboardListener.java | 39 +++++++++++++++++-- .../replay/gui/overlay/GuiReplayOverlay.java | 27 ++----------- .../simplepathing/ReplayModSimplePathing.java | 5 +-- .../simplepathing/gui/GuiPathing.java | 4 +- src/main/resources/mixins.core.replaymod.json | 2 +- 8 files changed, 73 insertions(+), 62 deletions(-) diff --git a/src/main/java/com/replaymod/core/KeyBindingRegistry.java b/src/main/java/com/replaymod/core/KeyBindingRegistry.java index 7859bf3f..3c6d2d14 100644 --- a/src/main/java/com/replaymod/core/KeyBindingRegistry.java +++ b/src/main/java/com/replaymod/core/KeyBindingRegistry.java @@ -4,6 +4,8 @@ import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; import com.replaymod.core.mixin.KeyBindingAccessor; import de.johni0702.minecraft.gui.utils.EventRegistrations; +import com.replaymod.core.events.KeyBindingEventCallback; +import com.replaymod.core.events.KeyEventCallback; import com.replaymod.core.versions.MCVer; import net.minecraft.client.options.KeyBinding; import net.minecraft.util.crash.CrashReport; @@ -21,13 +23,9 @@ import static com.replaymod.core.ReplayMod.MOD_ID; //#endif //#if MC>=11400 -import com.replaymod.core.events.KeyBindingEventCallback; -import com.replaymod.core.events.KeyEventCallback; import com.replaymod.core.events.PreRenderCallback; -import org.lwjgl.glfw.GLFW; //#else //$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -//$$ import net.minecraftforge.fml.common.gameevent.InputEvent; //$$ import net.minecraftforge.fml.common.gameevent.TickEvent; //$$ import org.lwjgl.input.Keyboard; //$$ import static com.replaymod.core.versions.MCVer.FML_BUS; @@ -42,6 +40,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Consumer; +import java.util.function.Supplier; public class KeyBindingRegistry extends EventRegistrations { private static final String CATEGORY = "replaymod.title"; @@ -51,7 +50,7 @@ public class KeyBindingRegistry extends EventRegistrations { private final Map bindings = new HashMap<>(); private Set onlyInReplay = new HashSet<>(); - private Multimap rawHandlers = ArrayListMultimap.create(); + private Multimap> rawHandlers = ArrayListMultimap.create(); public Binding registerKeyBinding(String name, int keyCode, Runnable whenPressed, boolean onlyInRepay) { Binding binding = registerKeyBinding(name, keyCode, onlyInRepay); @@ -91,7 +90,7 @@ public class KeyBindingRegistry extends EventRegistrations { return binding; } - public void registerRaw(int keyCode, Runnable whenPressed) { + public void registerRaw(int keyCode, Supplier whenPressed) { rawHandlers.put(keyCode, whenPressed); } @@ -104,17 +103,9 @@ public class KeyBindingRegistry extends EventRegistrations { } //#if MC>=11400 - { on(KeyBindingEventCallback.EVENT, this::handleKeyBindings); } - { on(KeyEventCallback.EVENT, (keyCode, scanCode, action, modifiers) -> handleRaw(keyCode, action)); } { on(PreRenderCallback.EVENT, this::handleRepeatedKeyBindings); } //#else //$$ @SubscribeEvent - //$$ public void onKeyInput(InputEvent.KeyInputEvent event) { - //$$ handleKeyBindings(); - //$$ handleRaw(); - //$$ } - //$$ - //$$ @SubscribeEvent //$$ public void onTick(TickEvent.RenderTickEvent event) { //$$ if (event.phase != TickEvent.Phase.START) return; //$$ handleRepeatedKeyBindings(); @@ -129,6 +120,7 @@ public class KeyBindingRegistry extends EventRegistrations { } } + { on(KeyBindingEventCallback.EVENT, this::handleKeyBindings); } private void handleKeyBindings() { for (Binding binding : bindings.values()) { while (binding.keyBinding.wasPressed()) { @@ -152,24 +144,23 @@ public class KeyBindingRegistry extends EventRegistrations { } } - //#if MC>=11400 - private void handleRaw(int keyCode, int action) { - if (action != GLFW.GLFW_PRESS) return; - //#else - //$$ private void handleRaw() { - //$$ int keyCode = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter() + 256 : Keyboard.getEventKey(); - //#endif - for (final Runnable runnable : rawHandlers.get(keyCode)) { + { on(KeyEventCallback.EVENT, (keyCode, scanCode, action, modifiers) -> handleRaw(keyCode, action)); } + private boolean handleRaw(int keyCode, int action) { + if (action != KeyEventCallback.ACTION_PRESS) return false; + for (final Supplier handler : rawHandlers.get(keyCode)) { try { - runnable.run(); + if (handler.get()) { + return true; + } } catch (Throwable cause) { CrashReport crashReport = CrashReport.create(cause, "Handling Raw Key Binding"); CrashReportSection category = crashReport.addElement("Key Binding"); MCVer.addDetail(category, "Key Code", () -> "" + keyCode); - MCVer.addDetail(category, "Handler", runnable::toString); + MCVer.addDetail(category, "Handler", handler::toString); throw new CrashException(crashReport); } } + return false; } public class Binding { diff --git a/src/main/java/com/replaymod/core/events/KeyBindingEventCallback.java b/src/main/java/com/replaymod/core/events/KeyBindingEventCallback.java index 942783ca..c9784d02 100644 --- a/src/main/java/com/replaymod/core/events/KeyBindingEventCallback.java +++ b/src/main/java/com/replaymod/core/events/KeyBindingEventCallback.java @@ -1,4 +1,3 @@ -//#if MC>=11400 package com.replaymod.core.events; import de.johni0702.minecraft.gui.utils.Event; @@ -14,4 +13,3 @@ public interface KeyBindingEventCallback { void onKeybindingEvent(); } -//#endif diff --git a/src/main/java/com/replaymod/core/events/KeyEventCallback.java b/src/main/java/com/replaymod/core/events/KeyEventCallback.java index 8403a1ba..894f822a 100644 --- a/src/main/java/com/replaymod/core/events/KeyEventCallback.java +++ b/src/main/java/com/replaymod/core/events/KeyEventCallback.java @@ -1,4 +1,3 @@ -//#if MC>=11400 package com.replaymod.core.events; import de.johni0702.minecraft.gui.utils.Event; @@ -7,11 +6,21 @@ public interface KeyEventCallback { Event EVENT = Event.create((listeners) -> (key, scanCode, action, modifiers) -> { for (KeyEventCallback listener : listeners) { - listener.onKeyEvent(key, scanCode, action, modifiers); + if (listener.onKeyEvent(key, scanCode, action, modifiers)) { + return true; + } } + return false; } ); - void onKeyEvent(int key, int scanCode, int action, int modifiers); + //#if MC>=11400 + int ACTION_RELEASE = org.lwjgl.glfw.GLFW.GLFW_RELEASE; + int ACTION_PRESS = org.lwjgl.glfw.GLFW.GLFW_PRESS; + //#else + //$$ int ACTION_RELEASE = 0; + //$$ int ACTION_PRESS = 1; + //#endif + + boolean onKeyEvent(int key, int scanCode, int action, int modifiers); } -//#endif diff --git a/src/main/java/com/replaymod/core/mixin/MixinKeyboardListener.java b/src/main/java/com/replaymod/core/mixin/MixinKeyboardListener.java index fb73d164..3a7c680c 100644 --- a/src/main/java/com/replaymod/core/mixin/MixinKeyboardListener.java +++ b/src/main/java/com/replaymod/core/mixin/MixinKeyboardListener.java @@ -1,20 +1,51 @@ -//#if MC>=11400 package com.replaymod.core.mixin; import com.replaymod.core.events.KeyBindingEventCallback; import com.replaymod.core.events.KeyEventCallback; -import net.minecraft.client.Keyboard; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +//#if MC>=11400 +import net.minecraft.client.Keyboard; +//#else +//$$ import net.minecraft.client.settings.KeyBinding; +//$$ import org.lwjgl.input.Keyboard; +//#endif + +//#if MC>=11400 @Mixin(Keyboard.class) public class MixinKeyboardListener { - @Inject(method = "onKey", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/options/KeyBinding;onKeyPressed(Lnet/minecraft/client/util/InputUtil$Key;)V", shift = At.Shift.AFTER)) + private static final String ON_KEY_PRESSED = "Lnet/minecraft/client/options/KeyBinding;onKeyPressed(Lnet/minecraft/client/util/InputUtil$Key;)V"; + + @Inject(method = "onKey", at = @At(value = "INVOKE", target = ON_KEY_PRESSED), cancellable = true) + private void beforeKeyBindingTick(long windowPointer, int key, int scanCode, int action, int modifiers, CallbackInfo ci) { + if (KeyEventCallback.EVENT.invoker().onKeyEvent(key, scanCode, action, modifiers)) { + ci.cancel(); + } + } + + @Inject(method = "onKey", at = @At(value = "INVOKE", target = ON_KEY_PRESSED, shift = At.Shift.AFTER)) private void afterKeyBindingTick(long windowPointer, int key, int scanCode, int action, int modifiers, CallbackInfo ci) { KeyBindingEventCallback.EVENT.invoker().onKeybindingEvent(); - KeyEventCallback.EVENT.invoker().onKeyEvent(key, scanCode, action, modifiers); } } +//#else +//$$ @Mixin(KeyBinding.class) +//$$ public class MixinKeyboardListener { +//$$ @Inject(method = "onTick", at = @At("HEAD"), cancellable = true) +//$$ private static void beforeKeyBindingTick(CallbackInfo ci) { +//$$ int keyCode = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter() + 256 : Keyboard.getEventKey(); +//$$ int action = Keyboard.getEventKeyState() ? KeyEventCallback.ACTION_PRESS : KeyEventCallback.ACTION_RELEASE; +//$$ if (KeyEventCallback.EVENT.invoker().onKeyEvent(keyCode, 0, action, 0)) { +//$$ ci.cancel(); +//$$ } +//$$ } +//$$ +//$$ @Inject(method = "onTick", at = @At("RETURN")) +//$$ private static void afterKeyBindingTick(CallbackInfo ci) { +//$$ KeyBindingEventCallback.EVENT.invoker().onKeybindingEvent(); +//$$ } +//$$ } //#endif diff --git a/src/main/java/com/replaymod/replay/gui/overlay/GuiReplayOverlay.java b/src/main/java/com/replaymod/replay/gui/overlay/GuiReplayOverlay.java index 4618774d..7a53b071 100644 --- a/src/main/java/com/replaymod/replay/gui/overlay/GuiReplayOverlay.java +++ b/src/main/java/com/replaymod/replay/gui/overlay/GuiReplayOverlay.java @@ -1,6 +1,8 @@ package com.replaymod.replay.gui.overlay; import com.replaymod.core.ReplayMod; +import com.replaymod.core.events.KeyBindingEventCallback; +import com.replaymod.core.events.KeyEventCallback; import com.replaymod.core.versions.MCVer.Keyboard; import com.replaymod.replay.ReplayHandler; import com.replaymod.replay.ReplayModReplay; @@ -23,15 +25,6 @@ import de.johni0702.minecraft.gui.utils.lwjgl.WritablePoint; import net.minecraft.client.options.GameOptions; import net.minecraft.client.resource.language.I18n; -//#if MC>=11400 -import com.replaymod.core.events.KeyBindingEventCallback; -import com.replaymod.core.events.KeyEventCallback; -import org.lwjgl.glfw.GLFW; -//#else -//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -//$$ import net.minecraftforge.fml.common.gameevent.InputEvent; -//#endif - import static com.replaymod.core.ReplayMod.TEXTURE_SIZE; public class GuiReplayOverlay extends AbstractGuiOverlay { @@ -183,13 +176,8 @@ public class GuiReplayOverlay extends AbstractGuiOverlay { //$$ public // All event handlers need to be public in 1.7.10 //#endif class EventHandler extends EventRegistrations { - //#if MC>=11400 { on(KeyBindingEventCallback.EVENT, this::onKeyBindingEvent); } private void onKeyBindingEvent() { - //#else - //$$ @SubscribeEvent - //$$ public void onKeyBindingEvent(InputEvent.KeyInputEvent event) { - //#endif GameOptions gameSettings = getMinecraft().options; while (gameSettings.keyChat.wasPressed() || gameSettings.keyCommand.wasPressed()) { if (!isMouseVisible()) { @@ -198,16 +186,9 @@ public class GuiReplayOverlay extends AbstractGuiOverlay { } } - //#if MC>=11400 - { on(KeyEventCallback.EVENT, (int key, int scanCode, int action, int modifiers) -> onKeyInput(key, action)); } + { on(KeyEventCallback.EVENT, (int key, int scanCode, int action, int modifiers) -> { onKeyInput(key, action); return false; }); } private void onKeyInput(int key, int action) { - if (action != GLFW.GLFW_PRESS) return; - //#else - //$$ @SubscribeEvent - //$$ public void onKeyInput(InputEvent.KeyInputEvent event) { - //$$ if (!Keyboard.getEventKeyState()) return; - //$$ int key = Keyboard.getEventKey(); - //#endif + if (action != KeyEventCallback.ACTION_PRESS) return; // Allow F1 to be used to hide the replay gui (e.g. for recording with OBS) if (isMouseVisible() && key == Keyboard.KEY_F1) { hidden = !hidden; diff --git a/src/main/java/com/replaymod/simplepathing/ReplayModSimplePathing.java b/src/main/java/com/replaymod/simplepathing/ReplayModSimplePathing.java index ca149839..f9ef0ee3 100644 --- a/src/main/java/com/replaymod/simplepathing/ReplayModSimplePathing.java +++ b/src/main/java/com/replaymod/simplepathing/ReplayModSimplePathing.java @@ -97,9 +97,8 @@ public class ReplayModSimplePathing extends EventRegistrations implements Module settingsRegistry.set(Setting.AUTO_SYNC, active); settingsRegistry.save(); }); - core.getKeyBindingRegistry().registerRaw(Keyboard.KEY_DELETE, () -> { - if (guiPathing != null) guiPathing.deleteButtonPressed(); - }); + core.getKeyBindingRegistry().registerRaw(Keyboard.KEY_DELETE, () -> + guiPathing != null && guiPathing.deleteButtonPressed()); keyPositionKeyframe = core.getKeyBindingRegistry().registerKeyBinding("replaymod.input.positionkeyframe", Keyboard.KEY_I, () -> { if (guiPathing != null) guiPathing.toggleKeyframe(SPPath.POSITION, false); }, true); diff --git a/src/main/java/com/replaymod/simplepathing/gui/GuiPathing.java b/src/main/java/com/replaymod/simplepathing/gui/GuiPathing.java index c0eb506b..289243cc 100644 --- a/src/main/java/com/replaymod/simplepathing/gui/GuiPathing.java +++ b/src/main/java/com/replaymod/simplepathing/gui/GuiPathing.java @@ -468,10 +468,12 @@ public class GuiPathing { }); } - public void deleteButtonPressed() { + public boolean deleteButtonPressed() { if (mod.getSelectedPath() != null) { toggleKeyframe(mod.getSelectedPath(), false); + return true; } + return false; } private void startLoadingEntityTracker() { diff --git a/src/main/resources/mixins.core.replaymod.json b/src/main/resources/mixins.core.replaymod.json index 111052a2..c002fc17 100644 --- a/src/main/resources/mixins.core.replaymod.json +++ b/src/main/resources/mixins.core.replaymod.json @@ -12,12 +12,12 @@ "Mixin_RegisterDynamicResourcePacks", //#endif //#if MC>=11400 - "MixinKeyboardListener", "MixinMouse", //#endif //#if MC<10800 //$$ "ResourcePackRepositoryAccessor", //#endif + "MixinKeyboardListener", "MixinMinecraft", "GuiMainMenuAccessor", "GuiScreenAccessor",