From 0c8f520e2aefada2958704bf58edc4ee4c9ead55 Mon Sep 17 00:00:00 2001 From: "Joshua A. Horton" Date: Wed, 17 Apr 2024 10:17:28 +0700 Subject: [PATCH 1/2] fix(web): prevents selection-clear for pure layer-switching multitaps --- .../input-processor/src/text/inputProcessor.ts | 16 ++++++++++++++-- .../keyboard-processor/src/text/outputTarget.ts | 11 +++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/common/web/input-processor/src/text/inputProcessor.ts b/common/web/input-processor/src/text/inputProcessor.ts index 76d8b288f42..55f7a1e8b6b 100644 --- a/common/web/input-processor/src/text/inputProcessor.ts +++ b/common/web/input-processor/src/text/inputProcessor.ts @@ -107,8 +107,20 @@ export default class InputProcessor { if(keyEvent.baseTranscriptionToken) { const transcription = this.contextCache.get(keyEvent.baseTranscriptionToken); if(transcription) { - // Restores full context, including deadkeys in their exact pre-keystroke state. - outputTarget.restoreTo(transcription.preInput); + // Has there been a context change at any point during the multitap? If so, we need + // to revert it. If not, we assume it's a layer-change multitap, in which case + // no such reset is needed. + if(!isEmptyTransform(transcription.transform) || !transcription.preInput.isEqual(Mock.from(outputTarget))) { + // Restores full context, including deadkeys in their exact pre-keystroke state. + outputTarget.restoreTo(transcription.preInput); + } + /* + else: + 1. We don't need to restore the original context, as it's already + in-place. + 2. Restoring anyway would obliterate any selected text, which is bad + if this is a purely-layer-switching multitap. (#11230) + */ } else { console.warn('The base context for the multitap could not be found'); } diff --git a/common/web/keyboard-processor/src/text/outputTarget.ts b/common/web/keyboard-processor/src/text/outputTarget.ts index ef3a3d74e33..2f83f17df42 100644 --- a/common/web/keyboard-processor/src/text/outputTarget.ts +++ b/common/web/keyboard-processor/src/text/outputTarget.ts @@ -446,6 +446,17 @@ export class Mock extends OutputTarget { this.text = this.getTextBeforeCaret() + s; } + /** + * Indicates if this Mock represents an identical context to that of another Mock. + * + * Does not currently validate a match for deadkeys. + * @param other + * @returns + */ + isEqual(other: Mock) { + return this.text == other.text && this.selStart == other.selStart && this.selEnd == other.selEnd; + } + doInputEvent() { // Mock isn't backed by an element, so it won't have any event listeners. } From fb127e761b77708d9dfc59b92a8c93d50c4e0de0 Mon Sep 17 00:00:00 2001 From: "Joshua A. Horton" Date: Wed, 17 Apr 2024 10:33:16 +0700 Subject: [PATCH 2/2] fix(web): more robustness in case of deadkeys --- .../keyboard-processor/src/text/deadkeys.ts | 22 +++++++++++++++++++ .../src/text/outputTarget.ts | 7 +++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/common/web/keyboard-processor/src/text/deadkeys.ts b/common/web/keyboard-processor/src/text/deadkeys.ts index e5b32a788fb..31bfa1100df 100644 --- a/common/web/keyboard-processor/src/text/deadkeys.ts +++ b/common/web/keyboard-processor/src/text/deadkeys.ts @@ -38,6 +38,10 @@ export class Deadkey { return dk; } + equal(other: Deadkey) { + return this.d == other.d && this.p == other.d && this.o == other.o; + } + /** * Sorts the deadkeys in reverse order. */ @@ -151,6 +155,24 @@ export class DeadkeyTracker { } } + equal(other: DeadkeyTracker) { + if(this.dks.length != other.dks.length) { + return false; + } + + const otherDks = other.dks; + const matchedDks: Deadkey[] = []; + + for(let dk of this.dks) { + const match = otherDks.find((otherDk) => dk.equal(otherDk)); + if(!match) { + return false; + } + } + + return matchedDks.length == otherDks.length; + } + count(): number { return this.dks.length; } diff --git a/common/web/keyboard-processor/src/text/outputTarget.ts b/common/web/keyboard-processor/src/text/outputTarget.ts index 2f83f17df42..c7f42d8ee56 100644 --- a/common/web/keyboard-processor/src/text/outputTarget.ts +++ b/common/web/keyboard-processor/src/text/outputTarget.ts @@ -448,13 +448,14 @@ export class Mock extends OutputTarget { /** * Indicates if this Mock represents an identical context to that of another Mock. - * - * Does not currently validate a match for deadkeys. * @param other * @returns */ isEqual(other: Mock) { - return this.text == other.text && this.selStart == other.selStart && this.selEnd == other.selEnd; + return this.text == other.text + && this.selStart == other.selStart + && this.selEnd == other.selEnd + && this.deadkeys().equal(other.deadkeys()); } doInputEvent() {