Changed Combo Button to be a HotKey, changed impl to be default multi choice, and removed StringMultiChoice details

This commit is contained in:
ADAS2024 2026-04-14 17:28:27 -04:00
parent 485778be95
commit c91fb120b1
15 changed files with 98 additions and 243 deletions

View file

@ -12,5 +12,6 @@ enum class Hotkey(val button: Int) {
QUICKSAVE(10005),
QUICKLOAD(10006),
TURBO_LIMIT(10007),
ENABLE(10008);
ENABLE(10008),
COMBO_KEY(10009);
}

View file

@ -13,9 +13,11 @@ import org.citra.citra_emu.NativeLibrary
import org.citra.citra_emu.R
import org.citra.citra_emu.utils.EmulationLifecycleUtil
import org.citra.citra_emu.utils.TurboHelper
import org.citra.citra_emu.utils.ComboHelper
import org.citra.citra_emu.display.ScreenAdjustmentUtil
import org.citra.citra_emu.features.settings.model.view.InputBindingSetting
import org.citra.citra_emu.features.settings.model.Settings
import org.citra.citra_emu.utils.Log
class HotkeyUtility(
private val screenAdjustmentUtil: ScreenAdjustmentUtil,
@ -81,6 +83,7 @@ class HotkeyUtility(
// this is a hotkey button
if (hotkeyButtons.contains(button)) {
currentlyPressedButtons.remove(button)
handleHotkeyRelease(button)
if (!currentlyPressedButtons.any { hotkeyButtons.contains(it) }) {
// all hotkeys are no longer pressed
hotkeyIsPressed = false
@ -106,6 +109,14 @@ class HotkeyUtility(
return handled
}
fun handleHotkeyRelease(bindedButton: Int): Boolean {
Log.debug("Handling hotkey button release: " + bindedButton)
if (bindedButton == Hotkey.COMBO_KEY.button) {
ComboHelper.comboActivate(NativeLibrary.ButtonState.RELEASED)
}
return true
}
fun handleHotkey(bindedButton: Int): Boolean {
when (bindedButton) {
Hotkey.SWAP_SCREEN.button -> screenAdjustmentUtil.swapScreen()
@ -121,7 +132,6 @@ class HotkeyUtility(
Toast.LENGTH_SHORT
).show()
}
Hotkey.QUICKLOAD.button -> {
val wasLoaded = NativeLibrary.loadStateIfAvailable(NativeLibrary.QUICKSAVE_SLOT)
val stringRes = if (wasLoaded) {
@ -135,6 +145,9 @@ class HotkeyUtility(
Toast.LENGTH_SHORT
).show()
}
Hotkey.COMBO_KEY.button -> {
ComboHelper.comboActivate(NativeLibrary.ButtonState.PRESSED)
}
else -> {}
}

View file

@ -55,8 +55,7 @@ enum class BooleanSetting(
COMPRESS_INSTALLED_CIA_CONTENT(SettingKeys.compress_cia_installs(), Settings.SECTION_STORAGE, false),
ANDROID_HIDE_IMAGES(SettingKeys.android_hide_images(), Settings.SECTION_MISC, false),
APPLY_REGION_FREE_PATCH(SettingKeys.apply_region_free_patch(), Settings.SECTION_SYSTEM, true),
USE_INTEGER_SCALING(SettingKeys.use_integer_scaling(), Settings.SECTION_RENDERER, false),
ENABLE_COMBO_KEY("enable_combo_key", Settings.SECTION_CONTROLS, true);
USE_INTEGER_SCALING(SettingKeys.use_integer_scaling(), Settings.SECTION_RENDERER, false);
override var boolean: Boolean = defaultValue

View file

@ -11,7 +11,8 @@ enum class IntListSetting(
val canBeEmpty: Boolean = true
) : AbstractListSetting<Int> {
LAYOUTS_TO_CYCLE("layouts_to_cycle", Settings.SECTION_LAYOUT, listOf(0, 1, 2, 3, 4, 5), canBeEmpty = false);
LAYOUTS_TO_CYCLE("layouts_to_cycle", Settings.SECTION_LAYOUT, listOf(0, 1, 2, 3, 4, 5), canBeEmpty = false),
COMBO_KEYS("combo_keys", Settings.SECTION_CONTROLS, listOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), canBeEmpty = true);
private var backingList: List<Int> = defaultValue
private var lastValidList : List<Int> = defaultValue

View file

@ -146,6 +146,7 @@ class Settings {
const val HOTKEY_QUICKSAVE = "hotkey_quickload"
const val HOTKEY_QUICKlOAD = "hotkey_quickpause"
const val HOTKEY_TURBO_LIMIT = "hotkey_turbo_limit"
const val HOTKEY_BUTTON_COMBO = "hotkey_button_combo"
val buttonKeys = listOf(
KEY_BUTTON_A,
@ -154,8 +155,7 @@ class Settings {
KEY_BUTTON_Y,
KEY_BUTTON_SELECT,
KEY_BUTTON_START,
KEY_BUTTON_HOME,
KEY_BUTTON_COMBO
KEY_BUTTON_HOME
)
val buttonTitles = listOf(
R.string.button_a,
@ -164,8 +164,7 @@ class Settings {
R.string.button_y,
R.string.button_select,
R.string.button_start,
R.string.button_home,
R.string.button_combo
R.string.button_home
)
val circlePadKeys = listOf(
KEY_CIRCLEPAD_AXIS_VERTICAL,
@ -215,7 +214,8 @@ class Settings {
HOTKEY_PAUSE_OR_RESUME,
HOTKEY_QUICKSAVE,
HOTKEY_QUICKlOAD,
HOTKEY_TURBO_LIMIT
HOTKEY_TURBO_LIMIT,
HOTKEY_BUTTON_COMBO
)
val hotkeyTitles = listOf(
R.string.controller_hotkey_enable_button,
@ -225,7 +225,8 @@ class Settings {
R.string.emulation_toggle_pause,
R.string.emulation_quicksave,
R.string.emulation_quickload,
R.string.turbo_limit_hotkey
R.string.turbo_limit_hotkey,
R.string.button_combo
)
// TODO: Move these in with the other setting keys in GenerateSettingKeys.cmake

View file

@ -1,52 +0,0 @@
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
package org.citra.citra_emu.features.settings.model
enum class StringListSetting(
override val key: String,
override val section: String,
override val defaultValue: List<String>,
val canBeEmpty: Boolean = true
) : AbstractListSetting<String> {
COMBO_KEYS("combo_keys", Settings.SECTION_CONTROLS, listOf("A", "B", "X", "Y", "L", "R", "ZL", "ZR", "Start", "Select"));
private var backingList: List<String> = defaultValue
private var lastValidList : List<String> = defaultValue
override var list: List<String>
get() = backingList
set(value) {
if (!canBeEmpty && value.isEmpty()) {
backingList = lastValidList
} else {
backingList = value
lastValidList = value
}
}
override val valueAsString: String
get() = list.joinToString()
override val isRuntimeEditable: Boolean
get() {
for (setting in NOT_RUNTIME_EDITABLE) {
if (setting == this) {
return false
}
}
return true
}
companion object {
private val NOT_RUNTIME_EDITABLE:List<StringListSetting> = listOf();
fun from(key: String): StringListSetting? =
values().firstOrNull { it.key == key }
fun clear() = values().forEach { it.list = it.defaultValue }
}
}

View file

@ -125,7 +125,7 @@ class InputBindingSetting(
Settings.KEY_BUTTON_SELECT -> NativeLibrary.ButtonType.BUTTON_SELECT
Settings.KEY_BUTTON_START -> NativeLibrary.ButtonType.BUTTON_START
Settings.KEY_BUTTON_HOME -> NativeLibrary.ButtonType.BUTTON_HOME
Settings.KEY_BUTTON_COMBO -> NativeLibrary.ButtonType.BUTTON_COMBO
//Settings.KEY_BUTTON_COMBO -> NativeLibrary.ButtonType.BUTTON_COMBO
Settings.KEY_BUTTON_UP -> NativeLibrary.ButtonType.DPAD_UP
Settings.KEY_BUTTON_DOWN -> NativeLibrary.ButtonType.DPAD_DOWN
Settings.KEY_BUTTON_LEFT -> NativeLibrary.ButtonType.DPAD_LEFT
@ -138,6 +138,7 @@ class InputBindingSetting(
Settings.HOTKEY_QUICKSAVE -> Hotkey.QUICKSAVE.button
Settings.HOTKEY_QUICKlOAD -> Hotkey.QUICKLOAD.button
Settings.HOTKEY_TURBO_LIMIT -> Hotkey.TURBO_LIMIT.button
Settings.HOTKEY_BUTTON_COMBO -> Hotkey.COMBO_KEY.button
else -> -1
}

View file

@ -1,53 +0,0 @@
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
package org.citra.citra_emu.features.settings.model.view
import org.citra.citra_emu.features.settings.model.AbstractSetting
import org.citra.citra_emu.features.settings.model.StringListSetting
class StringMultiChoiceSetting(
setting: AbstractSetting?,
titleId: Int,
descriptionId: Int,
val choices: Array<String>,
val values: Array<String>?,
val key: String? = null,
private val defaultValue: List<String>? = null,
override var isEnabled: Boolean = true
) : SettingsItem(setting, titleId, descriptionId) {
override val type = TYPE_STRING_MULTI_CHOICE
fun getValueAt(index: Int): String? {
if (values == null) return null
return if (index >= 0 && index < values.size) {
values[index]
} else {
""
}
}
val selectedValues: List<String>
get() {
if (setting == null) {
return defaultValue!!
}
try {
val setting = setting as StringListSetting
return setting.list
}catch (_: ClassCastException) {
}
return defaultValue!!
}
/**
* Write a value to the backing list. If that list was previously null,
* initializes a new one and returns it, so it can be added to the Hashmap.
*
* @param selection New value of the int.
* @return the existing setting with the new value applied.
*/
fun setSelectedValue(selection: List<String>): StringListSetting {
val stringSetting = setting as StringListSetting
stringSetting.list = selection
return stringSetting
}
}

View file

@ -52,7 +52,6 @@ import org.citra.citra_emu.features.settings.model.view.SingleChoiceSetting
import org.citra.citra_emu.features.settings.model.view.MultiChoiceSetting
import org.citra.citra_emu.features.settings.model.view.SliderSetting
import org.citra.citra_emu.features.settings.model.view.StringInputSetting
import org.citra.citra_emu.features.settings.model.view.StringMultiChoiceSetting
import org.citra.citra_emu.features.settings.model.view.StringSingleChoiceSetting
import org.citra.citra_emu.features.settings.model.view.SubmenuSetting
import org.citra.citra_emu.features.settings.model.view.SwitchSetting
@ -139,10 +138,6 @@ class SettingsAdapter(
StringInputViewHolder(ListItemSettingBinding.inflate(inflater), this)
}
SettingsItem.TYPE_MULTI_CHOICE, SettingsItem.TYPE_STRING_MULTI_CHOICE -> {
MultiChoiceViewHolder(ListItemSettingBinding.inflate(inflater), this)
}
else -> {
// TODO: Create an error view since we can't return null now
HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this)
@ -208,10 +203,6 @@ class SettingsAdapter(
SettingsItem.TYPE_MULTI_CHOICE -> {
(oldItem as MultiChoiceSetting).isEnabled == (newItem as MultiChoiceSetting).isEnabled
}
SettingsItem.TYPE_STRING_MULTI_CHOICE -> {
(oldItem as StringMultiChoiceSetting).isEnabled == (newItem as StringMultiChoiceSetting).isEnabled
}
SettingsItem.TYPE_DATETIME_SETTING -> {
(oldItem as DateTimeSetting).isEnabled == (newItem as DateTimeSetting).isEnabled
@ -282,26 +273,6 @@ class SettingsAdapter(
onMultiChoiceClick(item)
}
private fun onStringMultiChoiceClick(item: StringMultiChoiceSetting) {
clickedItem = item
val values: BooleanArray = getSelectionForStringMultiChoiceValue(item);
dialog = MaterialAlertDialogBuilder(context)
.setTitle(item.nameId)
.setMultiChoiceItems(item.choices, values, this)
.setOnDismissListener {
if (clickedPosition != -1) {
notifyItemChanged(clickedPosition)
clickedPosition = -1
}
}
.show()
}
fun onStringMultiChoiceClick(item: StringMultiChoiceSetting, position: Int) {
clickedPosition = position
onStringMultiChoiceClick(item)
}
private fun onStringSingleChoiceClick(item: StringSingleChoiceSetting) {
clickedItem = item
dialog = context?.let {
@ -616,20 +587,6 @@ class SettingsAdapter(
fragmentView.loadSettingsList()
}
}
is StringMultiChoiceSetting -> {
val mcsetting = clickedItem as? StringMultiChoiceSetting
mcsetting?.let {
val value = it.getValueAt(which)
if (it.selectedValues.contains(value) != isChecked) {
val setting =
it.setSelectedValue((if (isChecked) it.selectedValues + value.toString() else it.selectedValues - value.toString()))
fragmentView?.putSetting(setting)
fragmentView?.onSettingChanged()
}
fragmentView.loadSettingsList()
}
}
}
}
@ -798,26 +755,4 @@ class SettingsAdapter(
return BooleanArray(1){false};
}
//TODO: Properly Implement in line with string single choice
private fun getSelectionForStringMultiChoiceValue(item: StringMultiChoiceSetting): BooleanArray {
val values = item.selectedValues;
val available_values = item.values;
val res = BooleanArray(available_values?.size ?: 10){false} // 10 is used because we have 10 reasonable options.
// prob shouldn't hardcode the size value here
if (available_values != null) {
for (choice_val in available_values) {
if (values.contains(choice_val)) {
val index = available_values.indexOf(choice_val)
res[index] = true;
}
}
}
return if (res.isNotEmpty()) {
res;
} else {
BooleanArray(1) { false };
}
}
}

View file

@ -31,7 +31,6 @@ import org.citra.citra_emu.features.settings.model.IntSetting
import org.citra.citra_emu.features.settings.model.IntListSetting
import org.citra.citra_emu.features.settings.model.ScaledFloatSetting
import org.citra.citra_emu.features.settings.model.Settings
import org.citra.citra_emu.features.settings.model.StringListSetting
import org.citra.citra_emu.features.settings.model.StringSetting
import org.citra.citra_emu.features.settings.model.view.DateTimeSetting
import org.citra.citra_emu.features.settings.model.view.HeaderSetting
@ -42,7 +41,6 @@ import org.citra.citra_emu.features.settings.model.view.SettingsItem
import org.citra.citra_emu.features.settings.model.view.SingleChoiceSetting
import org.citra.citra_emu.features.settings.model.view.SliderSetting
import org.citra.citra_emu.features.settings.model.view.StringInputSetting
import org.citra.citra_emu.features.settings.model.view.StringMultiChoiceSetting
import org.citra.citra_emu.features.settings.model.view.StringSingleChoiceSetting
import org.citra.citra_emu.features.settings.model.view.SubmenuSetting
import org.citra.citra_emu.features.settings.model.view.SwitchSetting
@ -843,16 +841,15 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
)
)
val buttons = settingsActivity.resources.getStringArray(R.array.n3dsButtons).take(10).toTypedArray()
add(
StringMultiChoiceSetting(
StringListSetting.COMBO_KEYS,
MultiChoiceSetting(
IntListSetting.COMBO_KEYS,
R.string.combo_key_options,
R.string.combo_key_description,
buttons,
buttons,
StringListSetting.COMBO_KEYS.key,
StringListSetting.COMBO_KEYS.defaultValue
R.array.comboOptions,
R.array.comboOptionValues,
IntListSetting.COMBO_KEYS.key,
IntListSetting.COMBO_KEYS.defaultValue
)
)
}

View file

@ -8,7 +8,6 @@ import android.view.View
import org.citra.citra_emu.databinding.ListItemSettingBinding
import org.citra.citra_emu.features.settings.model.view.SettingsItem
import org.citra.citra_emu.features.settings.model.view.MultiChoiceSetting
import org.citra.citra_emu.features.settings.model.view.StringMultiChoiceSetting
import org.citra.citra_emu.features.settings.ui.SettingsAdapter
class MultiChoiceViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
@ -52,16 +51,6 @@ class MultiChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Settin
return resList.joinToString();
}
is StringMultiChoiceSetting -> {
var resList:List<String> = emptyList();
item.values?.forEachIndexed { i: Int, value: String ->
if (value in item.selectedValues) {
resList = resList + item.choices[i]
}
}
return resList.joinToString()
}
else -> return ""
}
}
@ -78,12 +67,6 @@ class MultiChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Settin
bindingAdapterPosition
)
}
if (setting is StringMultiChoiceSetting) {
adapter.onStringMultiChoiceClick(
(setting as StringMultiChoiceSetting),
bindingAdapterPosition
)
}
}
override fun onLongClick(clicked: View): Boolean {

View file

@ -17,7 +17,6 @@ import org.citra.citra_emu.features.settings.model.IntSetting
import org.citra.citra_emu.features.settings.model.ScaledFloatSetting
import org.citra.citra_emu.features.settings.model.SettingSection
import org.citra.citra_emu.features.settings.model.Settings.SettingsSectionMap
import org.citra.citra_emu.features.settings.model.StringListSetting
import org.citra.citra_emu.features.settings.model.StringSetting
import org.citra.citra_emu.features.settings.ui.SettingsActivityView
import org.citra.citra_emu.utils.BiMap
@ -256,15 +255,10 @@ object SettingsFile {
stringSetting.string = value
return stringSetting
}
val stringListSetting = StringListSetting.from(key)
if (stringListSetting != null) {
stringListSetting.list = value.split(", ").map { it }
}
val intListSetting = IntListSetting.from(key)
if (intListSetting != null) {
intListSetting.list = value.split(", ").map { it.toInt() }
intListSetting.list = value.split(", ").mapNotNull { it.toIntOrNull() }
}
return null

View file

@ -24,6 +24,7 @@ import androidx.preference.PreferenceManager
import org.citra.citra_emu.CitraApplication
import org.citra.citra_emu.NativeLibrary
import org.citra.citra_emu.R
import org.citra.citra_emu.features.hotkeys.Hotkey
import org.citra.citra_emu.utils.EmulationMenuSettings
import org.citra.citra_emu.utils.TurboHelper
import org.citra.citra_emu.utils.ComboHelper
@ -177,9 +178,16 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
else if (button.id == NativeLibrary.ButtonType.BUTTON_TURBO && button.status == NativeLibrary.ButtonState.PRESSED) {
TurboHelper.toggleTurbo(true)
}
else if (button.id == Hotkey.COMBO_KEY.button && button.status == NativeLibrary.ButtonState.PRESSED) {
ComboHelper.comboActivate(NativeLibrary.ButtonState.PRESSED)
}
/*
else if (button.id == NativeLibrary.ButtonType.BUTTON_COMBO) {
ComboHelper.comboActivate(button)
}
*/
NativeLibrary.onGamePadEvent(
NativeLibrary.TouchScreenDevice,
@ -580,7 +588,7 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
context,
R.drawable.button_combo,
R.drawable.button_combo_pressed,
NativeLibrary.ButtonType.BUTTON_COMBO,
Hotkey.COMBO_KEY.button,
orientation
)
)
@ -799,11 +807,11 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
resources.getInteger(R.integer.N3DS_BUTTON_TURBO_Y).toFloat() / 1000 * maxY
)
.putFloat(
NativeLibrary.ButtonType.BUTTON_COMBO.toString() + "-X",
Hotkey.COMBO_KEY.button.toString() + "-X",
resources.getInteger(R.integer.N3DS_BUTTON_COMBO_X).toFloat() / 1000 * maxX
)
.putFloat(
NativeLibrary.ButtonType.BUTTON_COMBO.toString() + "-Y",
Hotkey.COMBO_KEY.button.toString() + "-Y",
resources.getInteger(R.integer.N3DS_BUTTON_COMBO_Y).toFloat() / 1000 * maxY
)
.apply()
@ -958,11 +966,11 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
resources.getInteger(R.integer.N3DS_BUTTON_TURBO_PORTRAIT_Y).toFloat() / 1000 * maxY
)
.putFloat(
NativeLibrary.ButtonType.BUTTON_COMBO.toString() + portrait + "-X",
Hotkey.COMBO_KEY.button.toString() + portrait + "-X",
resources.getInteger(R.integer.N3DS_BUTTON_COMBO_PORTRAIT_X).toFloat() / 1000 * maxX
)
.putFloat(
NativeLibrary.ButtonType.BUTTON_COMBO.toString() + portrait + "-Y",
Hotkey.COMBO_KEY.button.toString() + portrait + "-Y",
resources.getInteger(R.integer.N3DS_BUTTON_COMBO_PORTRAIT_Y).toFloat() / 1000 * maxY
)
.apply()

View file

@ -5,39 +5,39 @@
package org.citra.citra_emu.utils
import org.citra.citra_emu.NativeLibrary
import org.citra.citra_emu.overlay.InputOverlayDrawableButton
import org.citra.citra_emu.features.settings.model.StringListSetting
import org.citra.citra_emu.features.settings.model.IntListSetting
object ComboHelper {
fun getButton(button: String): Int {
fun getButton(button: Int): Int {
when (button) {
"A" -> return NativeLibrary.ButtonType.BUTTON_A
"B" -> return NativeLibrary.ButtonType.BUTTON_B
"X" -> return NativeLibrary.ButtonType.BUTTON_X
"Y" -> return NativeLibrary.ButtonType.BUTTON_Y
"L" -> return NativeLibrary.ButtonType.TRIGGER_L
"R" -> return NativeLibrary.ButtonType.TRIGGER_R
"ZL" -> return NativeLibrary.ButtonType.BUTTON_ZL
"ZR" -> return NativeLibrary.ButtonType.BUTTON_ZR
"START" -> return NativeLibrary.ButtonType.BUTTON_START
"SELECT" -> return NativeLibrary.ButtonType.BUTTON_SELECT
0 -> return NativeLibrary.ButtonType.BUTTON_A
1 -> return NativeLibrary.ButtonType.BUTTON_B
2 -> return NativeLibrary.ButtonType.BUTTON_X
3 -> return NativeLibrary.ButtonType.BUTTON_Y
4 -> return NativeLibrary.ButtonType.TRIGGER_L
5 -> return NativeLibrary.ButtonType.TRIGGER_R
6 -> return NativeLibrary.ButtonType.BUTTON_ZL
7 -> return NativeLibrary.ButtonType.BUTTON_ZR
8 -> return NativeLibrary.ButtonType.BUTTON_START
9 -> return NativeLibrary.ButtonType.BUTTON_SELECT
}
return -1
}
fun comboActivate(button: InputOverlayDrawableButton) {
val comboArray = StringListSetting.COMBO_KEYS.list
for (selected_button in comboArray) {
val native_button = getButton(selected_button)
if (native_button == -1)
fun comboActivate(buttonStatus: Int) {
val comboArray = IntListSetting.COMBO_KEYS.list
Log.info("Combo Array: $comboArray")
for (selectedButton in comboArray) {
val nativeButton = getButton(selectedButton)
Log.info("Native Button: $nativeButton")
if (nativeButton == -1)
{
val cause = IllegalStateException("Button is not in bindable inputs.")
throw IllegalArgumentException("Input must be non-negative.", cause)
// We don't want to parse any bad inputs here so we continue loop
continue
}
else
{
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, native_button, button.status)
Log.debug("Handling combo button press: $nativeButton")
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, nativeButton, buttonStatus)
}
}
}

View file

@ -184,6 +184,33 @@
<item>@string/button_combo</item>
</string-array>
<string-array name="comboOptions">
<item>@string/button_a</item>
<item>@string/button_b</item>
<item>@string/button_x</item>
<item>@string/button_y</item>
<item>@string/button_l</item>
<item>@string/button_r</item>
<item>@string/button_zl</item>
<item>@string/button_zr</item>
<item>@string/button_start</item>
<item>@string/button_select</item>
</string-array>
<integer-array name="comboOptionValues">
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
<item>6</item>
<item>7</item>
<item>8</item>
<item>9</item>
</integer-array>
<string-array name="cameraImageSourceNames">
<item>@string/blank</item>
<item>@string/still_image</item>