This fixes crash reported as #6703. This issue was first reported in
14.0.282-stable. I have done a careful review of changes in 14.0.282
(and 14.0.281) but have been unable to find any changes that could have
bearing on this.
The basic issue is that there appears to be some circumstances where
`KMManager` thinks that it has a keyboard loaded (ref
`SystemKeyboardLoaded` variable), but `KMKeyboard.currentKeyboard` is
still `null`.
The crash has been reported for only a very small set of users, 119 at
time of fix, but average reports per user is over 100. As is usual with
this type of thing, a small fraction of those users are reporting the
majority of crashes. I have not found any real commonality across the
error reports -- they are geographically dispersed, across multiple
device types and Android versions.
Note that this addresses the error at hand but as I am unable to
reproduce the issue, does not necessarily address the root problem, so
there may still be other issues reported even after this is fixed.
A longer-term refactor would eliminate `SystemKeyboardLoaded` because
from what I can tell, we should always be able to determine that from
the state of `KMKeyboard.currentKeyboard`. However, the state
entanglement is a lot deeper than just those two variables, with cross
references to keyboard indexes between `KMManager` and `KMKeyboard`
which need to be resolved (`KMKeyboard` should *never* refer to
`KMManager`).
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.