From effa043061528e90352cd8ac138e5d59f39dbf84 Mon Sep 17 00:00:00 2001 From: arcade_kappa Date: Sat, 21 Dec 2024 10:30:00 +0800 Subject: [PATCH] Copied cocoa ime blocker --- build.gradle | 5 +- .../com/cleanroommc/client/IMEHandler.java | 4 +- .../client/ime/CocoaIMEHandler.java | 61 ++++++++++++++++++- .../client/ime/WindowsIMEHandler.java | 4 +- 4 files changed, 68 insertions(+), 6 deletions(-) diff --git a/build.gradle b/build.gradle index 8cf5cab6..713fd6ba 100644 --- a/build.gradle +++ b/build.gradle @@ -485,9 +485,6 @@ project(':cleanroom') { installer "io.netty:netty-codec-dns:$props.netty_version" installer "io.netty:netty-resolver-dns:$props.netty_version" - // installer 'io.netty:netty-all:4.1.93.Final' - - // TODO: Unpin in 1.18.1 or when Mojang bumps the Log4J version installer 'org.apache.logging.log4j:log4j-api:2.24.1' installer 'org.apache.logging.log4j:log4j-core:2.24.1' installer 'org.apache.logging.log4j:log4j-slf4j2-impl:2.24.1' @@ -504,6 +501,8 @@ project(':cleanroom') { installer 'jakarta.activation:jakarta.activation-api:2.1.3' installer 'org.glassfish.corba:glassfish-corba-omgapi:4.2.5' installer 'org.openjdk.nashorn:nashorn-core:15.4' + installer 'ca.weblite:java-objc-bridge:1.2' + // Mixin installer 'com.cleanroommc:sponge-mixin:0.20.7+mixin.0.8.7' diff --git a/src/main/java/com/cleanroommc/client/IMEHandler.java b/src/main/java/com/cleanroommc/client/IMEHandler.java index 1740582e..4752efcb 100644 --- a/src/main/java/com/cleanroommc/client/IMEHandler.java +++ b/src/main/java/com/cleanroommc/client/IMEHandler.java @@ -1,5 +1,6 @@ package com.cleanroommc.client; +import com.cleanroommc.client.ime.CocoaIMEHandler; import com.cleanroommc.client.ime.WindowsIMEHandler; import net.minecraftforge.fml.common.FMLLog; import org.lwjgl.glfw.GLFW; @@ -11,7 +12,8 @@ public class IMEHandler { static { switch (GLFW.glfwGetPlatform()) { case GLFW.GLFW_PLATFORM_WIN32 -> instance = new WindowsIMEHandler(); - default -> FMLLog.log.warn("Unsupported platform: " + GLFW.glfwGetPlatform()); + case GLFW.GLFW_PLATFORM_COCOA -> instance = new CocoaIMEHandler(); + default -> FMLLog.log.warn("Unsupported platform: {}", GLFW.glfwGetPlatform()); } } public static void setIME(boolean active) { diff --git a/src/main/java/com/cleanroommc/client/ime/CocoaIMEHandler.java b/src/main/java/com/cleanroommc/client/ime/CocoaIMEHandler.java index 03491f0b..1dfa61e0 100644 --- a/src/main/java/com/cleanroommc/client/ime/CocoaIMEHandler.java +++ b/src/main/java/com/cleanroommc/client/ime/CocoaIMEHandler.java @@ -1,13 +1,72 @@ package com.cleanroommc.client.ime; +import ca.weblite.objc.Runtime; +import ca.weblite.objc.RuntimeUtils; +import com.sun.jna.Callback; +import com.sun.jna.Library; +import com.sun.jna.Native; import com.sun.jna.Pointer; import java.util.function.Consumer; +/** + * Copied from IMBlocker + */ public class CocoaIMEHandler implements Consumer { + private static boolean active = false; + static private final Pointer viewClass = Runtime.INSTANCE.objc_getClass("GLFWContentView"); + static private Pointer view = null; + static private final InterpretKeyEventsCallback Imp; + static private final InterpretKeyEventsCallback NewImp; + + static { + // see https://github.com/glfw/glfw/blob/b4c3ef9d0fdf46845f3e81e5d989dab06e71e6c1/src/cocoa_window.m#L571 + // Replacing the method dynamically to determine whether to send text based on state + // see reference for objc_runtime's dynamic manipulation at https://developer.apple.com/documentation/objectivec/objective-c_runtime + var selector = RuntimeUtils.sel("interpretKeyEvents:"); + var method = Runtime.INSTANCE.class_getInstanceMethod(viewClass, selector); + Imp = ObjC.INSTANCE.method_getImplementation(method); + NewImp = (self, sel, eventArray) -> { + if (view == null) view = self; + if (!active) { + var textInputContext = RuntimeUtils.cls("NSTextInputContext"); + var current = RuntimeUtils.msgPointer(textInputContext, "currentInputContext"); + RuntimeUtils.msg(current, "discardMarkedText"); + return; + } + Imp.invoke(self, sel, eventArray); + }; + ObjC.INSTANCE.class_replaceMethod(viewClass, selector, NewImp, "v@:@"); + } + /** + * The underlying native type is IMP, which should be a function pointer to the implementation of interpretKeyEvents: + * @see Documentation for IMP + * @see Documentation for interpretKeyEvents: + */ + private interface InterpretKeyEventsCallback extends Callback { + /** + * @param self "this" pointer for NSObject + * @param selector selector for interpretKeyEvents: + * @param eventArray an array of NSEvent objects + */ + void invoke(Pointer self, Pointer selector, Pointer eventArray); + } + + /** + * @see Apple Developer Documentation for objc_runtime: + */ + private interface ObjC extends Library { + ObjC INSTANCE = Native.load("objc.A", ObjC.class); + + void class_replaceMethod(Pointer cls, Pointer selector, InterpretKeyEventsCallback imp, String types); + + InterpretKeyEventsCallback method_getImplementation(Pointer selector); + } @Override public void accept(Boolean aBoolean) { - + if (active != aBoolean) { + active = aBoolean; + } } } diff --git a/src/main/java/com/cleanroommc/client/ime/WindowsIMEHandler.java b/src/main/java/com/cleanroommc/client/ime/WindowsIMEHandler.java index e8f04d68..bcc23258 100644 --- a/src/main/java/com/cleanroommc/client/ime/WindowsIMEHandler.java +++ b/src/main/java/com/cleanroommc/client/ime/WindowsIMEHandler.java @@ -6,8 +6,10 @@ import com.sun.jna.platform.win32.WinNT; import java.util.function.Consumer; -import java.util.function.Supplier; +/** + * Copied from IMBlocker + */ public class WindowsIMEHandler implements Consumer { private static native WinNT.HANDLE ImmGetContext(WinDef.HWND hwnd);