refactor(web): add abstract Keyboard base class

Also rename `JSKeyboardData` → `KeyboardData`.

Test-bot: skip
This commit is contained in:
Eberhard Beilharz 2026-04-16 22:07:58 +02:00
parent 945556201e
commit 115ab18d71
No known key found for this signature in database
GPG key ID: E9140597606020D3
24 changed files with 180 additions and 71 deletions

View file

@ -689,18 +689,14 @@ export class KeymanEngine extends KeymanEngineBase<BrowserConfiguration, Context
argFormFactor?: DeviceSpec.FormFactor,
argLayerId?: string
): HTMLElement {
let PKbd: Keyboard = null;
const PKbd = (PInternalName != null ? this.keyboardRequisitioner.cache.getKeyboard(PInternalName) : null) || this.core.activeKeyboard;
if(PInternalName != null) {
PKbd = this.keyboardRequisitioner.cache.getKeyboard(PInternalName);
}
PKbd = PKbd || this.core.activeKeyboard;
if (PKbd instanceof KMXKeyboard) {
// TODO-web-core: implement for KMX keyboards (epic/embed-osk-in-kmx)
// TODO-embed-osk-in-kmx: implement for KMX keyboards
return null;
}
const Pstub = this.keyboardRequisitioner.cache.getStub(PKbd);
const jsKbd = PKbd as JSKeyboard;
const Pstub = this.keyboardRequisitioner.cache.getStub(jsKbd);
// help.keyman.com will set this function in place to specify the desired
// dimensions for the documentation-keyboards, so we'll give it priority. One of those
@ -712,7 +708,7 @@ export class KeymanEngine extends KeymanEngineBase<BrowserConfiguration, Context
const targetHeight = (typeof getOskHeight == 'function' ? getOskHeight() : null) || this.osk.computedHeight || 200;
return VisualKeyboard.buildDocumentationKeyboard(
PKbd,
jsKbd,
Pstub,
this.config.paths,
argFormFactor,

View file

@ -10,6 +10,7 @@ import { ModifierKeyConstants } from '@keymanapp/common-types';
import {
Codes,
JSKeyboard,
Keyboard,
KeyboardHarness,
KeyboardKeymanGlobal,
KeyMapping,
@ -194,11 +195,15 @@ export class JSKeyboardInterface extends KeyboardHarness {
_AnyIndices: number[] = []; // AnyIndex - array of any/index match indices
// Must be accessible to some of the keyboard API methods.
activeKeyboard: JSKeyboard;
activeKeyboard: Keyboard;
activeDevice: DeviceSpec;
variableStoreSerializer: VariableStoreSerializer;
private get activeJSKeyboard(): JSKeyboard {
return this.activeKeyboard as JSKeyboard;
}
// A 'reference point' that debug keyboards may use to access KMW's code constants.
public get Codes(): typeof Codes {
return Codes;
@ -569,7 +574,7 @@ export class JSKeyboardInterface extends KeyboardHarness {
let retVal = false; // I3318
let keyCode = (e.Lcode == 173 ? 189 : e.Lcode); //I3555 (Firefox hyphen issue)
const bitmask = this.activeKeyboard.modifierBitmask;
const bitmask = this.activeJSKeyboard.modifierBitmask;
const modifierBitmask = bitmask & Codes.modifierBitmasks["ALL"];
const stateBitmask = bitmask & Codes.stateBitmasks["ALL"];
@ -649,7 +654,7 @@ export class JSKeyboardInterface extends KeyboardHarness {
_ExplodeStore(store: KeyboardStore): ComplexKeyboardStore {
if(typeof(store) == 'string') {
const cachedStores = this.activeKeyboard.explodedStores;
const cachedStores = this.activeJSKeyboard.explodedStores;
// Is the result cached?
if(cachedStores[store]) {
@ -1005,7 +1010,7 @@ export class JSKeyboardInterface extends KeyboardHarness {
if(!this.activeKeyboard) {
throw "No active keyboard for keystroke processing!";
}
return this.process(this.activeKeyboard.processNewContextEvent.bind(this.activeKeyboard), textStore, keystroke, true);
return this.process(this.activeJSKeyboard.processNewContextEvent.bind(this.activeKeyboard), textStore, keystroke, true);
}
/**
@ -1020,7 +1025,7 @@ export class JSKeyboardInterface extends KeyboardHarness {
if(!this.activeKeyboard) {
throw "No active keyboard for keystroke processing!";
}
return this.process(this.activeKeyboard.processPostKeystroke.bind(this.activeKeyboard), textStore, keystroke, true);
return this.process(this.activeJSKeyboard.processPostKeystroke.bind(this.activeKeyboard), textStore, keystroke, true);
}
/**
@ -1035,7 +1040,7 @@ export class JSKeyboardInterface extends KeyboardHarness {
if(!this.activeKeyboard) {
throw "No active keyboard for keystroke processing!";
}
return this.process(this.activeKeyboard.process.bind(this.activeKeyboard), textStore, keystroke, false);
return this.process(this.activeJSKeyboard.process.bind(this.activeKeyboard), textStore, keystroke, false);
}
private process(callee: (textStore: TextStore, keystroke: KeyEvent) => boolean, textStore: TextStore, keystroke: KeyEvent, readonly: boolean): ProcessorAction {
@ -1057,7 +1062,7 @@ export class JSKeyboardInterface extends KeyboardHarness {
const preInput = SyntheticTextStore.from(textStore, true);
// Capture the initial state of any variable stores
const cachedVariableStores = this.activeKeyboard.variableStores;
const cachedVariableStores = this.activeJSKeyboard.variableStores;
// Establishes the results object, allowing corresponding commands to set values here as appropriate.
this.ruleBehavior = new ProcessorAction();
@ -1077,8 +1082,8 @@ export class JSKeyboardInterface extends KeyboardHarness {
// We always backup the changes to variable stores to the ProcessorAction, to
// be applied during finalization, then restore them to the cached initial
// values to avoid side-effects with predictive text mocks.
this.ruleBehavior.variableStores = this.activeKeyboard.variableStores;
this.activeKeyboard.variableStores = cachedVariableStores;
this.ruleBehavior.variableStores = this.activeJSKeyboard.variableStores;
this.activeJSKeyboard.variableStores = cachedVariableStores;
// `matched` refers to whether or not the FINAL rule (from any group) matched, rather than
// whether or not ANY rule matched. If the final rule doesn't match, we trigger the key's
@ -1104,7 +1109,7 @@ export class JSKeyboardInterface extends KeyboardHarness {
* keyboard
*/
applyVariableStores(stores: VariableStoreDictionary): void {
this.activeKeyboard.variableStores = stores;
this.activeJSKeyboard.variableStores = stores;
}
/**

View file

@ -68,7 +68,7 @@ export class JSKeyboardProcessor extends EventEmitter<EventMap> implements Keybo
}
public get activeKeyboard(): JSKeyboard {
return this.keyboardInterface.activeKeyboard;
return this.keyboardInterface.activeKeyboard as JSKeyboard;
}
public set activeKeyboard(keyboard: JSKeyboard) {

View file

@ -1,4 +1,4 @@
import { type Keyboard, JSKeyboard, KeyboardLoaderBase as KeyboardLoader, KMXKeyboard } from "keyman/engine/keyboard";
import { Keyboard, JSKeyboard, KeyboardLoaderBase as KeyboardLoader, KMXKeyboard } from "keyman/engine/keyboard";
import { EventEmitter } from "eventemitter3";
import { KeyboardStub } from "./keyboardStub.js";
@ -152,7 +152,7 @@ export class StubAndKeyboardCache extends EventEmitter<EventMap> {
keyboardID = toPrefixedKeyboardId(keyboardID);
const cachedEntry = this.keyboardTable[keyboardID];
if(cachedEntry instanceof JSKeyboard) {
if(cachedEntry instanceof Keyboard) {
return Promise.resolve(cachedEntry);
} else if(cachedEntry instanceof Promise) {
return cachedEntry;
@ -172,6 +172,7 @@ export class StubAndKeyboardCache extends EventEmitter<EventMap> {
promise.then((kbd) => {
// Overrides the built-in ID in case of keyboard namespacing.
// TODO-web-core: what do we have to do for KMX keyboards here?
if (kbd instanceof JSKeyboard) {
kbd.scriptObject["KI"] = keyboardID;
}
@ -197,12 +198,12 @@ export class StubAndKeyboardCache extends EventEmitter<EventMap> {
}
getStub(keyboardID: string, languageID: string): KeyboardStub;
getStub(keyboard: JSKeyboard, languageID?: string): KeyboardStub;
getStub(arg0: string | JSKeyboard, arg1?: string): KeyboardStub {
getStub(keyboard: Keyboard, languageID?: string): KeyboardStub;
getStub(arg0: string | Keyboard, arg1?: string): KeyboardStub {
let keyboardID: string;
const languageID = arg1 || '---';
if(arg0 instanceof JSKeyboard) {
if(arg0 instanceof Keyboard) {
keyboardID = arg0.id;
} else {
keyboardID = arg0;
@ -229,12 +230,12 @@ export class StubAndKeyboardCache extends EventEmitter<EventMap> {
/**
* Removes all metadata (stubs) associated with a specific keyboard from the cache, optionally
* removing the cached keyboard as well.
* @param keyboard Either the keyboard ID or `JSKeyboard` instance
* @param purge If `true`, will also purge the `JSKeyboard` instance itself from the cache.
* @param keyboard Either the keyboard ID or `Keyboard` instance
* @param purge If `true`, will also purge the `Keyboard` instance itself from the cache.
* If `false`, only forgets the metadata (stubs).
*/
forgetKeyboard(keyboard: string | JSKeyboard, purge: boolean = false) {
const id: string = (keyboard instanceof JSKeyboard) ? keyboard.id : toPrefixedKeyboardId(keyboard);
forgetKeyboard(keyboard: string | Keyboard, purge: boolean = false) {
const id: string = (keyboard instanceof Keyboard) ? keyboard.id : toPrefixedKeyboardId(keyboard);
if(this.stubSetTable[id]) {
delete this.stubSetTable[id];

View file

@ -1,10 +1,11 @@
export { ActiveKeyBase, ActiveKey, ActiveSubKey, ActiveRow, ActiveLayer, ActiveLayout } from "./keyboards/activeLayout.js";
export { ButtonClass, ButtonClasses, LayoutLayer, LayoutFormFactor, LayoutRow, LayoutKey, LayoutSubKey, Layouts } from "./keyboards/defaultLayouts.js";
export { JSKeyboard, LayoutState } from "./keyboards/jsKeyboard.js";
export { Keyboard } from './keyboards/keyboard.js';
export { KeyboardMinimalInterface } from './keyboards/keyboardMinimalInterface.js';
export { KMXKeyboard } from './keyboards/kmxKeyboard.js';
export { KeyboardHarness, KeyboardKeymanGlobal, MinimalCodesInterface, MinimalKeymanGlobal } from "./keyboards/keyboardHarness.js";
export { NotifyEventCode, Keyboard, KeyboardLoaderBase } from "./keyboards/keyboardLoaderBase.js";
export { NotifyEventCode, KeyboardLoaderBase } from "./keyboards/keyboardLoaderBase.js";
export { KeyboardLoadErrorBuilder, KeyboardMissingError, KeyboardScriptError, KeyboardDownloadError, InvalidKeyboardError } from './keyboards/keyboardLoadError.js'
export { BeepHandler, EventMap, KeyboardProcessor } from "./keyboards/keyboardProcessor.js";
export {

View file

@ -11,7 +11,7 @@ import { type DeviceSpec } from "keyman/common/web-utils";
import { Codes } from './codes.js';
import { DefaultOutputRules } from "./defaultOutputRules.js";
import { ActiveKeyBase } from './keyboards/activeLayout.js';
import { type Keyboard } from "./keyboards/keyboardLoaderBase.js";
import { type Keyboard } from "./keyboards/keyboard.js";
// Represents a probability distribution over a keyboard's keys.
// Defined here to avoid compilation issues.

View file

@ -15,6 +15,7 @@ type TouchLayoutSpec = TouchLayout.TouchLayoutPlatform & { isDefault?: boolean};
import { Version, DeviceSpec } from "keyman/common/web-utils";
import { StateKeyMap } from "./stateKeyMap.js";
import { NotifyEventCode } from './keyboardLoaderBase.js';
import { Keyboard } from './keyboard.js';
/**
* Stores preprocessed properties of a keyboard for quick retrieval later.
@ -49,7 +50,7 @@ type KmwKeyboardObject = KeyboardObject & {
* and keyboard-centered functionality in an object-oriented way without modifying the
* wrapped keyboard itself.
*/
export class JSKeyboard {
export class JSKeyboard extends Keyboard {
public static DEFAULT_SCRIPT_OBJECT: KmwKeyboardObject = {
'gs': function(textStore: TextStore, 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.
@ -68,6 +69,7 @@ export class JSKeyboard {
private layoutStates: {[layout: string]: LayoutState};
constructor(keyboardScript: any) {
super();
if(keyboardScript) {
this.scriptObject = keyboardScript;
} else {

View file

@ -0,0 +1,89 @@
/*
* Keyman is copyright (C) SIL Global. MIT License.
*/
import { DeviceSpec } from 'keyman/common/web-utils';
import { ActiveKey, ActiveLayout, ActiveSubKey } from './activeLayout.js';
import { StateKeyMap } from './stateKeyMap.js';
import { KeyEvent } from '../keyEvent.js';
import { TextStore } from '../textStore.js';
import { NotifyEventCode } from './keyboardLoaderBase.js';
/**
* Abstract base class for Keyman keyboards, providing common interface
* for JSKeyboard and KMXKeyboard.
*/
export abstract class Keyboard {
/**
* Unique identifier for the keyboard.
*/
abstract get id(): string;
/**
* Gets the name of the keyboard.
*/
abstract get name(): string;
/**
* Version string of the keyboard.
*/
abstract get version(): string;
/**
* Indicates whether the keyboard uses mnemonic layout.
*/
abstract get isMnemonic(): boolean;
/**
* Indicates whether the keyboard is chiral (distinguishes left/right modifiers).
*/
abstract get isChiral(): boolean;
/**
* Indicates whether the keyboard emulates AltGr.
*/
abstract get emulatesAltGr(): boolean;
/**
* Indicates whether the keyboard is right-to-left.
*/
abstract get isRTL(): boolean;
/**
* true if this keyboard uses a (legacy) pick list (Chinese, Japanese, Korean, etc.)
*/
abstract get isCJK(): boolean;
/**
* CSS styling for the on-screen keyboard.
*/
abstract get oskStyling(): string;
/**
* Returns an ActiveLayout object representing the keyboard's layout for this form factor.
* May return null if a custom desktop "help" OSK is defined.
* @param formFactor The desired form factor for the layout.
*/
abstract layout(formFactor: DeviceSpec.FormFactor): ActiveLayout;
/**
* Indicates whether the keyboard's desktop layout should be used for the specified device.
* @param device The device specification to check.
*/
abstract usesDesktopLayoutOnDevice(device: DeviceSpec): boolean;
/**
* Notifies keyboard of keystroke or other event.
* @param eventCode Event code (16-18: Shift, Control or Alt), or 0 for focus.
* @param textStore Text store.
* @param data 1 for KeyDown or FocusReceived, 0 for KeyUp or FocusLost.
*/
abstract notify(eventCode: NotifyEventCode, textStore: TextStore, data: number): void;
/**
* Constructs a KeyEvent from an ActiveKey or ActiveSubKey.
* @param key The key to construct the event for.
* @param device The device specification.
* @param stateKeys The current state of modifier keys.
*/
abstract constructKeyEvent(key: ActiveKey | ActiveSubKey, device: DeviceSpec, stateKeys: StateKeyMap): KeyEvent;
}

View file

@ -1,6 +1,7 @@
import { JSKeyboard } from "./jsKeyboard.js";
import { Codes } from "../codes.js";
import { DeviceSpec } from 'keyman/common/web-utils';
import { Keyboard } from './keyboard.js';
/**
* Defines members of the top-level `keyman` global object necessary to guarantee
@ -64,7 +65,7 @@ export class KeyboardHarness {
/**
* This field serves as the receptacle for a successfully-loaded Keyboard.
*/
public loadedKeyboard: JSKeyboard = null;
public loadedKeyboard: Keyboard = null;
/**
* Keyman keyboards register themselves into the Keyman Engine for Web by directly
@ -85,6 +86,7 @@ export class KeyboardHarness {
throw new Error("Unexpected state: the most-recently loaded keyboard field was not properly reset.");
}
this.loadedKeyboard = new JSKeyboard(scriptObject);
// TODO-web-core: do we have to do something similar for KMX keyboards?
}
// Is evaluated on script-load for some keyboards using variable stores.

View file

@ -1,10 +1,10 @@
import { KM_Core, KM_CORE_STATUS } from 'keyman/engine/core-adapter';
import { JSKeyboard } from "./jsKeyboard.js";
import { KMXKeyboard } from './kmxKeyboard.js';
import { KeyboardHarness } from "./keyboardHarness.js";
import { KeyboardProperties } from "./keyboardProperties.js";
import { KeyboardLoadErrorBuilder, StubBasedErrorBuilder, UriBasedErrorBuilder } from './keyboardLoadError.js';
import { Codes } from '../codes.js';
import { Keyboard } from './keyboard.js';
export enum NotifyEventCode {
FocusEvent = 0,
@ -14,7 +14,6 @@ export enum NotifyEventCode {
};
export type KeyboardStub = KeyboardProperties & { filename: string };
export type Keyboard = JSKeyboard | KMXKeyboard;
export abstract class KeyboardLoaderBase {
private _harness: KeyboardHarness;
@ -63,7 +62,7 @@ export abstract class KeyboardLoaderBase {
const name = this.extractIdFromUrl(uri);
const result = KM_Core.instance.keyboard_load_from_blob(name, byteArray);
if (result.status == KM_CORE_STATUS.OK) {
return new KMXKeyboard(result.object);
return new KMXKeyboard(name, result.object);
}
throw errorBuilder.invalidKeyboard(new Error(`Loading KMX keyboard from ${uri} failed with status ${result.status}`));
}
@ -86,5 +85,5 @@ export abstract class KeyboardLoaderBase {
protected abstract loadKeyboardBlob(uri: string, errorBuilder: KeyboardLoadErrorBuilder): Promise<Uint8Array>;
protected abstract loadKeyboardFromScript(scriptSrc: string, errorBuilder: KeyboardLoadErrorBuilder): Promise<JSKeyboard>;
protected abstract loadKeyboardFromScript(scriptSrc: string, errorBuilder: KeyboardLoadErrorBuilder): Promise<Keyboard>;
}

View file

@ -1,5 +1,5 @@
import { VariableStoreSerializer } from '../variableStore.js';
import { Keyboard } from './keyboardLoaderBase.js';
import { Keyboard } from './keyboard.js';
export interface KeyboardMinimalInterface {
activeKeyboard: Keyboard;

View file

@ -5,7 +5,7 @@ import { EventEmitter } from 'eventemitter3';
import { DeviceSpec } from 'keyman/common/web-utils';
import { KeyEvent } from '../keyEvent.js';
import { type MutableSystemStore } from "../systemStore.js";
import { Keyboard } from './keyboardLoaderBase.js';
import { Keyboard } from './keyboard.js';
import { KeyboardMinimalInterface } from './keyboardMinimalInterface.js';
import { ProcessorAction } from './processorAction.js';
import { StateKeyMap } from './stateKeyMap.js';

View file

@ -8,14 +8,16 @@ import { StateKeyMap } from './stateKeyMap.js';
import { KeyEvent } from '../keyEvent.js';
import { TextStore } from '../textStore.js';
import { NotifyEventCode } from './keyboardLoaderBase.js';
import { Keyboard } from './keyboard.js';
/**
* Acts as a wrapper class for KMX(+) Keyman keyboards
*/
export class KMXKeyboard {
private _state: km_core_state;
export class KMXKeyboard extends Keyboard {
private _state: km_core_state | null = null;
public constructor(private _keyboard: km_core_keyboard) {
public constructor(private _name: string, private _keyboard: km_core_keyboard) {
super();
const environment_opts =
[
{
@ -77,6 +79,10 @@ export class KMXKeyboard {
return id;
}
public get name(): string {
return this._name;
}
public get keyboard(): km_core_keyboard {
return this._keyboard;
}
@ -124,6 +130,15 @@ export class KMXKeyboard {
return false;
}
/**
* Returns always false because (legacy) pick lists (Chinese, Japanese, Korean, etc.)
* are not supported when using KMX keyboards.
*/
public get isCJK(): boolean {
// always return false
return false;
}
/**
* Returns an ActiveLayout object representing the keyboard's layout for this
* form factor. May return null if a custom desktop "help" OSK is defined,

View file

@ -2,7 +2,7 @@
///<reference lib="dom" />
import { JSKeyboard } from '../jsKeyboard.js';
import { Keyboard } from '../keyboard.js';
import { KeyboardHarness, MinimalKeymanGlobal } from '../keyboardHarness.js';
import { KeyboardLoaderBase } from '../keyboardLoaderBase.js';
import { KeyboardLoadErrorBuilder } from '../keyboardLoadError.js';
@ -54,7 +54,7 @@ export class DOMKeyboardLoader extends KeyboardLoaderBase {
return new Uint8Array(buffer);
}
protected async loadKeyboardFromScript(script: string, errorBuilder: KeyboardLoadErrorBuilder): Promise<JSKeyboard> {
protected async loadKeyboardFromScript(script: string, errorBuilder: KeyboardLoadErrorBuilder): Promise<Keyboard> {
try {
this.evalScriptInContext(script, this.harness._jsGlobal);
} catch (e) {

View file

@ -9,14 +9,14 @@ import { CoreKeyboardProcessor } from 'keyman/engine/core-processor';
import {
Codes,
JSKeyboard, // TODO-web-core: huh? why is this here
JSKeyboard, // required to be able to distinguish between JS and Core kbd processor
Keyboard,
KeyboardMinimalInterface,
SyntheticTextStore,
TextStore,
ProcessorAction,
SystemStoreIDs,
type Alternate,
type Keyboard,
type KeyEvent,
KeyboardProcessor,
VariableStoreSerializer

View file

@ -3,7 +3,7 @@ import { ProcessorInitOptions } from 'keyman/engine/js-processor';
import { DOMKeyboardLoader } from "keyman/engine/keyboard";
import { WorkerFactory } from "@keymanapp/lexical-model-layer/web"
import { InputProcessor } from './headless/inputProcessor.js';
import { OSKView, JSKeyboardData } from "keyman/engine/osk";
import { OSKView, KeyboardData } from "keyman/engine/osk";
import { KeyboardRequisitioner, ModelCache, toUnprefixedKeyboardId, DOMCloudRequester } from "keyman/engine/keyboard-storage";
import { ModelSpec, PredictionContext } from "keyman/engine/interfaces";
@ -386,7 +386,7 @@ export class KeymanEngineBase<
this.core.keyboardProcessor.contextDevice = value?.targetDevice ?? this.config.softDevice;
if(value) {
// Don't build an OSK if no keyboard is available yet; avoid the extra flash.
if (this.contextManager.activeKeyboard && this.contextManager.activeKeyboard instanceof JSKeyboardData) { // TODO-embed-osk-in-kmx: add support for OSK for KMX keyboards
if (this.contextManager.activeKeyboard && this.contextManager.activeKeyboard instanceof KeyboardData) { // TODO-embed-osk-in-kmx: add support for OSK for KMX keyboards
value.activeKeyboard = this.contextManager.activeKeyboard;
}
value.on('keyevent', this.keyEventListener);

View file

@ -1,6 +1,6 @@
import { EventEmitter } from 'eventemitter3';
import { JSKeyboard } from 'keyman/engine/keyboard';
import { Keyboard } from 'keyman/engine/keyboard';
import { OSKViewComponent } from './oskViewComponent.interface.js';
import { ParsedLengthStyle } from '../lengthStyle.js';
@ -102,7 +102,7 @@ export class TitleBar extends EventEmitter<EventMap, TitleBar> implements OSKVie
this._caption.innerHTML = str;
}
public setTitleFromKeyboard(keyboard: JSKeyboard) {
public setTitleFromKeyboard(keyboard: Keyboard) {
const title = "<span style='font-weight:bold'>" + keyboard?.name + '</span>'; // I1972 // I2186
this._caption.innerHTML = title;
}

View file

@ -2,7 +2,7 @@
export { DeviceSpec } from 'keyman/common/web-utils';
export { Codes, JSKeyboard, KeyboardProperties, SpacebarText } from 'keyman/engine/keyboard';
export { OSKView, JSKeyboardData } from './views/oskView.js';
export { OSKView, KeyboardData } from './views/oskView.js';
export { FloatingOSKView, FloatingOSKViewConfiguration } from './views/floatingOskView.js';
export { AnchoredOSKView } from './views/anchoredOskView.js';
export { InlinedOSKView } from './views/inlinedOskView.js';

View file

@ -14,6 +14,7 @@ import { DeviceSpec, ManagedPromise } from 'keyman/common/web-utils';
import {
Codes,
JSKeyboard,
Keyboard,
KeyboardProperties,
type MinimalCodesInterface,
type MutableSystemStore, type SystemStoreMutationHandler,
@ -58,8 +59,8 @@ export interface LegacyOSKEventMap {
}): void;
}
export class JSKeyboardData {
keyboard: JSKeyboard;
export class KeyboardData {
keyboard: Keyboard;
metadata: KeyboardProperties;
};
@ -172,7 +173,7 @@ export abstract class OSKView
private _boxBaseTouchStart: (e: TouchEvent) => boolean;
private _boxBaseTouchEventCancel: (e: TouchEvent) => boolean;
private keyboardData: JSKeyboardData;
private keyboardData: KeyboardData;
/**
* Provides the current parameterization for timings and distances used by
@ -553,11 +554,11 @@ export abstract class OSKView
}
}
public get activeKeyboard(): JSKeyboardData {
public get activeKeyboard(): KeyboardData {
return this.keyboardData;
}
public set activeKeyboard(keyboardData: JSKeyboardData) {
public set activeKeyboard(keyboardData: KeyboardData) {
this.keyboardData = keyboardData;
this.loadActiveKeyboard();
@ -765,7 +766,7 @@ export abstract class OSKView
// Create new ones for the new, incoming kbd.
this.kbdStyleSheetManager = new StylesheetManager(this._Box, this.config.doCacheBusting || false);
const kbdView = this.keyboardView = this._GenerateKeyboardView(this.keyboardData?.keyboard, this.keyboardData?.metadata);
const kbdView = this.keyboardView = this._GenerateKeyboardView(this.keyboardData?.keyboard as JSKeyboard, this.keyboardData?.metadata);
// Perform the replacement.
this._Box.replaceChild(kbdView.element, oldKbd.element);

View file

@ -1356,7 +1356,7 @@ export class VisualKeyboard extends EventEmitter<EventMap> implements KeyboardVi
* @return {Object} DIV object with filled keyboard layer content
*/
static buildDocumentationKeyboard(
PKbd: JSKeyboard,
PKbd: JSKeyboard, // TODO-web-core: do we have to do anything for KMX keyboards?
kbdProperties: KeyboardProperties,
pathConfig: OSKResourcePathConfiguration,
argFormFactor: DeviceSpec.FormFactor,

View file

@ -1,9 +1,7 @@
import {
DOMKeyboardLoader
} from 'keyman/engine/keyboard';
import {
DOMKeyboardLoader,
JSKeyboard,
Keyboard,
KeyboardProperties,
MinimalKeymanGlobal
} from 'keyman/engine/keyboard';
@ -18,13 +16,13 @@ export function loadKeyboardFromPath(path: string) {
}
export type KeyboardMap = {
[key: string]: KeyboardInfoPair & { keyboard: JSKeyboard }
[key: string]: KeyboardInfoPair & { keyboard: Keyboard }
};
export function loadKeyboardsFromStubs(apiStubs: any, baseDir: string) {
baseDir = baseDir || './';
const keyboards: KeyboardMap = {};
let priorPromise: Promise<void | JSKeyboard> = Promise.resolve();
let priorPromise: Promise<void | Keyboard> = Promise.resolve();
for(const stub of apiStubs) {
// We are keeping this strictly sequential because we don't have sandboxed
// loading yet; lack of sandboxing means that all loading keyboards compete

View file

@ -520,7 +520,7 @@ describe('CoreKeyboardProcessor', function () {
keyEvent.source = { type: eventType };
const coreKeyboard = loadKeyboard('/common/test/resources/keyboards/test_8568_deadkeys.kmx');
const kmxKeyboard = new KMXKeyboard(coreKeyboard);
const kmxKeyboard = new KMXKeyboard('test_8568_deadkeys', coreKeyboard);
sandbox.replaceGetter(coreProcessor, 'activeKeyboard', () => { return kmxKeyboard; });
// We return a non-ok value just so that we can return early from
// processKeyStroke()
@ -546,7 +546,7 @@ describe('CoreKeyboardProcessor', function () {
context = KM_Core.instance.state_context(state);
sandbox = sinon.createSandbox();
const coreKeyboard = loadKeyboard('/common/test/resources/keyboards/test_8568_deadkeys.kmx');
coreProcessor.activeKeyboard = new KMXKeyboard(coreKeyboard);
coreProcessor.activeKeyboard = new KMXKeyboard('test_8568_deadkeys', coreKeyboard);
});
afterEach(() => {

View file

@ -4,7 +4,7 @@ import { createRequire } from 'module';
const require = createRequire(import.meta.url);
import { DeviceSpec, KMWString } from 'keyman/common/web-utils';
import { Codes, DefaultOutputRules, JSKeyboard, KeyEvent, MinimalKeymanGlobal, SyntheticTextStore } from 'keyman/engine/keyboard';
import { Codes, DefaultOutputRules, KeyEvent, MinimalKeymanGlobal, SyntheticTextStore } from 'keyman/engine/keyboard';
import { JSKeyboardInterface, JSKeyboardProcessor } from 'keyman/engine/js-processor';
import { NodeKeyboardLoader } from 'keyman/test/resources';
import { ModifierKeyConstants } from '@keymanapp/common-types';
@ -103,7 +103,7 @@ describe('Engine - specialized backspace handling', function() {
// This part provides extra assurance that the keyboard properly loaded.
assert.equal(keyboard.id, "Keyboard_sil_ipa");
harness.activeKeyboard = keyboard as JSKeyboard;
harness.activeKeyboard = keyboard;
ipaWithHarness = harness;
// --------------
@ -117,7 +117,7 @@ describe('Engine - specialized backspace handling', function() {
// This part provides extra assurance that the keyboard properly loaded.
assert.equal(keyboard.id, "Keyboard_khmer_angkor");
harness.activeKeyboard = keyboard as JSKeyboard;
harness.activeKeyboard = keyboard;
angkorWithHarness = harness;
// --------------

View file

@ -3,7 +3,7 @@ import { readFile } from 'node:fs/promises';
import { globalObject } from 'keyman/common/web-utils';
import { JSKeyboard, KeyboardHarness, MinimalKeymanGlobal, KeyboardLoaderBase, KeyboardLoadErrorBuilder } from 'keyman/engine/keyboard';
import { Keyboard, KeyboardHarness, MinimalKeymanGlobal, KeyboardLoaderBase, KeyboardLoadErrorBuilder } from 'keyman/engine/keyboard';
export class NodeKeyboardLoader extends KeyboardLoaderBase {
constructor()
@ -38,7 +38,7 @@ export class NodeKeyboardLoader extends KeyboardLoaderBase {
return Uint8Array.from(buffer);
}
protected async loadKeyboardFromScript(scriptSrc: string, errorBuilder: KeyboardLoadErrorBuilder): Promise<JSKeyboard> {
protected async loadKeyboardFromScript(scriptSrc: string, errorBuilder: KeyboardLoadErrorBuilder): Promise<Keyboard> {
let script;
try {
script = new vm.Script(scriptSrc);