From 51ff795be419ff5102b262c90371340f76c74f2c Mon Sep 17 00:00:00 2001 From: Jules Aguillon Date: Sun, 20 Feb 2022 13:09:39 +0100 Subject: [PATCH] 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/KeyValue.java | 4 +- srcs/juloo.keyboard2/Keyboard2View.java | 358 ++++++------------------ srcs/juloo.keyboard2/Pointers.java | 262 +++++++++++++++++ 3 files changed, 355 insertions(+), 269 deletions(-) create mode 100644 srcs/juloo.keyboard2/Pointers.java diff --git a/srcs/juloo.keyboard2/KeyValue.java b/srcs/juloo.keyboard2/KeyValue.java index 8ce3cbe..15a3d18 100644 --- a/srcs/juloo.keyboard2/KeyValue.java +++ b/srcs/juloo.keyboard2/KeyValue.java @@ -17,7 +17,7 @@ class KeyValue public static final char CHAR_NONE = '\0'; // Behavior flags - public static final int FLAG_KEEP_ON = 1; + public static final int FLAG_LATCH = 1; public static final int FLAG_LOCK = (1 << 1); public static final int FLAG_NOREPEAT = (1 << 2); public static final int FLAG_NOCHAR = (1 << 3); @@ -126,7 +126,7 @@ class KeyValue private static void addModifierKey(String name, String symbol, int extra_flags) { addKey(name, symbol, CHAR_NONE, EVENT_NONE, - FLAG_KEEP_ON | FLAG_NOCHAR | FLAG_NOREPEAT | extra_flags); + FLAG_LATCH | FLAG_NOCHAR | FLAG_NOREPEAT | extra_flags); } private static void addSpecialKey(String name, String symbol, int event) 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) + private KeyboardData.Row getRowAtPosition(float ty) { - 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) - { - 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; - } + y += (row.shift + row.height) * _config.keyHeight; + if (ty < y) + return row; } + return null; } - // Whether a key is already activated (key down but pointer up) - private KeyDown getActivatedKey(KeyValue kv) + private KeyboardData.Key getKeyAtPosition(float tx, float ty) { - for (KeyDown k : _downKeys) + KeyboardData.Row row = getRowAtPosition(ty); + float x = _config.horizontalMargin; + if (row == null || tx < x) + return null; + for (KeyboardData.Key key : row.keys) { - if (k.value == kv && k.pointerId == -1) - return (k); + x += (key.shift + key.width) * _keyWidth; + if (tx < x) + return key; } - return (null); - } - - private void onTouchUp(int pointerId) - { - KeyDown k = getKeyDown(pointerId); - - if (k != null) - { - // 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(); - } - } - - 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; - } - } } diff --git a/srcs/juloo.keyboard2/Pointers.java b/srcs/juloo.keyboard2/Pointers.java new file mode 100644 index 0000000..0930c21 --- /dev/null +++ b/srcs/juloo.keyboard2/Pointers.java @@ -0,0 +1,262 @@ +package juloo.keyboard2; + +import android.os.Handler; +import android.os.Message; +import java.util.ArrayList; + +/** + * Manage pointers (fingers) on the screen and long presses. + * Call back to IPointerEventHandler. + */ +public final class Pointers implements Handler.Callback +{ + private Handler _keyrepeat_handler; + private ArrayList _ptrs = new ArrayList(); + private IPointerEventHandler _handler; + private Config _config; + + public Pointers(IPointerEventHandler h, Config c) + { + _keyrepeat_handler = new Handler(this); + _handler = h; + _config = c; + } + + public int getFlags() + { + int flags = 0; + for (Pointer p : _ptrs) + flags |= p.flags; + return flags; + } + + public void clear() + { + _ptrs.clear(); + } + + public boolean isKeyDown(KeyboardData.Key k) + { + for (Pointer p : _ptrs) + if (p.key == k) + return true; + return false; + } + + /** + * These flags can be different: + * FLAG_LOCK Removed when the key is locked + * FLAG_LOCKED Added when the key is locked + * FLAG_LATCH Removed when the key is latched (released but not consumed yet) + * Returns [-1] if not found. + */ + public int getKeyFlags(KeyValue kv) + { + for (Pointer p : _ptrs) + if (p.value == kv) + return p.flags; + return -1; + } + + // Receiving events + + public void onTouchUp(int pointerId) + { + Pointer ptr = getPtr(pointerId); + if (ptr == null) + return; + stopKeyRepeat(ptr); + Pointer latched = getLatched(ptr.value); + if (latched != null) // Already latched + { + removePtr(ptr); // Remove dupplicate + if ((latched.flags & KeyValue.FLAG_LOCK) != 0) // Locking key, toggle lock + { + latched.flags = (latched.flags & ~KeyValue.FLAG_LOCK) | KeyValue.FLAG_LOCKED; + _handler.onPointerFlagsChanged(); + } + else // Otherwise, unlatch + { + removePtr(latched); + _handler.onPointerUp(ptr.value); + } + } + else if ((ptr.flags & KeyValue.FLAG_LATCH) != 0) + { + ptr.flags &= ~KeyValue.FLAG_LATCH; + ptr.pointerId = -1; // Latch + _handler.onPointerFlagsChanged(); + } + else + { + clearLatched(); + removePtr(ptr); + _handler.onPointerUp(ptr.value); + } + } + + public void onTouchDown(float x, float y, int pointerId, KeyboardData.Key key) + { + KeyValue value = key.key0; + Pointer ptr = new Pointer(pointerId, key, value, x, y); + _ptrs.add(ptr); + if (value != null && (value.flags & KeyValue.FLAG_NOREPEAT) == 0) + startKeyRepeat(ptr); + _handler.onPointerDown(value); + } + + public void onTouchMove(float x, float y, int pointerId) + { + Pointer ptr = getPtr(pointerId); + if (ptr == null) + return; + float dx = x - ptr.downX; + float dy = y - ptr.downY; + float dist = Math.abs(dx) + Math.abs(dy); + ptr.ptrDist = dist; + KeyValue newValue; + if (dist < _config.swipe_dist_px) + { + newValue = ptr.key.key0; + } + else if (ptr.key.edgekeys) + { + if (Math.abs(dy) > Math.abs(dx)) // vertical swipe + newValue = (dy < 0) ? ptr.key.key1 : ptr.key.key4; + else // horizontal swipe + newValue = (dx < 0) ? ptr.key.key3 : ptr.key.key2; + } + else + { + if (dx < 0) // left side + newValue = (dy < 0) ? ptr.key.key1 : ptr.key.key3; + else // right side + newValue = (dy < 0) ? ptr.key.key2 : ptr.key.key4; + } + if (newValue != null && newValue != ptr.value) + { + stopKeyRepeat(ptr); + ptr.value = newValue; + ptr.flags = newValue.flags; + if ((newValue.flags & KeyValue.FLAG_NOREPEAT) == 0) + startKeyRepeat(ptr); + _handler.onPointerSwipe(newValue); + } + } + + // Pointers management + + private Pointer getPtr(int pointerId) + { + for (Pointer p : _ptrs) + if (p.pointerId == pointerId) + return p; + return null; + } + + private void removePtr(Pointer ptr) + { + _ptrs.remove(ptr); + } + + private Pointer getLatched(KeyValue kv) + { + for (Pointer p : _ptrs) + if (p.value == kv && p.pointerId == -1) + return p; + return null; + } + + private void clearLatched() + { + for (int i = _ptrs.size() - 1; i >= 0; i--) + { + Pointer ptr = _ptrs.get(i); + // Latched and not locked, remove + if (ptr.pointerId == -1 && (ptr.flags & KeyValue.FLAG_LOCKED) == 0) + _ptrs.remove(i); + // Not latched but pressed, don't latch once released + else if ((ptr.flags & KeyValue.FLAG_LATCH) != 0) + ptr.flags &= ~KeyValue.FLAG_LATCH; + } + } + + // Key repeat + + /** Message from [_keyrepeat_handler]. */ + @Override + public boolean handleMessage(Message msg) + { + for (Pointer ptr : _ptrs) + { + if (ptr.timeoutWhat == msg.what) + { + long nextInterval = _config.longPressInterval; + if (_config.preciseRepeat && (ptr.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, ptr.ptrDist / (_config.swipe_dist_px * 15.f))); + nextInterval = (long)((float)nextInterval / accel); + } + _keyrepeat_handler.sendEmptyMessageDelayed(msg.what, nextInterval); + _handler.onPointerHold(ptr.value); + return (true); + } + } + return (false); + } + + private static int uniqueTimeoutWhat = 0; + + private void startKeyRepeat(Pointer ptr) + { + int what = (uniqueTimeoutWhat++); + ptr.timeoutWhat = what; + _keyrepeat_handler.sendEmptyMessageDelayed(what, _config.longPressTimeout); + } + + private void stopKeyRepeat(Pointer ptr) + { + if (ptr.timeoutWhat != -1) + { + _keyrepeat_handler.removeMessages(ptr.timeoutWhat); + ptr.timeoutWhat = -1; + } + } + + private final class Pointer + { + /** -1 when latched. */ + public int pointerId; + public KeyboardData.Key key; + public KeyValue value; + public float downX; + public float downY; + /** Distance of the pointer to the initial press. */ + public float ptrDist; + public int flags; + /** Identify timeout messages. */ + public int timeoutWhat; + + public Pointer(int p, KeyboardData.Key k, KeyValue v, float x, float y) + { + pointerId = p; + key = k; + value = v; + downX = x; + downY = y; + ptrDist = 0.f; + flags = (v == null) ? 0 : v.flags; + timeoutWhat = -1; + } + } + + public interface IPointerEventHandler + { + public void onPointerDown(KeyValue k); + public void onPointerSwipe(KeyValue k); + public void onPointerUp(KeyValue k); + public void onPointerFlagsChanged(); + public void onPointerHold(KeyValue k); + } +}