Skip to content

Commit

Permalink
Support Wayland (BETA)
Browse files Browse the repository at this point in the history
  • Loading branch information
LemonCaramel committed Feb 7, 2024
1 parent 370584f commit 9279be1
Show file tree
Hide file tree
Showing 7 changed files with 264 additions and 13 deletions.
33 changes: 21 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -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)
<img src="common/src/main/resources/icon.png" width="96" alt="caramelChat Icon"/>

# caramelChat
Provides an enhanced IME input experience in Minecraft.

---
Expand All @@ -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.

Expand Down Expand Up @@ -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.

Expand Down
3 changes: 3 additions & 0 deletions common/src/main/java/moe/caramel/chat/driver/IController.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
};
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
Binary file not shown.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ mod_version=1.2.0-SNAPSHOT
maven_group=moe.caramel

minecraft_version=1.19.4
fabric_loader_version=0.14.22
fabric_loader_version=0.15.6
forge_version=1.19.4-45.1.16

# Other mods
Expand Down

0 comments on commit 9279be1

Please sign in to comment.