mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-07 17:36:00 +00:00
change(web): prevents auto-cancellation of simple-taps for flicked layouts when touchpoint moves
This commit is contained in:
parent
d8a6467b2d
commit
c2d69f8a7a
4 changed files with 46 additions and 28 deletions
|
|
@ -10,7 +10,7 @@ import { BannerSuggestion } from './suggestionBanner.js';
|
|||
import { simpleTapModelWithReset } from "../input/gestures/specsForLayout.js";
|
||||
|
||||
export const BannerSimpleTap: gestures.specs.GestureModel<BannerSuggestion> = {
|
||||
...deepCopy(simpleTapModelWithReset()),
|
||||
...deepCopy(simpleTapModelWithReset(null)),
|
||||
resolutionAction: {
|
||||
type: 'complete',
|
||||
item: 'current'
|
||||
|
|
|
|||
|
|
@ -87,7 +87,14 @@ export interface GestureParams<Item = any> {
|
|||
* The minimum _net_ touch-path distance after which the direction will be locked.
|
||||
*/
|
||||
dirLockDist: number
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Indicates whether roaming-touch oriented behaviors should be enabled.
|
||||
*
|
||||
* Note that run-time adjustments to this property after initialization will
|
||||
* not take affect, unlike the other properties of the overall parameter object.
|
||||
*/
|
||||
roamingEnabled?: boolean;
|
||||
}
|
||||
|
||||
export const DEFAULT_GESTURE_PARAMS: GestureParams = {
|
||||
|
|
@ -153,6 +160,9 @@ let dummy2: LayoutGestureSupportFlags = dummy;
|
|||
* @param params A set of tweakable gesture parameters. It will be closure-captured
|
||||
* and referred to by reference; changes to its values will take
|
||||
* immediate effect during gesture processing.
|
||||
*
|
||||
* If params.roamingEnabled is unset, it will be initialized by this
|
||||
* method based upon layout properties.
|
||||
* @returns
|
||||
*/
|
||||
export function gestureSetForLayout(flags: LayoutGestureSupportFlags, params: GestureParams): GestureModelDefs<KeyElement, string> {
|
||||
|
|
@ -185,9 +195,11 @@ export function gestureSetForLayout(flags: LayoutGestureSupportFlags, params: Ge
|
|||
}
|
||||
};
|
||||
|
||||
const _initialTapModel: GestureModel<KeyElement> = deepCopy(flags.hasFlicks ? initialTapModel(params) : initialTapModelWithReset(params));
|
||||
const _simpleTapModel: GestureModel<KeyElement> = deepCopy(flags.hasFlicks ? simpleTapModel() : simpleTapModelWithReset());
|
||||
const longpressModel: GestureModel<KeyElement> = deepCopy(longpressModelWithShortcut(params, true, !flags.hasFlicks));
|
||||
const doRoaming = params.roamingEnabled ||= !flags.hasFlicks;
|
||||
|
||||
const _initialTapModel: GestureModel<KeyElement> = deepCopy(!doRoaming ? initialTapModel(params) : initialTapModelWithReset(params));
|
||||
const _simpleTapModel: GestureModel<KeyElement> = deepCopy(!doRoaming ? simpleTapModel(params) : simpleTapModelWithReset(params));
|
||||
const longpressModel: GestureModel<KeyElement> = deepCopy(longpressModelWithShortcut(params, true, doRoaming));
|
||||
|
||||
// #region Functions for implementing and/or extending path initial-state checks
|
||||
function withKeySpecFiltering(model: GestureModel<KeyElement>, contactIndices: number | number[]) {
|
||||
|
|
@ -226,7 +238,7 @@ export function gestureSetForLayout(flags: LayoutGestureSupportFlags, params: Ge
|
|||
_initialTapModel,
|
||||
_simpleTapModel,
|
||||
withKeySpecFiltering(specialStartModel, 0),
|
||||
specialKeyEndModel(),
|
||||
specialKeyEndModel(params),
|
||||
subkeySelectModel(),
|
||||
withKeySpecFiltering(_modipressStartModel, 0),
|
||||
modipressHoldModel(params),
|
||||
|
|
@ -241,7 +253,7 @@ export function gestureSetForLayout(flags: LayoutGestureSupportFlags, params: Ge
|
|||
longpressModel.id, _initialTapModel.id, _modipressStartModel.id, specialStartModel.id
|
||||
];
|
||||
|
||||
if(flags.hasFlicks) {
|
||||
if(!doRoaming) {
|
||||
gestureModels.push(withKeySpecFiltering(flickStartModel(params), 0));
|
||||
gestureModels.push(flickMidModel(params));
|
||||
gestureModels.push(flickResetModel(params));
|
||||
|
|
@ -471,11 +483,17 @@ export function modipressContactEndModel(): ContactModel {
|
|||
};
|
||||
}
|
||||
|
||||
export function simpleTapContactModel(): ContactModel {
|
||||
export function simpleTapContactModel(params: GestureParams, isNotInitial?: boolean): ContactModel {
|
||||
// Snapshot at model construction; do not update if changed.
|
||||
const roamingEnabled = params?.roamingEnabled ?? true; // ?? true - used by the banner.
|
||||
|
||||
return {
|
||||
itemPriority: 0,
|
||||
itemChangeAction: 'reject',
|
||||
itemChangeAction: roamingEnabled ? 'reject' : undefined,
|
||||
pathResolutionAction: 'resolve',
|
||||
// if roaming, a tap reset should set the base key.
|
||||
// if not, block path resets.
|
||||
pathInheritance: (!roamingEnabled && isNotInitial) ? 'full' : 'chop',
|
||||
pathModel: {
|
||||
evaluate: (path) => {
|
||||
if(path.isComplete && !path.wasCancelled) {
|
||||
|
|
@ -531,14 +549,14 @@ export function specialKeyStartModel(): GestureModel<KeyElement> {
|
|||
};
|
||||
}
|
||||
|
||||
export function specialKeyEndModel(): GestureModel<any> {
|
||||
export function specialKeyEndModel(params: GestureParams): GestureModel<any> {
|
||||
return {
|
||||
id: 'special-key-end',
|
||||
resolutionPriority: 0,
|
||||
contacts : [
|
||||
{
|
||||
model: {
|
||||
...simpleTapContactModel(),
|
||||
...simpleTapContactModel(params),
|
||||
itemChangeAction: 'resolve'
|
||||
},
|
||||
endOnResolve: true,
|
||||
|
|
@ -763,7 +781,7 @@ export function multitapEndModel(params: GestureParams): GestureModel<any> {
|
|||
contacts: [
|
||||
{
|
||||
model: {
|
||||
...simpleTapContactModel(),
|
||||
...simpleTapContactModel(params),
|
||||
itemPriority: 1,
|
||||
timer: {
|
||||
duration: params.multitap.holdLength,
|
||||
|
|
@ -797,7 +815,7 @@ export function initialTapModel(params: GestureParams): GestureModel<any> {
|
|||
contacts: [
|
||||
{
|
||||
model: {
|
||||
...simpleTapContactModel(),
|
||||
...simpleTapContactModel(params),
|
||||
pathInheritance: 'chop',
|
||||
itemPriority: 1,
|
||||
timer: {
|
||||
|
|
@ -821,20 +839,19 @@ export function initialTapModel(params: GestureParams): GestureModel<any> {
|
|||
resolutionAction: {
|
||||
type: 'chain',
|
||||
next: 'multitap-start',
|
||||
item: 'current'
|
||||
item: 'base'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function simpleTapModel(): GestureModel<any> {
|
||||
export function simpleTapModel(params: GestureParams): GestureModel<any> {
|
||||
return {
|
||||
id: 'simple-tap',
|
||||
resolutionPriority: 1,
|
||||
contacts: [
|
||||
{
|
||||
model: {
|
||||
...simpleTapContactModel(),
|
||||
pathInheritance: 'chop',
|
||||
...simpleTapContactModel(params, true),
|
||||
itemPriority: 1
|
||||
},
|
||||
endOnResolve: true
|
||||
|
|
@ -846,7 +863,7 @@ export function simpleTapModel(): GestureModel<any> {
|
|||
sustainWhenNested: true,
|
||||
resolutionAction: {
|
||||
type: 'complete',
|
||||
item: 'current'
|
||||
item: 'base'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -865,8 +882,8 @@ export function initialTapModelWithReset(params: GestureParams): GestureModel<an
|
|||
}
|
||||
}
|
||||
|
||||
export function simpleTapModelWithReset(): GestureModel<any> {
|
||||
const simpleModel = simpleTapModel();
|
||||
export function simpleTapModelWithReset(params: GestureParams): GestureModel<any> {
|
||||
const simpleModel = simpleTapModel(params);
|
||||
return {
|
||||
...simpleModel,
|
||||
rejectionActions: {
|
||||
|
|
|
|||
|
|
@ -371,7 +371,9 @@ export default class VisualKeyboard extends EventEmitter<EventMap> implements Ke
|
|||
mouseEventRoot: document.body,
|
||||
// Note: at this point in execution, the value will evaluate to NaN! Height hasn't been set yet.
|
||||
// BUT: we need to establish the instance now; we can update it later when height _is_ set.
|
||||
maxRoamingBounds: new PaddedZoneSource(this.element, [NaN]),
|
||||
//
|
||||
// Allow keys to be preserved while the contact point is within banner space + a small fudge-factor.
|
||||
maxRoamingBounds: new PaddedZoneSource(this.topContainer, [NaN]),
|
||||
// touchEventRoot: this.element, // is the default
|
||||
itemIdentifier: (sample, target) => {
|
||||
/* ALWAYS use the findNearestKey function.
|
||||
|
|
@ -450,17 +452,14 @@ export default class VisualKeyboard extends EventEmitter<EventMap> implements Ke
|
|||
const key = sample.item;
|
||||
const oldKey = sourceTrackingMap[source.identifier].key;
|
||||
|
||||
if(key != oldKey) {
|
||||
if(!this.kbdLayout.hasFlicks && key != oldKey) {
|
||||
this.highlightKey(oldKey, false);
|
||||
this.gesturePreviewHost?.cancel();
|
||||
this.gesturePreviewHost = null;
|
||||
|
||||
if(!this.kbdLayout.hasFlicks) {
|
||||
const previewHost = this.highlightKey(key, true);
|
||||
if(previewHost) {
|
||||
this.gesturePreviewHost = previewHost;
|
||||
}
|
||||
|
||||
const previewHost = this.highlightKey(key, true);
|
||||
if(previewHost) {
|
||||
this.gesturePreviewHost = previewHost;
|
||||
trackingEntry.previewHost = previewHost;
|
||||
sourceTrackingMap[source.identifier].key = key;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@
|
|||
kmw.addKeyboards('sil_euro_latin@en');
|
||||
kmw.addKeyboards({id:'ye_old_ten_key',name:'Classic 10-key',languages:{id:'en',name:'English'},
|
||||
filename:('../keyboards/ye_old_ten_key/build/ye_old_ten_key.js')})
|
||||
kmw.addKeyboards({id:'gesture_prototyping',name:'Gesture prototyping',languages:{id:'en',name:'English'},
|
||||
filename:('../keyboards/gesture_prototyping/build/gesture_prototyping.js')})
|
||||
|
||||
var pageRef = (window.location.protocol == 'file:')
|
||||
? window.location.href.substr(0, window.location.href.lastIndexOf('/')+1)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue