Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion common/core/web/input-processor/src/text/inputProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,11 @@ namespace com.keyman.text {
if(pair.p < KEYSTROKE_EPSILON) {
break;
} else if(timer && timer() >= TIMEOUT_THRESHOLD) {
// Note: it's always possible that the thread _executing_ our JS
// got paused by the OS, even if JS itself is single-threaded.
//
// The case where `alternates` is initialized (line 167) but empty
// (because of net-zero loop iterations) MUST be handled.
break;
}

Expand All @@ -187,6 +192,8 @@ namespace com.keyman.text {

// If alternateBehavior.beep == true, ignore it. It's a disallowed key sequence,
// so we expect users to never intend their use.
//
// Also possible that this set of conditions fail for all evaluated alternates.
if(alternateBehavior && !alternateBehavior.beep && pair.p > 0) {
let transform: Transform = alternateBehavior.transcription.transform;

Expand Down Expand Up @@ -215,7 +222,9 @@ namespace com.keyman.text {
// -- All keystroke (and 'alternate') processing is now complete. Time to finalize everything! --

// Notify the ModelManager of new input - it's predictive text time!
ruleBehavior.transcription.alternates = alternates;
if(alternates && alternates.length > 0) {
ruleBehavior.transcription.alternates = alternates;
}
// Yes, even for ruleBehavior.triggersDefaultCommand. Those tend to change the context.
ruleBehavior.predictionPromise = this.languageProcessor.predict(ruleBehavior.transcription);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,8 +323,16 @@ namespace com.keyman.text.prediction {
this.lmEngine.resetContext(context);
}

let alternates = transcription.alternates;
if(!alternates || alternates.length == 0) {
alternates = [{
sample: transcription.transform,
p: 1.0
}];
}

let transform = transcription.transform;
var promise = this.currentPromise = this.lmEngine.predict(transcription.alternates || transcription.transform, context);
var promise = this.currentPromise = this.lmEngine.predict(alternates, context);

let lp = this;
return promise.then(function(suggestions: Suggestion[]) {
Expand Down
19 changes: 19 additions & 0 deletions common/predictive-text/worker/model-compositor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,25 @@ class ModelCompositor {

if(!(transformDistribution instanceof Array)) {
transformDistribution = [ {sample: transformDistribution, p: 1.0} ];
} else if(transformDistribution.length == 0) {
/*
Robust stop-gap: if our other filters somehow fail, this fixes the
zero-length array by making it match the form of the array that
would result if it were instead called with the other legal
parameter type - a single Transform.

Unfortunately, the method will lack all data about even
the original keystroke that resulted in the call... but this way,
we can at least get some predictions rather than shortcutting
and producing none whatsoever.
*/
transformDistribution.push({
sample: {
insert: '',
deleteLeft: 0
},
p: 1.0
})
}

let inputTransform = transformDistribution.sort(function(a, b) {
Expand Down