Re-engineer InputActivity for multi-touch support
This commit is contained in:
parent
a09d307f7e
commit
2169ad3259
|
@ -4,10 +4,10 @@ import android.os.Bundle
|
|||
import android.view.MotionEvent
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.widget.LinearLayoutCompat
|
||||
import io.gitlab.jfronny.hc05ac.util.Action
|
||||
import io.gitlab.jfronny.hc05ac.util.BaseActivity
|
||||
import io.gitlab.jfronny.hc05ac.util.clamp
|
||||
import io.gitlab.jfronny.hc05ac.util.jAction
|
||||
import io.gitlab.jfronny.hc05ac.util.putIfMissing
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Activity that divides the screen into two halves, each serving as an input controller.
|
||||
|
@ -25,41 +25,55 @@ abstract class InputActivity : BaseActivity() {
|
|||
rightView = findViewById(R.id.right)
|
||||
}
|
||||
|
||||
override fun onTouchEvent(event: MotionEvent?): Boolean {
|
||||
if (event != null) {
|
||||
if (event.x > root!!.width / 2) right(event.y, root!!.height.toFloat(), event.jAction)
|
||||
else left(event.y, root!!.height.toFloat(), event.jAction)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private var left: Byte = 0
|
||||
private var right: Byte = 0
|
||||
private val sides: MutableMap<Int, Side> = TreeMap()
|
||||
|
||||
private fun left(y: Float, height: Float, action: Action): Boolean {
|
||||
left = when (action) {
|
||||
Action.DOWN, Action.MOVE -> (127 - (y * 256 / height).clamp(0f, 256f)).toInt().toByte()
|
||||
Action.UP -> 0
|
||||
Action.OTHER -> return false
|
||||
override fun onTouchEvent(event: MotionEvent): Boolean {
|
||||
when (event.actionMasked) {
|
||||
MotionEvent.ACTION_UP -> {
|
||||
left = 0
|
||||
right = 0
|
||||
sides.clear()
|
||||
}
|
||||
MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN -> {
|
||||
val side = sides.putIfMissing(event.getPointerId(event.actionIndex)) {
|
||||
if (event.getX(event.actionIndex) > root!!.width / 2) Side.RIGHT
|
||||
else Side.LEFT
|
||||
}
|
||||
val mapped = screenToByte(event.getY(event.actionIndex))
|
||||
if (side == Side.LEFT) left = mapped
|
||||
else right = mapped
|
||||
}
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
for ((id, side) in sides) {
|
||||
val index = event.findPointerIndex(id)
|
||||
val mapped = screenToByte(event.getY(index))
|
||||
if (side == Side.LEFT) left = mapped
|
||||
else right = mapped
|
||||
}
|
||||
}
|
||||
MotionEvent.ACTION_POINTER_UP -> {
|
||||
val side = sides.remove(event.getPointerId(event.actionIndex))
|
||||
if (side != Side.LEFT) right = 0
|
||||
if (side != Side.RIGHT) left = 0
|
||||
}
|
||||
else -> return false
|
||||
}
|
||||
update()
|
||||
return false
|
||||
}
|
||||
|
||||
private fun right(y: Float, height: Float, action: Action): Boolean {
|
||||
right = when (action) {
|
||||
Action.DOWN, Action.MOVE -> (127 - (y * 256 / height).clamp(0f, 256f)).toInt().toByte()
|
||||
Action.UP -> 0
|
||||
Action.OTHER -> return false
|
||||
}
|
||||
update()
|
||||
return false
|
||||
}
|
||||
|
||||
private fun update() {
|
||||
leftView!!.text = left.toString()
|
||||
rightView!!.text = right.toString()
|
||||
send(left, right)
|
||||
return false
|
||||
}
|
||||
|
||||
private fun screenToByte(y: Float): Byte {
|
||||
val scaled = (y * 255f / root!!.height).toInt().clamp(0, 255)
|
||||
val mapped: Byte = scaled.xor(0x80).toByte()
|
||||
return (-mapped).toByte()
|
||||
}
|
||||
|
||||
private enum class Side {
|
||||
LEFT, RIGHT
|
||||
}
|
||||
|
||||
protected abstract fun send(left: Byte, right: Byte)
|
||||
|
|
|
@ -11,7 +11,6 @@ import android.net.Uri
|
|||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
import android.util.Log
|
||||
import android.view.MotionEvent
|
||||
import android.widget.Toast
|
||||
import androidx.core.app.ActivityCompat
|
||||
import kotlin.math.max
|
||||
|
@ -19,17 +18,6 @@ import kotlin.math.min
|
|||
|
||||
private val TAG = "HC05AC"
|
||||
|
||||
val MotionEvent.jAction get() = when (action) {
|
||||
MotionEvent.ACTION_UP -> Action.UP
|
||||
MotionEvent.ACTION_DOWN -> Action.DOWN
|
||||
MotionEvent.ACTION_MOVE -> Action.MOVE
|
||||
else -> Action.OTHER
|
||||
}
|
||||
|
||||
enum class Action {
|
||||
UP, DOWN, MOVE, OTHER;
|
||||
}
|
||||
|
||||
fun Context.goToNotificationSettings() {
|
||||
val intent = Intent()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
|
@ -53,7 +41,12 @@ fun Context.goToNotificationSettings() {
|
|||
startActivity(intent)
|
||||
}
|
||||
|
||||
fun Float.clamp(min: Float, max: Float) = min(max(this, min), max)
|
||||
fun <K, V> MutableMap<K, V>.putIfMissing(k: K, m: (K) -> V): V {
|
||||
if (!containsKey(k)) put(k, m(k))
|
||||
return get(k)!!
|
||||
}
|
||||
|
||||
fun Int.clamp(min: Int, max: Int) = min(max(this, min), max)
|
||||
|
||||
fun logI(message: String) = Log.i(TAG, message)
|
||||
|
||||
|
|
Loading…
Reference in New Issue