Re-engineer InputActivity for multi-touch support

This commit is contained in:
Johannes Frohnmeyer 2023-01-26 19:10:35 +01:00
parent a09d307f7e
commit 2169ad3259
Signed by: Johannes
GPG Key ID: E76429612C2929F4
2 changed files with 50 additions and 43 deletions

View File

@ -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)

View File

@ -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)