diff --git a/CMakeModules/GenerateSettingKeys.cmake b/CMakeModules/GenerateSettingKeys.cmake index 7aff65db5..14b7d5072 100644 --- a/CMakeModules/GenerateSettingKeys.cmake +++ b/CMakeModules/GenerateSettingKeys.cmake @@ -238,6 +238,7 @@ if (ANDROID) "android_hide_images" "screen_orientation" "performance_overlay_position" + "combo_buttons" ) string(REPLACE "_" "_1" KEY_JNI_ESCAPED ${KEY}) set(SETTING_KEY_LIST "${SETTING_KEY_LIST}\n\"${KEY}\",") diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/hotkeys/Hotkey.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/hotkeys/Hotkey.kt index e2319a7e4..1992e138b 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/hotkeys/Hotkey.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/hotkeys/Hotkey.kt @@ -12,5 +12,6 @@ enum class Hotkey(val button: Int) { QUICKSAVE(10005), QUICKLOAD(10006), TURBO_LIMIT(10007), - ENABLE(10008); + ENABLE(10008), + COMBO_BUTTON(10009); } diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/hotkeys/HotkeyUtility.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/hotkeys/HotkeyUtility.kt index d01d5f769..e23864731 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/hotkeys/HotkeyUtility.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/hotkeys/HotkeyUtility.kt @@ -13,6 +13,7 @@ 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 @@ -81,6 +82,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 +108,14 @@ class HotkeyUtility( return handled } + fun handleHotkeyRelease(bindedButton: Int): Boolean { + // Log.debug("Handling hotkey button release: " + bindedButton) + if (bindedButton == Hotkey.COMBO_BUTTON.button) { + ComboHelper.comboActivate(NativeLibrary.ButtonState.RELEASED) + } + return true + } + fun handleHotkey(bindedButton: Int): Boolean { when (bindedButton) { Hotkey.SWAP_SCREEN.button -> screenAdjustmentUtil.swapScreen() @@ -121,7 +131,6 @@ class HotkeyUtility( Toast.LENGTH_SHORT ).show() } - Hotkey.QUICKLOAD.button -> { val wasLoaded = NativeLibrary.loadStateIfAvailable(NativeLibrary.QUICKSAVE_SLOT) val stringRes = if (wasLoaded) { @@ -135,6 +144,9 @@ class HotkeyUtility( Toast.LENGTH_SHORT ).show() } + Hotkey.COMBO_BUTTON.button -> { + ComboHelper.comboActivate(NativeLibrary.ButtonState.PRESSED) + } else -> {} } diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/SettingKeys.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/SettingKeys.kt index 56ffb6789..0a5b05960 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/SettingKeys.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/SettingKeys.kt @@ -141,4 +141,5 @@ object SettingKeys { external fun android_hide_images(): String external fun screen_orientation(): String external fun performance_overlay_position(): String + external fun combo_buttons(): String } \ No newline at end of file diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/IntListSetting.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/IntListSetting.kt index 479d77ce1..8bfeb4df6 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/IntListSetting.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/IntListSetting.kt @@ -4,6 +4,8 @@ package org.citra.citra_emu.features.settings.model +import org.citra.citra_emu.CitraApplication +import org.citra.citra_emu.R import org.citra.citra_emu.features.settings.SettingKeys enum class IntListSetting( @@ -13,8 +15,11 @@ enum class IntListSetting( val canBeEmpty: Boolean = true ) : AbstractListSetting { - LAYOUTS_TO_CYCLE(SettingKeys.layouts_to_cycle(), Settings.SECTION_LAYOUT, listOf(0, 1, 2, 3, 4, 5), canBeEmpty = false); - + LAYOUTS_TO_CYCLE(SettingKeys.layouts_to_cycle(), Settings.SECTION_LAYOUT, listOf(0, 1, 2, 3, 4, 5), canBeEmpty = false), + COMBO_BUTTONS(SettingKeys.combo_buttons(), Settings.SECTION_CONTROLS, + CitraApplication.appContext.resources.getIntArray(R.array.comboOptionValues).toCollection(ArrayList()), + canBeEmpty = true); + private var backingList: List = defaultValue private var lastValidList : List = defaultValue diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/Settings.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/Settings.kt index 547a53594..54d2700c8 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/Settings.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/Settings.kt @@ -130,6 +130,7 @@ class Settings { const val KEY_BUTTON_R = "button_r" const val KEY_BUTTON_ZL = "button_zl" const val KEY_BUTTON_ZR = "button_zr" + const val KEY_BUTTON_COMBO = "button_combo" const val KEY_CIRCLEPAD_AXIS_VERTICAL = "circlepad_axis_vertical" const val KEY_CIRCLEPAD_AXIS_HORIZONTAL = "circlepad_axis_horizontal" const val KEY_CSTICK_AXIS_VERTICAL = "cstick_axis_vertical" @@ -144,6 +145,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, @@ -211,7 +213,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, @@ -221,7 +224,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 @@ -250,4 +254,4 @@ class Settings { ) } } -} \ No newline at end of file +} diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/InputBindingSetting.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/InputBindingSetting.kt index 6ec851db1..063a3436d 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/InputBindingSetting.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/InputBindingSetting.kt @@ -137,6 +137,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_BUTTON.button else -> -1 } diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsAdapter.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsAdapter.kt index 43a1dcbbd..8603f4dcc 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsAdapter.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsAdapter.kt @@ -44,6 +44,7 @@ import org.citra.citra_emu.features.settings.model.FloatSetting 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.AbstractShortSetting +import org.citra.citra_emu.features.settings.model.Settings import org.citra.citra_emu.features.settings.model.view.DateTimeSetting import org.citra.citra_emu.features.settings.model.view.InputBindingSetting import org.citra.citra_emu.features.settings.model.view.SettingsItem @@ -571,15 +572,20 @@ class SettingsAdapter( //onclick for multichoice override fun onClick(dialog: DialogInterface?, which: Int, isChecked: Boolean) { - val mcsetting = clickedItem as? MultiChoiceSetting - mcsetting?.let { - val value = getValueForMultiChoiceSelection(it, which) - if (it.selectedValues.contains(value) != isChecked) { - val setting = it.setSelectedValue((if (isChecked) it.selectedValues + value else it.selectedValues - value).sorted()) - fragmentView?.putSetting(setting) - fragmentView?.onSettingChanged() + when (clickedItem) { + is MultiChoiceSetting -> { + val mcsetting = clickedItem as? MultiChoiceSetting + mcsetting?.let { + val value = getValueForMultiChoiceSelection(it, which) + if (it.selectedValues.contains(value) != isChecked) { + val setting = + it.setSelectedValue((if (isChecked) it.selectedValues + value else it.selectedValues - value).sorted()) + fragmentView?.putSetting(setting) + fragmentView?.onSettingChanged() + } + fragmentView.loadSettingsList() + } } - fragmentView.loadSettingsList() } } diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsFragmentPresenter.kt index 94bfe78a9..12c920e3f 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -14,7 +14,6 @@ import android.os.Build import android.text.TextUtils import androidx.preference.PreferenceManager import com.google.android.material.dialog.MaterialAlertDialogBuilder -import kotlinx.serialization.builtins.IntArraySerializer import org.citra.citra_emu.CitraApplication import org.citra.citra_emu.R import org.citra.citra_emu.display.ScreenLayout @@ -787,6 +786,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) private fun addControlsSettings(sl: ArrayList) { settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_controls)) + sl.apply { add( RunnableSetting( @@ -798,6 +798,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) onLongClick = { settingsAdapter.onLongClickAutoMap() } ) ) + add(HeaderSetting(R.string.generic_buttons)) Settings.buttonKeys.forEachIndexed { i: Int, key: String -> val button = getInputObject(key) @@ -838,6 +839,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) val button = getInputObject(key) add(InputBindingSetting(button, Settings.hotkeyTitles[i])) } + add(HeaderSetting(R.string.miscellaneous)) add( SwitchSetting( @@ -848,6 +850,18 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) BooleanSetting.USE_ARTIC_BASE_CONTROLLER.defaultValue ) ) + + add( + MultiChoiceSetting( + IntListSetting.COMBO_BUTTONS, + R.string.combo_key_options, + R.string.combo_key_description, + R.array.comboOptions, + R.array.comboOptionValues, + IntListSetting.COMBO_BUTTONS.key, + IntListSetting.COMBO_BUTTONS.defaultValue + ) + ) } } diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/utils/SettingsFile.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/utils/SettingsFile.kt index a9e1d4743..ef34520db 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/utils/SettingsFile.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/utils/SettingsFile.kt @@ -258,7 +258,7 @@ object SettingsFile { val intListSetting = IntListSetting.from(key) if (intListSetting != null) { - intListSetting.list = value.split(", ").map { it.toInt() } + intListSetting.list = value.split(", ").mapNotNull { it.toIntOrNull() } } return null diff --git a/src/android/app/src/main/java/org/citra/citra_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/citra/citra_emu/fragments/EmulationFragment.kt index e1c1fc076..760ba36f7 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/fragments/EmulationFragment.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/fragments/EmulationFragment.kt @@ -67,9 +67,9 @@ import org.citra.citra_emu.databinding.FragmentEmulationBinding import org.citra.citra_emu.display.PortraitScreenLayout import org.citra.citra_emu.display.ScreenAdjustmentUtil import org.citra.citra_emu.display.ScreenLayout +import org.citra.citra_emu.features.hotkeys.Hotkey import org.citra.citra_emu.features.settings.model.BooleanSetting import org.citra.citra_emu.features.settings.model.IntSetting -import org.citra.citra_emu.features.settings.model.Settings import org.citra.citra_emu.features.settings.model.SettingsViewModel import org.citra.citra_emu.features.settings.ui.SettingsActivity import org.citra.citra_emu.features.settings.utils.SettingsFile @@ -78,7 +78,6 @@ import org.citra.citra_emu.utils.BuildUtil import org.citra.citra_emu.utils.DirectoryInitialization import org.citra.citra_emu.utils.DirectoryInitialization.DirectoryInitializationState import org.citra.citra_emu.utils.EmulationMenuSettings -import org.citra.citra_emu.utils.FileUtil import org.citra.citra_emu.utils.GameHelper import org.citra.citra_emu.utils.GameIconUtils import org.citra.citra_emu.utils.EmulationLifecycleUtil @@ -834,6 +833,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram true } + R.id.menu_emulation_adjust_scale_button_combo -> { + showAdjustScaleDialog("controlScale-" + Hotkey.COMBO_BUTTON.button) + true + } + R.id.menu_emulation_adjust_opacity -> { showAdjustOpacityDialog() true @@ -1051,13 +1055,13 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram private fun showToggleControlsDialog() { val editor = preferences.edit() - val enabledButtons = BooleanArray(16) + val enabledButtons = BooleanArray(17) enabledButtons.forEachIndexed { i: Int, _: Boolean -> // Buttons that are disabled by default var defaultValue = true when (i) { // TODO: Remove these magic numbers - 6, 7, 12, 13, 14, 15 -> defaultValue = false + 6, 7, 12, 13, 14, 15, 16 -> defaultValue = false } enabledButtons[i] = preferences.getBoolean("buttonToggle$i", defaultValue) } diff --git a/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlay.kt b/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlay.kt index f7519bb81..fec59f99f 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlay.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlay.kt @@ -24,8 +24,10 @@ 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 import java.lang.NullPointerException import kotlin.math.min @@ -175,6 +177,9 @@ 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_BUTTON.button && button.status == NativeLibrary.ButtonState.PRESSED) { + ComboHelper.comboActivate(NativeLibrary.ButtonState.PRESSED) + } NativeLibrary.onGamePadEvent( NativeLibrary.TouchScreenDevice, @@ -568,6 +573,18 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex ) ) } + + if (preferences.getBoolean("buttonToggle16", false)) { + overlayButtons.add( + initializeOverlayButton( + context, + R.drawable.button_combo, + R.drawable.button_combo_pressed, + Hotkey.COMBO_BUTTON.button, + orientation + ) + ) + } } fun refreshControls() { @@ -781,6 +798,14 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex NativeLibrary.ButtonType.BUTTON_TURBO.toString() + "-Y", resources.getInteger(R.integer.N3DS_BUTTON_TURBO_Y).toFloat() / 1000 * maxY ) + .putFloat( + Hotkey.COMBO_BUTTON.button.toString() + "-X", + resources.getInteger(R.integer.N3DS_BUTTON_COMBO_X).toFloat() / 1000 * maxX + ) + .putFloat( + Hotkey.COMBO_BUTTON.button.toString() + "-Y", + resources.getInteger(R.integer.N3DS_BUTTON_COMBO_Y).toFloat() / 1000 * maxY + ) .apply() } @@ -932,6 +957,14 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex NativeLibrary.ButtonType.BUTTON_TURBO.toString() + portrait + "-Y", resources.getInteger(R.integer.N3DS_BUTTON_TURBO_PORTRAIT_Y).toFloat() / 1000 * maxY ) + .putFloat( + Hotkey.COMBO_BUTTON.button.toString() + portrait + "-X", + resources.getInteger(R.integer.N3DS_BUTTON_COMBO_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + Hotkey.COMBO_BUTTON.button.toString() + portrait + "-Y", + resources.getInteger(R.integer.N3DS_BUTTON_COMBO_PORTRAIT_Y).toFloat() / 1000 * maxY + ) .apply() } diff --git a/src/android/app/src/main/java/org/citra/citra_emu/utils/ComboHelper.kt b/src/android/app/src/main/java/org/citra/citra_emu/utils/ComboHelper.kt new file mode 100644 index 000000000..533cf1b20 --- /dev/null +++ b/src/android/app/src/main/java/org/citra/citra_emu/utils/ComboHelper.kt @@ -0,0 +1,22 @@ +// 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.utils + +import org.citra.citra_emu.NativeLibrary +import org.citra.citra_emu.features.settings.model.IntListSetting + +object ComboHelper { + fun comboActivate(buttonStatus: Int) { + val comboArray = IntListSetting.COMBO_BUTTONS.list + for (nativeButton in comboArray) { + if (nativeButton == -1) { + // We don't want to parse any bad inputs here so we continue loop + continue + } else { + NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, nativeButton, buttonStatus) + } + } + } +} diff --git a/src/android/app/src/main/res/drawable/button_combo.xml b/src/android/app/src/main/res/drawable/button_combo.xml new file mode 100644 index 000000000..fdd9a79a4 --- /dev/null +++ b/src/android/app/src/main/res/drawable/button_combo.xml @@ -0,0 +1,32 @@ + + + + + + + + diff --git a/src/android/app/src/main/res/drawable/button_combo_pressed.xml b/src/android/app/src/main/res/drawable/button_combo_pressed.xml new file mode 100644 index 000000000..d8825692d --- /dev/null +++ b/src/android/app/src/main/res/drawable/button_combo_pressed.xml @@ -0,0 +1,28 @@ + + + + diff --git a/src/android/app/src/main/res/menu/menu_overlay_options.xml b/src/android/app/src/main/res/menu/menu_overlay_options.xml index 8bb19ee26..34589ebc3 100644 --- a/src/android/app/src/main/res/menu/menu_overlay_options.xml +++ b/src/android/app/src/main/res/menu/menu_overlay_options.xml @@ -79,6 +79,9 @@ + diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml index 2a08cd546..39d0c810f 100644 --- a/src/android/app/src/main/res/values/arrays.xml +++ b/src/android/app/src/main/res/values/arrays.xml @@ -181,8 +181,37 @@ @string/button_home @string/button_swap @string/button_turbo + @string/button_combo + + @string/button_a + @string/button_b + @string/button_x + @string/button_y + @string/button_l + @string/button_r + @string/button_zl + @string/button_zr + @string/button_start + @string/button_select + + + + + 700 + 701 + 702 + 703 + 773 + 774 + 707 + 708 + 704 + 705 + + + @string/blank @string/still_image diff --git a/src/android/app/src/main/res/values/integers.xml b/src/android/app/src/main/res/values/integers.xml index 1f19c2373..0c091a48b 100644 --- a/src/android/app/src/main/res/values/integers.xml +++ b/src/android/app/src/main/res/values/integers.xml @@ -35,6 +35,8 @@ 850 630 850 + 740 + 480 810 @@ -69,5 +71,7 @@ 675 453 720 + 445 + 925 diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index a94611efc..224c6f431 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -156,6 +156,7 @@ HOME Swap Screens Turbo + Combo Key X Y L @@ -167,6 +168,10 @@ Turbo Speed Turbo Speed Enabled Turbo Speed Disabled + Enable Combo Button + Combo Key Settings + Enable and Change Combo Button Bindings. + Changes whether or not Combo Button can be displayed and used in game. System Files