From 2b2e8fc85bc28ee3fa18661583f97cf87b32d731 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Thu, 15 May 2025 15:41:08 +0200 Subject: [PATCH] feat(web): dispose KMXKeyboards on shutdown --- .../keyboard-storage/src/keyboardRequisitioner.ts | 4 ++++ .../keyboard-storage/src/stubAndKeyboardCache.ts | 12 +++++++++++- web/src/engine/keyboard/src/keyboards/kmxKeyboard.ts | 7 +++++++ web/src/engine/keyboard/tsconfig.json | 3 +++ web/src/engine/main/src/hardKeyboard.ts | 2 +- web/src/engine/main/src/index.ts | 2 +- web/src/engine/main/src/keymanEngineBase.ts | 3 ++- 7 files changed, 29 insertions(+), 4 deletions(-) diff --git a/web/src/engine/keyboard-storage/src/keyboardRequisitioner.ts b/web/src/engine/keyboard-storage/src/keyboardRequisitioner.ts index 5ca184b217..5517857cbc 100644 --- a/web/src/engine/keyboard-storage/src/keyboardRequisitioner.ts +++ b/web/src/engine/keyboard-storage/src/keyboardRequisitioner.ts @@ -115,6 +115,10 @@ export default class KeyboardRequisitioner { }); } + shutdown(): void{ + this.cache.shutdown(); + } + addKeyboardArray(x: (string|RawKeyboardMetadata)[]): Promise<(KeyboardStub | ErrorStub)[]> { let completeStubs: KeyboardStub[] = []; let incompleteStubs: KeyboardStub[] = []; diff --git a/web/src/engine/keyboard-storage/src/stubAndKeyboardCache.ts b/web/src/engine/keyboard-storage/src/stubAndKeyboardCache.ts index d9db65dc0a..8547431552 100644 --- a/web/src/engine/keyboard-storage/src/stubAndKeyboardCache.ts +++ b/web/src/engine/keyboard-storage/src/stubAndKeyboardCache.ts @@ -1,4 +1,4 @@ -import { type Keyboard, JSKeyboard, KeyboardLoaderBase as KeyboardLoader } from "keyman/engine/keyboard"; +import { type Keyboard, JSKeyboard, KeyboardLoaderBase as KeyboardLoader, KMXKeyboard } from "keyman/engine/keyboard"; import { EventEmitter } from "eventemitter3"; import KeyboardStub from "./keyboardStub.js"; @@ -52,6 +52,16 @@ export default class StubAndKeyboardCache extends EventEmitter { this.keyboardLoader = keyboardLoader; } + shutdown(): void { + for (const kbdId in this.keyboardTable) { + const kbd = this.keyboardTable[kbdId]; + if (kbd instanceof KMXKeyboard) { + (kbd as KMXKeyboard).shutdown(); + } + // TODO-web-core: do we have to do something if instanceof Promise? + } + } + getKeyboardForStub(stub: KeyboardStub): Keyboard { return stub ? this.getKeyboard(stub.KI) : null; } diff --git a/web/src/engine/keyboard/src/keyboards/kmxKeyboard.ts b/web/src/engine/keyboard/src/keyboards/kmxKeyboard.ts index 88e3c1ddbc..80ca7be638 100644 --- a/web/src/engine/keyboard/src/keyboards/kmxKeyboard.ts +++ b/web/src/engine/keyboard/src/keyboards/kmxKeyboard.ts @@ -8,6 +8,13 @@ export class KMXKeyboard { constructor(private _keyboard: km_core_keyboard) { } + shutdown() { + if (this._keyboard) { + KM_Core.instance.keyboard_dispose(this._keyboard); + this._keyboard = null; + } + } + get isMnemonic(): boolean { return false; } diff --git a/web/src/engine/keyboard/tsconfig.json b/web/src/engine/keyboard/tsconfig.json index 84d96c8591..3e074f91c7 100644 --- a/web/src/engine/keyboard/tsconfig.json +++ b/web/src/engine/keyboard/tsconfig.json @@ -7,6 +7,9 @@ "tsBuildInfoFile": "../../../build/engine/keyboard/obj/tsconfig.tsbuildinfo", "rootDir": "./src/" }, + "references": [ + { "path": "../core-processor"}, + ], "include": [ "./src/**/*.ts"], "exclude": ["./src/keyboards/loaders/**/*.ts"] } diff --git a/web/src/engine/main/src/hardKeyboard.ts b/web/src/engine/main/src/hardKeyboard.ts index 09806caa21..6af4f27439 100644 --- a/web/src/engine/main/src/hardKeyboard.ts +++ b/web/src/engine/main/src/hardKeyboard.ts @@ -11,7 +11,7 @@ interface EventMap { 'keyevent': (event: KeyEvent, callback?: (result: RuleBehavior, error?: Error) => void) => void } -export default class HardKeyboard extends EventEmitter implements KeyEventSourceInterface { } +export class HardKeyboard extends EventEmitter implements KeyEventSourceInterface { } export function processForMnemonicsAndLegacy(s: KeyEvent, activeKeyboard: Keyboard, baseLayout: string): KeyEvent { if (!activeKeyboard) { diff --git a/web/src/engine/main/src/index.ts b/web/src/engine/main/src/index.ts index 23ba92caab..876ba65c3a 100644 --- a/web/src/engine/main/src/index.ts +++ b/web/src/engine/main/src/index.ts @@ -1,6 +1,6 @@ export { EngineConfiguration, InitOptionDefaults, InitOptionSpec } from './engineConfiguration.js'; export { ContextManagerBase, ContextManagerConfiguration } from './contextManagerBase.js'; -export { default as HardKeyboard, processForMnemonicsAndLegacy } from './hardKeyboard.js'; +export { HardKeyboard, processForMnemonicsAndLegacy } from './hardKeyboard.js'; export { KeyboardInterfaceBase } from './keyboardInterfaceBase.js'; export { KeymanEngineBase } from './keymanEngineBase.js'; export { LegacyAPIEvents } from './legacyAPIEvents.js'; diff --git a/web/src/engine/main/src/keymanEngineBase.ts b/web/src/engine/main/src/keymanEngineBase.ts index 99d9663ba6..f5fbef0260 100644 --- a/web/src/engine/main/src/keymanEngineBase.ts +++ b/web/src/engine/main/src/keymanEngineBase.ts @@ -11,7 +11,7 @@ import { ModelSpec, PredictionContext } from "keyman/engine/interfaces"; import { EngineConfiguration, InitOptionSpec } from "./engineConfiguration.js"; import { KeyboardInterfaceBase } from "./keyboardInterfaceBase.js"; import { ContextManagerBase } from "./contextManagerBase.js"; -import HardKeyboardBase from "./hardKeyboard.js"; +import { HardKeyboard as HardKeyboardBase } from "./hardKeyboard.js"; import { LegacyAPIEvents } from "./legacyAPIEvents.js"; import { EventNames, EventListener, LegacyEventEmitter } from "keyman/engine/events"; import DOMCloudRequester from "keyman/engine/keyboard-storage/dom-requester"; @@ -463,6 +463,7 @@ export class KeymanEngineBase< shutdown() { this.legacyAPIEvents.shutdown(); this.osk?.shutdown(); + this.keyboardRequisitioner?.shutdown(); } // API methods