diff --git a/common/src/main/java/me/shedaniel/architectury/event/events/client/ClientRawInputEvent.java b/common/src/main/java/me/shedaniel/architectury/event/events/client/ClientRawInputEvent.java new file mode 100644 index 00000000..587b494a --- /dev/null +++ b/common/src/main/java/me/shedaniel/architectury/event/events/client/ClientRawInputEvent.java @@ -0,0 +1,59 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021 shedaniel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package me.shedaniel.architectury.event.events.client; + +import me.shedaniel.architectury.event.Event; +import me.shedaniel.architectury.event.EventFactory; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.Minecraft; +import net.minecraft.world.InteractionResult; + +@Environment(EnvType.CLIENT) +public interface ClientRawInputEvent { + /** + * Invoked after the mouse has scrolled, but doesn't have a screen opened, and in a world, equivalent to forge's {@code InputEvent.MouseScrollEvent}. + */ + Event MOUSE_SCROLLED = EventFactory.createInteractionResult(MouseScrolled.class); + /** + * Invoked after the mouse has clicked, before the screen intercepts, equivalent to forge's {@code InputEvent.RawMouseEvent}. + */ + Event MOUSE_CLICKED_PRE = EventFactory.createInteractionResult(MouseClicked.class); + /** + * Invoked after the mouse has clicked, after the screen intercepts, equivalent to forge's {@code InputEvent.MouseInputEvent}. + */ + Event MOUSE_CLICKED_POST = EventFactory.createInteractionResult(MouseClicked.class); + /** + * Invoked after a key was pressed, after the screen intercepts, equivalent to forge's {@code InputEvent.KeyInputEvent}. + */ + Event KEY_PRESSED = EventFactory.createInteractionResult(KeyPressed.class); + + interface KeyPressed { + InteractionResult keyPressed(Minecraft client, int keyCode, int scanCode, int action, int modifiers); + } + + interface MouseScrolled { + InteractionResult mouseScrolled(Minecraft client, double amount); + } + + interface MouseClicked { + InteractionResult mouseClicked(Minecraft client, int button, int action, int mods); + } +} diff --git a/fabric/build.gradle b/fabric/build.gradle index 93da73c8..7b36866b 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -1,8 +1,8 @@ import com.github.jengelman.gradle.plugins.shadow.transformers.Transformer import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext import shadow.org.apache.tools.zip.ZipEntry -import shadow.org.codehaus.plexus.util.IOUtil import shadow.org.apache.tools.zip.ZipOutputStream +import shadow.org.codehaus.plexus.util.IOUtil plugins { id "com.github.johnrengelman.shadow" version "5.0.0" diff --git a/fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/client/MixinKeyboardHandler.java b/fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/client/MixinKeyboardHandler.java index ec0d5d23..e556b2bb 100644 --- a/fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/client/MixinKeyboardHandler.java +++ b/fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/client/MixinKeyboardHandler.java @@ -19,6 +19,7 @@ package me.shedaniel.architectury.mixin.fabric.client; +import me.shedaniel.architectury.event.events.client.ClientRawInputEvent; import me.shedaniel.architectury.event.events.client.ClientScreenInputEvent; import me.shedaniel.architectury.impl.fabric.ScreenInputDelegate; import net.minecraft.client.KeyboardHandler; @@ -111,4 +112,13 @@ public class MixinKeyboardHandler { info.cancel(); } } + + @Inject(method = "keyPress", at = @At("RETURN"), cancellable = true) + public void onRawKey(long handle, int key, int scanCode, int action, int modifiers, CallbackInfo info) { + if (handle == this.minecraft.getWindow().getWindow()) { + InteractionResult result = ClientRawInputEvent.KEY_PRESSED.invoker().keyPressed(minecraft, key, scanCode, action, modifiers); + if (result != InteractionResult.PASS) + info.cancel(); + } + } } diff --git a/fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/client/MixinMouseHandler.java b/fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/client/MixinMouseHandler.java index 840abd51..93597f76 100644 --- a/fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/client/MixinMouseHandler.java +++ b/fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/client/MixinMouseHandler.java @@ -19,6 +19,7 @@ package me.shedaniel.architectury.mixin.fabric.client; +import me.shedaniel.architectury.event.events.client.ClientRawInputEvent; import me.shedaniel.architectury.event.events.client.ClientScreenInputEvent; import me.shedaniel.architectury.impl.fabric.ScreenInputDelegate; import net.minecraft.client.Minecraft; @@ -52,7 +53,7 @@ public class MixinMouseHandler { @Inject(method = "onScroll", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/Screen;mouseScrolled(DDD)Z", ordinal = 0), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD) - public void onMouseScrolled(long long_1, double double_1, double double_2, CallbackInfo info, double amount, double x, double y) { + public void onMouseScrolled(long handle, double xOffset, double yOffset, CallbackInfo info, double amount, double x, double y) { if (!info.isCancelled()) { InteractionResult result = ClientScreenInputEvent.MOUSE_SCROLLED_PRE.invoker().mouseScrolled(minecraft, minecraft.screen, x, y, amount); if (result != InteractionResult.PASS) @@ -63,29 +64,62 @@ public class MixinMouseHandler { @Inject(method = "onScroll", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/Screen;mouseScrolled(DDD)Z", ordinal = 0, shift = At.Shift.AFTER), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD) - public void onMouseScrolledPost(long long_1, double double_1, double double_2, CallbackInfo info, double amount, double x, double y) { + public void onMouseScrolledPost(long handle, double xOffset, double yOffset, CallbackInfo info, double amount, double x, double y) { if (!info.isCancelled()) { InteractionResult result = ClientScreenInputEvent.MOUSE_SCROLLED_POST.invoker().mouseScrolled(minecraft, minecraft.screen, x, y, amount); } } - @Inject(method = "onPress", at = @At(value = "INVOKE", - target = "Lnet/minecraft/client/gui/screens/Screen;wrapScreenError(Ljava/lang/Runnable;Ljava/lang/String;Ljava/lang/String;)V", - ordinal = 0), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD) - public void onMouseClicked(long long_1, int button, int int_2, int int_3, CallbackInfo info, boolean bl, int i, boolean[] bls, double d, double e) { + @Inject(method = "onScroll", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/LocalPlayer;isSpectator()Z", + ordinal = 0), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD) + public void onRawMouseScrolled(long handle, double xOffset, double yOffset, CallbackInfo info, double amount) { if (!info.isCancelled()) { - InteractionResult result = ClientScreenInputEvent.MOUSE_CLICKED_PRE.invoker().mouseClicked(minecraft, minecraft.screen, d, e, button); + InteractionResult result = ClientRawInputEvent.MOUSE_SCROLLED.invoker().mouseScrolled(minecraft, amount); if (result != InteractionResult.PASS) info.cancel(); } } - @Inject(method = "onPress", at = @At(value = "INVOKE", - target = "Lnet/minecraft/client/gui/screens/Screen;wrapScreenError(Ljava/lang/Runnable;Ljava/lang/String;Ljava/lang/String;)V", - ordinal = 0, shift = At.Shift.AFTER), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD) - public void onMouseClickedPost(long long_1, int button, int int_2, int int_3, CallbackInfo info, boolean bl, int i, boolean[] bls, double d, double e) { + @SuppressWarnings("UnresolvedMixinReference") + @Inject(method = {"lambda$onPress$0", "method_1611"}, at = @At("HEAD"), cancellable = true, remap = false) + public void onGuiMouseClicked(boolean[] bls, double d, double e, int button, CallbackInfo info) { if (!info.isCancelled()) { + InteractionResult result = ClientScreenInputEvent.MOUSE_CLICKED_PRE.invoker().mouseClicked(minecraft, minecraft.screen, d, e, button); + if (result != InteractionResult.PASS) { + bls[0] = true; + info.cancel(); + } + } + } + + @SuppressWarnings("UnresolvedMixinReference") + @Inject(method = {"lambda$onPress$0", "method_1611"}, at = @At("RETURN"), cancellable = true, remap = false) + public void onGuiMouseClickedPost(boolean[] bls, double d, double e, int button, CallbackInfo info) { + if (!info.isCancelled() && !bls[0]) { InteractionResult result = ClientScreenInputEvent.MOUSE_CLICKED_POST.invoker().mouseClicked(minecraft, minecraft.screen, d, e, button); + if (result != InteractionResult.PASS) { + bls[0] = true; + info.cancel(); + } + } + } + + @Inject(method = "onPress", at = @At(value = "FIELD", + target = "Lnet/minecraft/client/Minecraft;overlay:Lnet/minecraft/client/gui/screens/Overlay;", + ordinal = 0), cancellable = true) + public void onRawMouseClicked(long handle, int button, int action, int mods, CallbackInfo info) { + if (!info.isCancelled()) { + InteractionResult result = ClientRawInputEvent.MOUSE_CLICKED_PRE.invoker().mouseClicked(minecraft, button, action, mods); + if (result != InteractionResult.PASS) + info.cancel(); + } + } + + @Inject(method = "onPress", at = @At("RETURN"), cancellable = true) + public void onRawMouseClickedPost(long handle, int button, int action, int mods, CallbackInfo info) { + if (handle == this.minecraft.getWindow().getWindow()) { + InteractionResult result = ClientRawInputEvent.MOUSE_CLICKED_POST.invoker().mouseClicked(minecraft, button, action, mods); if (result != InteractionResult.PASS) info.cancel(); } diff --git a/forge/src/main/java/me/shedaniel/architectury/event/forge/EventHandlerImplClient.java b/forge/src/main/java/me/shedaniel/architectury/event/forge/EventHandlerImplClient.java index c5dc285d..190240eb 100644 --- a/forge/src/main/java/me/shedaniel/architectury/event/forge/EventHandlerImplClient.java +++ b/forge/src/main/java/me/shedaniel/architectury/event/forge/EventHandlerImplClient.java @@ -264,6 +264,30 @@ public class EventHandlerImplClient { ClientScreenInputEvent.KEY_RELEASED_POST.invoker().keyReleased(Minecraft.getInstance(), event.getGui(), event.getKeyCode(), event.getScanCode(), event.getModifiers()); } + @SubscribeEvent + public static void event(InputEvent.MouseScrollEvent event) { + if (ClientRawInputEvent.MOUSE_SCROLLED.invoker().mouseScrolled(Minecraft.getInstance(), event.getScrollDelta()) == InteractionResult.FAIL) { + event.setCanceled(true); + } + } + + @SubscribeEvent + public static void event(InputEvent.RawMouseEvent event) { + if (ClientRawInputEvent.MOUSE_CLICKED_PRE.invoker().mouseClicked(Minecraft.getInstance(), event.getButton(), event.getAction(), event.getMods()) == InteractionResult.FAIL) { + event.setCanceled(true); + } + } + + @SubscribeEvent + public static void event(InputEvent.MouseInputEvent event) { + ClientRawInputEvent.MOUSE_CLICKED_POST.invoker().mouseClicked(Minecraft.getInstance(), event.getButton(), event.getAction(), event.getMods()); + } + + @SubscribeEvent + public static void event(InputEvent.KeyInputEvent event) { + ClientRawInputEvent.KEY_PRESSED.invoker().keyPressed(Minecraft.getInstance(), event.getKey(), event.getScanCode(), event.getAction(), event.getModifiers()); + } + @OnlyIn(Dist.CLIENT) public static class ModBasedEventHandler { @SubscribeEvent diff --git a/testmod-common/src/main/java/me/shedaniel/architectury/test/TestMod.java b/testmod-common/src/main/java/me/shedaniel/architectury/test/TestMod.java index 9eecf7ae..732322eb 100644 --- a/testmod-common/src/main/java/me/shedaniel/architectury/test/TestMod.java +++ b/testmod-common/src/main/java/me/shedaniel/architectury/test/TestMod.java @@ -21,7 +21,7 @@ package me.shedaniel.architectury.test; import me.shedaniel.architectury.platform.Platform; import me.shedaniel.architectury.test.debug.ConsoleMessageSink; -import me.shedaniel.architectury.test.debug.DebugEvents; +import me.shedaniel.architectury.test.events.DebugEvents; import me.shedaniel.architectury.test.debug.MessageSink; import me.shedaniel.architectury.test.debug.client.ClientOverlayMessageSink; import me.shedaniel.architectury.test.registry.TestRegistries; diff --git a/testmod-common/src/main/java/me/shedaniel/architectury/test/debug/DebugEvents.java b/testmod-common/src/main/java/me/shedaniel/architectury/test/events/DebugEvents.java similarity index 93% rename from testmod-common/src/main/java/me/shedaniel/architectury/test/debug/DebugEvents.java rename to testmod-common/src/main/java/me/shedaniel/architectury/test/events/DebugEvents.java index 4f482d39..3acf5dc1 100644 --- a/testmod-common/src/main/java/me/shedaniel/architectury/test/debug/DebugEvents.java +++ b/testmod-common/src/main/java/me/shedaniel/architectury/test/events/DebugEvents.java @@ -17,21 +17,14 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package me.shedaniel.architectury.test.debug; +package me.shedaniel.architectury.test.events; import com.mojang.blaze3d.platform.InputConstants; import me.shedaniel.architectury.event.events.*; -import me.shedaniel.architectury.event.events.client.ClientChatEvent; -import me.shedaniel.architectury.event.events.client.ClientScreenInputEvent; -import me.shedaniel.architectury.event.events.client.ClientLifecycleEvent; -import me.shedaniel.architectury.event.events.client.ClientPlayerEvent; +import me.shedaniel.architectury.event.events.client.*; import me.shedaniel.architectury.hooks.ExplosionHooks; import me.shedaniel.architectury.platform.Platform; -import me.shedaniel.architectury.test.debug.client.ClientOverlayMessageSink; -import me.shedaniel.architectury.test.debug.ConsoleMessageSink; -import me.shedaniel.architectury.test.debug.MessageSink; import me.shedaniel.architectury.utils.Env; -import me.shedaniel.architectury.utils.EnvExecutor; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.core.Position; @@ -229,7 +222,7 @@ public class DebugEvents { SINK.accept("Client texture stitched: " + atlas.location()); }); ClientScreenInputEvent.MOUSE_SCROLLED_PRE.register((client, screen, mouseX, mouseY, amount) -> { - SINK.accept("Screen Mouse amount: %.2f distance", amount); + SINK.accept("Screen Mouse scrolled: %.2f distance", amount); return InteractionResult.PASS; }); ClientScreenInputEvent.MOUSE_CLICKED_PRE.register((client, screen, mouseX, mouseY, button) -> { @@ -256,6 +249,18 @@ public class DebugEvents { SINK.accept("Screen Key released: " + InputConstants.getKey(keyCode, scanCode).getDisplayName().getString()); return InteractionResult.PASS; }); + ClientRawInputEvent.MOUSE_SCROLLED.register((client, amount) -> { + SINK.accept("Raw Mouse scrolled: %.2f distance", amount); + return InteractionResult.PASS; + }); + ClientRawInputEvent.MOUSE_CLICKED_PRE.register((client, button, action, mods) -> { + SINK.accept("Raw Mouse clicked: " + button); + return InteractionResult.PASS; + }); + ClientRawInputEvent.KEY_PRESSED.register((client, keyCode, scanCode, action, modifiers) -> { + SINK.accept("Raw Key pressed: " + InputConstants.getKey(keyCode, scanCode).getDisplayName().getString()); + return InteractionResult.PASS; + }); } private static String toSimpleName(Object o) {