Expand Up @@ -154,10 +154,10 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
event.getY(pointerIndex).toInt()
)
) {
button.setPressedState(true)
button.setPressedState(if (button.latching) !button.getPressedState() else true)
button.trackId = event.getPointerId(pointerIndex)
pressed = true
InputOverrider.setControlState(controllerIndex, button.control, 1.0)
InputOverrider.setControlState(controllerIndex, button.control, if (button.getPressedState()) 1.0 else 0.0)

val analogControl = getAnalogControlForTrigger(button.control)
if (analogControl >= 0)
Expand All @@ -173,8 +173,9 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
MotionEvent.ACTION_POINTER_UP -> {
// If a pointer ends, release the button it was pressing.
if (button.trackId == event.getPointerId(pointerIndex)) {
button.setPressedState(false)
InputOverrider.setControlState(controllerIndex, button.control, 0.0)
if (!button.latching)
button.setPressedState(false)
InputOverrider.setControlState(controllerIndex, button.control, if (button.getPressedState()) 1.0 else 0.0)

val analogControl = getAnalogControlForTrigger(button.control)
if (analogControl >= 0)
Expand Down Expand Up @@ -497,7 +498,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
R.drawable.gcpad_a_pressed,
ButtonType.BUTTON_A,
ControlId.GCPAD_A_BUTTON,
orientation
orientation,
BooleanSetting.MAIN_BUTTON_LATCHING_GC_0.boolean
)
)
}
Expand All @@ -509,7 +511,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
R.drawable.gcpad_b_pressed,
ButtonType.BUTTON_B,
ControlId.GCPAD_B_BUTTON,
orientation
orientation,
BooleanSetting.MAIN_BUTTON_LATCHING_GC_1.boolean
)
)
}
Expand All @@ -521,7 +524,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
R.drawable.gcpad_x_pressed,
ButtonType.BUTTON_X,
ControlId.GCPAD_X_BUTTON,
orientation
orientation,
BooleanSetting.MAIN_BUTTON_LATCHING_GC_2.boolean
)
)
}
Expand All @@ -533,7 +537,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
R.drawable.gcpad_y_pressed,
ButtonType.BUTTON_Y,
ControlId.GCPAD_Y_BUTTON,
orientation
orientation,
BooleanSetting.MAIN_BUTTON_LATCHING_GC_3.boolean
)
)
}
Expand All @@ -545,7 +550,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
R.drawable.gcpad_z_pressed,
ButtonType.BUTTON_Z,
ControlId.GCPAD_Z_BUTTON,
orientation
orientation,
BooleanSetting.MAIN_BUTTON_LATCHING_GC_4.boolean
)
)
}
Expand All @@ -557,7 +563,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
R.drawable.gcpad_start_pressed,
ButtonType.BUTTON_START,
ControlId.GCPAD_START_BUTTON,
orientation
orientation,
BooleanSetting.MAIN_BUTTON_LATCHING_GC_5.boolean
)
)
}
Expand All @@ -569,7 +576,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
R.drawable.gcpad_l_pressed,
ButtonType.TRIGGER_L,
ControlId.GCPAD_L_DIGITAL,
orientation
orientation,
BooleanSetting.MAIN_BUTTON_LATCHING_GC_6.boolean
)
)
}
Expand All @@ -581,7 +589,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
R.drawable.gcpad_r_pressed,
ButtonType.TRIGGER_R,
ControlId.GCPAD_R_DIGITAL,
orientation
orientation,
BooleanSetting.MAIN_BUTTON_LATCHING_GC_7.boolean
)
)
}
Expand Down Expand Up @@ -640,7 +649,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
R.drawable.wiimote_a_pressed,
ButtonType.WIIMOTE_BUTTON_A,
ControlId.WIIMOTE_A_BUTTON,
orientation
orientation,
BooleanSetting.MAIN_BUTTON_LATCHING_WII_0.boolean
)
)
}
Expand All @@ -652,7 +662,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
R.drawable.wiimote_b_pressed,
ButtonType.WIIMOTE_BUTTON_B,
ControlId.WIIMOTE_B_BUTTON,
orientation
orientation,
BooleanSetting.MAIN_BUTTON_LATCHING_WII_1.boolean
)
)
}
Expand All @@ -664,7 +675,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
R.drawable.wiimote_one_pressed,
ButtonType.WIIMOTE_BUTTON_1,
ControlId.WIIMOTE_ONE_BUTTON,
orientation
orientation,
BooleanSetting.MAIN_BUTTON_LATCHING_WII_2.boolean
)
)
}
Expand All @@ -676,7 +688,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
R.drawable.wiimote_two_pressed,
ButtonType.WIIMOTE_BUTTON_2,
ControlId.WIIMOTE_TWO_BUTTON,
orientation
orientation,
BooleanSetting.MAIN_BUTTON_LATCHING_WII_3.boolean
)
)
}
Expand All @@ -688,7 +701,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
R.drawable.wiimote_plus_pressed,
ButtonType.WIIMOTE_BUTTON_PLUS,
ControlId.WIIMOTE_PLUS_BUTTON,
orientation
orientation,
BooleanSetting.MAIN_BUTTON_LATCHING_WII_4.boolean
)
)
}
Expand All @@ -700,7 +714,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
R.drawable.wiimote_minus_pressed,
ButtonType.WIIMOTE_BUTTON_MINUS,
ControlId.WIIMOTE_MINUS_BUTTON,
orientation
orientation,
BooleanSetting.MAIN_BUTTON_LATCHING_WII_5.boolean
)
)
}
Expand All @@ -712,7 +727,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
R.drawable.wiimote_home_pressed,
ButtonType.WIIMOTE_BUTTON_HOME,
ControlId.WIIMOTE_HOME_BUTTON,
orientation
orientation,
BooleanSetting.MAIN_BUTTON_LATCHING_WII_6.boolean
)
)
}
Expand Down Expand Up @@ -743,7 +759,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
R.drawable.nunchuk_c_pressed,
ButtonType.NUNCHUK_BUTTON_C,
ControlId.NUNCHUK_C_BUTTON,
orientation
orientation,
BooleanSetting.MAIN_BUTTON_LATCHING_WII_8.boolean
)
)
}
Expand All @@ -755,7 +772,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
R.drawable.nunchuk_z_pressed,
ButtonType.NUNCHUK_BUTTON_Z,
ControlId.NUNCHUK_Z_BUTTON,
orientation
orientation,
BooleanSetting.MAIN_BUTTON_LATCHING_WII_9.boolean
)
)
}
Expand Down Expand Up @@ -784,7 +802,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
R.drawable.classic_a_pressed,
ButtonType.CLASSIC_BUTTON_A,
ControlId.CLASSIC_A_BUTTON,
orientation
orientation,
BooleanSetting.MAIN_BUTTON_LATCHING_CLASSIC_0.boolean
)
)
}
Expand All @@ -796,7 +815,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
R.drawable.classic_b_pressed,
ButtonType.CLASSIC_BUTTON_B,
ControlId.CLASSIC_B_BUTTON,
orientation
orientation,
BooleanSetting.MAIN_BUTTON_LATCHING_CLASSIC_1.boolean
)
)
}
Expand All @@ -808,7 +828,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
R.drawable.classic_x_pressed,
ButtonType.CLASSIC_BUTTON_X,
ControlId.CLASSIC_X_BUTTON,
orientation
orientation,
BooleanSetting.MAIN_BUTTON_LATCHING_CLASSIC_2.boolean
)
)
}
Expand All @@ -820,7 +841,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
R.drawable.classic_y_pressed,
ButtonType.CLASSIC_BUTTON_Y,
ControlId.CLASSIC_Y_BUTTON,
orientation
orientation,
BooleanSetting.MAIN_BUTTON_LATCHING_CLASSIC_3.boolean
)
)
}
Expand All @@ -832,7 +854,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
R.drawable.wiimote_plus_pressed,
ButtonType.CLASSIC_BUTTON_PLUS,
ControlId.CLASSIC_PLUS_BUTTON,
orientation
orientation,
BooleanSetting.MAIN_BUTTON_LATCHING_CLASSIC_4.boolean
)
)
}
Expand All @@ -844,7 +867,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
R.drawable.wiimote_minus_pressed,
ButtonType.CLASSIC_BUTTON_MINUS,
ControlId.CLASSIC_MINUS_BUTTON,
orientation
orientation,
BooleanSetting.MAIN_BUTTON_LATCHING_CLASSIC_5.boolean
)
)
}
Expand All @@ -856,7 +880,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
R.drawable.wiimote_home_pressed,
ButtonType.CLASSIC_BUTTON_HOME,
ControlId.CLASSIC_HOME_BUTTON,
orientation
orientation,
BooleanSetting.MAIN_BUTTON_LATCHING_CLASSIC_6.boolean
)
)
}
Expand All @@ -868,7 +893,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
R.drawable.classic_l_pressed,
ButtonType.CLASSIC_TRIGGER_L,
ControlId.CLASSIC_L_DIGITAL,
orientation
orientation,
BooleanSetting.MAIN_BUTTON_LATCHING_CLASSIC_7.boolean
)
)
}
Expand All @@ -880,7 +906,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
R.drawable.classic_r_pressed,
ButtonType.CLASSIC_TRIGGER_R,
ControlId.CLASSIC_R_DIGITAL,
orientation
orientation,
BooleanSetting.MAIN_BUTTON_LATCHING_CLASSIC_8.boolean
)
)
}
Expand All @@ -892,7 +919,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
R.drawable.classic_zl_pressed,
ButtonType.CLASSIC_BUTTON_ZL,
ControlId.CLASSIC_ZL_BUTTON,
orientation
orientation,
BooleanSetting.MAIN_BUTTON_LATCHING_CLASSIC_9.boolean
)
)
}
Expand All @@ -904,7 +932,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
R.drawable.classic_zr_pressed,
ButtonType.CLASSIC_BUTTON_ZR,
ControlId.CLASSIC_ZR_BUTTON,
orientation
orientation,
BooleanSetting.MAIN_BUTTON_LATCHING_CLASSIC_10.boolean
)
)
}
Expand Down Expand Up @@ -1094,11 +1123,17 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
* @param pressedResId The resource ID of the [Drawable] to get the [Bitmap] of (Pressed State).
* @param legacyId Legacy identifier for the button the InputOverlayDrawableButton represents.
* @param control Control identifier for the button the InputOverlayDrawableButton represents.
* @param latching Whether the button is latching.
* @return An [InputOverlayDrawableButton] with the correct drawing bounds set.
*/
private fun initializeOverlayButton(
context: Context,
defaultResId: Int, pressedResId: Int, legacyId: Int, control: Int, orientation: String
defaultResId: Int,
pressedResId: Int,
legacyId: Int,
control: Int,
orientation: String,
latching: Boolean
): InputOverlayDrawableButton {
// Decide scale based on button ID and user preference
var scale = when (legacyId) {
Expand Down Expand Up @@ -1140,12 +1175,14 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
resizeBitmap(context, BitmapFactory.decodeResource(resources, defaultResId), scale)
val pressedStateBitmap =
resizeBitmap(context, BitmapFactory.decodeResource(resources, pressedResId), scale)

val overlayDrawable = InputOverlayDrawableButton(
resources,
defaultStateBitmap,
pressedStateBitmap,
legacyId,
control
control,
latching
)

// The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay.
Expand Down
Expand Up @@ -18,13 +18,15 @@ import android.view.MotionEvent
* @param pressedStateBitmap [Bitmap] to use with the pressed state Drawable.
* @param legacyId Legacy identifier (ButtonType) for this type of button.
* @param control Control ID for this type of button.
* @param latching Whether this button is latching.
*/
class InputOverlayDrawableButton(
res: Resources,
defaultStateBitmap: Bitmap,
pressedStateBitmap: Bitmap,
val legacyId: Int,
val control: Int
val control: Int,
var latching: Boolean
) {
var trackId: Int = -1
private var previousTouchX = 0
Expand Down Expand Up @@ -94,4 +96,8 @@ class InputOverlayDrawableButton(
fun setPressedState(isPressed: Boolean) {
pressedState = isPressed
}

fun getPressedState(): Boolean {
return pressedState;
}
}
Expand Up @@ -10,6 +10,10 @@
android:id="@+id/menu_emulation_toggle_controls"
android:title="@string/emulation_toggle_controls"/>

<item
android:id="@+id/menu_emulation_latching_controls"
android:title="@string/emulation_latching_controls"/>

<item
android:id="@+id/menu_emulation_adjust_scale"
android:title="@string/emulation_control_adjustments"/>
Expand Down
Expand Up @@ -10,6 +10,10 @@
android:id="@+id/menu_emulation_toggle_controls"
android:title="@string/emulation_toggle_controls"/>

<item
android:id="@+id/menu_emulation_latching_controls"
android:title="@string/emulation_latching_controls"/>

<item
android:id="@+id/menu_emulation_adjust_scale"
android:title="@string/emulation_control_adjustments"/>
Expand Down
47 changes: 47 additions & 0 deletions Source/Android/app/src/main/res/values/arrays.xml
Expand Up @@ -400,6 +400,17 @@
<item>@string/gamepad_c_stick</item>
</string-array>

<string-array name="gcpadLatchableButtons">
<item>A</item>
<item>B</item>
<item>X</item>
<item>Y</item>
<item>Z</item>
<item>@string/gamepad_start</item>
<item>L</item>
<item>R</item>
</string-array>

<string-array name="wiimoteButtons">
<item>A</item>
<item>B</item>
Expand All @@ -411,6 +422,16 @@
<item>@string/gamepad_d_pad</item>
</string-array>

<string-array name="wiimoteLatchableButtons">
<item>A</item>
<item>B</item>
<item>1</item>
<item>2</item>
<item>+</item>
<item>-</item>
<item>@string/gamepad_home</item>
</string-array>

<string-array name="nunchukButtons">
<item>A</item>
<item>B</item>
Expand All @@ -425,6 +446,18 @@
<item>@string/gamepad_nunchuk_stick</item>
</string-array>

<string-array name="nunchukLatchableButtons">
<item>A</item>
<item>B</item>
<item>1</item>
<item>2</item>
<item>+</item>
<item>-</item>
<item>@string/gamepad_home</item>
<item>C</item>
<item>Z</item>
</string-array>

<string-array name="classicButtons">
<item>a</item>
<item>b</item>
Expand All @@ -442,6 +475,20 @@
<item>@string/gamepad_right_stick</item>
</string-array>

<string-array name="classicLatchableButtons">
<item>a</item>
<item>b</item>
<item>x</item>
<item>y</item>
<item>+</item>
<item>-</item>
<item>@string/gamepad_home</item>
<item>L</item>
<item>R</item>
<item>ZL</item>
<item>ZR</item>
</string-array>

<string-array name="irModeEntries">
<item>@string/ir_disabled</item>
<item>@string/ir_follow</item>
Expand Down
1 change: 1 addition & 0 deletions Source/Android/app/src/main/res/values/strings.xml
Expand Up @@ -571,6 +571,7 @@ It can efficiently compress both junk data and encrypted Wii data.
<string name="emulation_edit_layout">Edit Layout</string>
<string name="emulation_done">Done</string>
<string name="emulation_toggle_controls">Toggle Controls</string>
<string name="emulation_latching_controls">Latching Controls</string>
<string name="emulation_toggle_all">Toggle All</string>
<string name="emulation_control_scale">Scale</string>
<string name="emulation_control_opacity">Opacity</string>
Expand Down