mirror of
https://github.com/SimpleMobileTools/Simple-Keyboard.git
synced 2025-02-18 12:50:36 +01:00
do not complicate the code with nearest keys, we have no corrections
This commit is contained in:
parent
8a1b68f826
commit
aedc35ff02
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user