From 51ff795be419ff5102b262c90371340f76c74f2c Mon Sep 17 00:00:00 2001 From: Jules Aguillon Date: Sun, 20 Feb 2022 13:09:39 +0100 Subject: Move pointer handling code to its own class Separate the concerns and have a clearer interface between the two parts of the code. --- srcs/juloo.keyboard2/Keyboard2View.java | 358 ++++++++------------------------ 1 file changed, 91 insertions(+), 267 deletions(-) (limited to 'srcs/juloo.keyboard2/Keyboard2View.java') diff --git a/srcs/juloo.keyboard2/Keyboard2View.java b/srcs/juloo.keyboard2/Keyboard2View.java index 8123144..8584981 100644 --- a/srcs/juloo.keyboard2/Keyboard2View.java +++ b/srcs/juloo.keyboard2/Keyboard2View.java @@ -4,32 +4,27 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; -import android.os.Handler; -import android.os.Message; import android.os.Vibrator; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; -import android.widget.PopupWindow; -import java.util.ArrayList; public class Keyboard2View extends View - implements View.OnTouchListener, Handler.Callback + implements View.OnTouchListener, Pointers.IPointerEventHandler { private static final long VIBRATE_MIN_INTERVAL = 100; private KeyboardData _keyboard; - private ArrayList _downKeys = new ArrayList(); + private Pointers _pointers; private int _flags = 0; private Vibrator _vibratorService; private long _lastVibration = 0; - private Handler _handler; private static int _currentWhat = 0; private Config _config; @@ -51,9 +46,9 @@ public class Keyboard2View extends View { super(context, attrs); _vibratorService = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE); - _handler = new Handler(this); _theme = new Theme(getContext(), attrs); _config = Config.globalConfig(); + _pointers = new Pointers(this, _config); setOnTouchListener(this); reset(); } @@ -88,33 +83,74 @@ public class Keyboard2View extends View public void reset() { _flags = 0; - _downKeys.clear(); + _pointers.clear(); requestLayout(); invalidate(); } + public void onPointerDown(KeyValue k) + { + updateFlags(); + invalidate(); + if (k != null) + vibrate(); + } + + public void onPointerSwipe(KeyValue k) + { + updateFlags(); + invalidate(); + if (k != null) + vibrate(); + } + + public void onPointerUp(KeyValue k) + { + if (k != null && (k.flags & KeyValue.FLAG_NOCHAR) == 0) + _config.handler.handleKeyUp(k, _flags); + updateFlags(); + invalidate(); + } + + public void onPointerHold(KeyValue k) + { + if (k != null) + _config.handler.handleKeyUp(k, _flags); + } + + public void onPointerFlagsChanged() + { + updateFlags(); + invalidate(); + } + + private void updateFlags() + { + _flags = _pointers.getFlags(); + } + @Override public boolean onTouch(View v, MotionEvent event) { - float x; - float y; - float keyW; int p; - switch (event.getActionMasked()) { case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_UP: - onTouchUp(event.getPointerId(event.getActionIndex())); + _pointers.onTouchUp(event.getPointerId(event.getActionIndex())); break ; case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_POINTER_DOWN: p = event.getActionIndex(); - onTouchDown(event.getX(p), event.getY(p), event.getPointerId(p)); + float tx = event.getX(p); + float ty = event.getY(p); + KeyboardData.Key key = getKeyAtPosition(tx, ty); + if (key != null) + _pointers.onTouchDown(tx, ty, event.getPointerId(p), key); break ; case MotionEvent.ACTION_MOVE: for (p = 0; p < event.getPointerCount(); p++) - onTouchMove(event.getX(p), event.getY(p), event.getPointerId(p)); + _pointers.onTouchMove(event.getX(p), event.getY(p), event.getPointerId(p)); break ; default: return (false); @@ -122,197 +158,33 @@ public class Keyboard2View extends View return (true); } - private KeyDown getKeyDown(int pointerId) - { - for (KeyDown k : _downKeys) - { - if (k.pointerId == pointerId) - return (k); - } - return (null); - } - - private KeyDown getKeyDown(KeyboardData.Key key) - { - for (KeyDown k : _downKeys) - { - if (k.key == key) - return (k); - } - return (null); - } - - private KeyDown getKeyDown(KeyValue kv) - { - for (KeyDown k : _downKeys) - { - if (k.value == kv) - return (k); - } - return (null); - } - - private void onTouchMove(float moveX, float moveY, int pointerId) - { - KeyDown key = getKeyDown(pointerId); - KeyValue newValue; - - if (key != null) - { - moveX -= key.downX; - moveY -= key.downY; - float absDist = Math.abs(moveX) + Math.abs(moveY); - key.ptrDist = absDist; - if (absDist < _config.swipe_dist_px) - { - newValue = key.key.key0; - } - else if (key.key.edgekeys) - { - if (Math.abs(moveY) > Math.abs(moveX)) // vertical swipe - newValue = (moveY < 0) ? key.key.key1 : key.key.key4; - else if (moveX < 0) // left swipe - newValue = key.key.key3; - else // right swipe - newValue = key.key.key2; - } - else - { - if (moveX < 0) - newValue = (moveY < 0) ? key.key.key1 : key.key.key3; - else if (moveY < 0) - newValue = key.key.key2; - else - newValue = key.key.key4; - } - if (newValue != null && newValue != key.value) - { - if (key.timeoutWhat != -1) - { - _handler.removeMessages(key.timeoutWhat); - if ((newValue.flags & KeyValue.FLAG_NOREPEAT) == 0) - _handler.sendEmptyMessageDelayed(key.timeoutWhat, _config.longPressTimeout); - } - key.value = newValue; - key.flags = newValue.flags; - updateFlags(); - invalidate(); - handleKeyDown(newValue); - } - } - } - - private void onTouchDown(float touchX, float touchY, int pointerId) + private KeyboardData.Row getRowAtPosition(float ty) { - float y = _config.marginTop - _config.keyHeight; + float y = _config.marginTop; + if (ty < y) + return null; for (KeyboardData.Row row : _keyboard.rows) { - y += _config.keyHeight; - if (touchY < y || touchY >= (y + _config.keyHeight)) - continue ; - float x = _config.horizontalMargin; - for (KeyboardData.Key key : row.keys) - { - x += key.shift * _keyWidth; - float keyW = _keyWidth * key.width; - if (touchX >= x && touchX < (x + keyW)) - { - int what = _currentWhat++; - if (key.key0 != null && (key.key0.flags & KeyValue.FLAG_NOREPEAT) == 0) - _handler.sendEmptyMessageDelayed(what, _config.longPressTimeout); - _downKeys.add(new KeyDown(pointerId, key, touchX, touchY, what)); - handleKeyDown(key.key0); - updateFlags(); - invalidate(); - return ; - } - x += keyW; - } - } - } - - // Whether a key is already activated (key down but pointer up) - private KeyDown getActivatedKey(KeyValue kv) - { - for (KeyDown k : _downKeys) - { - if (k.value == kv && k.pointerId == -1) - return (k); + y += (row.shift + row.height) * _config.keyHeight; + if (ty < y) + return row; } - return (null); + return null; } - private void onTouchUp(int pointerId) + private KeyboardData.Key getKeyAtPosition(float tx, float ty) { - KeyDown k = getKeyDown(pointerId); - - if (k != null) + KeyboardData.Row row = getRowAtPosition(ty); + float x = _config.horizontalMargin; + if (row == null || tx < x) + return null; + for (KeyboardData.Key key : row.keys) { - // Stop key repeat - if (k.timeoutWhat != -1) - { - _handler.removeMessages(k.timeoutWhat); - k.timeoutWhat = -1; - } - KeyDown k_on = getActivatedKey(k.value); - if (k_on != null) - { - _downKeys.remove(k); // Remove dupplicate - // Same key with FLAG_LOCK is already on, do lock - if ((k_on.flags & KeyValue.FLAG_LOCK) != 0) - { - k_on.flags ^= KeyValue.FLAG_LOCK; // Next time, disable it - k_on.flags |= KeyValue.FLAG_LOCKED; - } - // Otherwise, toggle it - else - { - _downKeys.remove(k_on); - } - } - // Key stay activated - else if ((k.flags & KeyValue.FLAG_KEEP_ON) != 0) - { - k.pointerId = -1; // Set pointer up - } - else // Regular key up - { - for (int i = 0; i < _downKeys.size(); i++) - { - KeyDown downKey = _downKeys.get(i); - // Disable other activated keys that aren't locked - if (downKey.pointerId == -1 && (downKey.flags & KeyValue.FLAG_LOCKED) == 0) - _downKeys.remove(i--); - // Other keys currently down won't stay activated - else if ((downKey.flags & KeyValue.FLAG_KEEP_ON) != 0) - downKey.flags ^= KeyValue.FLAG_KEEP_ON; - } - _downKeys.remove(k); - handleKeyUp(k); - } - updateFlags(); - invalidate(); + x += (key.shift + key.width) * _keyWidth; + if (tx < x) + return key; } - } - - private void handleKeyUp(KeyDown key) - { - if (key.value != null && (key.flags & (KeyValue.FLAG_LOCKED | KeyValue.FLAG_NOCHAR)) == 0) - _config.handler.handleKeyUp(key.value, _flags); - } - - private void handleKeyDown(KeyValue key) - { - if (key == null) - return ; - vibrate(); - } - - private void updateFlags() - { - _flags = 0; - for (KeyDown k : _downKeys) - _flags |= k.flags; + return null; } private void vibrate() @@ -334,28 +206,6 @@ public class Keyboard2View extends View } } - @Override - public boolean handleMessage(Message msg) - { - for (KeyDown key : _downKeys) - { - if (key.timeoutWhat == msg.what) - { - long nextInterval = _config.longPressInterval; - if (_config.preciseRepeat && (key.flags & KeyValue.FLAG_PRECISE_REPEAT) != 0) - { - // Modulate repeat interval depending on the distance of the pointer - float accel = Math.min(4.f, Math.max(0.3f, key.ptrDist / (_config.swipe_dist_px * 15.f))); - nextInterval = (long)((float)nextInterval / accel); - } - _handler.sendEmptyMessageDelayed(msg.what, nextInterval); - _config.handler.handleKeyUp(key.value, _flags); - return (true); - } - } - return (false); - } - @Override public void onMeasure(int wSpec, int hSpec) { @@ -382,34 +232,34 @@ public class Keyboard2View extends View { x += k.shift * _keyWidth; float keyW = _keyWidth * k.width - _config.keyHorizontalInterval; - KeyDown keyDown = getKeyDown(k); + boolean isKeyDown = _pointers.isKeyDown(k); _tmpRect.set(x, y, x + keyW, y + keyH); canvas.drawRoundRect(_tmpRect, _theme.keyBorderRadius, _theme.keyBorderRadius, - (keyDown != null) ? _theme.keyDownBgPaint : _theme.keyBgPaint); + isKeyDown ? _theme.keyDownBgPaint : _theme.keyBgPaint); if (k.key0 != null) - drawLabel(canvas, k.key0, keyW / 2f + x, (keyH + _theme.labelTextSize) / 2f + y, keyDown); + drawLabel(canvas, k.key0, keyW / 2f + x, (keyH + _theme.labelTextSize) / 2f + y, isKeyDown); float subPadding = _config.keyPadding; if (k.edgekeys) { if (k.key1 != null) // top key - drawSubLabel(canvas, k.key1, x + keyW / 2f, y + subPadding, Paint.Align.CENTER, Vertical.TOP, keyDown); + drawSubLabel(canvas, k.key1, x + keyW / 2f, y + subPadding, Paint.Align.CENTER, Vertical.TOP, isKeyDown); if (k.key3 != null) // left key - drawSubLabel(canvas, k.key3, x + subPadding, y + keyH / 2f, Paint.Align.LEFT, Vertical.CENTER, keyDown); + drawSubLabel(canvas, k.key3, x + subPadding, y + keyH / 2f, Paint.Align.LEFT, Vertical.CENTER, isKeyDown); if (k.key2 != null) // right key - drawSubLabel(canvas, k.key2, x + keyW - subPadding, y + keyH / 2f, Paint.Align.RIGHT, Vertical.CENTER, keyDown); + drawSubLabel(canvas, k.key2, x + keyW - subPadding, y + keyH / 2f, Paint.Align.RIGHT, Vertical.CENTER, isKeyDown); if (k.key4 != null) // bottom key - drawSubLabel(canvas, k.key4, x + keyW / 2f, y + keyH - subPadding, Paint.Align.CENTER, Vertical.BOTTOM, keyDown); + drawSubLabel(canvas, k.key4, x + keyW / 2f, y + keyH - subPadding, Paint.Align.CENTER, Vertical.BOTTOM, isKeyDown); } else { if (k.key1 != null) // top left key - drawSubLabel(canvas, k.key1, x + subPadding, y + subPadding, Paint.Align.LEFT, Vertical.TOP, keyDown); + drawSubLabel(canvas, k.key1, x + subPadding, y + subPadding, Paint.Align.LEFT, Vertical.TOP, isKeyDown); if (k.key3 != null) // bottom left key - drawSubLabel(canvas, k.key3, x + subPadding, y + keyH - subPadding, Paint.Align.LEFT, Vertical.BOTTOM, keyDown); + drawSubLabel(canvas, k.key3, x + subPadding, y + keyH - subPadding, Paint.Align.LEFT, Vertical.BOTTOM, isKeyDown); if (k.key2 != null) // top right key - drawSubLabel(canvas, k.key2, x + keyW - subPadding, y + subPadding, Paint.Align.RIGHT, Vertical.TOP, keyDown); + drawSubLabel(canvas, k.key2, x + keyW - subPadding, y + subPadding, Paint.Align.RIGHT, Vertical.TOP, isKeyDown); if (k.key4 != null) // bottom right key - drawSubLabel(canvas, k.key4, x + keyW - subPadding, y + keyH - subPadding, Paint.Align.RIGHT, Vertical.BOTTOM, keyDown); + drawSubLabel(canvas, k.key4, x + keyW - subPadding, y + keyH - subPadding, Paint.Align.RIGHT, Vertical.BOTTOM, isKeyDown); } x += _keyWidth * k.width; } @@ -423,36 +273,36 @@ public class Keyboard2View extends View super.onDetachedFromWindow(); } - private int labelColor(KeyValue k, KeyDown hasKeyDown, int defaultColor) + private int labelColor(KeyValue k, boolean isKeyDown, int defaultColor) { - if (hasKeyDown != null) + if (isKeyDown && (k.flags & KeyValue.FLAG_LATCH) != 0) { - KeyDown kd = getKeyDown(k); - if (kd != null) + int flags = _pointers.getKeyFlags(k); + if (flags != -1) { - if ((kd.flags & KeyValue.FLAG_LOCKED) != 0) + if ((flags & KeyValue.FLAG_LOCKED) != 0) return _theme.lockedColor; - if (kd.pointerId == -1) + if ((flags & KeyValue.FLAG_LATCH) == 0) return _theme.activatedColor; } } return defaultColor; } - private void drawLabel(Canvas canvas, KeyValue k, float x, float y, KeyDown keyDown) + private void drawLabel(Canvas canvas, KeyValue k, float x, float y, boolean isKeyDown) { k = KeyModifier.handleFlags(k, _flags); Paint p = _theme.labelPaint(((k.flags & KeyValue.FLAG_KEY_FONT) != 0)); - p.setColor(labelColor(k, keyDown, _theme.labelColor)); + p.setColor(labelColor(k, isKeyDown, _theme.labelColor)); p.setTextSize(_theme.labelTextSize * scaleTextSize(k)); canvas.drawText(k.symbol, x, y, p); } - private void drawSubLabel(Canvas canvas, KeyValue k, float x, float y, Paint.Align a, Vertical v, KeyDown keyDown) + private void drawSubLabel(Canvas canvas, KeyValue k, float x, float y, Paint.Align a, Vertical v, boolean isKeyDown) { k = KeyModifier.handleFlags(k, _flags); Paint p = _theme.subLabelPaint(((k.flags & KeyValue.FLAG_KEY_FONT) != 0), a); - p.setColor(labelColor(k, keyDown, _theme.subLabelColor)); + p.setColor(labelColor(k, isKeyDown, _theme.subLabelColor)); p.setTextSize(_theme.sublabelTextSize * scaleTextSize(k)); if (v == Vertical.CENTER) y -= (p.ascent() + p.descent()) / 2f; @@ -465,30 +315,4 @@ public class Keyboard2View extends View { return ((k.symbol.length() < 2) ? 1.f : 0.8f) * _config.characterSize; } - - private static class KeyDown - { - /* -1 if pointer is up. */ - public int pointerId; - public KeyValue value; - public KeyboardData.Key key; - public float downX; - public float downY; - /* Manhattan distance of the pointer to the center of the key */ - public float ptrDist; - public int flags; - public int timeoutWhat; - - public KeyDown(int pointerId, KeyboardData.Key key, float x, float y, int what) - { - this.pointerId = pointerId; - value = key.key0; - this.key = key; - downX = x; - downY = y; - ptrDist = 0.f; - flags = (value == null) ? 0 : value.flags; - timeoutWhat = what; - } - } } -- cgit v1.2.3