diff --git a/app/src/main/java/emu/skyline/EmulationActivity.kt b/app/src/main/java/emu/skyline/EmulationActivity.kt index c2d3626e..768df54c 100644 --- a/app/src/main/java/emu/skyline/EmulationActivity.kt +++ b/app/src/main/java/emu/skyline/EmulationActivity.kt @@ -557,7 +557,7 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo return inputHandler.handleTouchEvent(view, event) } - private fun onButtonStateChanged(buttonId : ButtonId, state : ButtonState) = InputHandler.setButtonState(0, buttonId.value(), state.state) + private fun onButtonStateChanged(buttonId : ButtonId, state : ButtonState) = InputHandler.setButtonState(0, buttonId.value, state.state) private fun onStickStateChanged(stickId : StickId, position : PointF) { InputHandler.setAxisValue(0, stickId.xAxis.ordinal, (position.x * Short.MAX_VALUE).toInt()) diff --git a/app/src/main/java/emu/skyline/input/Controller.kt b/app/src/main/java/emu/skyline/input/Controller.kt index 544ccda1..630de870 100644 --- a/app/src/main/java/emu/skyline/input/Controller.kt +++ b/app/src/main/java/emu/skyline/input/Controller.kt @@ -13,13 +13,56 @@ import java.io.Serializable * * @param stringRes The string resource of the controller's name * @param firstController If the type only applies to the first controller + * @param optionalButtons Optional buttons that are allowed to be displayed on screen, but shouldn't be included in the controller mapping activity */ -enum class ControllerType(val stringRes : Int, val firstController : Boolean, val sticks : Array = arrayOf(), val buttons : Array = arrayOf(), val id : Int) { +enum class ControllerType(val stringRes : Int, val firstController : Boolean, val sticks : Array = arrayOf(), val buttons : Array = arrayOf(), val optionalButtons : Array = arrayOf(), val id : Int) { None(R.string.none, false, id = 0b0), - ProController(R.string.procon, false, arrayOf(StickId.Left, StickId.Right), arrayOf(ButtonId.A, ButtonId.B, ButtonId.X, ButtonId.Y, ButtonId.DpadUp, ButtonId.DpadDown, ButtonId.DpadLeft, ButtonId.DpadRight, ButtonId.L, ButtonId.R, ButtonId.ZL, ButtonId.ZR, ButtonId.Plus, ButtonId.Minus), 0b1), - HandheldProController(R.string.handheld_procon, true, arrayOf(StickId.Left, StickId.Right), arrayOf(ButtonId.A, ButtonId.B, ButtonId.X, ButtonId.Y, ButtonId.DpadUp, ButtonId.DpadDown, ButtonId.DpadLeft, ButtonId.DpadRight, ButtonId.L, ButtonId.R, ButtonId.ZL, ButtonId.ZR, ButtonId.Plus, ButtonId.Minus), 0b10), - JoyConLeft(R.string.ljoycon, false, arrayOf(StickId.Left), arrayOf(ButtonId.DpadUp, ButtonId.DpadDown, ButtonId.DpadLeft, ButtonId.DpadRight, ButtonId.L, ButtonId.ZL, ButtonId.Minus, ButtonId.LeftSL, ButtonId.LeftSR), 0b1000), - JoyConRight(R.string.rjoycon, false, arrayOf(StickId.Right), arrayOf(ButtonId.A, ButtonId.B, ButtonId.X, ButtonId.Y, ButtonId.R, ButtonId.ZR, ButtonId.Plus, ButtonId.RightSL, ButtonId.RightSR), 0b10000), + ProController( + R.string.procon, + false, + arrayOf(StickId.Left, StickId.Right), + arrayOf( + ButtonId.A, ButtonId.B, ButtonId.X, ButtonId.Y, + ButtonId.DpadUp, ButtonId.DpadDown, ButtonId.DpadLeft, ButtonId.DpadRight, + ButtonId.L, ButtonId.R, ButtonId.ZL, ButtonId.ZR, ButtonId.Plus, ButtonId.Minus + ), + arrayOf(ButtonId.L3, ButtonId.R3), + 0b1 + ), + HandheldProController( + R.string.handheld_procon, + true, + arrayOf(StickId.Left, StickId.Right), + arrayOf( + ButtonId.A, ButtonId.B, ButtonId.X, ButtonId.Y, + ButtonId.DpadUp, ButtonId.DpadDown, ButtonId.DpadLeft, ButtonId.DpadRight, + ButtonId.L, ButtonId.R, ButtonId.ZL, ButtonId.ZR, ButtonId.Plus, ButtonId.Minus + ), + arrayOf(ButtonId.L3, ButtonId.R3), + 0b10 + ), + JoyConLeft( + R.string.ljoycon, + false, + arrayOf(StickId.Left), + arrayOf( + ButtonId.DpadUp, ButtonId.DpadDown, ButtonId.DpadLeft, ButtonId.DpadRight, + ButtonId.L, ButtonId.ZL, ButtonId.Minus, ButtonId.LeftSL, ButtonId.LeftSR + ), + arrayOf(ButtonId.L3), + 0b1000 + ), + JoyConRight( + R.string.rjoycon, + false, + arrayOf(StickId.Right), + arrayOf( + ButtonId.A, ButtonId.B, ButtonId.X, ButtonId.Y, + ButtonId.R, ButtonId.ZR, ButtonId.Plus, ButtonId.RightSL, ButtonId.RightSR + ), + arrayOf(ButtonId.R3), + 0b10000 + ), } /** diff --git a/app/src/main/java/emu/skyline/input/GuestEvent.kt b/app/src/main/java/emu/skyline/input/GuestEvent.kt index f91e4c72..2f13557b 100644 --- a/app/src/main/java/emu/skyline/input/GuestEvent.kt +++ b/app/src/main/java/emu/skyline/input/GuestEvent.kt @@ -7,49 +7,44 @@ package emu.skyline.input import emu.skyline.R.string import java.io.Serializable -import java.util.* +import java.util.Objects import kotlin.math.abs /** * This enumerates all of the buttons that the emulator recognizes */ -enum class ButtonId(val short : String? = null, val long : Int? = null) { - A("A", string.a_button), - B("B", string.b_button), - X("X", string.x_button), - Y("Y", string.y_button), - LeftStick("L", string.left_stick), - RightStick("R", string.right_stick), - L("L", string.left_shoulder), - R("R", string.right_shoulder), - ZL("ZL", string.left_trigger), - ZR("ZR", string.right_trigger), - Plus("+", string.plus_button), - Minus("-", string.minus_button), - DpadLeft("◀︎", string.left), - DpadUp("▲︎", string.up), - DpadRight("▶︎", string.right), - DpadDown("▼︎", string.down), - LeftStickLeft, - LeftStickUp, - LeftStickRight, - LeftStickDown, - RightStickLeft, - RightStickUp, - RightStickRight, - RightStickDown, - LeftSL("SL", string.left_shoulder), - LeftSR("SR", string.right_shoulder), - RightSL("SL", string.left_shoulder), - RightSR("SR", string.right_shoulder), - Menu("⌂︎", string.emu_menu_button); - - /** - * This returns the value as setting the [ordinal]-th bit in a [Long] - */ - fun value() : Long { - return (1.toLong()) shl ordinal - } +enum class ButtonId(val value : Long, val short : String? = null, val long : Int? = null) { + A(1 shl 0, "A", string.a_button), + B(1 shl 1, "B", string.b_button), + X(1 shl 2, "X", string.x_button), + Y(1 shl 3, "Y", string.y_button), + LeftStick(1 shl 4, "L", string.left_stick), + RightStick(1 shl 5, "R", string.right_stick), + L3(1 shl 4, "L3", string.left_stick_button), + R3(1 shl 5, "R3", string.right_stick_button), + L(1 shl 6, "L", string.left_shoulder), + R(1 shl 7, "R", string.right_shoulder), + ZL(1 shl 8, "ZL", string.left_trigger), + ZR(1 shl 9, "ZR", string.right_trigger), + Plus(1 shl 10, "+", string.plus_button), + Minus(1 shl 11, "-", string.minus_button), + DpadLeft(1 shl 12, "◀︎", string.left), + DpadUp(1 shl 13, "▲︎", string.up), + DpadRight(1 shl 14, "▶︎", string.right), + DpadDown(1 shl 15, "▼︎", string.down), + LeftStickLeft(1 shl 16), + LeftStickUp(1 shl 17), + LeftStickRight(1 shl 18), + LeftStickDown(1 shl 19), + RightStickLeft(1 shl 20), + RightStickUp(1 shl 21), + RightStickRight(1 shl 22), + RightStickDown(1 shl 23), + LeftSL(1 shl 24, "SL", string.left_shoulder), + LeftSR(1 shl 25, "SR", string.right_shoulder), + RightSL(1 shl 26, "SL", string.left_shoulder), + RightSR(1 shl 27, "SR", string.right_shoulder), + Menu(1 shl 28, "⌂︎", string.emu_menu_button); } /** diff --git a/app/src/main/java/emu/skyline/input/InputHandler.kt b/app/src/main/java/emu/skyline/input/InputHandler.kt index d1512134..2955ca72 100644 --- a/app/src/main/java/emu/skyline/input/InputHandler.kt +++ b/app/src/main/java/emu/skyline/input/InputHandler.kt @@ -221,7 +221,7 @@ class InputHandler(private val inputManager : InputManager, private val emulatio return when (val guestEvent = inputManager.eventMap[KeyHostEvent(event.device.descriptor, event.keyCode)]) { is ButtonGuestEvent -> { if (guestEvent.button != ButtonId.Menu) - setButtonState(guestEvent.id, guestEvent.button.value(), action.state) + setButtonState(guestEvent.id, guestEvent.button.value, action.state) true } @@ -274,7 +274,7 @@ class InputHandler(private val inputManager : InputManager, private val emulatio is ButtonGuestEvent -> { val action = if (abs(value) >= guestEvent.threshold) ButtonState.Pressed.state else ButtonState.Released.state if (guestEvent.button != ButtonId.Menu) - setButtonState(guestEvent.id, guestEvent.button.value(), action) + setButtonState(guestEvent.id, guestEvent.button.value, action) } is AxisGuestEvent -> { diff --git a/app/src/main/java/emu/skyline/input/onscreen/OnScreenButton.kt b/app/src/main/java/emu/skyline/input/onscreen/OnScreenButton.kt index 060bbd04..0b8d14f9 100644 --- a/app/src/main/java/emu/skyline/input/onscreen/OnScreenButton.kt +++ b/app/src/main/java/emu/skyline/input/onscreen/OnScreenButton.kt @@ -27,7 +27,8 @@ abstract class OnScreenButton( private val defaultRelativeY : Float, private val defaultRelativeWidth : Float, private val defaultRelativeHeight : Float, - drawableId : Int + drawableId : Int, + private val defaultEnabled : Boolean ) { companion object { /** @@ -36,7 +37,7 @@ abstract class OnScreenButton( const val CONFIGURED_ASPECT_RATIO = 2074f / 874f } - val config = OnScreenConfiguration(onScreenControllerView.context, buttonId, defaultRelativeX, defaultRelativeY) + val config = OnScreenConfiguration(onScreenControllerView.context, buttonId, defaultRelativeX, defaultRelativeY, defaultEnabled) protected val drawable = ContextCompat.getDrawable(onScreenControllerView.context, drawableId)!! @@ -242,7 +243,7 @@ abstract class OnScreenButton( open fun resetConfig() { resetRelativeValues() - config.enabled = true + config.enabled = defaultEnabled config.scale = OnScreenConfiguration.DefaultScale } } diff --git a/app/src/main/java/emu/skyline/input/onscreen/OnScreenConfiguration.kt b/app/src/main/java/emu/skyline/input/onscreen/OnScreenConfiguration.kt index 06824f36..96bdfd62 100644 --- a/app/src/main/java/emu/skyline/input/onscreen/OnScreenConfiguration.kt +++ b/app/src/main/java/emu/skyline/input/onscreen/OnScreenConfiguration.kt @@ -10,7 +10,7 @@ import emu.skyline.input.ButtonId import emu.skyline.utils.SwitchColors import emu.skyline.utils.sharedPreferences -class OnScreenConfiguration(private val context : Context, private val buttonId : ButtonId, defaultRelativeX : Float, defaultRelativeY : Float) { +class OnScreenConfiguration(private val context : Context, private val buttonId : ButtonId, defaultRelativeX : Float, defaultRelativeY : Float, defaultEnabled : Boolean) { companion object { const val DefaultAlpha = 130 const val DefaultGlobalScale = 1.15f @@ -19,7 +19,7 @@ class OnScreenConfiguration(private val context : Context, private val buttonId private inline fun config(default : T, prefix : String = "${buttonId.name}_") = sharedPreferences(context, default, prefix, "controller_config") - var enabled by config(true) + var enabled by config(defaultEnabled) var alpha by config(DefaultAlpha, "") var textColor by config(SwitchColors.BLACK.color) 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 6aefe384..52a9ba43 100644 --- a/app/src/main/java/emu/skyline/input/onscreen/OnScreenControllerView.kt +++ b/app/src/main/java/emu/skyline/input/onscreen/OnScreenControllerView.kt @@ -35,7 +35,7 @@ typealias OnStickStateChangedListener = (stickId : StickId, position : PointF) - 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)) + it to (setOf(*it.buttons) + setOf(*it.optionalButtons) to setOf(*it.sticks)) }.toTypedArray()) private const val SCALE_STEP = 0.05f 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 2e981db2..f9c188cf 100644 --- a/app/src/main/java/emu/skyline/input/onscreen/OnScreenItemDefinitions.kt +++ b/app/src/main/java/emu/skyline/input/onscreen/OnScreenItemDefinitions.kt @@ -25,7 +25,8 @@ open class CircularButton( defaultRelativeX : Float, defaultRelativeY : Float, defaultRelativeRadiusToX : Float, - drawableId : Int = R.drawable.ic_button + drawableId : Int = R.drawable.ic_button, + defaultEnabled : Boolean = true ) : OnScreenButton( onScreenControllerView, buttonId, @@ -33,7 +34,8 @@ open class CircularButton( defaultRelativeY, defaultRelativeRadiusToX * 2f, defaultRelativeRadiusToX * CONFIGURED_ASPECT_RATIO * 2f, - drawableId + drawableId, + defaultEnabled ) { val radius get() = itemWidth / 2f @@ -60,7 +62,7 @@ class JoystickButton( private val innerButton = CircularButton(onScreenControllerView, buttonId, config.relativeX, config.relativeY, defaultRelativeRadiusToX * 0.75f, R.drawable.ic_stick) var recenterSticks = false - private lateinit var initialTapPosition : PointF + private var initialTapPosition = PointF() private var fingerDownTime = 0L private var fingerUpTime = 0L var shortDoubleTapped = false @@ -156,7 +158,8 @@ open class RectangularButton( defaultRelativeY : Float, defaultRelativeWidth : Float, defaultRelativeHeight : Float, - drawableId : Int = R.drawable.ic_rectangular_button + drawableId : Int = R.drawable.ic_rectangular_button, + defaultEnabled : Boolean = true ) : OnScreenButton( onScreenControllerView, buttonId, @@ -164,7 +167,8 @@ open class RectangularButton( defaultRelativeY, defaultRelativeWidth, defaultRelativeHeight, - drawableId + drawableId, + defaultEnabled ) { override fun isTouched(x : Float, y : Float) = currentBounds.contains(x.roundToInt(), y.roundToInt()) } @@ -209,13 +213,18 @@ class Controls(onScreenControllerView : OnScreenControllerView) { private val buttonZL = TriggerButton(onScreenControllerView, ZL, 0.1f, 0.1f, 0.09f, 0.1f) private val buttonZR = TriggerButton(onScreenControllerView, ZR, 0.9f, 0.1f, 0.09f, 0.1f) + private val buttonL3 = CircularButton(onScreenControllerView, L3, 0.35f, 0.87f, 0.025f, defaultEnabled = false) + private val buttonR3 = CircularButton(onScreenControllerView, R3, 0.65f, 0.87f, 0.025f, defaultEnabled = false) + private val circularButtonPairs = listOf(setOf(buttonA, buttonB, buttonX, buttonY), setOf(buttonDpadLeft, buttonDpadUp, buttonDpadRight, buttonDpadDown)) private val triggerButtonPairs = listOf(setOf(buttonL, buttonZL), setOf(buttonR, buttonZR)) + private val stickButtons = setOf(buttonL3, buttonR3) + val buttonPairs = circularButtonPairs + triggerButtonPairs - val circularButtons = circularButtonPairs.flatten() + listOf( + val circularButtons = circularButtonPairs.flatten() + stickButtons + 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) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7271b3fb..05426883 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -220,6 +220,8 @@ D-pad Left Stick Right Stick + Left Stick Button + Right Stick Button Face Buttons Shoulder & Trigger Buttons Shoulder Buttons on Joy-Con Rail