Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

epic: web-core 🎼 #12291

Draft
wants to merge 122 commits into
base: master
Choose a base branch
from
Draft

epic: web-core 🎼 #12291

wants to merge 122 commits into from

Conversation

mcdurdin
Copy link
Member

@mcdurdin mcdurdin commented Aug 27, 2024

ermshiperete and others added 11 commits August 20, 2024 22:45
`emcc.py` is not marked as executable in emcripten's git repo so the
build failed when trying to locate emscripten. However, it turns out
that `emcc` is marked as executable, so we use that instead.

On Windows however, we still need to use `emcc.py` because otherwise
Meson won't detect it as valid compiler.
- add temporary function to Core for this POC
- add new CoreProcessor to access Keyman Core WASM
- add unit tests for new core processor
- add code to KeymanEngine and InputProcessor to load the new CoreProcessor
- add web server to manual tests and new action `start` to build script

This change requires the manual tests to be loaded from a web server
instead of loaded as file, because otherwise the wasm code won't be
loaded.

Currently we always load CoreProcessor. This should be improved in a future
change to only load when it is actually needed.

Part-of: #11293
feat(web): POC of Core WASM integration into Keyman Web
@mcdurdin mcdurdin added this to the A18S9 milestone Aug 27, 2024
@mcdurdin mcdurdin added web/ core/ Keyman Core epic A long lived branch, home for a new feature, usually will have child PRs based on it labels Aug 27, 2024
@mcdurdin mcdurdin changed the title epic: web-core epic: web-core 🎼 Aug 27, 2024
ermshiperete and others added 2 commits August 30, 2024 14:44
- loading a keyboard from a BLOB
- getting the on-screen keyboard layout from Core. This is an internal-
  only API because of it's use of C++.

Part-of: #11293
Part-of: #8093
@srl295 srl295 self-requested a review August 30, 2024 17:28
@darcywong00 darcywong00 modified the milestones: A18S9, A18S10 Aug 31, 2024
…core

chore: merge master into web-core 🎼
- split keyboard loading into loading into blob and then loading the script
- look at first four bytes to see if it's a .js or a .kmx keyboard
- for domKeyboardLoader, use fetch to get the blob, then use indirect
  eval to load the script, instead of injecting a script element.

This does not yet implement the loading of .kmx keyboards.
Copy link
Member

@srl295 srl295 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice!

Addresses code review comments.
@darcywong00 darcywong00 added this to the B18S2 milestone Feb 15, 2025
@darcywong00 darcywong00 modified the milestones: B18S2, B18S3 Feb 28, 2025
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's cherry-pick the async changes in ui back to master

Comment on lines -194 to +198
this.keyboardRequisitioner.cloudQueryEngine.once('unboundregister', () => {
this.keyboardRequisitioner.cloudQueryEngine.once('unboundregister', async () => {
if(!this.contextManager.activeKeyboard?.keyboard) {
// Autoselects this.keyboardRequisitioner.cache.defaultStub, which will be
// set to an actual keyboard on mobile devices.
this.setActiveKeyboard('', '');
await this.setActiveKeyboard('', '');
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't technically need to await here because this is a callback which has no other action after the call to this.setActiveKeyboard. But we should consider code hygiene around await because it is far too easy to miss an important await -- perhaps eslint can help us with this?

Comment on lines +440 to +441
// TODO-web-core: implement for KMX keyboards if needed
return kbd && kbd instanceof JSKeyboard && kbd.isCJK;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// TODO-web-core: implement for KMX keyboards if needed
return kbd && kbd instanceof JSKeyboard && kbd.isCJK;
// We only support isCJK on legacy .js keyboards; see #7928
return kbd && kbd instanceof JSKeyboard && kbd.isCJK;

@@ -0,0 +1,3 @@
export { CoreFactory, KM_CORE_STATUS } from './core-factory.js';
import { type MainModule, type km_core_keyboard, type CoreKeyboardReturn } from './import/core/keymancore.js';
export { MainModule, km_core_keyboard, CoreKeyboardReturn };
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
export { MainModule, km_core_keyboard, CoreKeyboardReturn };
export { MainModule as CoreMainModule, km_core_keyboard, CoreKeyboardReturn };

optional but may help for clarity elsewhere

const result = (await this._km_core).keyboard_load_from_blob(uri, byteArray);
if (result.status == KM_CORE_STATUS.OK) {
// extract keyboard name from URI
const id = uri.split('#')[0].split('?')[0].split('/').pop().split('.')[0];
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest refactoring this into a separate function

private async loadKeyboardInternal(uri: string, errorBuilder: KeyboardLoadErrorBuilder): Promise<Keyboard> {
const byteArray = await this.loadKeyboardBlob(uri, errorBuilder);

if (byteArray.slice(0, 4) == Uint8Array.from([0x4b, 0x58, 0x54, 0x53])) { // 'KXTS'
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest a helper function for this test

@@ -52,7 +52,7 @@ type KmwKeyboardObject = KeyboardObject & {
* and keyboard-centered functionality in an object-oriented way without modifying the
* wrapped keyboard itself.
*/
export default class Keyboard {
export class JSKeyboard {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good for this and KMXKeyboard to inherit from an abstract base class.

/**
* Acts as a wrapper class for KMX(+) Keyman keyboards
*/
export class KMXKeyboard {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Abstract base class with JSKeyboard

Comment on lines +48 to +53
let buffer: ArrayBuffer;
try {
buffer = await response.arrayBuffer();
} catch (e) {
throw errorBuilder.invalidKeyboard(e);
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let buffer: ArrayBuffer;
try {
buffer = await response.arrayBuffer();
} catch (e) {
throw errorBuilder.invalidKeyboard(e);
}
const buffer: ArrayBuffer = await (async () => {
try {
return await response.arrayBuffer();
} catch (e) {
throw errorBuilder.invalidKeyboard(e);
})();

Is this nicer? Hmm, it might be uglier.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we have three files all named keymanEngine.ts?

throw new Error(`Keyboard '${k0}' has not been loaded.`);
} else if (!(kbdObj instanceof JSKeyboard)) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
} else if (!(kbdObj instanceof JSKeyboard)) {
} else if (kbdObj instanceof KMXKeyboard) {

easier to read

ermshiperete and others added 5 commits March 5, 2025 18:05
feat(core): expose context and actions APIs to WASM 🎼
…gine

refactor(web): rename base `KeymanEngine` to `KeymanEngineBase` 🎼
…arget

refactor(web): cleanup OutputTarget class names 🎼
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
common/resources/ Build infrastructure common/ core/ Keyman Core developer/ide/ developer/ docs epic A long lived branch, home for a new feature, usually will have child PRs based on it epic-web-core linux/engine/ linux/ web/
Projects
Status: No status
Development

Successfully merging this pull request may close these issues.

6 participants