From d2a043ae436207fbcb8de6d2dfd6bf81095ab955 Mon Sep 17 00:00:00 2001 From: "Joshua A. Horton" Date: Tue, 6 Feb 2024 09:15:15 +0700 Subject: [PATCH] fix(web): prevent invalid longpress shortcut triggers --- .../headless/gestures/matchers/pathMatcher.ts | 14 +++++++---- .../headless/gestures/specs/contactModel.ts | 24 ++++++++++--------- .../osk/src/input/gestures/specsForLayout.ts | 4 ++-- 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/common/web/gesture-recognizer/src/engine/headless/gestures/matchers/pathMatcher.ts b/common/web/gesture-recognizer/src/engine/headless/gestures/matchers/pathMatcher.ts index 5d03e74ab0..608f85d07d 100644 --- a/common/web/gesture-recognizer/src/engine/headless/gestures/matchers/pathMatcher.ts +++ b/common/web/gesture-recognizer/src/engine/headless/gestures/matchers/pathMatcher.ts @@ -93,11 +93,7 @@ export class PathMatcher { } // Check for validation as needed. - if(!model.timer.validateItem) { - this.finalize(true, 'timer'); - } else { - this.finalize(model.timer.validateItem(this.source.path.stats.lastSample.item, this.baseItem), 'timer'); - } + this.finalize(true, 'timer'); }); } } @@ -108,6 +104,14 @@ export class PathMatcher { } const model = this.model; + + // Check for validation as needed. + if(model.validateItem && result) { + // If we're finalizing on a positive note but there's an item-validation check, we need + // to obey the results of that check. + result = model.validateItem(this.source.path.stats.lastSample.item, this.baseItem); + } + let retVal: PathMatchResult; if(result) { retVal = { diff --git a/common/web/gesture-recognizer/src/engine/headless/gestures/specs/contactModel.ts b/common/web/gesture-recognizer/src/engine/headless/gestures/specs/contactModel.ts index 8796afd69c..800fa67ec4 100644 --- a/common/web/gesture-recognizer/src/engine/headless/gestures/specs/contactModel.ts +++ b/common/web/gesture-recognizer/src/engine/headless/gestures/specs/contactModel.ts @@ -23,6 +23,18 @@ export interface ContactModel { // gesture-state updates and resolution. Higher = better. itemPriority: number; + /** + * An optional function parameter. If specified and other conditions are met, + * this function will validate the model on the basis of the associated 'items' when + * a model match is being finalized. + * @param currentItem + * @param baseItem + * @returns + * - `true` if the model is valid for the associated items, resulting in a model match + * - `false` if the model is invalid, leading to model rejection + */ + validateItem?: (currentItem: Type, baseItem: Type) => boolean + /** * Used for resolving or rejecting this component of a gesture based on a time threshold * for the touch contact point's lifetime. @@ -41,17 +53,7 @@ export interface ContactModel { * If `true`, the timer will use the inherited `path.stats.duration` stat as an * offset that has already elapsed, counting it against the timer. */ - inheritElapsed?: boolean, - /** - * An optional timer-spec function parameter. If specified and other conditions are met, - * this function will validate the model on the basis of the associated 'items'. - * @param currentItem - * @param baseItem - * @returns - * - `true` if the model is valid for the associated items, resulting in a model match - * - `false` if the model is invalid, leading to model rejection - */ - validateItem?: (currentItem: Type, baseItem: Type) => boolean + inheritElapsed?: boolean } // This field is primarly used at the `GestureMatcher` level, rather than the diff --git a/web/src/engine/osk/src/input/gestures/specsForLayout.ts b/web/src/engine/osk/src/input/gestures/specsForLayout.ts index 96a3cbf2eb..0fb58f7df8 100644 --- a/web/src/engine/osk/src/input/gestures/specsForLayout.ts +++ b/web/src/engine/osk/src/input/gestures/specsForLayout.ts @@ -441,9 +441,9 @@ export function longpressContactModel(params: GestureParams, enabledFlicks: bool pathResolutionAction: 'resolve', timer: { duration: spec.waitLength, - expectedResult: true, - validateItem: (key: KeyElement) => !!key?.key.spec.sk + expectedResult: true }, + validateItem: (key: KeyElement) => !!key?.key.spec.sk, pathModel: { evaluate: (path) => { const stats = path.stats;