mirror of
https://github.com/keymanapp/keyman.git
synced 2026-10-07 22:47:29 +00:00
Merge pull request #11424 from keymanapp/chore/web/partial-config-cleanup
chore(web): clean up remaining low-level Web .tsconfig settings 🔩
This commit is contained in:
commit
604d2fcb11
35 changed files with 356 additions and 115 deletions
|
|
@ -178,7 +178,7 @@ export class GestureMatcher<Type, StateToken = any> implements PredecessorMatch<
|
|||
return this._isCancelled;
|
||||
}
|
||||
|
||||
private finalize(matched: boolean, cause: FulfillmentCause) {
|
||||
private finalize(matched: boolean, cause: FulfillmentCause): MatchResult<Type> {
|
||||
if(this.publishedPromise.isFulfilled) {
|
||||
return this._result;
|
||||
}
|
||||
|
|
@ -242,6 +242,13 @@ export class GestureMatcher<Type, StateToken = any> implements PredecessorMatch<
|
|||
/* c8 ignore next 3 */
|
||||
} catch(err) {
|
||||
this.publishedPromise.reject(err);
|
||||
return {
|
||||
matched: false,
|
||||
action: {
|
||||
type: 'none',
|
||||
item: null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -211,7 +211,7 @@ export class MatcherSelector<Type, StateToken = any> extends EventEmitter<EventM
|
|||
*/
|
||||
const sourceNotYetStaged = source instanceof GestureSource;
|
||||
|
||||
const determinePredecessorSources = (source: PredecessorMatch<Type, StateToken>) => {
|
||||
const determinePredecessorSources = (source: PredecessorMatch<Type, StateToken>): GestureSource<Type>[] => {
|
||||
const directSources = (source.sources as GestureSourceSubview<Type>[]).map((source => source.baseSource));
|
||||
|
||||
if(directSources && directSources.length > 0) {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { FulfillmentCause } from "../matchers/pathMatcher.js";
|
||||
import { GestureResolutionSpec, RejectionReplace } from "./gestureModel.js";
|
||||
import { GestureModelDefs } from "./gestureModelDefs.js";
|
||||
|
||||
|
|
@ -99,7 +100,7 @@ export function validateModelDefs(definitions: GestureModelDefs<any, any>): Mode
|
|||
processAction(entry.resolutionAction, `model: ${entry.id}`);
|
||||
|
||||
Object.keys(entry.rejectionActions ?? {}).forEach((key) => {
|
||||
processAction(entry.rejectionActions[key], `model: ${entry.id}`);
|
||||
processAction(entry.rejectionActions[key as Exclude<FulfillmentCause, 'cancelled'>], `model: ${entry.id}`);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -115,8 +115,9 @@ export abstract class InputEngineBase<HoveredItemType, StateToken = any> extends
|
|||
|
||||
this._activeTouchpoints = this._activeTouchpoints.filter((pt) => point != pt);
|
||||
for(const key of Object.keys(this.identifierMap)) {
|
||||
if(this.identifierMap[key] == id) {
|
||||
delete this.identifierMap[key];
|
||||
const keyVal = Number.parseInt(key, 10);
|
||||
if(this.identifierMap[keyVal] == id) {
|
||||
delete this.identifierMap[keyVal];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -323,7 +323,7 @@ export class TouchpointCoordinator<HoveredItemType, StateToken=any> extends Even
|
|||
}
|
||||
|
||||
public get historyJSON() {
|
||||
const sanitizingReplacer = function (key: string, value) {
|
||||
const sanitizingReplacer = function (key: string, value: any) {
|
||||
if(key == 'item') {
|
||||
// KMW 'key' elements involve circular refs.
|
||||
// Just return the key ID. (Assumes use in KMW)
|
||||
|
|
|
|||
|
|
@ -76,8 +76,9 @@ export class TouchEventEngine<ItemType, StateToken = any> extends InputEventEngi
|
|||
super.dropTouchpoint(source);
|
||||
|
||||
for(const key of Object.keys(this.safeBoundMaskMap)) {
|
||||
if(this.getTouchpointWithId(Number.parseInt(key, 10)) == source) {
|
||||
delete this.safeBoundMaskMap[key];
|
||||
const keyVal = Number.parseInt(key, 10);
|
||||
if(this.getTouchpointWithId(keyVal) == source) {
|
||||
delete this.safeBoundMaskMap[keyVal];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -226,6 +227,8 @@ export class TouchEventEngine<ItemType, StateToken = any> extends InputEventEngi
|
|||
this.inputStartSignalMap.set(touchpoint, eventSignalPromise);
|
||||
|
||||
return eventSignalPromise.corePromise;
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,5 +9,7 @@
|
|||
// Not needed when testing via Node, and when `true` it seems to desync preset breakpoints
|
||||
// worse than when `false`.
|
||||
"importHelpers": false,
|
||||
// Makes the tests... somewhat tricky to handle properly.
|
||||
"noImplicitAny": false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { GestureDebugSource } from "@keymanapp/gesture-recognizer";
|
||||
import { GestureDebugSource, GestureSource } from "@keymanapp/gesture-recognizer";
|
||||
import { HostFixtureLayoutController } from "./hostFixtureLayoutController.js";
|
||||
import { RecordedCoordSequenceSet } from "./inputRecording.js";
|
||||
|
||||
|
|
@ -32,9 +32,9 @@ export class SequenceRecorder {
|
|||
}
|
||||
|
||||
private _attachRecognizerHooks() {
|
||||
this.controller.recognizer.on('inputstart', (wrappedSequence: WrappedInputSequence) => {
|
||||
this.controller.recognizer.on('inputstart', (wrappedSequence: GestureSource<any>) => {
|
||||
const id = wrappedSequence.identifier;
|
||||
this.records[id] = wrappedSequence;
|
||||
this.records[id] = wrappedSequence as WrappedInputSequence;
|
||||
|
||||
this.startOrder.push(id);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,7 +5,16 @@
|
|||
"lib": [ "dom", "es6" ],
|
||||
"outDir": "./build/obj/",
|
||||
"rootDir": "./src/engine",
|
||||
"tsBuildInfoFile": "./build/obj/tsconfig.tsbuildinfo"
|
||||
"tsBuildInfoFile": "./build/obj/tsconfig.tsbuildinfo",
|
||||
|
||||
// TODO: These override ../tsconfig.base.json settings, and so should be removed if possible,
|
||||
// but existing code in web/ breaks some of these settings
|
||||
//
|
||||
// At present, the code actually compiles without them... but the TS tests are a different matter.
|
||||
"noImplicitAny": false,
|
||||
"noUnusedLocals": false,
|
||||
"strictFunctionTypes": false,
|
||||
"noImplicitReturns": false
|
||||
},
|
||||
"include": ["./src/engine/**/*.ts"],
|
||||
"exclude": ["./src/test/**/*.ts", "./src/tools/**/*.ts"],
|
||||
|
|
|
|||
|
|
@ -167,6 +167,12 @@ export default class LanguageProcessor extends EventEmitter<LanguageProcessorEve
|
|||
} else if(outputTarget) {
|
||||
let transcription = outputTarget.buildTranscriptionFrom(outputTarget, null, false);
|
||||
return this.predict_internal(transcription, true, layerId);
|
||||
} else {
|
||||
// if there's no active context source, there's nothing to
|
||||
// provide suggestions for. In that case, there's no reason
|
||||
// to even request suggestions, so bypass the prediction
|
||||
// engine and say that there aren't any.
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -290,7 +296,7 @@ export default class LanguageProcessor extends EventEmitter<LanguageProcessorEve
|
|||
let original = this.getPredictionState(-reversion.transformId);
|
||||
if(!original) {
|
||||
console.warn("Could not apply the Suggestion!");
|
||||
return;
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
// Apply the Reversion!
|
||||
|
|
|
|||
|
|
@ -80,6 +80,8 @@ export default class PredictionContext extends EventEmitter<PredictionContextEve
|
|||
this.suggestionApplier = (suggestion) => {
|
||||
if(validSuggestionState()) {
|
||||
return langProcessor.applySuggestion(suggestion, this.currentTarget, () => kbdProcessor.layerId);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -131,7 +133,7 @@ export default class PredictionContext extends EventEmitter<PredictionContextEve
|
|||
}
|
||||
|
||||
public get currentSuggestions(): Suggestion[] {
|
||||
let suggestions = [];
|
||||
let suggestions: Suggestion[] = [];
|
||||
// Insert 'current text' if/when valid as the leading option.
|
||||
// Since we don't yet do auto-corrections, we only show 'keep' whenever it's
|
||||
// a valid word (according to the model).
|
||||
|
|
@ -243,7 +245,7 @@ export default class PredictionContext extends EventEmitter<PredictionContextEve
|
|||
* Should return 'false' if the current state allows reverting a recently-applied suggestion and act accordingly.
|
||||
* Otherwise, return true.
|
||||
*/
|
||||
private doTryRevert = (/*returnObj: {shouldSwallow: boolean}*/): boolean => {
|
||||
private doTryRevert = (/*returnObj: {shouldSwallow: boolean}*/): void => {
|
||||
// Has the revert keystroke (BKSP) already been sent once since the last accept?
|
||||
if(this.doRevert) {
|
||||
// If so, clear the 'revert' option and start doing normal predictions again.
|
||||
|
|
|
|||
|
|
@ -297,9 +297,9 @@ export class ActiveKeyBase {
|
|||
const value = KeyTypesOfKeyMap[key as keyof typeof KeyTypesOfKeyMap];
|
||||
switch(value) {
|
||||
case 'subkeys':
|
||||
const arr = rawKey[key] as LayoutSubKey[];
|
||||
const arr = rawKey[key as 'sk' | 'multitap'] as LayoutSubKey[];
|
||||
if(!Array.isArray(arr)) {
|
||||
delete rawKey[key];
|
||||
delete rawKey[key as 'sk' | 'multitap'];
|
||||
} else {
|
||||
for(let i=0; i < arr.length; i++) {
|
||||
const sk = arr[i];
|
||||
|
|
@ -312,9 +312,9 @@ export class ActiveKeyBase {
|
|||
}
|
||||
break;
|
||||
case 'flicks':
|
||||
const flickObj = rawKey[key];
|
||||
const flickObj = rawKey[key as 'flick'];
|
||||
if(typeof flickObj != 'object') {
|
||||
delete rawKey[key];
|
||||
delete rawKey[key as 'flick'];
|
||||
} else {
|
||||
for(const flickKey of KeyTypesOfFlickList) {
|
||||
const sk = flickObj[flickKey];
|
||||
|
|
@ -327,9 +327,9 @@ export class ActiveKeyBase {
|
|||
}
|
||||
break;
|
||||
default:
|
||||
const prop = rawKey[key];
|
||||
const prop = rawKey[key as keyof (LayoutKey | LayoutSubKey)];
|
||||
if(typeof prop != value) {
|
||||
delete rawKey[key];
|
||||
delete rawKey[key as keyof (LayoutKey | LayoutSubKey)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -395,7 +395,7 @@ export class ActiveKeyBase {
|
|||
if(defaultHint?.includes('flick-')) {
|
||||
if(spec.flick) {
|
||||
// 6 = length of 'flick-'
|
||||
const dir = defaultHint.substring(6);
|
||||
const dir = defaultHint.substring(6) as keyof TouchLayoutFlick;
|
||||
|
||||
if(spec.flick[dir]?.text) {
|
||||
spec.hintSrc = spec.flick[dir];
|
||||
|
|
|
|||
|
|
@ -19,7 +19,26 @@ export { ButtonClasses };
|
|||
import Codes from "../text/codes.js";
|
||||
import type Keyboard from "./keyboard.js";
|
||||
|
||||
export type KLS = {[layerName: string]: string[]};
|
||||
export interface EncodedVisualKeyboard {
|
||||
/** Represents CSS font styling to use for VisualKeyboard text */
|
||||
F: string;
|
||||
/** Should there be a 102nd key? */
|
||||
K102?: boolean,
|
||||
/**
|
||||
* Keyboard Layer Specification: an object-based map of layer name to the keycaps for its
|
||||
* 65 keys. The 65 keys are ordered from left to right, then top to bottom.
|
||||
*
|
||||
* The key ID corresponding to each index of the array is specified within `Codes.dfltCodes`.
|
||||
* Entries corresponding to `K_*` in `Codes.dfltCodes` are reserved for future use.
|
||||
*/
|
||||
KLS?: {[layerName: string]: string[]},
|
||||
/**
|
||||
* @deprecated
|
||||
* The older form for data in KLS - defines keycaps for 'default' keys, then 'shift' keys,
|
||||
* in a single concatenated array.
|
||||
*/
|
||||
BK?: string[];
|
||||
}
|
||||
|
||||
// The following types provide type definitions for the full JSON format we use for visual keyboard definitions.
|
||||
export type ButtonClass = 0 | 1 | 2 | 3 | 4 | /*5 | 6 | 7 |*/ 8 | 9 | 10;
|
||||
|
|
@ -30,9 +49,9 @@ export interface LayoutLayer extends LayoutLayerBase {
|
|||
capsKey?: LayoutKey,
|
||||
numKey?: LayoutKey,
|
||||
scrollKey?: LayoutKey,
|
||||
aligned?: boolean
|
||||
aligned?: boolean,
|
||||
nextlayer?: string
|
||||
};
|
||||
|
||||
export interface LayoutFormFactor extends LayoutFormFactorBase {
|
||||
// To facilitate those post-processing elements.
|
||||
layer: LayoutLayer[]
|
||||
|
|
@ -96,9 +115,9 @@ export class Layouts {
|
|||
* @param {string} formFactor (really utils.FormFactor)
|
||||
* @return {LayoutFormFactor}
|
||||
*/
|
||||
static buildDefaultLayout(PVK, keyboard: Keyboard, formFactor: string): LayoutFormFactor {
|
||||
static buildDefaultLayout(PVK: EncodedVisualKeyboard, keyboard: Keyboard, formFactor: string): LayoutFormFactor {
|
||||
// Build a layout using the default for the device
|
||||
var layoutType=formFactor;
|
||||
let layoutType = formFactor as keyof TouchLayout.TouchLayoutFile;
|
||||
|
||||
if(typeof Layouts.dfltLayout[layoutType] != 'object') {
|
||||
layoutType = 'desktop';
|
||||
|
|
@ -119,7 +138,7 @@ export class Layouts {
|
|||
// Clone the default layout object for this device
|
||||
var layout: LayoutFormFactor = deepCopy(Layouts.dfltLayout[layoutType]);
|
||||
|
||||
var n,layers=layout['layer'], keyLabels: KLS=PVK['KLS'], key102=PVK['K102'];
|
||||
var n,layers=layout['layer'], keyLabels: EncodedVisualKeyboard['KLS'] = PVK['KLS'], key102=PVK['K102'];
|
||||
var i, j, k, rows: LayoutRow[], key: LayoutKey, keys: LayoutKey[];
|
||||
var chiral: boolean = (kbdBitmask & Codes.modifierBitmasks.IS_CHIRAL) != 0;
|
||||
|
||||
|
|
@ -142,7 +161,7 @@ export class Layouts {
|
|||
// *** Step 1: instantiate the layer objects. ***
|
||||
|
||||
// Get the list of valid layers, enforcing that the 'default' layer must be the first one processed.
|
||||
var validIdList = Object.getOwnPropertyNames(keyLabels), invalidIdList = [];
|
||||
var validIdList = Object.getOwnPropertyNames(keyLabels), invalidIdList: string[] = [];
|
||||
validIdList.splice(validIdList.indexOf('default'), 1);
|
||||
validIdList = [ 'default' ].concat(validIdList);
|
||||
|
||||
|
|
@ -200,14 +219,14 @@ export class Layouts {
|
|||
// Erase the legacy shifted subkey array.
|
||||
shiftKey['sk'] = [];
|
||||
|
||||
for(var layerID in keyLabels) {
|
||||
for(let layerID in keyLabels) {
|
||||
if(layerID == 'default' || layerID == 'shift') {
|
||||
// These two are accessible from the layer without subkeys.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create a new subkey for the specified layer so that it will be accessible via OSK.
|
||||
var specialChar = Layouts.modifierSpecials[layerID];
|
||||
var specialChar = Layouts.modifierSpecials[(layerID as keyof typeof Layouts.modifierSpecials)];
|
||||
let subkey: LayoutSubKey = {
|
||||
id: `K_${specialChar}`,
|
||||
text: specialChar,
|
||||
|
|
@ -307,12 +326,14 @@ export class Layouts {
|
|||
layer.numKey=numKey;
|
||||
layer.scrollKey=scrollKey;
|
||||
|
||||
const layerId = layers[n].id as keyof typeof Layouts.modifierSpecials;
|
||||
|
||||
// Set modifier key appearance and behaviour for non-desktop devices using the default layout
|
||||
if(formFactor != 'desktop') {
|
||||
if(n > 0 && shiftKey != null) {
|
||||
shiftKey['sp']=ButtonClasses.specialActive;
|
||||
shiftKey['sk']=null;
|
||||
shiftKey['text'] = Layouts.modifierSpecials[layers[n].id] ? Layouts.modifierSpecials[layers[n].id] : "*Shift*";
|
||||
shiftKey['text'] = Layouts.modifierSpecials[layerId] ?? "*Shift*";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -482,11 +503,11 @@ export class Layouts {
|
|||
* @param {Array} BK keyboard object (as loaded)
|
||||
* @return {Object}
|
||||
*/
|
||||
static processLegacyDefinitions(BK: string[]): KLS {
|
||||
static processLegacyDefinitions(BK: string[]): EncodedVisualKeyboard['KLS'] {
|
||||
//['default','shift','ctrl','shiftctrl','alt','shiftalt','ctrlalt','shiftctrlalt'];
|
||||
var idList=Layouts.generateLayerIds(false); // Non-chiral.
|
||||
|
||||
var KLS: KLS = {};
|
||||
var KLS: EncodedVisualKeyboard['KLS'] = {};
|
||||
|
||||
// The old default: eight auto-managed layers...
|
||||
for(var n=0; n<idList.length; n++) {
|
||||
|
|
@ -851,6 +872,6 @@ export class Layouts {
|
|||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
} as TouchLayout.TouchLayoutFile;
|
||||
/* c8 ignore end */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import Codes from "../text/codes.js";
|
||||
import { Layouts, type LayoutFormFactor } from "./defaultLayouts.js";
|
||||
import { EncodedVisualKeyboard, LayoutSpec, Layouts, type LayoutFormFactor } from "./defaultLayouts.js";
|
||||
import { ActiveKey, ActiveLayout, ActiveSubKey } from "./activeLayout.js";
|
||||
import KeyEvent from "../text/keyEvent.js";
|
||||
import type OutputTarget from "../text/outputTarget.js";
|
||||
|
|
@ -30,6 +30,156 @@ export interface VariableStoreDictionary {
|
|||
[name: string]: string;
|
||||
};
|
||||
|
||||
export type KeyboardObject = {
|
||||
/**
|
||||
* Used internally by Keyman Engine for Web to hold preprocessed stores.
|
||||
*/
|
||||
_kmw?: CacheTag;
|
||||
|
||||
/**
|
||||
* group-start: the function triggering processing for the keyboard's
|
||||
* "Unicode" start group, corresponding to `begin Unicode > use(_____)` in
|
||||
* Keyman keyboard language.
|
||||
* @param outputTarget The context to which the keystroke applies
|
||||
* @param keystroke The full, pre-processed keystroke triggering
|
||||
* keyboard-rule application.
|
||||
*/
|
||||
gs(outputTarget: OutputTarget, keystroke: KeyEvent): boolean;
|
||||
|
||||
/**
|
||||
* group-newcontext: the function triggering processing for the keyboard's
|
||||
* "NewContext" start group, corresponding to `begin NewContext > use(_____)`
|
||||
* in Keyman keyboard language.
|
||||
* @param outputTarget The new context to be used with future keystrokes
|
||||
* @param keystroke A 'null' `KeyEvent` providing current modifier + state information.
|
||||
*/
|
||||
gn?(outputTarget: OutputTarget, keystroke: KeyEvent): boolean;
|
||||
|
||||
/**
|
||||
* group-postkeystroke: the function triggering processing for the keyboard's
|
||||
* "PostKeystroke" start group, corresponding to `begin PostKeystroke >
|
||||
* use(_____)` in Keyman keyboard language.
|
||||
* @param outputTarget The context altered by a recent keystroke. As a
|
||||
* precondition, all changes due to `gs` / `begin Unicode` should already be
|
||||
* applied.
|
||||
* @param keystroke A 'null' `KeyEvent` providing current modifier + state information.
|
||||
*/
|
||||
gpk?(outputTarget: OutputTarget, keystroke: KeyEvent): boolean;
|
||||
|
||||
/**
|
||||
* Keyboard ID: the uniquely-identifying name for this keyboard. Includes the standard
|
||||
* `Keyboard_` prefix. May be 'namespaced' with a prefix corresponding to a package name
|
||||
* within app/webview.
|
||||
*/
|
||||
KI: string;
|
||||
/**
|
||||
* Keyboard Name: the human-readable name of the keyboard.
|
||||
*/
|
||||
KN: string;
|
||||
/**
|
||||
* Encoded data usable to construct a desktop/hardware-oriented on-screen keyboard.
|
||||
*/
|
||||
KV: EncodedVisualKeyboard;
|
||||
/**
|
||||
* Keyboard Language Code: set within select keyboards.
|
||||
*
|
||||
* Currently, it's only used to determine the need for CJK-picker support. Is missing
|
||||
* in most compiled keyboards.
|
||||
*/
|
||||
KLC?: string;
|
||||
/**
|
||||
* @deprecated
|
||||
* Keyboard Language Code: set within select keyboards.
|
||||
*
|
||||
* Currently, it's only used to determine the need for CJK-picker support.
|
||||
* Is (probably) an older name of KLC with the identical purpose. Is missing
|
||||
* in most compiled keyboards.
|
||||
*/
|
||||
LanguageCode?: string;
|
||||
/**
|
||||
* Keyboard CSS: provides the definition for custom keyboard style sheets
|
||||
*/
|
||||
KCSS?: string;
|
||||
/**
|
||||
* Keyboard is RTL: a simple flag noting if the keyboard's script is RTL.
|
||||
*/
|
||||
KRTL?: boolean;
|
||||
/**
|
||||
* Keyboard Modifier BitMask: a set of bitflags indicating which modifiers
|
||||
* the keyboard's rules utilize. See also: `Codes.modifierCodes`.
|
||||
*/
|
||||
KMBM?: number;
|
||||
/**
|
||||
* Keyboard Supplementary plane: set to 1 if the keyboard uses non-BMP Unicode
|
||||
* characters.
|
||||
*/
|
||||
KS?: number;
|
||||
/**
|
||||
* Keyman Visual Keyboard Layout: defines the touch-layout definitions used for
|
||||
* 'phone' and 'tablet' form-factors.
|
||||
*/
|
||||
KVKL?: LayoutSpec;
|
||||
/**
|
||||
* Keyboard is Mnemonic: set to 1 if the keyboard uses a mnemonic layout.
|
||||
*/
|
||||
KM?: number;
|
||||
/**
|
||||
* KeyBoard VERsion: the version of this keyboard.
|
||||
*/
|
||||
KBVER?: string;
|
||||
/**
|
||||
* Keyman VERsion: the version of Keyman Developer used to compile this keyboard.
|
||||
*/
|
||||
KVER?: string;
|
||||
/**
|
||||
* Keyman Variable Stores: an array of the names of all variable stores used by the
|
||||
* keyboard.
|
||||
*/
|
||||
KVS?: (`s${number}`)[];
|
||||
/**
|
||||
* Keyboard Help: HTML help text, as specified by either the &kmw_helptext or &kmw_helpfile system stores.
|
||||
*
|
||||
* Reference: https://help.keyman.com/developer/language/reference/kmw_helptext,
|
||||
* https://help.keyman.com/developer/language/reference/kmw_helpfile
|
||||
*/
|
||||
KH?: string;
|
||||
/**
|
||||
* Keyboard Virtual Key Dictionary: the Developer-compiled, minified dictionary of virtual-key codes
|
||||
*/
|
||||
KVKD?: string;
|
||||
/**
|
||||
* Keyboard Display Underlying: set to 1 if the desktop form of the keyboard
|
||||
* should show the US QWERTY underlying keycaps. These may also appear on
|
||||
* touch layouts if set and no touch-layout information is available.
|
||||
*/
|
||||
KDU?: number;
|
||||
/**
|
||||
* Virtual Key Dictionary: the engine pre-processed, unminified dictionary. This is built within
|
||||
* Keyman Engine for Web at runtime as needed based on the definitions in `KVKD`.
|
||||
*/
|
||||
VKDictionary?: Record<string, number>,
|
||||
/**
|
||||
* Keyboard Help File: Embedded JS script designed for use with a keyboard's
|
||||
* HTML help text. Always defined within the file referenced by &kmw_embedjs
|
||||
* in a keyboard's source, though that file may also contain _other_ script
|
||||
* definitions as well. (`KHF` must be explicitly defined within that file.)
|
||||
* @param e Will be provided with the root element (a <div>) of the On-Screen Keyboard.
|
||||
* @returns
|
||||
*/
|
||||
KHF?: (e: any) => string;
|
||||
|
||||
/**
|
||||
* Keyboard Notify Shift: Provided by CJK-picker keyboards to properly
|
||||
* interface them with Keyman Engine for Web.
|
||||
* @param {number} _PCommand event code (16,17,18) or 0; 16-18
|
||||
* correspond to modifier codes when pressed, while 0 corresponds to loss of focus
|
||||
* @param {Object} _PTarget target element
|
||||
* @param {number} _PData 1 or 0
|
||||
* @returns
|
||||
*/
|
||||
KNS?: (_PCommand: number, _PTarget: OutputTarget, _PData: number) => void;
|
||||
} & Record<`s${number}`, string>
|
||||
|
||||
|
||||
/**
|
||||
* Acts as a wrapper class for Keyman keyboards compiled to JS, providing type information
|
||||
|
|
@ -37,8 +187,8 @@ export interface VariableStoreDictionary {
|
|||
* wrapped keyboard itself.
|
||||
*/
|
||||
export default class Keyboard {
|
||||
public static DEFAULT_SCRIPT_OBJECT = {
|
||||
'gs': function(outputTarget, keystroke) { return false; }, // no matching rules; rely on defaultRuleOutput entirely
|
||||
public static DEFAULT_SCRIPT_OBJECT: KeyboardObject = {
|
||||
'gs': function(outputTarget: OutputTarget, keystroke: KeyEvent) { return false; }, // no matching rules; rely on defaultRuleOutput entirely
|
||||
'KI': '', // The currently-existing default keyboard ID; we already have checks that focus against this.
|
||||
'KN': '',
|
||||
'KV': Layouts.DEFAULT_RAW_SPEC,
|
||||
|
|
@ -51,7 +201,7 @@ export default class Keyboard {
|
|||
*
|
||||
* TODO: Make this private instead. But there are a LOT of references that must be rooted out first.
|
||||
*/
|
||||
public readonly scriptObject: any;
|
||||
public readonly scriptObject: KeyboardObject;
|
||||
private layoutStates: {[layout: string]: LayoutState};
|
||||
|
||||
constructor(keyboardScript: any) {
|
||||
|
|
@ -109,7 +259,7 @@ export default class Keyboard {
|
|||
*/
|
||||
get variableStores(): VariableStoreDictionary {
|
||||
const storeNames = this.scriptObject['KVS'];
|
||||
let values = {};
|
||||
let values: VariableStoreDictionary = {};
|
||||
if(Array.isArray(storeNames)) {
|
||||
for(let store of storeNames) {
|
||||
values[store] = this.scriptObject[store];
|
||||
|
|
@ -147,11 +297,11 @@ export default class Keyboard {
|
|||
}
|
||||
|
||||
// May return null if no layouts exist or have been initialized.
|
||||
private get _layouts(): {[formFactor: string]: LayoutFormFactor} {
|
||||
private get _layouts(): LayoutSpec {
|
||||
return this.scriptObject['KVKL']; // This one is compiled by Developer's visual keyboard layout editor.
|
||||
}
|
||||
|
||||
private set _layouts(value) {
|
||||
private set _layouts(value: LayoutSpec) {
|
||||
this.scriptObject['KVKL'] = value;
|
||||
}
|
||||
|
||||
|
|
@ -488,7 +638,7 @@ export default class Keyboard {
|
|||
'K_NUMLOCK': Codes.stateBitmasks.NUM_LOCK,
|
||||
'K_SCROLL': Codes.stateBitmasks.SCROLL_LOCK
|
||||
};
|
||||
const bitmask = bitmap[Lkc.kName];
|
||||
const bitmask = bitmap[Lkc.kName as keyof typeof bitmap];
|
||||
|
||||
if(bitmask) {
|
||||
Lkc.Lstates ^= bitmask;
|
||||
|
|
@ -558,8 +708,8 @@ export default class Keyboard {
|
|||
* @return {number} key code > 255 on success, or 0 if not found
|
||||
*/
|
||||
getVKDictionaryCode(keyName: string) {
|
||||
const dict = this.scriptObject['VKDictionary'] || {} as KeyboardObject['VKDictionary'];
|
||||
if(!this.scriptObject['VKDictionary']) {
|
||||
const a=[];
|
||||
if(typeof this.scriptObject['KVKD'] == 'string') {
|
||||
// Build the VK dictionary
|
||||
// TODO: Move the dictionary build into the compiler -- so compiler generates code such as following.
|
||||
|
|
@ -567,13 +717,13 @@ export default class Keyboard {
|
|||
// this.KVKD={"K_ABC":256,"K_DEF":257,...};
|
||||
const s=this.scriptObject['KVKD'].split(' ');
|
||||
for(var i=0; i<s.length; i++) {
|
||||
a[s[i].toUpperCase()]=i+256; // We force upper-case since virtual keys should be case-insensitive.
|
||||
dict[s[i].toUpperCase()]=i+256; // We force upper-case since virtual keys should be case-insensitive.
|
||||
}
|
||||
}
|
||||
this.scriptObject['VKDictionary']=a;
|
||||
this.scriptObject['VKDictionary']=dict;
|
||||
}
|
||||
|
||||
const res=this.scriptObject['VKDictionary'][keyName.toUpperCase()];
|
||||
const res=dict[keyName.toUpperCase()];
|
||||
return res ? res : 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -5,8 +5,8 @@ import KeyboardProperties from "./keyboardProperties.js";
|
|||
type KeyboardStub = KeyboardProperties & { filename: string };
|
||||
|
||||
export interface KeyboardLoadErrorBuilder {
|
||||
scriptError(err?: Error);
|
||||
missingError(err: Error);
|
||||
scriptError(err?: Error): void;
|
||||
missingError(err: Error): void;
|
||||
}
|
||||
|
||||
export class KeyboardScriptError extends Error {
|
||||
|
|
|
|||
|
|
@ -136,6 +136,7 @@ export default class KeyboardProperties implements KeyboardInternalPropertySpec
|
|||
public constructor(keyboardId: string, languageCode: string);
|
||||
public constructor(arg1: MetadataObj | string, arg2?: string) {
|
||||
if(!(typeof arg1 == 'string')) {
|
||||
// @ts-ignore
|
||||
if(arg1['KI'] || arg1['KL'] || arg1['KLC'] || arg1['KFont'] || arg1['KOskFont']) {
|
||||
const other = arg1 as KeyboardInternalPropertySpec;
|
||||
this.KI = other.KI;
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ export class DOMKeyboardLoader extends KeyboardLoaderBase {
|
|||
script.id = id;
|
||||
}
|
||||
document.head.appendChild(script);
|
||||
script.onerror = (err) => {
|
||||
script.onerror = (err: any) => {
|
||||
promise.reject(errorBuilder.missingError(err));
|
||||
}
|
||||
script.onload = () => {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ const Codes = {
|
|||
// Note: keys_mod_other = 0x10000, used by KMX+ for the
|
||||
// other modifier flag in layers, > 16 bit so not available here.
|
||||
// See keys_mod_other in keyman_core_ldml.ts
|
||||
},
|
||||
} as {[name: string]: number},
|
||||
|
||||
modifierBitmasks: {
|
||||
"ALL":0x007F,
|
||||
|
|
@ -39,14 +39,14 @@ const Codes = {
|
|||
"NON_CHIRAL":0x0070, // The default bitmask, for non-chiral keyboards,
|
||||
// Represents all modifier codes not supported by KMW 1.0 legacy keyboards.
|
||||
"NON_LEGACY": 0x006F // ALL, but without the SHIFT bit
|
||||
},
|
||||
} as {[name: string]: number},
|
||||
|
||||
stateBitmasks: {
|
||||
"ALL":0x3F00,
|
||||
"CAPS":0x0300,
|
||||
"NUM_LOCK":0x0C00,
|
||||
"SCROLL_LOCK":0x3000
|
||||
},
|
||||
} as {[name: string]: number},
|
||||
|
||||
// Define standard keycode numbers (exposed for use by other modules)
|
||||
keyCodes: {
|
||||
|
|
@ -79,7 +79,7 @@ const Codes = {
|
|||
"K_UPPER":50006,"K_LOWER":50007,"K_ALPHA":50008,
|
||||
"K_SHIFTED":50009,"K_ALTGR":50010,
|
||||
"K_TABBACK":50011,"K_TABFWD":50012
|
||||
},
|
||||
} as {[name: string]: number},
|
||||
|
||||
codesUS: [
|
||||
['0123456789',';=,-./`', '[\\]\''],
|
||||
|
|
|
|||
|
|
@ -48,12 +48,12 @@ type RuleChar = string;
|
|||
class RuleDeadkey {
|
||||
/** Discriminant field - 'd' for Deadkey.
|
||||
*/
|
||||
['t']: 'd';
|
||||
t: 'd';
|
||||
|
||||
/**
|
||||
* Value: the deadkey's ID.
|
||||
*/
|
||||
['d']: number; // For 'd'eadkey; also reflects the Deadkey class's 'd' property.
|
||||
d: number; // For 'd'eadkey; also reflects the Deadkey class's 'd' property.
|
||||
}
|
||||
|
||||
class ContextAny {
|
||||
|
|
@ -254,7 +254,7 @@ export default class KeyboardInterface extends KeyboardHarness {
|
|||
* In web-core, this also activates the keyboard; in other modules, this method
|
||||
* may be replaced with other implementations.
|
||||
*/
|
||||
registerKeyboard(Pk): void {
|
||||
registerKeyboard(Pk: any): void {
|
||||
// NOTE: This implementation is web-core specific and is intentionally replaced, whole-sale,
|
||||
// by DOM-aware code.
|
||||
let keyboard = new Keyboard(Pk);
|
||||
|
|
@ -400,7 +400,7 @@ export default class KeyboardInterface extends KeyboardHarness {
|
|||
var subCache = cache;
|
||||
subCache.valContext = subCache.valContext.slice(0, ln);
|
||||
for(var i=0; i < subCache.valContext.length; i++) {
|
||||
if(subCache[i] == '\ufffe') {
|
||||
if(subCache.valContext[i] == '\ufffe') {
|
||||
subCache.valContext.splice(0, 1);
|
||||
subCache.deadContext.splice(0, 1);
|
||||
}
|
||||
|
|
@ -709,12 +709,14 @@ export default class KeyboardInterface extends KeyboardHarness {
|
|||
s = this._ExplodeStore(s);
|
||||
var Lix = -1;
|
||||
for(var i=0; i < s.length; i++) {
|
||||
if(typeof(s[i]) == 'string') {
|
||||
const entry = s[i];
|
||||
if(typeof(entry) == 'string') {
|
||||
if(s[i] == ch) {
|
||||
Lix = i;
|
||||
break;
|
||||
}
|
||||
} else if(s[i]['d'] === ch['d']) {
|
||||
// @ts-ignore // Needs to test against .t for automatic inference, but it's not actually there.
|
||||
} else if(entry.d === (ch as RuleDeadkey).d) {
|
||||
Lix = i;
|
||||
break;
|
||||
}
|
||||
|
|
@ -765,21 +767,19 @@ export default class KeyboardInterface extends KeyboardHarness {
|
|||
if(indexChar !== "") {
|
||||
if(typeof indexChar == 'string' ) {
|
||||
this.output(Pdn, outputTarget, indexChar); //I3319
|
||||
} else if(indexChar['t']) {
|
||||
var storeEntry = indexChar as StoreNonCharEntry;
|
||||
|
||||
switch(storeEntry.t) {
|
||||
} else if(indexChar.t) {
|
||||
switch(indexChar.t) {
|
||||
case 'b': // Beep commands may appear within stores.
|
||||
this.beep(outputTarget);
|
||||
break;
|
||||
case 'd':
|
||||
this.deadkeyOutput(Pdn, outputTarget, indexChar['d']);
|
||||
this.deadkeyOutput(Pdn, outputTarget, indexChar.d);
|
||||
break;
|
||||
default:
|
||||
assertNever(storeEntry);
|
||||
assertNever(indexChar);
|
||||
}
|
||||
} else { // For keyboards developed during 10.0's alpha phase - t:'d' was assumed.
|
||||
this.deadkeyOutput(Pdn, outputTarget, indexChar['d']);
|
||||
this.deadkeyOutput(Pdn, outputTarget, (indexChar as any).d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1057,7 +1057,7 @@ export default class KeyboardInterface extends KeyboardHarness {
|
|||
return this.process(this.activeKeyboard.process.bind(this.activeKeyboard), outputTarget, keystroke, false);
|
||||
}
|
||||
|
||||
private process(callee, outputTarget: OutputTarget, keystroke: KeyEvent, readonly: boolean): RuleBehavior {
|
||||
private process(callee: (outputTarget: OutputTarget, keystroke: KeyEvent) => boolean, outputTarget: OutputTarget, keystroke: KeyEvent, readonly: boolean): RuleBehavior {
|
||||
// Clear internal state tracking data from prior keystrokes.
|
||||
if(!outputTarget) {
|
||||
throw "No target specified for keyboard output!";
|
||||
|
|
@ -1138,16 +1138,19 @@ export default class KeyboardInterface extends KeyboardHarness {
|
|||
// Keyboard callbacks
|
||||
let prototype = this.prototype;
|
||||
|
||||
var exportKBCallback = function(miniName: string, longName: string) {
|
||||
var exportKBCallback = function(miniName: string, longName: keyof KeyboardInterface) {
|
||||
if(prototype[longName]) {
|
||||
// @ts-ignore
|
||||
prototype[miniName] = prototype[longName];
|
||||
}
|
||||
}
|
||||
|
||||
exportKBCallback('KSF', 'saveFocus');
|
||||
// @ts-ignore // is defined at a higher level
|
||||
exportKBCallback('KBR', 'beepReset');
|
||||
exportKBCallback('KT', 'insertText');
|
||||
exportKBCallback('KR', 'registerKeyboard');
|
||||
// @ts-ignore // is defined at a higher level
|
||||
exportKBCallback('KRS', 'registerStub');
|
||||
exportKBCallback('KC', 'context');
|
||||
exportKBCallback('KN', 'nul');
|
||||
|
|
|
|||
|
|
@ -104,7 +104,9 @@ export default class KeyEvent implements KeyEventSpec {
|
|||
|
||||
public constructor(keyEventSpec: KeyEventSpec) {
|
||||
for(let key in keyEventSpec) {
|
||||
// @ts-ignore
|
||||
if(keyEventSpec[key] !== undefined) {
|
||||
// @ts-ignore
|
||||
this[key] = keyEventSpec[key];
|
||||
}
|
||||
}
|
||||
|
|
@ -146,7 +148,8 @@ export default class KeyEvent implements KeyEventSpec {
|
|||
// We need to determine the mnemonic base character - for example, SHIFT + K_PERIOD needs to map to '>'.
|
||||
let mappingEvent: KeyEvent = new KeyEvent(this);
|
||||
for(let key in (this as KeyEvent)) {
|
||||
mappingEvent[key] = this[key];
|
||||
// @ts-ignore
|
||||
mappingEvent[key as keyof KeyEvent] = this[key];
|
||||
}
|
||||
|
||||
// To facilitate storing relevant commands, we should probably reverse-lookup
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ export type LogMessageHandler = (str: string) => void;
|
|||
|
||||
export interface VariableStoreSerializer {
|
||||
loadStore(keyboardID: string, storeName: string): VariableStore;
|
||||
saveStore(keyboardID: string, storeName: string, storeMap: VariableStore);
|
||||
saveStore(keyboardID: string, storeName: string, storeMap: VariableStore): void;
|
||||
}
|
||||
|
||||
export interface ProcessorInitOptions {
|
||||
|
|
@ -273,8 +273,8 @@ export default class KeyboardProcessor extends EventEmitter<EventMap> {
|
|||
_UpdateVKShift(e: KeyEvent): boolean {
|
||||
let keyShiftState=0;
|
||||
|
||||
const lockNames = ['CAPS', 'NUM_LOCK', 'SCROLL_LOCK'];
|
||||
const lockKeys = ['K_CAPS', 'K_NUMLOCK', 'K_SCROLL'];
|
||||
const lockNames = ['CAPS', 'NUM_LOCK', 'SCROLL_LOCK'] as const;
|
||||
const lockKeys = ['K_CAPS', 'K_NUMLOCK', 'K_SCROLL'] as const;
|
||||
|
||||
if(!this.activeKeyboard) {
|
||||
return true;
|
||||
|
|
@ -322,8 +322,8 @@ export default class KeyboardProcessor extends EventEmitter<EventMap> {
|
|||
}
|
||||
|
||||
private updateStates(): void {
|
||||
var lockNames = ['CAPS', 'NUM_LOCK', 'SCROLL_LOCK'];
|
||||
var lockKeys = ['K_CAPS', 'K_NUMLOCK', 'K_SCROLL'];
|
||||
var lockNames = ['CAPS', 'NUM_LOCK', 'SCROLL_LOCK'] as const;
|
||||
var lockKeys = ['K_CAPS', 'K_NUMLOCK', 'K_SCROLL'] as const;
|
||||
|
||||
for(let i=0; i < lockKeys.length; i++) {
|
||||
const key = lockKeys[i];
|
||||
|
|
@ -443,7 +443,7 @@ export default class KeyboardProcessor extends EventEmitter<EventMap> {
|
|||
|
||||
// Do not change layer unless needed (27/08/2015)
|
||||
if(id == activeLayer && keyEvent.device.formFactor != DeviceSpec.FormFactor.Desktop) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
var idx=id;
|
||||
|
|
|
|||
|
|
@ -109,4 +109,13 @@ export var LMLayerWorkerSourcemapComment = "${srcMapString}";
|
|||
// --END:LMLayerWorkerCode
|
||||
`;
|
||||
|
||||
fs.writeFileSync(destFile, wrapper);
|
||||
fs.writeFileSync(destFile, wrapper);
|
||||
|
||||
// Don't let there be multiples; TS may signal typing conflict if it thinks
|
||||
// these are defined multiple times.
|
||||
let wrapperDeclarations = `
|
||||
export const LMLayerWorkerCode: string;
|
||||
export const LMLayerWorkerSourcemapComment: string;
|
||||
`;
|
||||
|
||||
fs.writeFileSync('build/lib/worker-main.wrapped.d.ts', wrapperDeclarations);
|
||||
|
|
@ -5,10 +5,12 @@
|
|||
"exports": {
|
||||
"./worker-main.wrapped.js": {
|
||||
"es6-bundling": "./build/lib/worker-main.wrapped.js",
|
||||
"types": "./build/lib/worker-main.wrapped.d.ts",
|
||||
"default": "./build/lib/worker-main.wrapped.es5.js"
|
||||
},
|
||||
"./worker-main.wrapped.min.js": {
|
||||
"es6-bundling": "./build/lib/worker-main.wrapped.min.js",
|
||||
"types": "./build/lib/worker-main.wrapped.d.ts",
|
||||
"default": "./build/lib/worker-main.wrapped.es5.min.js"
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -413,7 +413,7 @@ export class ContextTracker extends CircularArray<TrackedContextState> {
|
|||
There's already an implied whitespace to the left, so we conceptually
|
||||
merge the new whitespace with that one.
|
||||
*/
|
||||
return state;
|
||||
return;
|
||||
} else if(isBackspace) {
|
||||
// Consider backspace entry for this case?
|
||||
state.replaceTailForBackspace(finalToken, primaryInput.id);
|
||||
|
|
|
|||
|
|
@ -39,9 +39,9 @@ export class SearchNode {
|
|||
// Internal lazy-cache for .inputSamplingCost, as it's a bit expensive to re-compute.
|
||||
private _inputCost?: number;
|
||||
|
||||
constructor(rootTraversal: LexiconTraversal, toKey?: (USVString) => USVString);
|
||||
constructor(rootTraversal: LexiconTraversal, toKey?: (arg0: USVString) => USVString);
|
||||
constructor(node: SearchNode);
|
||||
constructor(rootTraversal: LexiconTraversal | SearchNode, toKey?: (USVString) => USVString) {
|
||||
constructor(rootTraversal: LexiconTraversal | SearchNode, toKey?: (arg0: USVString) => USVString) {
|
||||
toKey = toKey || (x => x);
|
||||
|
||||
if(rootTraversal instanceof SearchNode) {
|
||||
|
|
@ -549,7 +549,7 @@ export class SearchSpace {
|
|||
|
||||
let inputIndex = nextTier.index;
|
||||
|
||||
let deletionEdges = [];
|
||||
let deletionEdges: SearchNode[] = [];
|
||||
if(!substitutionsOnly) {
|
||||
deletionEdges = currentNode.buildDeletionEdges(this.inputSequence[inputIndex-1]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,7 +97,10 @@ export default class LMLayerWorker {
|
|||
|
||||
private _currentModelSource: ModelSourceSpec;
|
||||
|
||||
constructor(options = {
|
||||
constructor(options: {
|
||||
importScripts: typeof importScripts,
|
||||
postMessage: typeof postMessage
|
||||
} = {
|
||||
importScripts: null,
|
||||
postMessage: null
|
||||
}) {
|
||||
|
|
@ -401,9 +404,13 @@ export default class LMLayerWorker {
|
|||
|
||||
// Ensures that the worker instance is accessible for loaded model scripts.
|
||||
// Assists unit-testing.
|
||||
// @ts-ignore
|
||||
scope['LMLayerWorker'] = worker;
|
||||
// @ts-ignore
|
||||
scope['models'] = models;
|
||||
// @ts-ignore
|
||||
scope['correction'] = correction;
|
||||
// @ts-ignore
|
||||
scope['wordBreakers'] = wordBreakers;
|
||||
|
||||
return worker;
|
||||
|
|
|
|||
|
|
@ -434,18 +434,24 @@ export default class ModelCompositor {
|
|||
});
|
||||
|
||||
let suggestions = suggestionDistribution.splice(0, ModelCompositor.MAX_SUGGESTIONS).map(function(value) {
|
||||
if(value.sample['p']) {
|
||||
let sample: Suggestion & {
|
||||
p?: number,
|
||||
"lexical-p"?: number,
|
||||
"correction-p"?: number
|
||||
} = value.sample;
|
||||
|
||||
if(sample['p']) {
|
||||
// For analysis / debugging
|
||||
value.sample['lexical-p'] = value.sample['p'];
|
||||
value.sample['correction-p'] = value.p / value.sample['p'];
|
||||
sample['lexical-p'] = sample['p'];
|
||||
sample['correction-p'] = value.p / sample['p'];
|
||||
// Use of the Trie model always exposed the lexical model's probability for a word to KMW.
|
||||
// It's useful for debugging right now, so may as well repurpose it as the posterior.
|
||||
//
|
||||
// We still condition on 'p' existing so that test cases aren't broken.
|
||||
value.sample['p'] = value.p;
|
||||
sample['p'] = value.p;
|
||||
}
|
||||
//
|
||||
return value.sample;
|
||||
return sample;
|
||||
});
|
||||
|
||||
if(keepOption) {
|
||||
|
|
|
|||
|
|
@ -104,6 +104,8 @@ export abstract class RecordedKeystroke {
|
|||
return new RecordedPhysicalKeystroke(obj as RecordedPhysicalKeystroke);
|
||||
} else if(obj.type == "osk") {
|
||||
return new RecordedSyntheticKeystroke(obj as RecordedSyntheticKeystroke);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ export default abstract class Proctor {
|
|||
abstract beforeAll(): Promise<void>;
|
||||
|
||||
// Performs per-test setup
|
||||
abstract before();
|
||||
abstract before(): void;
|
||||
|
||||
/**
|
||||
* Allows the proctor to indicate if is capable of executing a suite of tests or not.
|
||||
|
|
@ -43,7 +43,7 @@ export default abstract class Proctor {
|
|||
/**
|
||||
* Indicates whether or not this Proctor is capable of running the specified set of tests.
|
||||
*/
|
||||
abstract matchesTestSet(testSet: TestSet<any>);
|
||||
abstract matchesTestSet(testSet: TestSet<any>): boolean;
|
||||
|
||||
/**
|
||||
* Simulates the specified test sequence for use in testing.
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { default as SentryType } from '@sentry/browser';
|
|||
// a pre-bundled Sentry build artifact.
|
||||
let Sentry: {
|
||||
init: typeof SentryType.init;
|
||||
// @ts-ignore
|
||||
} = window['Sentry'];
|
||||
|
||||
/**
|
||||
|
|
@ -34,7 +35,7 @@ export class KeymanSentryManager {
|
|||
'kmwuitoggle.js': 'kmwuitoggle.js',
|
||||
'kmwuitoolbar.js': 'kmwuitoolbar.js'
|
||||
// Also add entries for the naming system used by Android and iOS - and map them to the EMBEDDED upload, not the std 'native' one.
|
||||
}
|
||||
} as Record<string, string>;
|
||||
|
||||
static DEFAULT_OPTIONS: Options = {
|
||||
hostPlatform: "native-web"
|
||||
|
|
@ -104,6 +105,7 @@ export class KeymanSentryManager {
|
|||
attachEventMetadata(event: any) {
|
||||
// Ensure that the 'extra' object exists. (May not exist for synthetic/custom Errors.)
|
||||
event.extra = event.extra || {};
|
||||
//@ts-ignore
|
||||
event.extra.keymanState = window['keyman']?.['getDebugInfo']?.();
|
||||
event.extra.keymanHostPlatform = this.keymanPlatform;
|
||||
}
|
||||
|
|
@ -215,7 +217,7 @@ export class KeymanSentryManager {
|
|||
return oldConsoleWarn.apply(console, args);
|
||||
}
|
||||
|
||||
function reduceConsoleArgs(args) {
|
||||
function reduceConsoleArgs(args: any) {
|
||||
let errorMsg = args[0];
|
||||
// Make sure errorMsg is either an error or string.
|
||||
// It's therefore best to pass in new Error('msg') instead of just 'msg' since
|
||||
|
|
@ -225,7 +227,7 @@ export class KeymanSentryManager {
|
|||
if (!(errorMsg instanceof Error)) {
|
||||
// stringify all args as a new Error (which creates a stack trace)
|
||||
errorMsg = new Error(
|
||||
args.reduce(function(accumulator, currentValue) {
|
||||
args.reduce(function(accumulator: any, currentValue: any) {
|
||||
return accumulator.toString() + ' ' + currentValue.toString();
|
||||
}, '')
|
||||
);
|
||||
|
|
@ -259,4 +261,5 @@ export class KeymanSentryManager {
|
|||
}
|
||||
|
||||
// Publish to the window.
|
||||
// @ts-ignore
|
||||
window['KeymanSentryManager'] = KeymanSentryManager;
|
||||
|
|
@ -2,22 +2,26 @@
|
|||
* Function deepCopy
|
||||
* Scope Private
|
||||
* @param {Object} p object to copy
|
||||
* @param {Array=} c0 array member being copied
|
||||
* @return {Object} clone ('deep copy') of object
|
||||
* Description Makes an actual copy (not a reference) of an object, copying simple members,
|
||||
* arrays and member objects but not functions, so use with care!
|
||||
*/
|
||||
export default function deepCopy<T>(p:T, c0?): T {
|
||||
var c = c0 || {};
|
||||
for (var i in p) {
|
||||
if(typeof p[i] === 'object' && p[i] != null) {
|
||||
c[i] = (p[i].constructor === Array ) ? [] : {};
|
||||
deepCopy(p[i],c[i]);
|
||||
}
|
||||
else {
|
||||
c[i] = p[i];
|
||||
}
|
||||
}
|
||||
export default function deepCopy<T extends ({[key: string | number | symbol]: any} | Array<any>)>(p:T): T {
|
||||
// typeof undefined == 'undefined', ![] == false, !{} == false
|
||||
if(typeof p != 'object' || !p) {
|
||||
return p;
|
||||
} else {
|
||||
const clone = Array.isArray(p) ? [] : {};
|
||||
// For arrays, skips over sparse entries. Not that we use sparse arrays, but still.
|
||||
const keys = Object.keys(p);
|
||||
|
||||
return c;
|
||||
for(let key of keys) {
|
||||
// @ts-ignore
|
||||
if(p[key] !== undefined) {
|
||||
// @ts-ignore
|
||||
clone[key] = deepCopy(p[key]);
|
||||
}
|
||||
}
|
||||
return clone as T;
|
||||
}
|
||||
}
|
||||
|
|
@ -12,7 +12,7 @@ declare global {
|
|||
interface StringConstructor {
|
||||
kmwFromCharCode(cp0: number): string,
|
||||
_kmwFromCharCode(cp0: number): string,
|
||||
kmwEnableSupplementaryPlane(bEnable: boolean)
|
||||
kmwEnableSupplementaryPlane(bEnable: boolean): void
|
||||
}
|
||||
|
||||
interface String {
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ export default class TimeoutPromise extends ManagedPromise<Boolean> {
|
|||
* A simplified, but non-cancelable, version of `TimeoutPromise`. Returns a simple,
|
||||
* Promise that resolves after the specified timeout duration.
|
||||
*/
|
||||
export const timedPromise = (time) => {
|
||||
export const timedPromise = (time: number) => {
|
||||
const promise = new TimeoutPromise(time);
|
||||
return promise.corePromise;
|
||||
}
|
||||
|
|
@ -2,6 +2,12 @@
|
|||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"lib": [ "DOM", "ES6"]
|
||||
"lib": [ "DOM", "ES6"],
|
||||
// TODO: These override ../tsconfig.base.json settings, and so should be removed if possible,
|
||||
// but existing code in web/ breaks some of these settings
|
||||
"noImplicitAny": false,
|
||||
"strictFunctionTypes": false,
|
||||
"noImplicitReturns": false,
|
||||
"strictNullChecks": false,
|
||||
}
|
||||
}
|
||||
|
|
@ -10,13 +10,6 @@
|
|||
"lib": ["es6"],
|
||||
"target": "es5",
|
||||
|
||||
// TODO: These override ../tsconfig.base.json settings, and so should be removed if possible,
|
||||
// but existing code in web/ breaks some of these settinsg
|
||||
"noImplicitReturns": false,
|
||||
"noImplicitAny": false,
|
||||
"strictFunctionTypes": false,
|
||||
"strictNullChecks": false,
|
||||
|
||||
// Other settings - declaration files, sourcemapping, and other miscellaneous bits.
|
||||
"allowJs": false,
|
||||
"declaration": true,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue