Files
Unexpected-Keyboard/srcs/juloo.keyboard2/UnexpectedKeyboardSwipeAdapter.java
harley 55a7bd2643
Check generated files / Layout list (push) Has been cancelled
Check generated files / Layout warnings (push) Has been cancelled
Check generated files / Compose key data (push) Has been cancelled
Make Apk CI / Build-Apk (push) Has been cancelled
Point libswipetype submodule to our Gitea fork with absolute-coordinate DTW
submodule vendor/libswipetype now points to
http://10.0.1.49:3010/harley/libswipetype.git (commit e4aef2f)
instead of upstream github.com/libswipetype/libswipetype.

Key change: removed [0,1] bounding-box normalization from both
PathProcessor and IdealPathGenerator. Paths now stay in original dp
coordinates so DTW measures actual keyboard distance between keys.
2026-07-07 03:41:21 -04:00

141 lines
4.3 KiB
Java

package juloo.keyboard2;
import android.content.Context;
import android.util.Log;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import dev.dettmer.swipetype.android.GesturePoint;
import dev.dettmer.swipetype.android.KeyboardLayoutDescriptor;
import dev.dettmer.swipetype.android.KeyboardLayoutDescriptor.KeyInfo;
import dev.dettmer.swipetype.android.SwipeTypeAdapter;
import dev.dettmer.swipetype.android.SwipeTypeCandidate;
import dev.dettmer.swipetype.android.SwipeTypeEngine;
import dev.dettmer.swipetype.android.SwipeTypeError;
public class UnexpectedKeyboardSwipeAdapter implements SwipeTypeAdapter
{
private static final String TAG = "SwipeAdapter";
private SwipeTypeEngine _engine;
private Context _context;
private List<GesturePoint> _gesturePoints = new ArrayList<>();
private boolean _gestureActive = false;
private CandidatesCallback _candidatesCallback;
/** Key positions (dp) set by the view after layout. */
private List<KeyInfo> _cachedKeys = null;
private float _layoutWidthDp = 0;
private float _layoutHeightDp = 0;
public interface CandidatesCallback
{
void onSwipeCandidates(String[] words, float[] scores);
}
public UnexpectedKeyboardSwipeAdapter(Context context)
{
_context = context;
}
/** Called by the view after layout with all key positions in dp. */
public void setKeyLayout(List<KeyInfo> keys, float widthDp, float heightDp)
{
_cachedKeys = keys;
_layoutWidthDp = widthDp;
_layoutHeightDp = heightDp;
if (_engine != null && _engine.isInitialized())
_engine.notifyLayoutChanged();
}
public void init(CandidatesCallback callback)
{
_candidatesCallback = callback;
_engine = new SwipeTypeEngine();
_engine.init(_context, this);
loadDict();
}
private void loadDict()
{
int resId = _context.getResources().getIdentifier(
"en_us_sample", "raw", _context.getPackageName());
if (resId == 0) { Log.w(TAG, "Dictionary resource not found"); return; }
try (InputStream is = _context.getResources().openRawResource(resId))
{
boolean ok = _engine.loadDictionary("en-US", is);
Log.i(TAG, "loadDictionary: " + ok);
}
catch (Exception e) { Log.e(TAG, "Failed: " + e.getMessage()); }
}
public void startGesture() { _gesturePoints.clear(); _gestureActive = true; }
public void addPoint(float x, float y, long timestamp)
{
if (_gestureActive) _gesturePoints.add(new GesturePoint(x, y, timestamp));
}
public void finishGesture()
{
_gestureActive = false;
if (_gesturePoints.size() < 3) { _gesturePoints.clear(); return; }
_engine.processGesture(_gesturePoints);
_gesturePoints.clear();
}
public void cancelGesture() { _gestureActive = false; _gesturePoints.clear(); }
// ===== SwipeTypeAdapter =====
@Override
public void onInit(SwipeTypeEngine engine) { Log.i(TAG, "Engine initialized"); }
@Override
public KeyboardLayoutDescriptor getKeyboardLayout()
{
if (_cachedKeys != null && !_cachedKeys.isEmpty())
return new KeyboardLayoutDescriptor("en-US", _cachedKeys,
_layoutWidthDp, _layoutHeightDp);
// Fallback — should not be reached once the view reports layout
List<KeyInfo> stub = new ArrayList<>();
float d = _context.getResources().getDisplayMetrics().density;
String[] rows = {"qwertyuiop", "asdfghjkl", "zxcvbnm"};
float y = 0;
for (String r : rows) {
float x = 0;
for (int i = 0; i < r.length(); i++) {
char c = r.charAt(i);
stub.add(new KeyInfo(String.valueOf(c), (int)c, x+12f/d, y+12f/d, 24f/d, 24f/d));
x += 24f/d;
}
y += 24f/d;
}
return new KeyboardLayoutDescriptor("en-US", stub, 240f/d, 72f/d);
}
@Override
public void onCandidatesReady(List<SwipeTypeCandidate> candidates)
{
if (_candidatesCallback == null || candidates.isEmpty()) return;
String[] words = new String[candidates.size()];
float[] scores = new float[candidates.size()];
for (int i = 0; i < candidates.size(); i++)
{
words[i] = candidates.get(i).word;
scores[i] = candidates.get(i).confidence;
}
_candidatesCallback.onSwipeCandidates(words, scores);
}
@Override
public void onError(SwipeTypeError error) { Log.e(TAG, "Error: " + error.name()); }
public void shutdown()
{
if (_engine != null) _engine.shutdown();
}
}