do not complicate the code with nearest keys, we have no corrections

This commit is contained in:
tibbi 2022-02-19 17:32:02 +01:00
parent 8a1b68f826
commit aedc35ff02
3 changed files with 12 additions and 124 deletions

View File

@ -6,7 +6,6 @@ import android.content.res.Resources
import android.content.res.TypedArray import android.content.res.TypedArray
import android.content.res.XmlResourceParser import android.content.res.XmlResourceParser
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.util.SparseArray
import android.util.TypedValue import android.util.TypedValue
import android.util.Xml import android.util.Xml
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
@ -45,14 +44,10 @@ class MyKeyboard {
/** Width of the screen available to fit the keyboard */ /** Width of the screen available to fit the keyboard */
private var mDisplayWidth = 0 private var mDisplayWidth = 0
/** What icon should we show at Enter key */ /** What icon should we show at Enter key */
private var mEnterKeyType = IME_ACTION_NONE private var mEnterKeyType = IME_ACTION_NONE
/** Keyboard mode, or zero, if none. */ /** Keyboard rows */
private var mCellWidth = 0
private var mCellHeight = 0
private var mGridNeighbors: SparseArray<IntArray?>? = null
private var mProximityThreshold = 0
private val mRows = ArrayList<Row?>() private val mRows = ArrayList<Row?>()
companion object { companion object {
@ -61,22 +56,12 @@ class MyKeyboard {
private const val TAG_KEY = "Key" private const val TAG_KEY = "Key"
private const val EDGE_LEFT = 0x01 private const val EDGE_LEFT = 0x01
private const val EDGE_RIGHT = 0x02 private const val EDGE_RIGHT = 0x02
private const val EDGE_TOP = 0x04
private const val EDGE_BOTTOM = 0x08
const val KEYCODE_SHIFT = -1 const val KEYCODE_SHIFT = -1
const val KEYCODE_MODE_CHANGE = -2 const val KEYCODE_MODE_CHANGE = -2
const val KEYCODE_ENTER = -4 const val KEYCODE_ENTER = -4
const val KEYCODE_DELETE = -5 const val KEYCODE_DELETE = -5
const val KEYCODE_SPACE = 32 const val KEYCODE_SPACE = 32
// Variables for pre-computing nearest keys.
private const val GRID_WIDTH = 10
private const val GRID_HEIGHT = 5
private const val GRID_SIZE = GRID_WIDTH * GRID_HEIGHT
/** Number of key widths from current touch point to search for nearest keys. */
private const val SEARCH_DISTANCE = 1.8f
fun getDimensionOrFraction(a: TypedArray, index: Int, base: Int, defValue: Int): Int { fun getDimensionOrFraction(a: TypedArray, index: Int, base: Int, defValue: Int): Int {
val value = a.peekValue(index) ?: return defValue val value = a.peekValue(index) ?: return defValue
return when (value.type) { return when (value.type) {
@ -174,7 +159,7 @@ class MyKeyboard {
/** /**
* Flags that specify the anchoring to edges of the keyboard for detecting touch events that are just out of the boundary of the key. * Flags that specify the anchoring to edges of the keyboard for detecting touch events that are just out of the boundary of the key.
* This is a bit mask of [MyKeyboard.EDGE_LEFT], [MyKeyboard.EDGE_RIGHT], [MyKeyboard.EDGE_TOP] and [MyKeyboard.EDGE_BOTTOM]. * This is a bit mask of [MyKeyboard.EDGE_LEFT], [MyKeyboard.EDGE_RIGHT].
*/ */
private var edgeFlags = 0 private var edgeFlags = 0
@ -240,24 +225,10 @@ class MyKeyboard {
fun isInside(x: Int, y: Int): Boolean { fun isInside(x: Int, y: Int): Boolean {
val leftEdge = edgeFlags and EDGE_LEFT > 0 val leftEdge = edgeFlags and EDGE_LEFT > 0
val rightEdge = edgeFlags and EDGE_RIGHT > 0 val rightEdge = edgeFlags and EDGE_RIGHT > 0
val topEdge = edgeFlags and EDGE_TOP > 0
val bottomEdge = edgeFlags and EDGE_BOTTOM > 0
return ((x >= this.x || leftEdge && x <= this.x + width) return ((x >= this.x || leftEdge && x <= this.x + width)
&& (x < this.x + width || rightEdge && x >= this.x) && (x < this.x + width || rightEdge && x >= this.x)
&& (y >= this.y || topEdge && y <= this.y + height) && (y >= this.y && y <= this.y + height)
&& (y < this.y + height || bottomEdge && y >= this.y)) && (y < this.y + height && y >= this.y))
}
/**
* Returns the square of the distance between the center of the key and the given point.
* @param x the x-coordinate of the point
* @param y the y-coordinate of the point
* @return the square of the distance of the point from the center of the key
*/
fun squaredDistanceFrom(x: Int, y: Int): Int {
val xDist = this.x + width / 2 - x
val yDist = this.y + height / 2 - y
return xDist * xDist + yDist * yDist
} }
} }
@ -332,60 +303,6 @@ class MyKeyboard {
return false return false
} }
private fun computeNearestNeighbors() {
// Round-up so we don't have any pixels outside the grid
mCellWidth = (mMinWidth + GRID_WIDTH - 1) / GRID_WIDTH
mCellHeight = (mHeight + GRID_HEIGHT - 1) / GRID_HEIGHT
mGridNeighbors = SparseArray<IntArray?>(GRID_SIZE)
val indices = IntArray(mKeys!!.size)
val gridWidth: Int = GRID_WIDTH * mCellWidth
val gridHeight: Int = GRID_HEIGHT * mCellHeight
var x = 0
while (x < gridWidth) {
var y = 0
while (y < gridHeight) {
var count = 0
for (i in mKeys!!.indices) {
val key = mKeys!![i]
if (key!!.squaredDistanceFrom(x, y) < mProximityThreshold || key.squaredDistanceFrom(
x + mCellWidth - 1, y
) < mProximityThreshold || (key.squaredDistanceFrom(x + mCellWidth - 1, y + mCellHeight - 1)
< mProximityThreshold) || key.squaredDistanceFrom(x, y + mCellHeight - 1) < mProximityThreshold
) {
indices[count++] = i
}
}
val cell = IntArray(count)
System.arraycopy(indices, 0, cell, 0, count)
mGridNeighbors!!.put(y / mCellHeight * GRID_WIDTH + x / mCellWidth, cell)
y += mCellHeight
}
x += mCellWidth
}
}
/**
* Returns the indices of the keys that are closest to the given point.
* @param x the x-coordinate of the point
* @param y the y-coordinate of the point
* @return the array of integer indices for the nearest keys to the given point. If the given point is out of range, then an array of size zero is returned.
*/
fun getNearestKeys(x: Int, y: Int): IntArray {
if (mGridNeighbors == null) {
computeNearestNeighbors()
}
if (x in 0 until mMinWidth && y >= 0 && y < mHeight) {
val index = y / mCellHeight * GRID_WIDTH + x / mCellWidth
if (index < GRID_SIZE) {
return mGridNeighbors!![index]!!
}
}
return IntArray(0)
}
private fun createRowFromXml(res: Resources, parser: XmlResourceParser?): Row { private fun createRowFromXml(res: Resources, parser: XmlResourceParser?): Row {
return Row(res, this, parser) return Row(res, this, parser)
} }
@ -458,8 +375,6 @@ class MyKeyboard {
mDefaultWidth = getDimensionOrFraction(a, R.styleable.MyKeyboard_keyWidth, mDisplayWidth, mDisplayWidth / 10) mDefaultWidth = getDimensionOrFraction(a, R.styleable.MyKeyboard_keyWidth, mDisplayWidth, mDisplayWidth / 10)
mDefaultHeight = res.getDimension(R.dimen.key_height).toInt() mDefaultHeight = res.getDimension(R.dimen.key_height).toInt()
mDefaultHorizontalGap = getDimensionOrFraction(a, R.styleable.MyKeyboard_horizontalGap, mDisplayWidth, 0) mDefaultHorizontalGap = getDimensionOrFraction(a, R.styleable.MyKeyboard_horizontalGap, mDisplayWidth, 0)
mProximityThreshold = (mDefaultWidth * SEARCH_DISTANCE).toInt()
mProximityThreshold *= mProximityThreshold // Square it for comparison
a.recycle() a.recycle()
} }
} }

View File

@ -678,41 +678,16 @@ class MyKeyboardView @JvmOverloads constructor(context: Context, attrs: Attribut
} }
} }
private fun getKeyIndices(x: Int, y: Int): Int { private fun getPressedKeyIndex(x: Int, y: Int): Int {
val keys = mKeys return mKeys.indexOfFirst {
var primaryIndex = NOT_A_KEY it.isInside(x, y)
var closestKey = NOT_A_KEY
var closestKeyDist = mProximityThreshold + 1
val nearestKeyIndices = mKeyboard!!.getNearestKeys(x, y)
val keyCount = nearestKeyIndices.size
for (i in 0 until keyCount) {
val key = keys[nearestKeyIndices[i]]
val dist = 0
val isInside = key.isInside(x, y)
if (isInside) {
primaryIndex = nearestKeyIndices[i]
}
if (isInside && key.code > KEYCODE_SPACE) {
if (dist < closestKeyDist) {
closestKeyDist = dist
closestKey = nearestKeyIndices[i]
}
}
} }
if (primaryIndex == NOT_A_KEY) {
primaryIndex = closestKey
}
return primaryIndex
} }
private fun detectAndSendKey(index: Int, x: Int, y: Int, eventTime: Long) { private fun detectAndSendKey(index: Int, x: Int, y: Int, eventTime: Long) {
if (index != NOT_A_KEY && index < mKeys.size) { if (index != NOT_A_KEY && index < mKeys.size) {
val key = mKeys[index] val key = mKeys[index]
getKeyIndices(x, y) getPressedKeyIndex(x, y)
mOnKeyboardActionListener!!.onKey(key.code) mOnKeyboardActionListener!!.onKey(key.code)
mLastTapTime = eventTime mLastTapTime = eventTime
} }
@ -1095,7 +1070,7 @@ class MyKeyboardView @JvmOverloads constructor(context: Context, attrs: Attribut
val action = me.actionMasked val action = me.actionMasked
val eventTime = me.eventTime val eventTime = me.eventTime
val keyIndex = getKeyIndices(touchX, touchY) val keyIndex = getPressedKeyIndex(touchX, touchY)
// Ignore all motion events until a DOWN. // Ignore all motion events until a DOWN.
if (mAbortKey && action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_CANCEL) { if (mAbortKey && action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_CANCEL) {
@ -1118,7 +1093,7 @@ class MyKeyboardView @JvmOverloads constructor(context: Context, attrs: Attribut
val newPointerX = me.getX(1).toInt() val newPointerX = me.getX(1).toInt()
val newPointerY = me.getY(1).toInt() val newPointerY = me.getY(1).toInt()
val secondKeyIndex = getKeyIndices(newPointerX, newPointerY) val secondKeyIndex = getPressedKeyIndex(newPointerX, newPointerY)
showPreview(secondKeyIndex) showPreview(secondKeyIndex)
detectAndSendKey(secondKeyIndex, newPointerX, newPointerY, eventTime) detectAndSendKey(secondKeyIndex, newPointerX, newPointerY, eventTime)

View File

@ -118,9 +118,7 @@
app:keyEdgeFlags="left" app:keyEdgeFlags="left"
app:keyLabel="123" app:keyLabel="123"
app:keyWidth="15%p" /> app:keyWidth="15%p" />
<Key <Key app:keyLabel="," />
app:keyLabel=","
app:keyWidth="10%p" />
<Key <Key
app:code="32" app:code="32"
app:isRepeatable="true" app:isRepeatable="true"