From e6d4b6ae8de15a5f72d8c6964077efba0ffb1c2f Mon Sep 17 00:00:00 2001 From: caramel Date: Thu, 8 Feb 2024 00:05:30 +0900 Subject: [PATCH] Support Wayland (BETA) --- README.md | 33 ++++-- .../moe/caramel/chat/driver/IController.java | 3 + .../driver/arch/wayland/Driver_Wayland.java | 72 ++++++++++++ .../arch/wayland/WaylandController.java | 108 ++++++++++++++++++ .../driver/arch/wayland/WaylandOperator.java | 59 ++++++++++ .../main/resources/native/libcaramelchatwl.so | Bin 0 -> 26864 bytes gradle.properties | 2 +- 7 files changed, 264 insertions(+), 13 deletions(-) create mode 100644 common/src/main/java/moe/caramel/chat/driver/arch/wayland/Driver_Wayland.java create mode 100644 common/src/main/java/moe/caramel/chat/driver/arch/wayland/WaylandController.java create mode 100644 common/src/main/java/moe/caramel/chat/driver/arch/wayland/WaylandOperator.java create mode 100644 common/src/main/resources/native/libcaramelchatwl.so diff --git a/README.md b/README.md index af9d6f8..195e6b3 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ -# caramelChat - -![GitHub Issues](https://img.shields.io/github/issues/LemonCaramel/caramelChat.svg) -![GitHub Tag](https://img.shields.io/github/tag/LemonCaramel/caramelChat.svg) +caramelChat Icon +# caramelChat Provides an enhanced IME input experience in Minecraft. --- @@ -17,14 +15,16 @@ It must be the same as the OS compatibility of CocoaInput. We plan to use our Native library in caramelChat v2.0. Compatibility will gradually improve. -| OS | Compatibility | -|:-------------------------:|:-----------------------------:| -| **Windows** (x86_64) | 🟢 Compatible | -| **Windows** (arm64) | 🔴 Incompatible | -| **macOS** (Intel) | 🟢 Compatible | -| **macOS** (Apple Silicon) | 🟢 Compatible | -| **X11 Linux** (x86_64) | 🟡 Incompatible in some cases | -| **X11 Linux** (arm64) | 🔴 Incompatible | +| OS | Compatibility | +|:---------------------------:|:-----------------------------:| +| **Windows** (x86_64) | 🟢 Compatible | +| **Windows** (arm64) | 🔴 Incompatible | +| **macOS** (Intel) | 🟢 Compatible | +| **macOS** (Apple Silicon) | 🟢 Compatible | +| **Linux X11** (x86_64) | 🟡 Incompatible in some cases | +| **Linux X11** (arm64) | 🔴 Incompatible | +| **Linux Wayland** (x86_64) | 🟡 Incompatible in some cases | +| **Linux Wayland** (arm64) | 🔴 Incompatible | Below is the ModLoader compatibility. @@ -52,6 +52,15 @@ sudo /usr/libexec/PlistBuddy -c "Add 'redesigned_text_cursor:Enabled' bool false ``` And then, reboot your Macintosh. This will return you to the input environment from before Sonoma. +## 🛠️ Troubleshooting (Linux Wayland) + +In some Linux distributions that use the Wayland protocol, crashes may occur. +This happens because Xwayland is present in the system, causing GLFW to attempt to run based on X11. + +Fortunately, there are third-party mods available to address this issue. + +**WayGL:** [Modrinth](https://modrinth.com/mod/waygl), [Github](https://github.com/wired-tomato/WayGL) + ## 🚀️ Contributing All contributions are welcome regardless of Native or Java. diff --git a/common/src/main/java/moe/caramel/chat/driver/IController.java b/common/src/main/java/moe/caramel/chat/driver/IController.java index 05c926b..cead3c5 100644 --- a/common/src/main/java/moe/caramel/chat/driver/IController.java +++ b/common/src/main/java/moe/caramel/chat/driver/IController.java @@ -2,6 +2,7 @@ import moe.caramel.chat.driver.arch.darwin.DarwinController; import moe.caramel.chat.driver.arch.unknown.UnknownController; +import moe.caramel.chat.driver.arch.wayland.WaylandController; import moe.caramel.chat.driver.arch.win.WinController; import moe.caramel.chat.driver.arch.x11.X11Controller; import moe.caramel.chat.util.ModLogger; @@ -61,6 +62,8 @@ static IController getController() { case GLFW.GLFW_PLATFORM_COCOA -> new DarwinController(); // Linux (X11) case GLFW.GLFW_PLATFORM_X11 -> new X11Controller(); + // Linux (Wayland) + case GLFW.GLFW_PLATFORM_WAYLAND -> new WaylandController(); // What? default -> throw new UnsupportedOperationException(); }; diff --git a/common/src/main/java/moe/caramel/chat/driver/arch/wayland/Driver_Wayland.java b/common/src/main/java/moe/caramel/chat/driver/arch/wayland/Driver_Wayland.java new file mode 100644 index 0000000..089c2d1 --- /dev/null +++ b/common/src/main/java/moe/caramel/chat/driver/arch/wayland/Driver_Wayland.java @@ -0,0 +1,72 @@ +package moe.caramel.chat.driver.arch.wayland; + +import com.sun.jna.Callback; +import com.sun.jna.Library; +import com.sun.jna.Pointer; +import com.sun.jna.WString; + +/** + * caramelChat Wayland Driver + */ +public interface Driver_Wayland extends Library { + + /** + * Initialize caramelChat Wayland Driver. + * + * @param wlDisplay Wayland Display + * @param preEdit PreEdit Callback + * @param preEditNull PreEdit Null Callback + * @param done Done Callback + * @param rect Rect Callback + * @param log Log Info Callback + * @param error Log Error Callback + * @param debug Log Debug Callback + */ + void initialize( + final long wlDisplay, + final PreeditCallback preEdit, + final PreeditNullCallback preEditNull, + final DoneCallback done, + final RectCallback rect, + final LogInfoCallback log, + final LogErrorCallback error, + final LogDebugCallback debug + ); + + /** + * Set whether to focus or not. + * + * @param flag focus + */ + void setFocus(final boolean flag); + + // ================================ + + interface PreeditCallback extends Callback { + void invoke(final WString string); + } + + interface PreeditNullCallback extends Callback { + void invoke(); + } + + interface DoneCallback extends Callback { + void invoke(final WString string); + } + + interface RectCallback extends Callback { + int invoke(final Pointer pointer); + } + + interface LogInfoCallback extends Callback { + void invoke(final String log); + } + + interface LogErrorCallback extends Callback { + void invoke(final String log); + } + + interface LogDebugCallback extends Callback { + void invoke(final String log); + } +} diff --git a/common/src/main/java/moe/caramel/chat/driver/arch/wayland/WaylandController.java b/common/src/main/java/moe/caramel/chat/driver/arch/wayland/WaylandController.java new file mode 100644 index 0000000..a79d85e --- /dev/null +++ b/common/src/main/java/moe/caramel/chat/driver/arch/wayland/WaylandController.java @@ -0,0 +1,108 @@ +package moe.caramel.chat.driver.arch.wayland; + +import com.mojang.blaze3d.platform.Window; +import com.sun.jna.Native; +import moe.caramel.chat.Main; +import moe.caramel.chat.controller.ScreenController; +import moe.caramel.chat.driver.IController; +import moe.caramel.chat.driver.IOperator; +import moe.caramel.chat.util.ModLogger; +import moe.caramel.chat.wrapper.AbstractIMEWrapper; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; +import org.lwjgl.glfw.GLFWNativeWayland; + +/** + * Wayland Controller + */ +public final class WaylandController implements IController { + + static WaylandOperator focused; + + private final Driver_Wayland driver; + + /** + * Create Wayland Controller + */ + public WaylandController() { + ModLogger.log("[Native] Load the Wayland Controller."); + this.driver = Native.load(Main.copyLibrary("libcaramelchatwl.so"), Driver_Wayland.class); + + this.driver.initialize( + // Wayland Display Id + GLFWNativeWayland.glfwGetWaylandDisplay(), + // PreEdit + (str) -> { + if (focused != null) { + ModLogger.debug("[Native|Java] Preedit Callback (" + str.toString() + ")"); + focused.getWrapper().appendPreviewText(str.toString()); + } + }, + // PreEdit (Null) + () -> { + if (focused != null) { + ModLogger.debug("[Native|Java] Preedit Null Callback"); + focused.getWrapper().appendPreviewText(""); + } + }, + // Done + (str) -> { + if (focused != null) { + ModLogger.debug("[Native|Java] Done Callback (" + str.toString() + ")"); + focused.getWrapper().insertText(str.toString()); + } + }, + // Rect + (rect) -> { + if (focused != null) { + ModLogger.debug("[Native|Java] Rect Callback"); + final Window window = Minecraft.getInstance().getWindow(); + final int osScale = (window.getHeight() / window.getScreenHeight()); + + final float[] buff = focused.getWrapper().getRect().copy(); + final float factor = (float) window.getGuiScale(); + buff[0] *= factor; + buff[1] *= factor; + buff[2] *= factor; + buff[3] *= factor; + + buff[1] /= osScale; + + rect.write(0, buff, 0, 4); + return 0; + } + return 1; + }, + // Info + (log) -> ModLogger.log("[Native|C] " + log), + // Error + (log) -> ModLogger.error("[Native|C] " + log), + // Debug + (log) -> ModLogger.debug("[Native|C] " + log) + ); + + this.setFocus(false); + } + + @Override + public IOperator createOperator(final AbstractIMEWrapper wrapper) { + return new WaylandOperator(this, wrapper); + } + + @Override + public void changeFocusedScreen(final Screen screen) { + if (screen instanceof ScreenController) { + return; + } + + if (WaylandController.focused != null) { + WaylandController.focused.setFocused(false); + WaylandController.focused = null; + } + } + + @Override + public void setFocus(final boolean focus) { + this.driver.setFocus(focus); + } +} diff --git a/common/src/main/java/moe/caramel/chat/driver/arch/wayland/WaylandOperator.java b/common/src/main/java/moe/caramel/chat/driver/arch/wayland/WaylandOperator.java new file mode 100644 index 0000000..d51b410 --- /dev/null +++ b/common/src/main/java/moe/caramel/chat/driver/arch/wayland/WaylandOperator.java @@ -0,0 +1,59 @@ +package moe.caramel.chat.driver.arch.wayland; + +import moe.caramel.chat.driver.IController; +import moe.caramel.chat.driver.IOperator; +import moe.caramel.chat.util.ModLogger; +import moe.caramel.chat.wrapper.AbstractIMEWrapper; + +/** + * Wayland IME Operator + */ +public final class WaylandOperator implements IOperator { + + private final WaylandController controller; + private final AbstractIMEWrapper wrapper; + private boolean nowFocused; + + public WaylandOperator(final WaylandController controller, final AbstractIMEWrapper wrapper) { + this.controller = controller; + this.wrapper = wrapper; + } + + /** + * Gets the IME wrapper. + * + * @return IME wrapper + */ + public AbstractIMEWrapper getWrapper() { + return wrapper; + } + + @Override + public IController getController() { + return controller; + } + + @Override + public void setFocused(final boolean focus) { + if (focus == this.nowFocused) { + return; + } + + ModLogger.debug("[Native|Java] Called setFocused: " + focus); + this.nowFocused = focus; + + if (focus) { + WaylandController.focused = this; + this.controller.setFocus(true); + } else if (WaylandController.focused == this) { + this.wrapper.insertText(""); + WaylandController.focused = null; + this.controller.setFocus(false); + } + } + + @Override + public boolean isFocused() { + return nowFocused; + } +} diff --git a/common/src/main/resources/native/libcaramelchatwl.so b/common/src/main/resources/native/libcaramelchatwl.so new file mode 100644 index 0000000000000000000000000000000000000000..a4e4598f9dae93ef90d79a9c1922cccde62f3fed GIT binary patch literal 26864 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 hhWuyG-KNs&oY)L6?TYSXRC3v0?l&4UECY*G{{