Skip to content

Commit 2ab9aca

Browse files
Foster HoulstonFoster Houlston
authored andcommitted
fix(composition): stabilize IME preedit layout for JP input (@FosterHoulston)
1 parent 5d169e9 commit 2ab9aca

File tree

2 files changed

+26
-6
lines changed

2 files changed

+26
-6
lines changed

frontend/src/ts/input/listeners/composition.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import { setLastInsertCompositionTextData } from "../state";
66
import * as CompositionDisplay from "../../elements/composition-display";
77
import { onInsertText } from "../handlers/insert-text";
88
import * as TestUI from "../../test/test-ui";
9+
import * as TestWords from "../../test/test-words";
10+
import * as TestInput from "../../test/test-input";
11+
import * as Strings from "../../utils/strings";
912

1013
const inputEl = getInputElement();
1114

@@ -31,8 +34,22 @@ inputEl.addEventListener("compositionupdate", (event) => {
3134
});
3235

3336
if (TestState.testRestarting || TestUI.resultCalculating) return;
34-
CompositionState.setData(event.data);
35-
CompositionDisplay.update(event.data);
37+
const currentWord = TestWords.words.getCurrent();
38+
const typedSoFar = TestInput.input.current;
39+
const remainingChars =
40+
Strings.splitIntoCharacters(currentWord).length -
41+
Strings.splitIntoCharacters(typedSoFar).length;
42+
// Prevent rendering more composition glyphs than the word has remaining letters,
43+
// so IME preedit strings (e.g. romaji) don't push text to the next line.
44+
const limitedCompositionData =
45+
remainingChars > 0
46+
? Strings.splitIntoCharacters(event.data)
47+
.slice(0, remainingChars)
48+
.join("")
49+
: "";
50+
51+
CompositionState.setData(limitedCompositionData);
52+
CompositionDisplay.update(limitedCompositionData);
3653
});
3754

3855
inputEl.addEventListener("compositionend", async (event) => {

frontend/src/ts/test/test-ui.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -805,15 +805,18 @@ export async function updateWordLetters({
805805

806806
for (let i = 0; i < compositionData.length; i++) {
807807
const compositionChar = compositionData[i];
808-
let charToShow =
809-
currentWordChars[input.length + i] ?? compositionChar;
808+
// Render the target character (if known) during composition to keep line width stable,
809+
// falling back to the preedit char when beyond the word length.
810+
const targetChar = currentWordChars[input.length + i];
811+
let charToShow = targetChar ?? compositionChar;
810812

811813
if (Config.compositionDisplay === "replace") {
812-
charToShow = compositionChar === " " ? "_" : compositionChar;
814+
charToShow =
815+
targetChar ?? (compositionChar === " " ? "_" : compositionChar);
813816
}
814817

815818
let correctClass = "";
816-
if (compositionChar === currentWordChars[input.length + i]) {
819+
if (compositionChar === targetChar) {
817820
correctClass = "correct";
818821
}
819822

0 commit comments

Comments
 (0)