From 20cdab1ab7c614b0f85f00797c59928ec48090af Mon Sep 17 00:00:00 2001 From: Windmill_City <1449182174@qq.com> Date: Tue, 16 Jan 2024 11:05:29 +0800 Subject: [PATCH] advanced state management --- .../city/windmill/ingameime/ClientProxy.java | 47 +++++++-- .../windmill/ingameime/IMEventHandler.java | 16 +++ .../city/windmill/ingameime/IMStates.java | 98 +++++++++++++++++++ .../city/windmill/ingameime/Internal.java | 58 ++++------- .../ingameime/mixins/MixinGuiTextField.java | 2 +- .../ingameime/mixins/MixinMinecraft.java | 7 +- IngameIME-Native/build.gradle.kts | 2 + 7 files changed, 182 insertions(+), 48 deletions(-) create mode 100644 1.7.10/src/main/java/city/windmill/ingameime/IMEventHandler.java create mode 100644 1.7.10/src/main/java/city/windmill/ingameime/IMStates.java diff --git a/1.7.10/src/main/java/city/windmill/ingameime/ClientProxy.java b/1.7.10/src/main/java/city/windmill/ingameime/ClientProxy.java index 100e500..d7ed812 100644 --- a/1.7.10/src/main/java/city/windmill/ingameime/ClientProxy.java +++ b/1.7.10/src/main/java/city/windmill/ingameime/ClientProxy.java @@ -10,13 +10,16 @@ import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; +import javax.annotation.Nonnull; + import static city.windmill.ingameime.IngameIME_Forge.LOG; import static org.lwjgl.input.Keyboard.KEY_HOME; -public class ClientProxy extends CommonProxy { +public class ClientProxy extends CommonProxy implements IMEventHandler { + public static ClientProxy INSTANCE = null; public static OverlayScreen Screen = new OverlayScreen(); public static KeyBinding KeyBind = new KeyBinding("ingameime.key.desc", KEY_HOME, "IngameIME"); - public static boolean IsToggledManually = false; + public static city.windmill.ingameime.IMEventHandler IMEventHandler = IMStates.Disabled; private static boolean IsKeyDown = false; @SubscribeEvent @@ -27,23 +30,51 @@ public void onRenderScreen(GuiScreenEvent.DrawScreenEvent.Post event) { IsKeyDown = true; } else if (IsKeyDown) { IsKeyDown = false; - ClientProxy.IsToggledManually = true; - Internal.toggleInputMethod(); - LOG.info("Toggled by keybinding"); + onToggleKey(); } if (Config.TurnOffOnMouseMove.getBoolean()) - if (ClientProxy.IsToggledManually && (Mouse.getDX() > 0 || Mouse.getDY() > 0)) { - Internal.setActivated(false); - LOG.info("Turned off by mouse move"); + if (IMEventHandler == IMStates.OpenedManual && (Mouse.getDX() > 0 || Mouse.getDY() > 0)) { + onMouseMove(); } } public void preInit(FMLPreInitializationEvent event) { + INSTANCE = this; Config.synchronizeConfiguration(event.getSuggestedConfigurationFile()); ClientRegistry.registerKeyBinding(KeyBind); Internal.loadLibrary(); Internal.createInputCtx(); MinecraftForge.EVENT_BUS.register(this); } + + @Override + public IMStates onScreenClose() { + IMEventHandler = IMEventHandler.onScreenClose(); + return null; + } + + @Override + public IMStates onControlFocus(@Nonnull Object control, boolean focused) { + IMEventHandler = IMEventHandler.onControlFocus(control, focused); + return null; + } + + @Override + public IMStates onScreenOpen(Object screen) { + IMEventHandler = IMEventHandler.onScreenOpen(screen); + return null; + } + + @Override + public IMStates onToggleKey() { + IMEventHandler = IMEventHandler.onToggleKey(); + return null; + } + + @Override + public IMStates onMouseMove() { + IMEventHandler = IMEventHandler.onMouseMove(); + return null; + } } diff --git a/1.7.10/src/main/java/city/windmill/ingameime/IMEventHandler.java b/1.7.10/src/main/java/city/windmill/ingameime/IMEventHandler.java new file mode 100644 index 0000000..598521d --- /dev/null +++ b/1.7.10/src/main/java/city/windmill/ingameime/IMEventHandler.java @@ -0,0 +1,16 @@ +package city.windmill.ingameime; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public interface IMEventHandler { + IMStates onScreenClose(); + + IMStates onControlFocus(@Nonnull Object control, boolean focused); + + IMStates onScreenOpen(@Nullable Object screen); + + IMStates onToggleKey(); + + IMStates onMouseMove(); +} diff --git a/1.7.10/src/main/java/city/windmill/ingameime/IMStates.java b/1.7.10/src/main/java/city/windmill/ingameime/IMStates.java new file mode 100644 index 0000000..a6b00b5 --- /dev/null +++ b/1.7.10/src/main/java/city/windmill/ingameime/IMStates.java @@ -0,0 +1,98 @@ +package city.windmill.ingameime; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public enum IMStates implements IMEventHandler { + Disabled { + @Override + public IMStates onControlFocus(@Nonnull Object control, boolean focused) { + if (focused) { + ActiveControl = control; + IngameIME_Forge.LOG.info("Opened by control focus: {}", ActiveControl.getClass()); + Internal.setActivated(true); + return OpenedAuto; + } else { + return this; + } + } + + @Override + public IMStates onToggleKey() { + IngameIME_Forge.LOG.info("Turned on by toggle key"); + Internal.setActivated(true); + return OpenedManual; + } + + }, + OpenedManual { + @Override + public IMStates onControlFocus(@Nonnull Object control, boolean focused) { + // Ignore all focus event + return this; + } + + @Override + public IMStates onMouseMove() { + if (!Config.TurnOffOnMouseMove.getBoolean()) return this; + IngameIME_Forge.LOG.info("Turned off by mouse move"); + Internal.setActivated(false); + return Disabled; + } + }, + OpenedAuto { + @Override + public IMStates onControlFocus(@Nonnull Object control, boolean focused) { + // Ignore not active focus one + if (!focused && control != ActiveControl) return this; + + if (!focused) { + IngameIME_Forge.LOG.info("Turned off by losing control focus: {}", ActiveControl.getClass()); + Internal.setActivated(false); + return Disabled; + } + + // Update active focused control + if (ActiveControl != control) { + ActiveControl = control; + IngameIME_Forge.LOG.info("Opened by control focus: {}", ActiveControl.getClass()); + Internal.setActivated(true); + ClientProxy.Screen.WInputMode.setActive(true); + } + return this; + } + }; + + @Nullable + public static Object ActiveScreen = null; + @Nullable + public static Object ActiveControl = null; + + @Override + public IMStates onScreenClose() { + if (ActiveScreen != null) IngameIME_Forge.LOG.info("Screen closed: {}", ActiveScreen.getClass()); + Internal.setActivated(false); + ActiveScreen = null; + return Disabled; + } + + @Override + public IMStates onScreenOpen(Object screen) { + if (ActiveScreen == screen) return this; + ActiveScreen = screen; + if (ActiveScreen != null) IngameIME_Forge.LOG.info("Screen Opened: {}", ActiveScreen.getClass()); + return this; + } + + @Override + public IMStates onMouseMove() { + return this; + } + + @Override + public IMStates onToggleKey() { + IngameIME_Forge.LOG.info("Turned off by toggle key"); + Internal.setActivated(false); + return Disabled; + } +} diff --git a/1.7.10/src/main/java/city/windmill/ingameime/Internal.java b/1.7.10/src/main/java/city/windmill/ingameime/Internal.java index 9ef07dd..a2c076b 100644 --- a/1.7.10/src/main/java/city/windmill/ingameime/Internal.java +++ b/1.7.10/src/main/java/city/windmill/ingameime/Internal.java @@ -32,20 +32,18 @@ public class Internal { static InputModeCallback inputModeCallback = null; private static void tryLoadLibrary(String libName) { - if (!LIBRARY_LOADED) - try { - InputStream lib = IngameIME.class.getClassLoader().getResourceAsStream(libName); - if (lib == null) throw new RuntimeException("Required library resource not exist!"); - Path path = Files.createTempFile("IngameIME-Native", null); - Files.copy(lib, path, StandardCopyOption.REPLACE_EXISTING); - System.load(path.toString()); - LIBRARY_LOADED = true; - LOG.info("Library [{}] has loaded!", libName); - } catch (Throwable e) { - LOG.warn("Try to load library [{}] but failed: {}", libName, e.getClass().getSimpleName()); - } - else - LOG.info("Library has loaded, skip loading of [{}]", libName); + if (!LIBRARY_LOADED) try { + InputStream lib = IngameIME.class.getClassLoader().getResourceAsStream(libName); + if (lib == null) throw new RuntimeException("Required library resource not exist!"); + Path path = Files.createTempFile("IngameIME-Native", null); + Files.copy(lib, path, StandardCopyOption.REPLACE_EXISTING); + System.load(path.toString()); + LIBRARY_LOADED = true; + LOG.info("Library [{}] has loaded!", libName); + } catch (Throwable e) { + LOG.warn("Try to load library [{}] but failed: {}", libName, e.getClass().getSimpleName()); + } + else LOG.info("Library has loaded, skip loading of [{}]", libName); } private static long getWindowHandle_LWJGL3() { @@ -89,13 +87,10 @@ public static void createInputCtx() { LOG.info("Using IngameIME-Native: {}", InputContext.getVersion()); - long hWnd = Loader.isModLoaded("lwjgl3ify") ? - getWindowHandle_LWJGL3() : - getWindowHandle_LWJGL2(); + long hWnd = Loader.isModLoaded("lwjgl3ify") ? getWindowHandle_LWJGL3() : getWindowHandle_LWJGL2(); if (hWnd != 0) { // Once switched to the full screen, we can't back to not UiLess mode, unless restart the game - if (Minecraft.getMinecraft().isFullScreen()) - Config.UiLess_Windows.set(true); + if (Minecraft.getMinecraft().isFullScreen()) Config.UiLess_Windows.set(true); API api = Config.API_Windows.getString().equals("TextServiceFramework") ? API.TextServiceFramework : API.Imm32; LOG.info("Using API: {}, UiLess: {}", api, Config.UiLess_Windows.getBoolean()); InputCtx = IngameIME.CreateInputContextWin32(hWnd, api, Config.UiLess_Windows.getBoolean()); @@ -112,13 +107,10 @@ protected void call(CompositionState arg0, PreEditContext arg1) { LOG.info("PreEdit State: {}", arg0); //Hide Indicator when PreEdit start - if (arg0 == CompositionState.Begin) - ClientProxy.Screen.WInputMode.setActive(false); + if (arg0 == CompositionState.Begin) ClientProxy.Screen.WInputMode.setActive(false); - if (arg1 != null) - ClientProxy.Screen.PreEdit.setContent(arg1.getContent(), arg1.getSelStart()); - else - ClientProxy.Screen.PreEdit.setContent(null, -1); + if (arg1 != null) ClientProxy.Screen.PreEdit.setContent(arg1.getContent(), arg1.getSelStart()); + else ClientProxy.Screen.PreEdit.setContent(null, -1); } catch (Throwable e) { LOG.error("Exception thrown during callback handling", e); } @@ -156,8 +148,7 @@ protected void call(CandidateListState arg0, CandidateListContext arg1) { try { if (arg1 != null) ClientProxy.Screen.CandidateList.setContent(new ArrayList<>(arg1.getCandidates()), arg1.getSelection()); - else - ClientProxy.Screen.CandidateList.setContent(null, -1); + else ClientProxy.Screen.CandidateList.setContent(null, -1); } catch (Throwable e) { LOG.error("Exception thrown during callback handling", e); } @@ -203,21 +194,14 @@ static void loadLibrary() { } public static boolean getActivated() { - if (InputCtx != null) { - return InputCtx.getActivated(); - } - return false; + if (InputCtx != null) return InputCtx.getActivated(); + else return false; } public static void setActivated(boolean activated) { if (InputCtx != null && getActivated() != activated) { InputCtx.setActivated(activated); - if (!activated) ClientProxy.IsToggledManually = false; - LOG.info("InputMethod activated: {}", activated); + LOG.info("IM active state: {}", activated); } } - - public static void toggleInputMethod() { - setActivated(!getActivated()); - } } diff --git a/1.7.10/src/main/java/city/windmill/ingameime/mixins/MixinGuiTextField.java b/1.7.10/src/main/java/city/windmill/ingameime/mixins/MixinGuiTextField.java index c47bcea..ff72408 100644 --- a/1.7.10/src/main/java/city/windmill/ingameime/mixins/MixinGuiTextField.java +++ b/1.7.10/src/main/java/city/windmill/ingameime/mixins/MixinGuiTextField.java @@ -24,6 +24,6 @@ void onDrawCaret(CallbackInfo ci, int var1, int var2, int var3, String var4, int @Inject(method = "setFocused", at = @At(value = "HEAD")) void onSetFocus(boolean focused, CallbackInfo ci) { - Internal.setActivated(focused); + ClientProxy.INSTANCE.onControlFocus(this, focused); } } diff --git a/1.7.10/src/main/java/city/windmill/ingameime/mixins/MixinMinecraft.java b/1.7.10/src/main/java/city/windmill/ingameime/mixins/MixinMinecraft.java index 2fe1578..77a5b46 100644 --- a/1.7.10/src/main/java/city/windmill/ingameime/mixins/MixinMinecraft.java +++ b/1.7.10/src/main/java/city/windmill/ingameime/mixins/MixinMinecraft.java @@ -26,7 +26,10 @@ void postDisplayScreen(GuiScreen guiScreenIn, CallbackInfo ci) { // Reset pos when screen changes ClientProxy.Screen.setCaretPos(0, 0); // Disable input method when not screen - if (Minecraft.getMinecraft().currentScreen == null) - Internal.setActivated(false); + GuiScreen currentScreen = Minecraft.getMinecraft().currentScreen; + if (currentScreen == null) + ClientProxy.INSTANCE.onScreenClose(); + else + ClientProxy.INSTANCE.onScreenOpen(currentScreen); } } diff --git a/IngameIME-Native/build.gradle.kts b/IngameIME-Native/build.gradle.kts index b27c277..4d545c5 100644 --- a/IngameIME-Native/build.gradle.kts +++ b/IngameIME-Native/build.gradle.kts @@ -22,10 +22,12 @@ plugins { tasks.compileJava { options.encoding = "UTF-8" + sourceCompatibility = "1.8" } tasks.compileTestJava { options.encoding = "UTF-8" + sourceCompatibility = "1.8" } configurations.all {