From ea37960b3bf7bbfe27702f8011f51498f73ef015 Mon Sep 17 00:00:00 2001 From: Jack Date: Wed, 10 Dec 2025 16:08:53 +0100 Subject: [PATCH] fix: composition issues with ending test and new line handling (@miodec) (#7210) closes #4968 --- frontend/src/ts/input/handlers/keydown.ts | 11 +--------- frontend/src/ts/input/listeners/input.ts | 25 +++++++++++++++++++++++ frontend/src/ts/test/test-ui.ts | 7 ++++++- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/frontend/src/ts/input/handlers/keydown.ts b/frontend/src/ts/input/handlers/keydown.ts index 4bbe80224..7f3daa780 100644 --- a/frontend/src/ts/input/handlers/keydown.ts +++ b/frontend/src/ts/input/handlers/keydown.ts @@ -10,7 +10,6 @@ import * as JSONData from "../../utils/json-data"; import * as Notifications from "../../elements/notifications"; import * as KeyConverter from "../../utils/key-converter"; import * as ShiftTracker from "../../test/shift-tracker"; -import * as CompositionState from "../../states/composition"; import * as ManualRestart from "../../test/manual-restart-tracker"; import { canQuickRestart } from "../../utils/quick-restart"; import * as CustomText from "../../test/custom-text"; @@ -45,7 +44,7 @@ export async function handleTab(e: KeyboardEvent, now: number): Promise { export async function handleEnter( e: KeyboardEvent, - now: number, + _now: number, ): Promise { if (e.shiftKey) { if (Config.mode === "zen") { @@ -92,14 +91,6 @@ export async function handleEnter( return; } } - if ( - TestWords.hasNewline || - (Config.mode === "zen" && !CompositionState.getComposing()) - ) { - await emulateInsertText({ data: "\n", now }); - e.preventDefault(); - return; - } } export async function handleOppositeShift(event: KeyboardEvent): Promise { diff --git a/frontend/src/ts/input/listeners/input.ts b/frontend/src/ts/input/listeners/input.ts index f0ccea37b..18539e00e 100644 --- a/frontend/src/ts/input/listeners/input.ts +++ b/frontend/src/ts/input/listeners/input.ts @@ -9,6 +9,11 @@ import { import * as TestUI from "../../test/test-ui"; import { onBeforeInsertText } from "../handlers/before-insert-text"; import { onBeforeDelete } from "../handlers/before-delete"; +import * as TestInput from "../../test/test-input"; +import * as TestWords from "../../test/test-words"; +import * as CompositionState from "../../states/composition"; +import { activeWordIndex } from "../../test/test-state"; +import { areAllTestWordsGenerated } from "../../test/test-logic"; const inputEl = getInputElement(); @@ -114,6 +119,26 @@ inputEl.addEventListener("input", async (event) => { inputType === "insertCompositionText" || inputType === "insertFromComposition" ) { + const allWordsTyped = activeWordIndex >= TestWords.words.length - 1; + const inputPlusComposition = + TestInput.input.current + (CompositionState.getData() ?? ""); + const inputPlusCompositionIsCorrect = + TestWords.words.getCurrent() === inputPlusComposition; + + // composition quick end + // if the user typed the entire word correctly but is still in composition + // dont wait for them to end the composition manually, just end the test + // by dispatching a compositionend which will trigger onInsertText + if ( + areAllTestWordsGenerated() && + allWordsTyped && + inputPlusCompositionIsCorrect + ) { + getInputElement().dispatchEvent( + new CompositionEvent("compositionend", { data: event.data ?? "" }), + ); + } + // in case the data is the same as the last one, just ignore it if (getLastInsertCompositionTextData() !== event.data) { setLastInsertCompositionTextData(event.data ?? ""); diff --git a/frontend/src/ts/test/test-ui.ts b/frontend/src/ts/test/test-ui.ts index f05bc21ac..f98ab36c3 100644 --- a/frontend/src/ts/test/test-ui.ts +++ b/frontend/src/ts/test/test-ui.ts @@ -884,7 +884,12 @@ export async function updateWordLetters({ charToShow = compositionChar === " " ? "_" : compositionChar; } - ret += `${charToShow}`; + let correctClass = ""; + if (compositionChar === currentWordChars[input.length + i]) { + correctClass = "correct"; + } + + ret += `${charToShow}`; } for (