diff --git a/patchwork-events-input/build.gradle b/patchwork-events-input/build.gradle new file mode 100644 index 00000000..6bd98d9a --- /dev/null +++ b/patchwork-events-input/build.gradle @@ -0,0 +1,6 @@ +archivesBaseName = "patchwork-events-input" +version = getSubprojectVersion(project, "0.1.0") + +dependencies { + compile project(path: ':patchwork-fml', configuration: 'dev') +} diff --git a/patchwork-events-input/src/main/java/com/patchworkmc/mixin/event/input/MixinKeyboard.java b/patchwork-events-input/src/main/java/com/patchworkmc/mixin/event/input/MixinKeyboard.java new file mode 100644 index 00000000..6586d1ff --- /dev/null +++ b/patchwork-events-input/src/main/java/com/patchworkmc/mixin/event/input/MixinKeyboard.java @@ -0,0 +1,44 @@ +/* + * Minecraft Forge, Patchwork Project + * Copyright (c) 2016-2020, 2019-2020 + * + * This library 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 version 2.1 + * of the License. + * + * This library 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 library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.patchworkmc.mixin.event.input; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import net.minecraftforge.client.event.InputEvent; +import net.minecraftforge.common.MinecraftForge; + +import net.minecraft.client.Keyboard; +import net.minecraft.client.MinecraftClient; + +@Mixin(Keyboard.class) +public abstract class MixinKeyboard { + @Shadow + MinecraftClient client; + + @Inject(method = "onKey", at = @At("RETURN")) + private void fireKeyInput(long window, int key, int scancode, int i, int j, CallbackInfo info) { + if (window == this.client.window.getHandle()) { + MinecraftForge.EVENT_BUS.post(new InputEvent.KeyInputEvent(key, scancode, i, j)); + } + } +} diff --git a/patchwork-events-input/src/main/java/com/patchworkmc/mixin/event/input/MixinMouse.java b/patchwork-events-input/src/main/java/com/patchworkmc/mixin/event/input/MixinMouse.java new file mode 100644 index 00000000..c78b8814 --- /dev/null +++ b/patchwork-events-input/src/main/java/com/patchworkmc/mixin/event/input/MixinMouse.java @@ -0,0 +1,68 @@ +/* + * Minecraft Forge, Patchwork Project + * Copyright (c) 2016-2020, 2019-2020 + * + * This library 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 version 2.1 + * of the License. + * + * This library 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 library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.patchworkmc.mixin.event.input; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.At.Shift; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; +import net.minecraftforge.client.event.InputEvent; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.eventbus.api.Event; + +import net.minecraft.client.Mouse; + +@Mixin(Mouse.class) +public abstract class MixinMouse { + @Shadow + boolean middleButtonClicked; + @Shadow + abstract boolean wasLeftButtonClicked(); + @Shadow + abstract boolean wasRightButtonClicked(); + @Shadow + abstract double getX(); + @Shadow + abstract double getY(); + + @Inject(method = "onMouseButton", at = @At("RETURN"), cancellable = true) + private void fireMouseInput(long window, int button, int action, int mods, CallbackInfo info) { + MinecraftForge.EVENT_BUS.post(new InputEvent.MouseInputEvent(button, action, mods)); + } + + @Inject(method = "onMouseButton", at = @At(value = "FIELD", ordinal = 3, target = "Lnet/minecraft/client/Mouse;client:Lnet/minecraft/client/MinecraftClient;", shift = Shift.BEFORE), cancellable = true) + private void onRawMouseClicked(long window, int button, int action, int mods, CallbackInfo info) { + if (MinecraftForge.EVENT_BUS.post(new InputEvent.RawMouseEvent(button, action, mods))) { + info.cancel(); + } + } + + @Inject(method = "onMouseScroll", locals = LocalCapture.CAPTURE_FAILHARD, at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;isSpectator()Z", shift = Shift.BEFORE), cancellable = true) + private void onMouseScroll(long window, double d, double e, CallbackInfo info, double f, float i) { + final Event event = new InputEvent.MouseScrollEvent(f, wasLeftButtonClicked(), middleButtonClicked, wasRightButtonClicked(), getX(), getY()); + + if (MinecraftForge.EVENT_BUS.post(event)) { + info.cancel(); + } + } +} diff --git a/patchwork-events-input/src/main/java/net/minecraftforge/client/event/InputEvent.java b/patchwork-events-input/src/main/java/net/minecraftforge/client/event/InputEvent.java new file mode 100644 index 00000000..5d7854e3 --- /dev/null +++ b/patchwork-events-input/src/main/java/net/minecraftforge/client/event/InputEvent.java @@ -0,0 +1,259 @@ +/* + * Minecraft Forge, Patchwork Project + * Copyright (c) 2016-2020, 2019-2020 + * + * This library 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 version 2.1 + * of the License. + * + * This library 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 library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.client.event; + +import net.minecraftforge.eventbus.api.Event; +import org.lwjgl.glfw.GLFW; + +public class InputEvent extends Event { + /** + * A cancellable mouse event fired before key bindings are updated. + */ + public static class RawMouseEvent extends InputEvent { + private final int action; + private final int button; + private final int mods; + + // For EventBus + public RawMouseEvent() { + this(-1, -1, -1); + } + + public RawMouseEvent(int button, int action, int mods) { + this.button = button; + this.action = action; + this.mods = mods; + } + + /** + * The mouse button that triggered this event. + * https://www.glfw.org/docs/latest/group__buttons.html + * + * @see GLFW mouse constants starting with "GLFW_MOUSE_BUTTON_" + */ + public int getButton() { + return this.button; + } + + /** + * Integer representing the mouse button's action. + * + * @see GLFW#GLFW_PRESS + * @see GLFW#GLFW_RELEASE + */ + public int getAction() { + return this.action; + } + + /** + * Bit field representing the modifier keys pressed. + * https://www.glfw.org/docs/latest/group__mods.html + * + * @see GLFW#GLFW_MOD_SHIFT + * @see GLFW#GLFW_MOD_CONTROL + * @see GLFW#GLFW_MOD_ALT + * @see GLFW#GLFW_MOD_SUPER + */ + public int getMods() { + return this.mods; + } + + @Override + public boolean isCancelable() { + return true; + } + } + + /** + * This event fires when a mouse input is detected. + */ + public static class MouseInputEvent extends InputEvent { + private final int button; + private final int action; + private final int mods; + + // For EventBus + public MouseInputEvent() { + this(-1, -1, -1); + } + + public MouseInputEvent(int button, int action, int mods) { + this.button = button; + this.action = action; + this.mods = mods; + } + + /** + * The mouse button that triggered this event. + * https://www.glfw.org/docs/latest/group__buttons.html + * + * @see GLFW mouse constants starting with "GLFW_MOUSE_BUTTON_" + */ + public int getButton() { + return this.button; + } + + /** + * Integer representing the mouse button's action. + * + * @see GLFW#GLFW_PRESS + * @see GLFW#GLFW_RELEASE + */ + public int getAction() { + return this.action; + } + + /** + * Bit field representing the modifier keys pressed. + * https://www.glfw.org/docs/latest/group__mods.html + * + * @see GLFW#GLFW_MOD_SHIFT + * @see GLFW#GLFW_MOD_CONTROL + * @see GLFW#GLFW_MOD_ALT + * @see GLFW#GLFW_MOD_SUPER + */ + public int getMods() { + return this.mods; + } + } + + /** + * This event fires when the mouse scroll wheel is used outside of a gui. + */ + public static class MouseScrollEvent extends InputEvent { + private final double scrollDelta; + private final double mouseX; + private final double mouseY; + private final boolean leftDown; + private final boolean middleDown; + private final boolean rightDown; + + // For EventBus + public MouseScrollEvent() { + this(-1, false, false, false, -1, -1); + } + + public MouseScrollEvent(double scrollDelta, boolean leftDown, boolean middleDown, boolean rightDown, double mouseX, double mouseY) { + this.scrollDelta = scrollDelta; + this.leftDown = leftDown; + this.middleDown = middleDown; + this.rightDown = rightDown; + this.mouseX = mouseX; + this.mouseY = mouseY; + } + + public double getScrollDelta() { + return this.scrollDelta; + } + + public boolean isLeftDown() { + return this.leftDown; + } + + public boolean isRightDown() { + return this.rightDown; + } + + public boolean isMiddleDown() { + return this.middleDown; + } + + public double getMouseX() { + return this.mouseX; + } + + public double getMouseY() { + return this.mouseY; + } + + @Override + public boolean isCancelable() { + return true; + } + } + + /** + * This event fires when a keyboard input is detected. + */ + public static class KeyInputEvent extends InputEvent { + private final int key; + private final int scanCode; + private final int action; + private final int modifiers; + + // For EventBus + public KeyInputEvent() { + this(-1, -1, -1, -1); + } + + public KeyInputEvent(int key, int scanCode, int action, int modifiers) { + this.key = key; + this.scanCode = scanCode; + this.action = action; + this.modifiers = modifiers; + } + + /** + * The keyboard key that triggered this event. + * https://www.glfw.org/docs/latest/group__keys.html + * + * @see GLFW key constants starting with "GLFW_KEY_" + */ + public int getKey() { + return this.key; + } + + /** + * Platform-specific scan code. + * Used for {@link InputMappings#getInputByCode(int, int)} + * + *
The scan code is unique for every key, regardless of whether it has a key code. + * Scan codes are platform-specific but consistent over time, so keys will have different scan codes depending + * on the platform but they are safe to save to disk as custom key bindings. + */ + public int getScanCode() { + return this.scanCode; + } + + /** + * Integer representing the key's action. + * + * @see GLFW#GLFW_PRESS + * @see GLFW#GLFW_RELEASE + * @see GLFW#GLFW_REPEAT + */ + public int getAction() { + return this.action; + } + + /** + * Bit field representing the modifier keys pressed. + * https://www.glfw.org/docs/latest/group__mods.html + * + * @see GLFW#GLFW_MOD_SHIFT + * @see GLFW#GLFW_MOD_CONTROL + * @see GLFW#GLFW_MOD_ALT + * @see GLFW#GLFW_MOD_SUPER + */ + public int getModifiers() { + return this.modifiers; + } + } +} diff --git a/patchwork-events-input/src/main/resources/assets/patchwork-events-input/icon.png b/patchwork-events-input/src/main/resources/assets/patchwork-events-input/icon.png new file mode 100644 index 00000000..de75d2fb Binary files /dev/null and b/patchwork-events-input/src/main/resources/assets/patchwork-events-input/icon.png differ diff --git a/patchwork-events-input/src/main/resources/fabric.mod.json b/patchwork-events-input/src/main/resources/fabric.mod.json new file mode 100644 index 00000000..16aaabc5 --- /dev/null +++ b/patchwork-events-input/src/main/resources/fabric.mod.json @@ -0,0 +1,27 @@ +{ + "schemaVersion": 1, + "id": "patchwork-events-input", + "name": "Patchwork Input Events", + "version": "${version}", + "license": "LGPL-2.1-only", + "icon": "assets/patchwork-events-input/icon.png", + "contact": { + "issues": "https://github.com/PatchworkMC/patchwork-api/issues", + "sources": "https://github.com/PatchworkMC/patchwork-api" + }, + "authors": [ + "PatchworkMC" + ], + "depends": { + "fabricloader": ">=0.6.2", + "patchwork-fml": "*" + }, + "mixins": [ + "patchwork-events-input.mixins.json" + ], + "description": "Implementation of the Forge Mouse/Keyboard Input Hooks.", + "custom": { + "modmenu:api": true, + "modmenu:parent": "patchwork" + } +} diff --git a/patchwork-events-input/src/main/resources/patchwork-events-input.mixins.json b/patchwork-events-input/src/main/resources/patchwork-events-input.mixins.json new file mode 100644 index 00000000..af35c946 --- /dev/null +++ b/patchwork-events-input/src/main/resources/patchwork-events-input.mixins.json @@ -0,0 +1,12 @@ +{ + "required": true, + "package": "com.patchworkmc.mixin.event.input", + "compatibilityLevel": "JAVA_8", + "client": [ + "MixinKeyboard", + "MixinMouse" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/settings.gradle b/settings.gradle index a344d50c..cbe723c3 100644 --- a/settings.gradle +++ b/settings.gradle @@ -15,6 +15,7 @@ rootProject.name = "patchwork-api" include 'patchwork-biomes' include 'patchwork-dispatcher' include 'patchwork-events-entity' +include 'patchwork-events-input' include 'patchwork-events-lifecycle' include 'patchwork-events-world' include 'patchwork-extensions-shearing'