chore(web): Merge branch 'refactor/web/common-layout-typing' into feat/web/base-recognizer-integration

This commit is contained in:
Joshua A. Horton 2023-10-16 11:33:39 +07:00
commit fd71de16e5
9 changed files with 44 additions and 47 deletions

View file

@ -59,26 +59,17 @@ export abstract class InputEngineBase<HoveredItemType, StateToken = any> extends
*/
maintainTouchpointsWithIds(identifiers: number[]) {
const identifiersToMaintain = identifiers.map((internal_id) => this.identifierMap[internal_id]);
const sourcesToDrop: GestureSource<HoveredItemType>[] = [];
this._activeTouchpoints.forEach((source) => {
if(identifiersToMaintain.indexOf(source.rawIdentifier) == -1) {
sourcesToDrop.push(source);
}
});
sourcesToDrop.forEach((source) => {
this._activeTouchpoints
.filter((source) => !identifiersToMaintain.includes(source.rawIdentifier))
// Will trigger `.dropTouchpoint` later in the event chain.
source.terminate(true);
});
.forEach((source) => source.terminate(true));
}
/**
* @param identifier The identifier number corresponding to the input sequence.
*/
hasActiveTouchpoint(identifier: number) {
const id = this.identifierMap[identifier];
return id !== undefined; //this.getTouchpointWithId(id) !== undefined;
return this.identifierMap[identifier] !== undefined;
}
/**
@ -117,7 +108,7 @@ export abstract class InputEngineBase<HoveredItemType, StateToken = any> extends
const id = point.rawIdentifier;
this._activeTouchpoints = this._activeTouchpoints.filter((pt) => point != pt);
for(let key in this.identifierMap) {
for(const key of Object.keys(this.identifierMap)) {
if(this.identifierMap[key] == id) {
delete this.identifierMap[key];
}

View file

@ -76,7 +76,7 @@ export class TouchEventEngine<HoveredItemType, StateToken = any> extends InputEv
public dropTouchpoint(source: GestureSource<HoveredItemType>) {
super.dropTouchpoint(source);
for(let key in this.safeBoundMaskMap) {
for(const key of Object.keys(this.safeBoundMaskMap)) {
if(this.getTouchpointWithId(Number.parseInt(key, 10)) == source) {
delete this.safeBoundMaskMap[key];
}
@ -104,7 +104,10 @@ export class TouchEventEngine<HoveredItemType, StateToken = any> extends InputEv
const allTouches = touchListToArray(event.touches);
const newTouches = touchListToArray(event.changedTouches);
// Maintain all touches in the `.touches` array that are NOT marked as `.changedTouches` (and therefore, new)
this.maintainTouchpointsWithIds(allTouches.filter((touch) => (newTouches.indexOf(touch) == -1)).map((touch) => touch.identifier));
this.maintainTouchpointsWithIds(allTouches
.filter((touch) => (newTouches.indexOf(touch) == -1))
.map((touch) => touch.identifier)
);
// Ensure the same timestamp is used for all touches being updated.
const timestamp = performance.now();
@ -134,7 +137,9 @@ export class TouchEventEngine<HoveredItemType, StateToken = any> extends InputEv
// Ensure the same timestamp is used for all touches being updated.
const timestamp = performance.now();
this.maintainTouchpointsWithIds(touchListToArray(event.touches).map((touch) => touch.identifier));
this.maintainTouchpointsWithIds(touchListToArray(event.touches)
.map((touch) => touch.identifier)
);
// Do not change to `changedTouches` - we need a sample for all active touches in order
// to facilitate path-update synchronization for multi-touch gestures.

View file

@ -87,9 +87,12 @@ export class InputSequenceSimulator<HoveredItemType> {
const mappedSample = this.getSampleClientPos(data.sample);
let touch: Touch;
let touchDict = {identifier: data.identifier,
target: targetElement || config.targetRoot,
...mappedSample};
let touchDict = {
identifier: data.identifier,
target: targetElement || config.targetRoot,
...mappedSample
};
if(window['Touch'] !== undefined) {
touch = new Touch(touchDict);
} else {

View file

@ -2,6 +2,7 @@ import Codes from "../text/codes.js";
import KeyEvent, { KeyEventSpec } from "../text/keyEvent.js";
import KeyMapping from "../text/keyMapping.js";
import type { KeyDistribution } from "../text/keyEvent.js";
import { Layouts } from "./defaultLayouts.js";
import type { LayoutKey, LayoutSubKey, LayoutRow, LayoutLayer, LayoutFormFactor, ButtonClass } from "./defaultLayouts.js";
import type Keyboard from "./keyboard.js";
@ -63,7 +64,7 @@ class ActiveKeyBase {
// While they're only valid on ActiveKey, spec'ing them here makes references more concise within the OSK.
sk?: ActiveKey[];
multitap?: ActiveSubkey[];
multitap?: ActiveSubKey[];
flick?: TouchLayout.TouchLayoutFlick;
// Keeping things simple here, as this was added LATE in 14.0 beta.
@ -96,7 +97,7 @@ class ActiveKeyBase {
public get isPadding(): boolean {
// Does not include 9 (class: blank) as that may be an intentional 'catch' for misplaced
// keystrokes.
return this.sp == 10; // Button class: hidden.
return this.sp == Layouts.buttonClasses.HIDDEN; // Button class: hidden.
}
/**
@ -233,7 +234,7 @@ class ActiveKeyBase {
// Ensure subkeys are also properly extended.
if((key as LayoutKey).sk) {
for(let subkey of (key as LayoutKey).sk) {
ActiveSubkey.polyfill(subkey, keyboard, layout, displayLayer);
ActiveSubKey.polyfill(subkey, keyboard, layout, displayLayer);
}
}
@ -241,8 +242,6 @@ class ActiveKeyBase {
aKey.displayLayer = displayLayer;
aKey.layer = aKey.layer || displayLayer;
aKey.default = (key as LayoutSubKey).default;
// Compute the key's base KeyEvent properties for use in future event generation
aKey.constructBaseKeyEvent(keyboard, layout, displayLayer);
}
@ -321,7 +320,7 @@ export class ActiveKey extends ActiveKeyBase implements LayoutKey {
}
export class ActiveSubkey extends ActiveKeyBase implements LayoutSubKey {
export class ActiveSubKey extends ActiveKeyBase implements LayoutSubKey {
}
@ -372,14 +371,14 @@ export class ActiveRow implements LayoutRow {
// to allow the keyboard font to ovveride the SpecialOSK font.
// Blank keys are no longer reclassed - can use before/after CSS to add text
switch(key['sp']) {
case 1:
case Layouts.buttonClasses['SHIFT']:
if(!ActiveRow.SPECIAL_LABEL.test(key['text']) && key['text'] != '') {
key.sp=3;
key.sp=Layouts.buttonClasses['SPECIAL'];
}
break;
case 2:
case Layouts.buttonClasses['SHIFT-ON']:
if(!ActiveRow.SPECIAL_LABEL.test(key['text']) && key['text'] != '') {
key.sp=4;
key.sp=Layouts.buttonClasses['SPECIAL-ON'];
}
break;
}

View file

@ -22,10 +22,7 @@ export type KLS = {[layerName: string]: string[]};
export type ButtonClass = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;
export type ButtonClassString = "0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"|"10";
export type LayoutLayer = {
"id": string,
"row": LayoutRow[],
export interface LayoutLayer extends LayoutLayerBase {
// Post-processing elements.
shiftKey?: LayoutKey,
capsKey?: LayoutKey,
@ -45,6 +42,8 @@ export type LayoutSpec = {
"tablet"?: LayoutFormFactor
}
const KEY_102_WIDTH = 200;
// This class manages default layout construction for consumption by OSKs without a specified layout.
export class Layouts {
static dfltCodes=[
@ -65,9 +64,9 @@ export class Layouts {
// Cross-reference with the ids in osk.setButtonClass.
static buttonClasses: {[name: string]: ButtonClass} = {
'DEFAULT':0,
'SHIFT':1,
'SHIFT':1, // special-key / frame key styling: uses our custom, PUA OSK font
'SHIFT-ON':2,
'SPECIAL':3,
'SPECIAL':3, // special-key / frame key styling: uses the keyboard's font
'SPECIAL-ON':4,
'DEADKEY':8,
'BLANK':9,
@ -479,7 +478,7 @@ export class Layouts {
if(typeof key102 == 'undefined' || !key102) {
if(formFactor == 'desktop') {
keys.splice(j--, 1);
keys[0]['width']=200;
keys[0]['width']=KEY_102_WIDTH;
} else {
keys[j]['sp']=buttonClasses['HIDDEN'];
}

View file

@ -1,10 +1,10 @@
import { ActiveSubkey } from '@keymanapp/keyboard-processor';
import { ActiveSubKey } from '@keymanapp/keyboard-processor';
import OSKKey from '../../../keyboard-layout/oskKey.js';
import { KeyData, KeyElement, link } from '../../../keyElement.js';
import VisualKeyboard from '../../../visualKeyboard.js';
export default class OSKSubKey extends OSKKey {
constructor(spec: ActiveSubkey, layer: string) {
constructor(spec: ActiveSubKey, layer: string) {
if(typeof(layer) != 'string' || layer == '') {
throw "The 'layer' parameter for subkey construction must be properly defined.";
}
@ -24,7 +24,7 @@ export default class OSKSubKey extends OSKKey {
let tKey = osk.getDefaultKeyObject();
let ks=kDiv.style;
for(var tp in tKey) {
for(const tp of Object.keys(tKey)) {
// We've already preprocessed the keyboard's version of the subkey. While certain
// layout properties are fine to overwrite, certain functional properties must
// be preserved.

View file

@ -5,7 +5,7 @@ import OSKBaseKey from '../../../keyboard-layout/oskBaseKey.js';
import VisualKeyboard from '../../../visualKeyboard.js';
import InputEventCoordinate from '../../../input/inputEventCoordinate.js';
import { DeviceSpec, KeyEvent, ActiveSubkey } from '@keymanapp/keyboard-processor';
import { DeviceSpec, KeyEvent, ActiveSubKey } from '@keymanapp/keyboard-processor';
import { InputSample } from '@keymanapp/gesture-recognizer';
/**
@ -58,7 +58,7 @@ export default class SubkeyPopup implements RealizedGesture {
e.key.highlight(true);
// A tag we directly set on a key element during its construction.
let subKeySpec: ActiveSubkey[] = e['subKeys'];
let subKeySpec: ActiveSubKey[] = e['subKeys'];
// The holder is position:fixed, but the keys do not need to be, as no scrolling
// is possible while the array is visible. So it is simplest to let the keys have

View file

@ -1,10 +1,10 @@
import { ActiveSubkey } from '@keymanapp/keyboard-processor';
import { ActiveSubKey } from '@keymanapp/keyboard-processor';
import OSKKey from "./keyboard-layout/oskKey.js";
export class KeyData {
['key']: OSKKey;
['keyId']: string;
['subKeys']?: ActiveSubkey[];
['subKeys']?: ActiveSubKey[];
constructor(keyData: OSKKey, keyId: string) {
this['key'] = keyData;

View file

@ -1,4 +1,4 @@
import { ActiveKey, ActiveSubkey, ButtonClass, DeviceSpec, LayoutKey } from '@keymanapp/keyboard-processor';
import { ActiveKey, ActiveSubKey, ButtonClass, DeviceSpec, LayoutKey } from '@keymanapp/keyboard-processor';
import { TouchLayout } from '@keymanapp/common-types';
import TouchLayoutFlick = TouchLayout.TouchLayoutFlick;
@ -20,7 +20,7 @@ export default abstract class OSKKey {
static readonly BUTTON_CLASSES = buttonClassNames;
static readonly HIGHLIGHT_CLASS = 'kmw-key-touched';
readonly spec: ActiveKey | ActiveSubkey;
readonly spec: ActiveKey | ActiveSubKey;
btn: KeyElement;
label: HTMLSpanElement;
@ -31,7 +31,7 @@ export default abstract class OSKKey {
*/
readonly layer: string;
constructor(spec: ActiveKey | ActiveSubkey, layer: string) {
constructor(spec: ActiveKey | ActiveSubKey, layer: string) {
this.spec = spec;
this.layer = layer;
}