Filter on screen buttons by controller type

This commit is contained in:
Willi Ye 2021-04-30 21:38:13 +02:00 committed by ◱ Mark
parent 2ff06d5421
commit ce60101989
4 changed files with 97 additions and 80 deletions

View File

@ -218,7 +218,10 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
// Hide on screen controls when first controller is not set
binding.onScreenControllerView.apply {
isGone = inputManager.controllers[0]!!.type == ControllerType.None || !settings.onScreenControl
inputManager.controllers[0]!!.type.let {
controllerType = it
isGone = it == ControllerType.None || !settings.onScreenControl
}
setOnButtonStateChangedListener(::onButtonStateChanged)
setOnStickStateChangedListener(::onStickStateChanged)
recenterSticks = settings.onScreenControlRecenterSticks
@ -414,14 +417,7 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
private fun onButtonStateChanged(buttonId : ButtonId, state : ButtonState) = setButtonState(0, buttonId.value(), state.state)
private fun onStickStateChanged(buttonId : ButtonId, position : PointF) {
val stickId = when (buttonId) {
ButtonId.LeftStick -> StickId.Left
ButtonId.RightStick -> StickId.Right
else -> error("Invalid button ID")
}
private fun onStickStateChanged(stickId : StickId, position : PointF) {
setAxisValue(0, stickId.xAxis.ordinal, (position.x * Short.MAX_VALUE).toInt())
setAxisValue(0, stickId.yAxis.ordinal, (-position.y * Short.MAX_VALUE).toInt()) // Y is inverted, since drawing starts from top left
}

View File

@ -17,22 +17,35 @@ import android.view.View
import android.view.View.OnTouchListener
import emu.skyline.input.ButtonId
import emu.skyline.input.ButtonState
import emu.skyline.input.ControllerType
import emu.skyline.input.StickId
import emu.skyline.utils.add
import emu.skyline.utils.multiply
import emu.skyline.utils.normalize
import kotlin.math.roundToLong
typealias OnButtonStateChangedListener = (buttonId : ButtonId, state : ButtonState) -> Unit
typealias OnStickStateChangedListener = (buttonId : ButtonId, position : PointF) -> Unit
typealias OnStickStateChangedListener = (stickId : StickId, position : PointF) -> Unit
/**
* Renders On-Screen Controls as a single view, handles touch inputs and button toggling
*/
class OnScreenControllerView @JvmOverloads constructor(context : Context, attrs : AttributeSet? = null, defStyleAttr : Int = 0, defStyleRes : Int = 0) : View(context, attrs, defStyleAttr, defStyleRes) {
companion object {
private val controllerTypeMappings = mapOf(*ControllerType.values().map {
it to (setOf(*it.buttons) to setOf(*it.sticks))
}.toTypedArray())
}
private val controls = Controls(this)
private var onButtonStateChangedListener : OnButtonStateChangedListener? = null
private var onStickStateChangedListener : OnStickStateChangedListener? = null
private val joystickAnimators = mutableMapOf<JoystickButton, Animator?>()
var controllerType : ControllerType? = null
set(value) {
field = value
invalidate()
}
var recenterSticks = false
set(value) {
field = value
@ -42,11 +55,16 @@ class OnScreenControllerView @JvmOverloads constructor(context : Context, attrs
override fun onDraw(canvas : Canvas) {
super.onDraw(canvas)
controls.allButtons.forEach {
if (it.config.enabled) {
it.width = width
it.height = height
it.render(canvas)
val allowedIds = controllerTypeMappings[controllerType]
controls.allButtons.forEach { button ->
if (button.config.enabled
&& allowedIds?.let { (buttonIds, stickIds) ->
if (button is JoystickButton) stickIds.contains(button.stickId) else buttonIds.contains(button.buttonId)
} != false
) {
button.width = width
button.height = height
button.render(canvas)
}
}
}
@ -128,14 +146,14 @@ class OnScreenControllerView @JvmOverloads constructor(context : Context, attrs
val vector = direction.multiply(value)
val newPosition = position.add(vector)
joystick.onFingerMoved(newPosition.x, newPosition.y, false)
onStickStateChangedListener?.invoke(joystick.buttonId, vector.multiply(1f / radius))
onStickStateChangedListener?.invoke(joystick.stickId, vector.multiply(1f / radius))
invalidate()
}
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationCancel(animation : Animator?) {
super.onAnimationCancel(animation)
onAnimationEnd(animation)
onStickStateChangedListener?.invoke(joystick.buttonId, PointF(0f, 0f))
onStickStateChangedListener?.invoke(joystick.stickId, PointF(0f, 0f))
}
override fun onAnimationEnd(animation : Animator?) {
@ -163,7 +181,7 @@ class OnScreenControllerView @JvmOverloads constructor(context : Context, attrs
if (joystick.shortDoubleTapped)
onButtonStateChangedListener?.invoke(joystick.buttonId, ButtonState.Pressed)
if (recenterSticks)
onStickStateChangedListener?.invoke(joystick.buttonId, joystick.outerToInnerRelative())
onStickStateChangedListener?.invoke(joystick.stickId, joystick.outerToInnerRelative())
performClick()
handled = true
}
@ -173,7 +191,7 @@ class OnScreenControllerView @JvmOverloads constructor(context : Context, attrs
for (i in 0 until event.pointerCount) {
if (event.getPointerId(i) == joystick.touchPointerId) {
val centerToPoint = joystick.onFingerMoved(event.getX(i), event.getY(i))
onStickStateChangedListener?.invoke(joystick.buttonId, centerToPoint)
onStickStateChangedListener?.invoke(joystick.stickId, centerToPoint)
handled = true
}
}

View File

@ -12,6 +12,8 @@ import androidx.core.graphics.minus
import emu.skyline.R
import emu.skyline.input.ButtonId
import emu.skyline.input.ButtonId.*
import emu.skyline.input.StickId
import emu.skyline.input.StickId.*
import emu.skyline.utils.add
import emu.skyline.utils.multiply
import kotlin.math.roundToInt
@ -50,13 +52,13 @@ open class CircularButton(
class JoystickButton(
onScreenControllerView : OnScreenControllerView,
buttonId : ButtonId,
val stickId : StickId,
defaultRelativeX : Float,
defaultRelativeY : Float,
defaultRelativeRadiusToX : Float
) : CircularButton(
onScreenControllerView,
buttonId,
stickId.button,
defaultRelativeX,
defaultRelativeY,
defaultRelativeRadiusToX,
@ -235,8 +237,8 @@ class Controls(onScreenControllerView : OnScreenControllerView) {
)
val joysticks = listOf(
JoystickButton(onScreenControllerView, LeftStick, 0.1f, 0.8f, 0.05f),
JoystickButton(onScreenControllerView, RightStick, 0.75f, 0.6f, 0.05f)
JoystickButton(onScreenControllerView, Left, 0.1f, 0.8f, 0.05f),
JoystickButton(onScreenControllerView, Right, 0.75f, 0.6f, 0.05f)
)
val rectangularButtons = listOf(buttonL, buttonR)

View File

@ -4,6 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".MainActivity">
<com.google.android.material.appbar.AppBarLayout
@ -20,7 +21,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
app:layout_scrollFlags="enterAlwaysCollapsed">
app:layout_scrollFlags="scroll">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"