Add pure-Java gesture typing fallback (SwipeGestureEngine)#2351
Add pure-Java gesture typing fallback (SwipeGestureEngine)#2351simon-liesinger wants to merge 1 commit intoHeliBorg:mainfrom
Conversation
eaa029d to
96d4b31
Compare
HeliBoard's gesture typing infrastructure (touch tracking, trail rendering, settings UI) has always been present, but word matching requires a native library — either the proprietary Google libjni_latinimegoogle.so or the open replacement being developed under the NLnet grant (HeliBorg#2226, HeliBorg#668). Users without a compatible library get no suggestions at all when swiping. This commit adds SwipeGestureEngine: a self-contained Java implementation that makes gesture typing work without any native library. Algorithm (arc-length resampling + L2 distance): - At index build time, each dictionary word is converted to a normalized gesture path: letter key centres are looked up from the live Keyboard object, deduplicated, then resampled to 16 evenly-spaced (x,y) points. Words are grouped by first letter for fast lookup. - At gesture end, the raw InputPointers stroke is resampled the same way. Candidates are filtered by first/last letter, then ranked by L2 distance to their precomputed path with a small log-frequency bonus so common words win ties. Integration points: - JniUtils: sHaveGestureLib is set to true unconditionally so the gesture toggle appears in settings and touch input is routed as batch input. - Suggest.getSuggestedWordsForBatchInput: builds the index lazily on the first gesture (background thread) and caches it; clears on dictionary or layout change. Never calls the JNI stub with SESSION_ID_GESTURE. - Dictionary hierarchy: getAllWordsWithFrequency() added to Dictionary, ReadOnlyBinaryDictionary (token-based JNI iteration with probability), and DictionaryCollection; DictionaryFacilitator/Impl expose it. Properties: - Pure Java, no new dependencies, ~270 lines. - Layout-aware: key positions are read from the live Keyboard object, so any user layout (QWERTY, Dvorak, custom) works correctly. - Index is rebuilt automatically on layout or dictionary change. - Coexists with the native library: if a native library is loaded, it takes over and this engine is dormant. This is intentionally a simple baseline — the NLnet native library (HeliBorg#2226) will eventually supersede it with higher accuracy. Until then this gives every HeliBoard user working gesture typing out of the box. Relates to: HeliBorg#668, HeliBorg#2226
96d4b31 to
766d08c
Compare
|
This is super cool @simon-liesinger I'm going to look over the code you wrote soon! I'm on my weekend at the moment though. It's very cool that you got something working here. :-) It's a good idea to have a fall back in the interim. Do you, perchance, use long press key labels in this to handle diatrics and ligatures? (As I said, Haven't read it over yet). Edit: I just snuck a peak at some code. You claim 270 lines of Java, but it looks like 370 lines of kotlin and Java to me. It's also unusual the way some of this is worded. It says users who swipe without the library get no suggestions at all. They can't swipe, so there are no suggestions to give. It's a small distinction, but one I find a bit awkward. This feels a bit off to me. It's also all in one commit... Can you confirm you wrote this, and not an LLM? Cheers. |
|
Yes, an LLM wrote this (writing by hand now, though). Sorry about the errors in the description (although in it's defense, some of them may have been caused by the force-pushes). code: 100% claude code Is there a tag or something I should use in future? Again, sorry, I should have said something at the start. Edit: I feel like I should explain some of the mistakes it made. gesture/SwipeGestureEngine.java has +277 lines of pure java. I'm pretty sure it's just talking about that file, not the changes as a whole. the 'swipe without library' thing was probably a reference to when it enabled swiping before implementing the word matching. Still not reasonable to put in the PR, though. The singular commit was actually not it's fault, as I mentioned this was going to be a personal project, not a contribution here, and so all the work was done in a local clone. Edit 2: After your comment, it can now handle diacritics. |
Context
HeliBoard's gesture typing infrastructure — touch tracking, trail rendering, the settings toggle — has always been present, but word matching requires a native
.so. Without the proprietary Googlelibjni_latinimegoogle.so(or the open replacement being built under the NLnet grant, #2226), users who swipe get no suggestions at all.This PR adds a self-contained Java fallback that makes gesture typing work for everyone, without any native library.
Algorithm
SwipeGestureEngineuses arc-length resampling + L2 distance scoring, a technique closely related to SHARK2 (documented in #668):Index build (once per dictionary/layout, background thread):
Keyboardobject.(x, y)points, normalised to keyboard dimensions.Gesture match (each swipe):
log(freq+1)bonus so common words win ties.SuggestedWordInfo.Integration
gesture/SwipeGestureEngine.javaSuggest.ktgetSuggestedWordsForBatchInputbuilds/caches the index and calls the engine; never calls the JNI stub withSESSION_ID_GESTURE(which crashes on the AOSP stub)JniUtils.javasHaveGestureLib = trueunconditionally so the gesture toggle appears in settings and touch input is routed as batch inputDictionary.javagetAllWordsWithFrequency()returning empty mapReadOnlyBinaryDictionary.javaDictionaryCollection.javaDictionaryFacilitator.java/DictionaryFacilitatorImpl.ktgetAllMainDictionaryWordsWithFrequency()Properties
Keyboardobject at index build time, so QWERTY, Dvorak, custom layouts, and layout changes all work correctly.JniUtilsstill tries to load the native.sofirst; if it succeeds, the native engine takes over and this code is dormant.Relation to #2226 / #668
This is intentionally a simple baseline — the NLnet open native library will eventually supersede it with higher accuracy (SHARK2-level matching, multi-language, etc). Until that ships, this gives every HeliBoard user working gesture typing out of the box. The two can coexist during the transition.
Testing
Tested on a Pixel 6a (Android 14) with the default English dictionary and QWERTY layout. Common short words (hello, game, world, the, because, …) resolve correctly with a casual swipe. Index build takes ~1–2 s on first gesture; subsequent gestures are instant.