The system keyboard, when deleting-left, would not count the number of
surrogate pairs correctly in the text to delete. This would often leave
it deleting half a surrogate pair.
Rather than change the countSurrogatePairs function, I opted to write
this inline. The countSurrogatePairs function is used elsewhere, it
appears correctly.
If there is an active selection, we delete the selection before
inserting text. In this case, we also ignore the deleteLeft value coming
from KeymanWeb, so we won't delete twice.
Note: in the future, we will hopefully refactor this to use
OutputTarget, which will change the way this function works and will
probably clean up some of the spaghetti.
This is part of the fix chain for #5853. Split android-host.js out from
keyboard.html in order to make it easier to debug and mock. No changes
to the content of the script, just moving it here.
This small harness simulates the Android app. I used it to try and
dig deeper into the interactions with selected text in #5853.
It is very rough, but with some extra effort we could use this
relatively easily for some low-level testing of KeymanWeb embedded
integration.
Summary of these changes:
Two targeted improvements; more optimization is possible but IMO this is
a significant enough improvement to go through test:
1. In oskView.ts, avoid calling `VisualKeyboard.refreshLayout` twice
from `OSKView.refreshLayout`. This roughly halves the time spent in
`VisualKeyboard.refreshLayout` for a keyboard switch.
2. In modelManager.ts, we avoid a very expensive `unloadModel` /
`loadModel` sequence from `registerModel` by checking to see if the
model spec we are passed is already registered. This avoids an
expensive callback to Keyman for Android which causes the banner to
'bounce'.
Longer notes:
So `VisualKeyboard.refreshLayout` is called 20+ times during a keyboard
switch. It is a very expensive call. It is the bulk of the time spent
when you press the globe key in Keyman for Android. This seems ripe for
optimization; see the following functions in keyboard.html:
* `setKeymanLanguage` -> `setActiveKeyboard` -> 6 calls
* `enableSuggestions` -> `registerModel` -> 8 calls
* `stateChange` -> 6+ calls
`OSKView.refreshLayout` always seems to call
`VisualKeyboard.refreshLayout` twice: first with `setSize`, and then
again itself.
Keyman for Android and KeymanWeb seem to fight over who is responsible
for selecting models (KMW first calls `loadModel`, then Keyman for
Android calls `unloadModel`, `loadModel`, through `enableSuggestions`).
The fix for rotation (`correctOSKTextSize()`), as called from
`stateChange()`, is expensive as well, because it rebuilds the entire
keyboard from scratch.
Along with that, we have the size of the webview changing as the model
is unloaded and reloaded and lots of back-and-forth between the
KeymanWeb and KMEA which seems unnecessary.
Shouldn't KeymanWeb be responsible for loading and unloading models,
once they are all registered? We should only need to register the models
once at page load time (when config changes, do we just reload the
page?).