From ce6010198905d8ecdba67125b9fed5856c3d13c9 Mon Sep 17 00:00:00 2001 From: Willi Ye Date: Fri, 30 Apr 2021 21:38:13 +0200 Subject: [PATCH] Filter on screen buttons by controller type --- .../java/emu/skyline/EmulationActivity.kt | 14 +- .../input/onscreen/OnScreenControllerView.kt | 38 ++++-- .../input/onscreen/OnScreenItemDefinitions.kt | 122 +++++++++--------- app/src/main/res/layout/main_activity.xml | 3 +- 4 files changed, 97 insertions(+), 80 deletions(-) diff --git a/app/src/main/java/emu/skyline/EmulationActivity.kt b/app/src/main/java/emu/skyline/EmulationActivity.kt index 4898b1de..0be6ffa5 100644 --- a/app/src/main/java/emu/skyline/EmulationActivity.kt +++ b/app/src/main/java/emu/skyline/EmulationActivity.kt @@ -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 } diff --git a/app/src/main/java/emu/skyline/input/onscreen/OnScreenControllerView.kt b/app/src/main/java/emu/skyline/input/onscreen/OnScreenControllerView.kt index b8796539..f6b28f2f 100644 --- a/app/src/main/java/emu/skyline/input/onscreen/OnScreenControllerView.kt +++ b/app/src/main/java/emu/skyline/input/onscreen/OnScreenControllerView.kt @@ -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() + 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 } } diff --git a/app/src/main/java/emu/skyline/input/onscreen/OnScreenItemDefinitions.kt b/app/src/main/java/emu/skyline/input/onscreen/OnScreenItemDefinitions.kt index 1d8114a9..9d9ea616 100644 --- a/app/src/main/java/emu/skyline/input/onscreen/OnScreenItemDefinitions.kt +++ b/app/src/main/java/emu/skyline/input/onscreen/OnScreenItemDefinitions.kt @@ -12,25 +12,27 @@ 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 open class CircularButton( - onScreenControllerView : OnScreenControllerView, - buttonId : ButtonId, - defaultRelativeX : Float, - defaultRelativeY : Float, - defaultRelativeRadiusToX : Float, - drawableId : Int = R.drawable.ic_button + onScreenControllerView : OnScreenControllerView, + buttonId : ButtonId, + defaultRelativeX : Float, + defaultRelativeY : Float, + defaultRelativeRadiusToX : Float, + drawableId : Int = R.drawable.ic_button ) : OnScreenButton( - onScreenControllerView, - buttonId, - defaultRelativeX, - defaultRelativeY, - defaultRelativeRadiusToX * 2f, - defaultRelativeRadiusToX * CONFIGURED_ASPECT_RATIO * 2f, - drawableId + onScreenControllerView, + buttonId, + defaultRelativeX, + defaultRelativeY, + defaultRelativeRadiusToX * 2f, + defaultRelativeRadiusToX * CONFIGURED_ASPECT_RATIO * 2f, + drawableId ) { val radius get() = itemWidth / 2f @@ -49,18 +51,18 @@ open class CircularButton( } class JoystickButton( - onScreenControllerView : OnScreenControllerView, - buttonId : ButtonId, - defaultRelativeX : Float, - defaultRelativeY : Float, - defaultRelativeRadiusToX : Float + onScreenControllerView : OnScreenControllerView, + val stickId : StickId, + defaultRelativeX : Float, + defaultRelativeY : Float, + defaultRelativeRadiusToX : Float ) : CircularButton( - onScreenControllerView, - buttonId, - defaultRelativeX, - defaultRelativeY, - defaultRelativeRadiusToX, - R.drawable.ic_button + onScreenControllerView, + stickId.button, + defaultRelativeX, + defaultRelativeY, + defaultRelativeRadiusToX, + R.drawable.ic_button ) { private val innerButton = CircularButton(onScreenControllerView, buttonId, config.relativeX, config.relativeY, defaultRelativeRadiusToX * 0.75f, R.drawable.ic_stick) @@ -155,21 +157,21 @@ class JoystickButton( } open class RectangularButton( - onScreenControllerView : OnScreenControllerView, - buttonId : ButtonId, - defaultRelativeX : Float, - defaultRelativeY : Float, - defaultRelativeWidth : Float, - defaultRelativeHeight : Float, - drawableId : Int = R.drawable.ic_rectangular_button + onScreenControllerView : OnScreenControllerView, + buttonId : ButtonId, + defaultRelativeX : Float, + defaultRelativeY : Float, + defaultRelativeWidth : Float, + defaultRelativeHeight : Float, + drawableId : Int = R.drawable.ic_rectangular_button ) : OnScreenButton( - onScreenControllerView, - buttonId, - defaultRelativeX, - defaultRelativeY, - defaultRelativeWidth, - defaultRelativeHeight, - drawableId + onScreenControllerView, + buttonId, + defaultRelativeX, + defaultRelativeY, + defaultRelativeWidth, + defaultRelativeHeight, + drawableId ) { override fun isTouched(x : Float, y : Float) = currentBounds.contains(x.roundToInt(), y.roundToInt()) @@ -183,26 +185,26 @@ open class RectangularButton( } class TriggerButton( - onScreenControllerView : OnScreenControllerView, - buttonId : ButtonId, - defaultRelativeX : Float, - defaultRelativeY : Float, - defaultRelativeWidth : Float, - defaultRelativeHeight : Float + onScreenControllerView : OnScreenControllerView, + buttonId : ButtonId, + defaultRelativeX : Float, + defaultRelativeY : Float, + defaultRelativeWidth : Float, + defaultRelativeHeight : Float ) : RectangularButton( - onScreenControllerView, - buttonId, - defaultRelativeX, - defaultRelativeY, - defaultRelativeWidth, - defaultRelativeHeight, - when (buttonId) { - ZL -> R.drawable.ic_trigger_button_left + onScreenControllerView, + buttonId, + defaultRelativeX, + defaultRelativeY, + defaultRelativeWidth, + defaultRelativeHeight, + when (buttonId) { + ZL -> R.drawable.ic_trigger_button_left - ZR -> R.drawable.ic_trigger_button_right + ZR -> R.drawable.ic_trigger_button_right - else -> error("Unsupported trigger button") - } + else -> error("Unsupported trigger button") + } ) class Controls(onScreenControllerView : OnScreenControllerView) { @@ -229,14 +231,14 @@ class Controls(onScreenControllerView : OnScreenControllerView) { val buttonPairs = circularButtonPairs + triggerButtonPairs val circularButtons = circularButtonPairs.flatten() + listOf( - CircularButton(onScreenControllerView, Plus, 0.57f, 0.75f, 0.025f), - CircularButton(onScreenControllerView, Minus, 0.43f, 0.75f, 0.025f), - CircularButton(onScreenControllerView, Menu, 0.5f, 0.75f, 0.025f) + CircularButton(onScreenControllerView, Plus, 0.57f, 0.75f, 0.025f), + CircularButton(onScreenControllerView, Minus, 0.43f, 0.75f, 0.025f), + CircularButton(onScreenControllerView, Menu, 0.5f, 0.75f, 0.025f) ) 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) diff --git a/app/src/main/res/layout/main_activity.xml b/app/src/main/res/layout/main_activity.xml index aa0680ec..44c1cff7 100644 --- a/app/src/main/res/layout/main_activity.xml +++ b/app/src/main/res/layout/main_activity.xml @@ -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"> + app:layout_scrollFlags="scroll">