Add separate L3 and R3 buttons to OSC

As part of this commit, a `defaultEnabled` property was added to `OnScreenButton` to determine the default visibility of buttons. This is required because L3 and R3 should be hidden by default and only enabled by the user on demand.
Additionally, the buttons' mask values were added to `ButtonId` members, as adding entries in the middle of the class conflicted with the `ordinal` enum property, making it unfit to use for our purposes.
Finally, the `ControllerType` class was extended with an array of optional buttons. Optional buttons represent buttons that are allowed to be displayed on screen, but shouldn't be included in the controller mapping activity.
This commit is contained in:
lynxnb 2023-03-18 00:26:32 +01:00 committed by Niccolò Betto
parent acdf4e6823
commit a799cb63f1
9 changed files with 108 additions and 58 deletions

View File

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

View File

@ -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<StickId> = arrayOf(), val buttons : Array<ButtonId> = arrayOf(), val id : Int) {
enum class ControllerType(val stringRes : Int, val firstController : Boolean, val sticks : Array<StickId> = arrayOf(), val buttons : Array<ButtonId> = arrayOf(), val optionalButtons : Array<ButtonId> = 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
),
}
/**

View File

@ -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);
}
/**

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -220,6 +220,8 @@
<string name="dpad">D-pad</string>
<string name="left_stick">Left Stick</string>
<string name="right_stick">Right Stick</string>
<string name="left_stick_button">Left Stick Button</string>
<string name="right_stick_button">Right Stick Button</string>
<string name="face_buttons">Face Buttons</string>
<string name="shoulder_trigger">Shoulder &amp; Trigger Buttons</string>
<string name="shoulder_rail">Shoulder Buttons on Joy-Con Rail</string>