diff --git a/web/src/engine/osk/src/input/gestures/specsForLayout.ts b/web/src/engine/osk/src/input/gestures/specsForLayout.ts index f9bc02f4614..213278277e4 100644 --- a/web/src/engine/osk/src/input/gestures/specsForLayout.ts +++ b/web/src/engine/osk/src/input/gestures/specsForLayout.ts @@ -31,10 +31,16 @@ export interface GestureParams { */ permitsFlick: (item?: Item) => boolean, + /** + * The minimum _net_ distance traveled before a longpress flick-shortcut will cancel any + * conflicting flick models. + */ + flickDistStart: number, + /** * The minimum _net_ distance traveled before a longpress flick-shortcut will trigger. */ - flickDist: number, + flickDistFinal: number, /** * The maximum amount of raw-distance movement allowed for a longpress before it is @@ -104,7 +110,8 @@ export const DEFAULT_GESTURE_PARAMS: GestureParams = { permitsFlick: () => true, // Note: actual runtime value is determined at runtime based upon row height. // See `VisualKeyboard.refreshLayout`, CTRL-F "Step 3". - flickDist: 5, + flickDistStart: 8, + flickDistFinal: 40, waitLength: 500, noiseTolerance: 10 }, @@ -349,11 +356,34 @@ export function instantContactResolutionModel(): ContactModel { }; } -export function flickStartContactModel(params: GestureParams): ContactModel { +export function flickStartContactModel(params: GestureParams): gestures.specs.ContactModel { + const flickParams = params.flick; + return { itemPriority: 1, pathModel: { - evaluate: (path) => path.stats.netDistance > params.flick.startDist ? 'resolve' : null + evaluate: (path, _, item) => { + const stats = path.stats; + const keySpec = item?.key.spec; + + if(keySpec && keySpec.sk) { + const flickSpec = keySpec.flick; + const hasUpFlick = flickSpec.nw || flickSpec.n || flickSpec.ne; + + if(!hasUpFlick) { + // Check for possible conflict with the longpress up-flick shortcut; + // it's supported on this key, as there is no true northish flick. + const baseDistance = stats.netDistance; + const angle = stats.angle; // from <0, -1> (straight up) going clockwise. + const verticalDistance = baseDistance * Math.cos(angle); + if(verticalDistance > params.longpress.flickDistStart) { + return 'reject'; + } + } + } + + return stats.netDistance > flickParams.startDist ? 'resolve' : null; + } }, pathResolutionAction: 'resolve', pathInheritance: 'partial' @@ -467,7 +497,7 @@ export function longpressContactModel(params: GestureParams, enabledFlicks: bool const baseDistance = stats.netDistance; const angle = stats.angle; // from <0, -1> (straight up) going clockwise. const verticalDistance = baseDistance * Math.cos(angle); - if(verticalDistance > spec.flickDist) { + if(verticalDistance > spec.flickDistFinal) { return 'resolve'; } } else if(resetForRoaming) { diff --git a/web/src/engine/osk/src/visualKeyboard.ts b/web/src/engine/osk/src/visualKeyboard.ts index 2edfc9fb374..97afe3352d8 100644 --- a/web/src/engine/osk/src/visualKeyboard.ts +++ b/web/src/engine/osk/src/visualKeyboard.ts @@ -1307,10 +1307,11 @@ export default class VisualKeyboard extends EventEmitter implements Ke (The range _will_ be notably tighter on keys with both longpresses and flicks as a result.) */ - this.gestureParams.longpress.flickDist = 0.24 * this.currentLayer.rowHeight; - this.gestureParams.flick.startDist = 0.30 * this.currentLayer.rowHeight; - this.gestureParams.flick.dirLockDist = 0.35 * this.currentLayer.rowHeight; - this.gestureParams.flick.triggerDist = 0.75 * this.currentLayer.rowHeight; + this.gestureParams.longpress.flickDistStart = 0.24 * this.currentLayer.rowHeight; + this.gestureParams.flick.startDist = 0.30 * this.currentLayer.rowHeight; + this.gestureParams.flick.dirLockDist = 0.35 * this.currentLayer.rowHeight; + this.gestureParams.flick.triggerDist = 0.75 * this.currentLayer.rowHeight; + this.gestureParams.longpress.flickDistFinal = 0.75 * this.currentLayer.rowHeight; } // Phase 4: Refresh the layout of the layer-group and active layer.