diff --git a/src/main/java/dev/isxander/yacl3/gui/OptionListWidget.java b/src/main/java/dev/isxander/yacl3/gui/OptionListWidget.java index 28e1131c..5fe0aa4f 100644 --- a/src/main/java/dev/isxander/yacl3/gui/OptionListWidget.java +++ b/src/main/java/dev/isxander/yacl3/gui/OptionListWidget.java @@ -21,6 +21,7 @@ import net.minecraft.client.input.CharacterEvent; import net.minecraft.client.input.KeyEvent; import net.minecraft.client.input.MouseButtonEvent; +import net.minecraft.client.input.PreeditEvent; import net.minecraft.network.chat.Component; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -211,6 +212,16 @@ public boolean charTyped(CharacterEvent characterEvent) { return super.charTyped(characterEvent); } + @Override + public boolean preeditUpdated(@Nullable PreeditEvent event) { + for (Entry child : children()) { + if (child.preeditUpdated(event)) + return true; + } + + return super.preeditUpdated(event); + } + private List superModifiableChildren() { // noinspection unchecked return (List) ((AbstractSelectionListAccessor) this).getChildren(); @@ -299,6 +310,10 @@ protected void onBecameViewable() { protected void onBecameHidden() { this.setHeight(0); } + + public boolean preeditUpdated(@Nullable PreeditEvent event) { + return false; + } } public class OptionEntry extends Entry { @@ -373,6 +388,11 @@ public boolean charTyped(@NonNull CharacterEvent event) { return widget.charTyped(event); } + @Override + public boolean preeditUpdated(@Nullable PreeditEvent event) { + return widget.preeditUpdated(event); + } + @Override public boolean updateSearchQuery(String searchQuery) { this.searchQueryMatches = searchQuery.isEmpty() diff --git a/src/main/java/dev/isxander/yacl3/gui/controllers/ListEntryWidget.java b/src/main/java/dev/isxander/yacl3/gui/controllers/ListEntryWidget.java index 564e1ad8..d088251c 100644 --- a/src/main/java/dev/isxander/yacl3/gui/controllers/ListEntryWidget.java +++ b/src/main/java/dev/isxander/yacl3/gui/controllers/ListEntryWidget.java @@ -14,6 +14,7 @@ import net.minecraft.client.input.CharacterEvent; import net.minecraft.client.input.KeyEvent; import net.minecraft.client.input.MouseButtonEvent; +import net.minecraft.client.input.PreeditEvent; import net.minecraft.network.chat.Component; import org.jetbrains.annotations.Nullable; import org.jspecify.annotations.NonNull; @@ -159,4 +160,11 @@ public boolean keyReleased(KeyEvent keyEvent) { public boolean charTyped(CharacterEvent characterEvent) { return ContainerEventHandler.super.charTyped(characterEvent); } + + @Override + public boolean preeditUpdated(@Nullable PreeditEvent event) { + if (entryWidget.preeditUpdated(event)) + return true; + return ContainerEventHandler.super.preeditUpdated(event); + } } diff --git a/src/main/java/dev/isxander/yacl3/gui/controllers/PopupControllerScreen.java b/src/main/java/dev/isxander/yacl3/gui/controllers/PopupControllerScreen.java index 9793a436..6a10d2cb 100644 --- a/src/main/java/dev/isxander/yacl3/gui/controllers/PopupControllerScreen.java +++ b/src/main/java/dev/isxander/yacl3/gui/controllers/PopupControllerScreen.java @@ -8,6 +8,8 @@ import net.minecraft.client.input.CharacterEvent; import net.minecraft.client.input.KeyEvent; import net.minecraft.client.input.MouseButtonEvent; +import net.minecraft.client.input.PreeditEvent; +import org.jetbrains.annotations.Nullable; import org.jspecify.annotations.NonNull; public class PopupControllerScreen extends Screen { @@ -78,6 +80,11 @@ public boolean charTyped(@NonNull CharacterEvent characterEvent) { return controllerPopup.charTyped(characterEvent); } + @Override + public boolean preeditUpdated(@Nullable PreeditEvent event) { + return controllerPopup.preeditUpdated(event); + } + @Override public boolean keyPressed(@NonNull KeyEvent keyEvent) { return controllerPopup.keyPressed(keyEvent); diff --git a/src/main/java/dev/isxander/yacl3/gui/controllers/string/StringControllerElement.java b/src/main/java/dev/isxander/yacl3/gui/controllers/string/StringControllerElement.java index 01ce0eeb..9ed52119 100644 --- a/src/main/java/dev/isxander/yacl3/gui/controllers/string/StringControllerElement.java +++ b/src/main/java/dev/isxander/yacl3/gui/controllers/string/StringControllerElement.java @@ -10,10 +10,13 @@ import dev.isxander.yacl3.gui.utils.UndoRedoHelper; import net.minecraft.ChatFormatting; import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.client.gui.components.IMEPreeditOverlay; import net.minecraft.client.input.CharacterEvent; import net.minecraft.client.input.KeyEvent; import net.minecraft.client.input.MouseButtonEvent; +import net.minecraft.client.input.PreeditEvent; import net.minecraft.network.chat.Component; +import org.jetbrains.annotations.Nullable; import org.jspecify.annotations.NonNull; import java.util.function.Consumer; @@ -37,6 +40,8 @@ public class StringControllerElement extends ControllerWidget control, YACLScreen screen, Dimension dim, boolean instantApply) { super(control, screen, dim); this.instantApply = instantApply; @@ -103,6 +108,14 @@ protected void extractValueText(GuiGraphicsExtractor graphics, int mouseX, int m } else if (this.hovered) { graphics.requestCursor(isAvailable() ? com.mojang.blaze3d.platform.cursor.CursorTypes.POINTING_HAND : com.mojang.blaze3d.platform.cursor.CursorTypes.NOT_ALLOWED); } + + if (preeditOverlay != null && inputFieldFocused) { + String text = getValueText().getString(); + int preeditTextX = getDimension().xLimit() - textRenderer.width(getValueText()) + renderOffset - getXPadding(); + int preeditCaretX = preeditTextX + textRenderer.width(text.substring(0, Math.min(caretPos, text.length()))); + preeditOverlay.updateInputPosition(preeditCaretX, getTextY()); + graphics.setPreeditOverlay(preeditOverlay); + } } private boolean isHoveredInputField(double mouseX, double mouseY) { @@ -112,7 +125,7 @@ private boolean isHoveredInputField(double mouseX, double mouseY) { @Override public boolean mouseClicked(@NonNull MouseButtonEvent event, boolean doubleClick) { if (isAvailable() && getDimension().isPointInside((int) event.x(), (int) event.y())) { - inputFieldFocused = true; + setInputEditing(true); if (!isHoveredInputField(event.x(), event.y())) { caretPos = getDefaultCaretPos(); @@ -322,9 +335,13 @@ protected void checkRenderOffset() { } } + public boolean canConsumeInput() { + return inputFieldFocused && isAvailable(); + } + @Override public boolean charTyped(@NonNull CharacterEvent event) { - if (!inputFieldFocused) + if (!canConsumeInput()) return false; write(event.codepointAsString()); @@ -332,6 +349,17 @@ public boolean charTyped(@NonNull CharacterEvent event) { return true; } + @Override + public boolean preeditUpdated(@Nullable PreeditEvent event) { + if (!canConsumeInput()) + return false; + + preeditOverlay = event != null + ? new IMEPreeditOverlay(event, textRenderer, textRenderer.lineHeight + 1) + : null; + return true; + } + protected void doBackspace() { if (selectionLength != 0) { write(""); @@ -431,17 +459,27 @@ protected int findSpaceIndex(boolean reverse) { @Override public void setFocused(boolean focused) { super.setFocused(focused); - inputFieldFocused = focused; + setInputEditing(focused); } @Override public void unfocus() { + setInputEditing(false); super.unfocus(); - inputFieldFocused = false; renderOffset = 0; if (!instantApply) updateControl(); } + private void setInputEditing(boolean editing) { + if (inputFieldFocused == editing) + return; + + inputFieldFocused = editing; + client.onTextInputFocusChange(this, editing); + if (!editing) + preeditOverlay = null; + } + @Override public void setDimension(Dimension dim) { super.setDimension(dim);