-
-
Notifications
You must be signed in to change notification settings - Fork 114
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
base: master
Are you sure you want to change the base?
epic: web-core 🎼 #12291
Conversation
`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
…core chore: merge master into web-core
Co-authored-by: Marc Durdin <[email protected]>
feat(web): POC of Core WASM integration into Keyman Web
User Test ResultsTest specification and instructions User tests are not required Test Artifacts
|
…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.
There was a problem hiding this 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.
web/src/app/ui/kmwuifloat.ts
Outdated
There was a problem hiding this comment.
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
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('', ''); |
There was a problem hiding this comment.
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?
// TODO-web-core: implement for KMX keyboards if needed | ||
return kbd && kbd instanceof JSKeyboard && kbd.isCJK; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// 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 }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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]; |
There was a problem hiding this comment.
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' |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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
let buffer: ArrayBuffer; | ||
try { | ||
buffer = await response.arrayBuffer(); | ||
} catch (e) { | ||
throw errorBuilder.invalidKeyboard(e); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
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)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} else if (!(kbdObj instanceof JSKeyboard)) { | |
} else if (kbdObj instanceof KMXKeyboard) { |
easier to read
…core chore: merge master into web-core 🎼
feat(web): implement getting properties of KMXKeyboard 🎼
feat(core): expose state and event API to WASM 🎼
- rename `js-processor`'s `OutputTarget` → `OutputTargetBase` - rename `element-wrappers`' `OutputTarget` → `OutputTargetElementWrapper`
Addresses code review comment.
feat(core): expose context and actions APIs to WASM 🎼
…gine refactor(web): rename base `KeymanEngine` to `KeymanEngineBase` 🎼
…arget refactor(web): cleanup OutputTarget class names 🎼
Adds support for Keyman Core (incl. LDML keyboards) to KeymanWeb, bringing LDML keyboards to Android, iOS, and web platforms
References
Seed PR:
@keymanapp-test-bot skip