-
-
Notifications
You must be signed in to change notification settings - Fork 111
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
fix(web): fix engine initialization when initial keyboard is debug-compiled #11968
Conversation
…mpiled Fixes: #11962 Debug-mode keyboards refer to keyman.osk API points, but we try to load initial keyboards before constructing the OSK for optimization reasons, making those API points unavailable. These changes enforce the "try" aspect, retrying after OSK load once those API points become available.
@@ -886,10 +886,12 @@ private static void copyAssets(Context context) { | |||
|
|||
// Copy default keyboard font | |||
copyAsset(context, KMDefault_KeyboardFont, "", true); | |||
// Includes something needed up to Chrome 61, which has full ES5 support. | |||
// Thus, this one isn't legacy-only. | |||
copyAsset(context, KMFilename_JSPolyfill2, "", true); |
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.
Addresses a side detail, though that side detail's documentation is within the same base issue. Got lumped together there, so "why not here?"
@@ -824,9 +824,9 @@ export default class ContextManager extends ContextManagerBase<BrowserConfigurat | |||
|
|||
// Sets the default stub (as specified with the `getSavedKeyboard` call) as active. | |||
if(stub) { | |||
return this.activateKeyboard(stub.id, stub.langId); | |||
return this.activateKeyboard(stub.id, stub.langId, true); |
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.
Without the added true
parameter, the first reload would remember the old keyboard, but the setting wouldn't be preserved for all subsequent reloads; the first-time default keyboard would appear instead.
…uto-tests Shifting to async-await had unexpected side effects that complicate certain tested guarantees, so it's simplest to just undo that shift and clean up the original format.
Test ResultsI tested this issue with the attached "Keyman 18.0.71-alpha-test-11968" build on the Windows 10 and Ubuntu Mantic 23.10 OS environments(Chrome browser): Here is my observation.
|
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.
This screams ugly hack, and I think it is fragile and will cause us long-term grief.
The underlying issue is that the (implicit) API contract that KeymanWeb offered (osk.modifierCodes
et al) is no longer being met. Hacking around a script load error masks the problem -- we cannot assume that the keyboard is generated by the compiler -- it may use modifierCodes
for other purposes. We need to make keyman.osk.modifierCodes
available at all times.
It is implicit because we don't have formal documentation of the API surface. But it's still real, because there are real keyboards using it.
Alternate possibility: is it possible to create a stub osk
object with the necessary members when keyman object is constructed -- e.g. osk = {modifierCodes: ..., keyCodes: ...}
? We'd just throw the stub away when we rebuild the osk.
That was my first thought, but to me, that screamed "uglier hack" - it's why I decided on this approach. It might look weird to API consumers to have a not-OSK available when no OSK has been set in place. (Originally noted as a possibliity here: #11962 (comment) - CTRL-F It wouldn't be too hard to set it during script-load and then remove it once the script-load is done. That said, it'd also be kind of ugly to have such a core field of the engine subject to this sort of variability. |
Also of note: we only noticed this now because of how late the OSK is being initialized. If we somehow had a state in 16.0 or before where the OSK was left uninitialized while a keyboard loaded, we'd have had the same problem there as well. It's simply that such a state never existed then - mostly due to loading an initial "blank" / "stand-in" keyboard. (This got labeled as The only difference for 17.0 is by optimizing away that initial blank-keyboard state that was originally part of the OSK lifecycle, we enter a state where we can try to load the initial keyboard before the keyman.osk.* endpoints are available. |
The appropriate fix may be to roll back the optimization in v17. Correct behavior is more important than speed.
Sorry, I think faking out the global script load error handler is definitely uglier! I also can't see how it could even work correctly -- surely the keyboard object would then have invalid KeymanWeb.KR(new Keyboard_kbdal());
function Keyboard_kbdal()
{
var modCodes = keyman.osk.modifierCodes;
var keyCodes = keyman.osk.keyCodes;
... Other keyboards may do other things, we should always assume But I agree it's not ideal either way. It feels like We could do something like this for the stub?
So, given the stubbing approach is incomplete, perhaps we should approach this differently.
|
As you've noted, the early-load will be subject to failure. The keyboard doesn't even finish loading due to the error, so we never get the keyboard object during that load. (The keyboard script-object's constructor never completes.) The workaround is pretty easy, though - just retry once the codes are available. We track if a failure occurred; if so, once the OSK is loaded, retry the load. That's the purpose behind the new The whole point of the error-checking + silencing is to say "Let's try to load it early. If that fails, try at the old, unoptimized time." Of note: the user who reported the error was still able to use the keyboard despite the error + error alert. We kind of lucked out in that existing mobile-app code triggered the retry for us there, admittedly. |
I'd say the perspective on this changed once we introduced the "inlined OSK" for KMW 15.0. (See: #5665) Before then, there was only ever the "one true OSK" for a device, but afterward we allowed OSK hotswapping - a feature needed for the Developer test-host page.
Yeah, I don't think we gave too much thought to this at the time. I think we're kind of operating under a policy of "if you're comfortable manipulating this undocumented OSK-hotswap feature, you should be able to figure this out for yourself too." |
I don't think we should ever be re-running keyboard scripts. We cannot assume what the script looks like. It might define a global const, which would fail on second run, for example.
But did the modifier keys work correctly? Unless they were testing with a hardware keyboard, they might never know. |
So... it sounds like you're asking for a reversion of #11174. We already know it's possible to initialize For 18.0, we have some additional optimization improvements should significantly mitigate this, as we won't need to build as much of the blank/default OSK as we previously did. That won't really help things for 17.0-stable, though. |
Yes, I think we have to do that. |
Closing in favor of #12015, which was merged earlier today and implements the reversion mentioned above. |
Fixes: #11962
Debug-mode keyboards refer to keyman.osk API points, but we try to load initial keyboards before constructing the OSK for optimization reasons, making those API points unavailable. These changes enforce the "try" aspect, retrying after OSK load once those API points become available.
User Testing
TEST_REPRO: Attempt to reproduce #11962 using Keyman for Android.
TEST_STANDARD_ERROR_ALERTS: Verify that all standard keyboard error alerts still operate normally.
TEST_BROWSER_KEYBOARDS: Using the "Tests unminified Keymanweb" test page, verify that refreshing the page always restores the previously used keyboard, never displaying an error message. Do not use mobile-device emulation.
Other notes
Within the JS console, we actually still get a copy of the keyboard-load error message for debug-mode keyboards within app/browser. No alerts will be shown and the error will be fully handled, but the call here still occurs:
keyman/web/src/app/browser/src/contextManager.ts
Lines 541 to 545 in c537bcd
The re-thrown error (see line 559) is caught and handled by
keymanEngine.ts
, line 246 from this PR's changes.