From bf652fb18c77414545112e0367e5c308b0727d63 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Fri, 28 Nov 2025 12:03:11 +0100 Subject: [PATCH] fix(web): another simplification Plus another unit test. Test-bot: skip --- .../core-processor/coreKeyboardProcessor.ts | 30 +++++++---------- .../coreKeyboardProcessor.tests.ts | 32 +++++++++++++++++++ 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/web/src/engine/src/core-processor/coreKeyboardProcessor.ts b/web/src/engine/src/core-processor/coreKeyboardProcessor.ts index a6f4b19f28..85bba45178 100644 --- a/web/src/engine/src/core-processor/coreKeyboardProcessor.ts +++ b/web/src/engine/src/core-processor/coreKeyboardProcessor.ts @@ -177,32 +177,26 @@ export class CoreKeyboardProcessor extends EventEmitter implements Key const deadkeyIterator = deadkeys.values(); let deadkey = deadkeyIterator.next(); - const textMax = Math.min(text.length, caretPosition + 1); let textIndex = 0; - while (!deadkey.done || textIndex < textMax) { - // insert 0 or more deadkeys at current index - while (!deadkey.done && deadkey.value.p <= textIndex) { - if (deadkey.value.p < textIndex) { - // this should never happen -- it would mean that - // a deadkey position was < 0 or in the middle of a - // surrogate pair. We'll silently drop it - console.warn(`invalid deadkey '${deadkey.value.d}' position ${deadkey.value.p}`); - } else { - const contextItem = new KM_Core.instance.km_core_context_item(); - contextItem.marker = deadkey.value.d; - contextItems.push_back(contextItem); - } + while (!deadkey.done || textIndex < text.length) { + // flush out invalid deadkeys + while (!deadkey.done && (deadkey.value.p < textIndex || deadkey.value.p > text.length)) { + // this should never happen -- it would mean that a deadkey position was < 0, in the + // middle of a surrogate pair, or after the caret. + console.warn(`invalid deadkey '${deadkey.value.d}' position ${deadkey.value.p}`); deadkey = deadkeyIterator.next(); } - // flush out invalid deadkeys - while (!deadkey.done && deadkey.value.p > textMax) { - console.warn(`invalid deadkey '${deadkey.value.d}' position ${deadkey.value.p} after end of text ${textMax}`); + // insert 0 or more deadkeys at current index + while (!deadkey.done && deadkey.value.p == textIndex) { + const contextItem = new KM_Core.instance.km_core_context_item(); + contextItem.marker = deadkey.value.d; + contextItems.push_back(contextItem); deadkey = deadkeyIterator.next(); } // insert next character - if (textIndex < textMax) { + if (textIndex < text.length) { const contextItem = new KM_Core.instance.km_core_context_item(); contextItem.character = text.codePointAt(textIndex); contextItems.push_back(contextItem); diff --git a/web/src/test/auto/headless/engine/core-processor/coreKeyboardProcessor.tests.ts b/web/src/test/auto/headless/engine/core-processor/coreKeyboardProcessor.tests.ts index 4c1ea84317..8090308eb6 100644 --- a/web/src/test/auto/headless/engine/core-processor/coreKeyboardProcessor.tests.ts +++ b/web/src/test/auto/headless/engine/core-processor/coreKeyboardProcessor.tests.ts @@ -454,5 +454,37 @@ describe('CoreKeyboardProcessor', function () { assert.equal(items.get(2).type, KM_CORE_CT.END, 'Item 2 should be END'); result.delete(); }); + + it('skips invalid deadkeys', function () { + // Setup + textStore = new SyntheticTextStore('abcde', 3); + textStore.deadkeys().add(new Deadkey(-1, 1)); // invalid + textStore.deadkeys().add(new Deadkey(1, 2)); // after 'b' + textStore.deadkeys().add(new Deadkey(4, 3)); // invalid (after caret) + + // Execute + coreProcessor.unitTestEndPoints.applyContextFromTextStore(context, textStore); + + // Verify + const result = KM_Core.instance.context_get(context); + assert.equal(result.status, KM_CORE_STATUS.OK); + const items = result.object; + + // Text index : 0 1 1 2 3 + // Text: : | + // context index: 0 1 2 3 4 + // ContextItems : a dk2 b c END + assert.equal(items.size(), 5, 'Should have 5 context items'); + assert.equal(items.get(0).type, KM_CORE_CT.CHAR, 'Item 0 should be CHAR'); + assert.equal(items.get(0).character, 'a'.charCodeAt(0), 'Item 0 should be "a"'); + assert.equal(items.get(1).type, KM_CORE_CT.MARKER, 'Item 1 should be MARKER'); + assert.equal(items.get(1).marker, 2, 'Item 1 should be marker 2'); + assert.equal(items.get(2).type, KM_CORE_CT.CHAR, 'Item 2 should be CHAR'); + assert.equal(items.get(2).character, 'b'.charCodeAt(0), 'Item 2 should be "b"'); + assert.equal(items.get(3).type, KM_CORE_CT.CHAR, 'Item 3 should be CHAR'); + assert.equal(items.get(3).character, 'c'.charCodeAt(0), 'Item 3 should be "c"'); + assert.equal(items.get(4).type, KM_CORE_CT.END, 'Item 4 should be END'); + result.delete(); + }); }); });