Merge pull request #12518 from t895/theme-settings
android: Migrate remaining settings to ini
This commit is contained in:
		| @@ -10,7 +10,7 @@ plugins { | ||||
|     id("com.android.application") | ||||
|     id("org.jetbrains.kotlin.android") | ||||
|     id("kotlin-parcelize") | ||||
|     kotlin("plugin.serialization") version "1.8.21" | ||||
|     kotlin("plugin.serialization") version "1.9.20" | ||||
|     id("androidx.navigation.safeargs.kotlin") | ||||
|     id("org.jlleitschuh.gradle.ktlint") version "11.4.0" | ||||
| } | ||||
|   | ||||
| @@ -49,6 +49,7 @@ import org.yuzu.yuzu_emu.utils.ForegroundService | ||||
| import org.yuzu.yuzu_emu.utils.InputHandler | ||||
| import org.yuzu.yuzu_emu.utils.Log | ||||
| import org.yuzu.yuzu_emu.utils.MemoryUtil | ||||
| import org.yuzu.yuzu_emu.utils.NativeConfig | ||||
| import org.yuzu.yuzu_emu.utils.NfcReader | ||||
| import org.yuzu.yuzu_emu.utils.ThemeHelper | ||||
| import java.text.NumberFormat | ||||
| @@ -170,6 +171,11 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { | ||||
|         stopMotionSensorListener() | ||||
|     } | ||||
|  | ||||
|     override fun onStop() { | ||||
|         super.onStop() | ||||
|         NativeConfig.saveGlobalConfig() | ||||
|     } | ||||
|  | ||||
|     override fun onUserLeaveHint() { | ||||
|         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { | ||||
|             if (BooleanSetting.PICTURE_IN_PICTURE.getBoolean() && !isInPictureInPictureMode) { | ||||
|   | ||||
| @@ -18,7 +18,14 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting { | ||||
|     RENDERER_REACTIVE_FLUSHING("use_reactive_flushing"), | ||||
|     RENDERER_DEBUG("debug"), | ||||
|     PICTURE_IN_PICTURE("picture_in_picture"), | ||||
|     USE_CUSTOM_RTC("custom_rtc_enabled"); | ||||
|     USE_CUSTOM_RTC("custom_rtc_enabled"), | ||||
|     BLACK_BACKGROUNDS("black_backgrounds"), | ||||
|     JOYSTICK_REL_CENTER("joystick_rel_center"), | ||||
|     DPAD_SLIDE("dpad_slide"), | ||||
|     HAPTIC_FEEDBACK("haptic_feedback"), | ||||
|     SHOW_PERFORMANCE_OVERLAY("show_performance_overlay"), | ||||
|     SHOW_INPUT_OVERLAY("show_input_overlay"), | ||||
|     TOUCHSCREEN("touchscreen"); | ||||
|  | ||||
|     override fun getBoolean(needsGlobal: Boolean): Boolean = | ||||
|         NativeConfig.getBoolean(key, needsGlobal) | ||||
|   | ||||
| @@ -19,7 +19,11 @@ enum class IntSetting(override val key: String) : AbstractIntSetting { | ||||
|     RENDERER_SCREEN_LAYOUT("screen_layout"), | ||||
|     RENDERER_ASPECT_RATIO("aspect_ratio"), | ||||
|     AUDIO_OUTPUT_ENGINE("output_engine"), | ||||
|     MAX_ANISOTROPY("max_anisotropy"); | ||||
|     MAX_ANISOTROPY("max_anisotropy"), | ||||
|     THEME("theme"), | ||||
|     THEME_MODE("theme_mode"), | ||||
|     OVERLAY_SCALE("control_scale"), | ||||
|     OVERLAY_OPACITY("control_opacity"); | ||||
|  | ||||
|     override fun getInt(needsGlobal: Boolean): Int = NativeConfig.getInt(key, needsGlobal) | ||||
|  | ||||
|   | ||||
| @@ -15,18 +15,10 @@ object Settings { | ||||
|         SECTION_DEBUG(R.string.preferences_debug); | ||||
|     } | ||||
|  | ||||
|     const val PREF_FIRST_APP_LAUNCH = "FirstApplicationLaunch" | ||||
|     const val PREF_MEMORY_WARNING_SHOWN = "MemoryWarningShown" | ||||
|  | ||||
|     const val PREF_OVERLAY_VERSION = "OverlayVersion" | ||||
|     const val PREF_LANDSCAPE_OVERLAY_VERSION = "LandscapeOverlayVersion" | ||||
|     const val PREF_PORTRAIT_OVERLAY_VERSION = "PortraitOverlayVersion" | ||||
|     const val PREF_FOLDABLE_OVERLAY_VERSION = "FoldableOverlayVersion" | ||||
|     val overlayLayoutPrefs = listOf( | ||||
|         PREF_LANDSCAPE_OVERLAY_VERSION, | ||||
|         PREF_PORTRAIT_OVERLAY_VERSION, | ||||
|         PREF_FOLDABLE_OVERLAY_VERSION | ||||
|     ) | ||||
|  | ||||
|     // Deprecated input overlay preference keys | ||||
|     const val PREF_CONTROL_SCALE = "controlScale" | ||||
|     const val PREF_CONTROL_OPACITY = "controlOpacity" | ||||
|     const val PREF_TOUCH_ENABLED = "isTouchEnabled" | ||||
| @@ -47,23 +39,12 @@ object Settings { | ||||
|     const val PREF_BUTTON_STICK_R = "buttonToggle14" | ||||
|     const val PREF_BUTTON_HOME = "buttonToggle15" | ||||
|     const val PREF_BUTTON_SCREENSHOT = "buttonToggle16" | ||||
|  | ||||
|     const val PREF_MENU_SETTINGS_JOYSTICK_REL_CENTER = "EmulationMenuSettings_JoystickRelCenter" | ||||
|     const val PREF_MENU_SETTINGS_DPAD_SLIDE = "EmulationMenuSettings_DpadSlideEnable" | ||||
|     const val PREF_MENU_SETTINGS_HAPTICS = "EmulationMenuSettings_Haptics" | ||||
|     const val PREF_MENU_SETTINGS_SHOW_FPS = "EmulationMenuSettings_ShowFps" | ||||
|     const val PREF_MENU_SETTINGS_SHOW_OVERLAY = "EmulationMenuSettings_ShowOverlay" | ||||
|  | ||||
|     const val PREF_FIRST_APP_LAUNCH = "FirstApplicationLaunch" | ||||
|     const val PREF_THEME = "Theme" | ||||
|     const val PREF_THEME_MODE = "ThemeMode" | ||||
|     const val PREF_BLACK_BACKGROUNDS = "BlackBackgrounds" | ||||
|  | ||||
|     val overlayPreferences = listOf( | ||||
|         PREF_OVERLAY_VERSION, | ||||
|         PREF_CONTROL_SCALE, | ||||
|         PREF_CONTROL_OPACITY, | ||||
|         PREF_TOUCH_ENABLED, | ||||
|         PREF_BUTTON_A, | ||||
|         PREF_BUTTON_B, | ||||
|         PREF_BUTTON_X, | ||||
| @@ -83,6 +64,21 @@ object Settings { | ||||
|         PREF_BUTTON_STICK_R | ||||
|     ) | ||||
|  | ||||
|     // Deprecated layout preference keys | ||||
|     const val PREF_LANDSCAPE_SUFFIX = "_Landscape" | ||||
|     const val PREF_PORTRAIT_SUFFIX = "_Portrait" | ||||
|     const val PREF_FOLDABLE_SUFFIX = "_Foldable" | ||||
|     val overlayLayoutSuffixes = listOf( | ||||
|         PREF_LANDSCAPE_SUFFIX, | ||||
|         PREF_PORTRAIT_SUFFIX, | ||||
|         PREF_FOLDABLE_SUFFIX | ||||
|     ) | ||||
|  | ||||
|     // Deprecated theme preference keys | ||||
|     const val PREF_THEME = "Theme" | ||||
|     const val PREF_THEME_MODE = "ThemeMode" | ||||
|     const val PREF_BLACK_BACKGROUNDS = "BlackBackgrounds" | ||||
|  | ||||
|     const val LayoutOption_Unspecified = 0 | ||||
|     const val LayoutOption_MobilePortrait = 4 | ||||
|     const val LayoutOption_MobileLandscape = 5 | ||||
|   | ||||
| @@ -3,10 +3,8 @@ | ||||
|  | ||||
| package org.yuzu.yuzu_emu.features.settings.ui | ||||
|  | ||||
| import android.content.SharedPreferences | ||||
| import android.os.Build | ||||
| import android.widget.Toast | ||||
| import androidx.preference.PreferenceManager | ||||
| import org.yuzu.yuzu_emu.NativeLibrary | ||||
| import org.yuzu.yuzu_emu.R | ||||
| import org.yuzu.yuzu_emu.YuzuApplication | ||||
| @@ -29,9 +27,6 @@ class SettingsFragmentPresenter( | ||||
| ) { | ||||
|     private var settingsList = ArrayList<SettingsItem>() | ||||
|  | ||||
|     private val preferences: SharedPreferences | ||||
|         get() = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) | ||||
|  | ||||
|     // Extension for altering settings list based on each setting's properties | ||||
|     fun ArrayList<SettingsItem>.add(key: String) { | ||||
|         val item = SettingsItem.settingsItems[key]!! | ||||
| @@ -170,25 +165,19 @@ class SettingsFragmentPresenter( | ||||
|     private fun addThemeSettings(sl: ArrayList<SettingsItem>) { | ||||
|         sl.apply { | ||||
|             val theme: AbstractIntSetting = object : AbstractIntSetting { | ||||
|                 override fun getInt(needsGlobal: Boolean): Int = | ||||
|                     preferences.getInt(Settings.PREF_THEME, 0) | ||||
|  | ||||
|                 override fun getInt(needsGlobal: Boolean): Int = IntSetting.THEME.getInt() | ||||
|                 override fun setInt(value: Int) { | ||||
|                     preferences.edit() | ||||
|                         .putInt(Settings.PREF_THEME, value) | ||||
|                         .apply() | ||||
|                     IntSetting.THEME.setInt(value) | ||||
|                     settingsViewModel.setShouldRecreate(true) | ||||
|                 } | ||||
|  | ||||
|                 override val key: String = Settings.PREF_THEME | ||||
|                 override val isRuntimeModifiable: Boolean = false | ||||
|                 override fun getValueAsString(needsGlobal: Boolean): String = getInt().toString() | ||||
|                 override val defaultValue: Int = 0 | ||||
|                 override fun reset() { | ||||
|                     preferences.edit() | ||||
|                         .putInt(Settings.PREF_THEME, defaultValue) | ||||
|                         .apply() | ||||
|                 } | ||||
|                 override val key: String = IntSetting.THEME.key | ||||
|                 override val isRuntimeModifiable: Boolean = IntSetting.THEME.isRuntimeModifiable | ||||
|                 override fun getValueAsString(needsGlobal: Boolean): String = | ||||
|                     IntSetting.THEME.getValueAsString() | ||||
|  | ||||
|                 override val defaultValue: Int = IntSetting.THEME.defaultValue | ||||
|                 override fun reset() = IntSetting.THEME.setInt(defaultValue) | ||||
|             } | ||||
|  | ||||
|             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { | ||||
| @@ -214,24 +203,22 @@ class SettingsFragmentPresenter( | ||||
|             } | ||||
|  | ||||
|             val themeMode: AbstractIntSetting = object : AbstractIntSetting { | ||||
|                 override fun getInt(needsGlobal: Boolean): Int = | ||||
|                     preferences.getInt(Settings.PREF_THEME_MODE, -1) | ||||
|  | ||||
|                 override fun getInt(needsGlobal: Boolean): Int = IntSetting.THEME_MODE.getInt() | ||||
|                 override fun setInt(value: Int) { | ||||
|                     preferences.edit() | ||||
|                         .putInt(Settings.PREF_THEME_MODE, value) | ||||
|                         .apply() | ||||
|                     IntSetting.THEME_MODE.setInt(value) | ||||
|                     settingsViewModel.setShouldRecreate(true) | ||||
|                 } | ||||
|  | ||||
|                 override val key: String = Settings.PREF_THEME_MODE | ||||
|                 override val isRuntimeModifiable: Boolean = false | ||||
|                 override fun getValueAsString(needsGlobal: Boolean): String = getInt().toString() | ||||
|                 override val defaultValue: Int = -1 | ||||
|                 override val key: String = IntSetting.THEME_MODE.key | ||||
|                 override val isRuntimeModifiable: Boolean = | ||||
|                     IntSetting.THEME_MODE.isRuntimeModifiable | ||||
|  | ||||
|                 override fun getValueAsString(needsGlobal: Boolean): String = | ||||
|                     IntSetting.THEME_MODE.getValueAsString() | ||||
|  | ||||
|                 override val defaultValue: Int = IntSetting.THEME_MODE.defaultValue | ||||
|                 override fun reset() { | ||||
|                     preferences.edit() | ||||
|                         .putInt(Settings.PREF_BLACK_BACKGROUNDS, defaultValue) | ||||
|                         .apply() | ||||
|                     IntSetting.THEME_MODE.setInt(defaultValue) | ||||
|                     settingsViewModel.setShouldRecreate(true) | ||||
|                 } | ||||
|             } | ||||
| @@ -248,25 +235,24 @@ class SettingsFragmentPresenter( | ||||
|  | ||||
|             val blackBackgrounds: AbstractBooleanSetting = object : AbstractBooleanSetting { | ||||
|                 override fun getBoolean(needsGlobal: Boolean): Boolean = | ||||
|                     preferences.getBoolean(Settings.PREF_BLACK_BACKGROUNDS, false) | ||||
|                     BooleanSetting.BLACK_BACKGROUNDS.getBoolean() | ||||
|  | ||||
|                 override fun setBoolean(value: Boolean) { | ||||
|                     preferences.edit() | ||||
|                         .putBoolean(Settings.PREF_BLACK_BACKGROUNDS, value) | ||||
|                         .apply() | ||||
|                     BooleanSetting.BLACK_BACKGROUNDS.setBoolean(value) | ||||
|                     settingsViewModel.setShouldRecreate(true) | ||||
|                 } | ||||
|  | ||||
|                 override val key: String = Settings.PREF_BLACK_BACKGROUNDS | ||||
|                 override val isRuntimeModifiable: Boolean = false | ||||
|                 override fun getValueAsString(needsGlobal: Boolean): String = | ||||
|                     getBoolean().toString() | ||||
|                 override val key: String = BooleanSetting.BLACK_BACKGROUNDS.key | ||||
|                 override val isRuntimeModifiable: Boolean = | ||||
|                     BooleanSetting.BLACK_BACKGROUNDS.isRuntimeModifiable | ||||
|  | ||||
|                 override val defaultValue: Boolean = false | ||||
|                 override fun getValueAsString(needsGlobal: Boolean): String = | ||||
|                     BooleanSetting.BLACK_BACKGROUNDS.getValueAsString() | ||||
|  | ||||
|                 override val defaultValue: Boolean = BooleanSetting.BLACK_BACKGROUNDS.defaultValue | ||||
|                 override fun reset() { | ||||
|                     preferences.edit() | ||||
|                         .putBoolean(Settings.PREF_BLACK_BACKGROUNDS, defaultValue) | ||||
|                         .apply() | ||||
|                     BooleanSetting.BLACK_BACKGROUNDS | ||||
|                         .setBoolean(BooleanSetting.BLACK_BACKGROUNDS.defaultValue) | ||||
|                     settingsViewModel.setShouldRecreate(true) | ||||
|                 } | ||||
|             } | ||||
|   | ||||
| @@ -7,7 +7,6 @@ import android.annotation.SuppressLint | ||||
| import android.app.AlertDialog | ||||
| import android.content.Context | ||||
| import android.content.DialogInterface | ||||
| import android.content.SharedPreferences | ||||
| import android.content.pm.ActivityInfo | ||||
| import android.content.res.Configuration | ||||
| import android.net.Uri | ||||
| @@ -33,7 +32,6 @@ import androidx.lifecycle.lifecycleScope | ||||
| import androidx.lifecycle.repeatOnLifecycle | ||||
| import androidx.navigation.findNavController | ||||
| import androidx.navigation.fragment.navArgs | ||||
| import androidx.preference.PreferenceManager | ||||
| import androidx.window.layout.FoldingFeature | ||||
| import androidx.window.layout.WindowInfoTracker | ||||
| import androidx.window.layout.WindowLayoutInfo | ||||
| @@ -46,22 +44,22 @@ import kotlinx.coroutines.launch | ||||
| import org.yuzu.yuzu_emu.HomeNavigationDirections | ||||
| import org.yuzu.yuzu_emu.NativeLibrary | ||||
| import org.yuzu.yuzu_emu.R | ||||
| import org.yuzu.yuzu_emu.YuzuApplication | ||||
| import org.yuzu.yuzu_emu.activities.EmulationActivity | ||||
| import org.yuzu.yuzu_emu.databinding.DialogOverlayAdjustBinding | ||||
| import org.yuzu.yuzu_emu.databinding.FragmentEmulationBinding | ||||
| import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting | ||||
| import org.yuzu.yuzu_emu.features.settings.model.IntSetting | ||||
| import org.yuzu.yuzu_emu.features.settings.model.Settings | ||||
| import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile | ||||
| import org.yuzu.yuzu_emu.model.DriverViewModel | ||||
| import org.yuzu.yuzu_emu.model.Game | ||||
| import org.yuzu.yuzu_emu.model.EmulationViewModel | ||||
| import org.yuzu.yuzu_emu.overlay.InputOverlay | ||||
| import org.yuzu.yuzu_emu.overlay.model.OverlayControl | ||||
| import org.yuzu.yuzu_emu.overlay.model.OverlayLayout | ||||
| import org.yuzu.yuzu_emu.utils.* | ||||
| import java.lang.NullPointerException | ||||
|  | ||||
| class EmulationFragment : Fragment(), SurfaceHolder.Callback { | ||||
|     private lateinit var preferences: SharedPreferences | ||||
|     private lateinit var emulationState: EmulationState | ||||
|     private var emulationActivity: EmulationActivity? = null | ||||
|     private var perfStatsUpdater: (() -> Unit)? = null | ||||
| @@ -141,7 +139,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | ||||
|  | ||||
|         // So this fragment doesn't restart on configuration changes; i.e. rotation. | ||||
|         retainInstance = true | ||||
|         preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) | ||||
|         emulationState = EmulationState(game.path) | ||||
|     } | ||||
|  | ||||
| @@ -382,24 +379,25 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | ||||
|         } | ||||
|  | ||||
|         updateScreenLayout() | ||||
|         val showInputOverlay = BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean() | ||||
|         if (emulationActivity?.isInPictureInPictureMode == true) { | ||||
|             if (binding.drawerLayout.isOpen) { | ||||
|                 binding.drawerLayout.close() | ||||
|             } | ||||
|             if (EmulationMenuSettings.showOverlay) { | ||||
|             if (showInputOverlay) { | ||||
|                 binding.surfaceInputOverlay.visibility = View.INVISIBLE | ||||
|             } | ||||
|         } else { | ||||
|             if (EmulationMenuSettings.showOverlay && emulationViewModel.emulationStarted.value) { | ||||
|             if (showInputOverlay && emulationViewModel.emulationStarted.value) { | ||||
|                 binding.surfaceInputOverlay.visibility = View.VISIBLE | ||||
|             } else { | ||||
|                 binding.surfaceInputOverlay.visibility = View.INVISIBLE | ||||
|             } | ||||
|             if (!isInFoldableLayout) { | ||||
|                 if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { | ||||
|                     binding.surfaceInputOverlay.layout = InputOverlay.PORTRAIT | ||||
|                     binding.surfaceInputOverlay.layout = OverlayLayout.Portrait | ||||
|                 } else { | ||||
|                     binding.surfaceInputOverlay.layout = InputOverlay.LANDSCAPE | ||||
|                     binding.surfaceInputOverlay.layout = OverlayLayout.Landscape | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| @@ -423,17 +421,15 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | ||||
|     } | ||||
|  | ||||
|     private fun resetInputOverlay() { | ||||
|         preferences.edit() | ||||
|             .remove(Settings.PREF_CONTROL_SCALE) | ||||
|             .remove(Settings.PREF_CONTROL_OPACITY) | ||||
|             .apply() | ||||
|         IntSetting.OVERLAY_SCALE.reset() | ||||
|         IntSetting.OVERLAY_OPACITY.reset() | ||||
|         binding.surfaceInputOverlay.post { | ||||
|             binding.surfaceInputOverlay.resetLayoutVisibilityAndPlacement() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private fun updateShowFpsOverlay() { | ||||
|         if (EmulationMenuSettings.showFps) { | ||||
|         if (BooleanSetting.SHOW_PERFORMANCE_OVERLAY.getBoolean()) { | ||||
|             val SYSTEM_FPS = 0 | ||||
|             val FPS = 1 | ||||
|             val FRAMETIME = 2 | ||||
| @@ -496,7 +492,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | ||||
|                         binding.inGameMenu.layoutParams.height = it.bounds.bottom | ||||
|  | ||||
|                         isInFoldableLayout = true | ||||
|                         binding.surfaceInputOverlay.layout = InputOverlay.FOLDABLE | ||||
|                         binding.surfaceInputOverlay.layout = OverlayLayout.Foldable | ||||
|                     } | ||||
|                 } | ||||
|                 it.isSeparating | ||||
| @@ -535,18 +531,22 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | ||||
|         popup.menuInflater.inflate(R.menu.menu_overlay_options, popup.menu) | ||||
|  | ||||
|         popup.menu.apply { | ||||
|             findItem(R.id.menu_toggle_fps).isChecked = EmulationMenuSettings.showFps | ||||
|             findItem(R.id.menu_rel_stick_center).isChecked = EmulationMenuSettings.joystickRelCenter | ||||
|             findItem(R.id.menu_dpad_slide).isChecked = EmulationMenuSettings.dpadSlide | ||||
|             findItem(R.id.menu_show_overlay).isChecked = EmulationMenuSettings.showOverlay | ||||
|             findItem(R.id.menu_haptics).isChecked = EmulationMenuSettings.hapticFeedback | ||||
|             findItem(R.id.menu_toggle_fps).isChecked = | ||||
|                 BooleanSetting.SHOW_PERFORMANCE_OVERLAY.getBoolean() | ||||
|             findItem(R.id.menu_rel_stick_center).isChecked = | ||||
|                 BooleanSetting.JOYSTICK_REL_CENTER.getBoolean() | ||||
|             findItem(R.id.menu_dpad_slide).isChecked = BooleanSetting.DPAD_SLIDE.getBoolean() | ||||
|             findItem(R.id.menu_show_overlay).isChecked = | ||||
|                 BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean() | ||||
|             findItem(R.id.menu_haptics).isChecked = BooleanSetting.HAPTIC_FEEDBACK.getBoolean() | ||||
|             findItem(R.id.menu_touchscreen).isChecked = BooleanSetting.TOUCHSCREEN.getBoolean() | ||||
|         } | ||||
|  | ||||
|         popup.setOnMenuItemClickListener { | ||||
|             when (it.itemId) { | ||||
|                 R.id.menu_toggle_fps -> { | ||||
|                     it.isChecked = !it.isChecked | ||||
|                     EmulationMenuSettings.showFps = it.isChecked | ||||
|                     BooleanSetting.SHOW_PERFORMANCE_OVERLAY.setBoolean(it.isChecked) | ||||
|                     updateShowFpsOverlay() | ||||
|                     true | ||||
|                 } | ||||
| @@ -564,11 +564,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | ||||
|                 } | ||||
|  | ||||
|                 R.id.menu_toggle_controls -> { | ||||
|                     val preferences = | ||||
|                         PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) | ||||
|                     val optionsArray = BooleanArray(Settings.overlayPreferences.size) | ||||
|                     Settings.overlayPreferences.forEachIndexed { i, _ -> | ||||
|                         optionsArray[i] = preferences.getBoolean("buttonToggle$i", i < 15) | ||||
|                     val overlayControlData = NativeConfig.getOverlayControlData() | ||||
|                     val optionsArray = BooleanArray(overlayControlData.size) | ||||
|                     overlayControlData.forEachIndexed { i, _ -> | ||||
|                         optionsArray[i] = overlayControlData.firstOrNull { data -> | ||||
|                             OverlayControl.entries[i].id == data.id | ||||
|                         }?.enabled == true | ||||
|                     } | ||||
|  | ||||
|                     val dialog = MaterialAlertDialogBuilder(requireContext()) | ||||
| @@ -577,11 +578,13 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | ||||
|                             R.array.gamepadButtons, | ||||
|                             optionsArray | ||||
|                         ) { _, indexSelected, isChecked -> | ||||
|                             preferences.edit() | ||||
|                                 .putBoolean("buttonToggle$indexSelected", isChecked) | ||||
|                                 .apply() | ||||
|                             overlayControlData.firstOrNull { data -> | ||||
|                                 OverlayControl.entries[indexSelected].id == data.id | ||||
|                             }?.enabled = isChecked | ||||
|                         } | ||||
|                         .setPositiveButton(android.R.string.ok) { _, _ -> | ||||
|                             NativeConfig.setOverlayControlData(overlayControlData) | ||||
|                             NativeConfig.saveGlobalConfig() | ||||
|                             binding.surfaceInputOverlay.refreshControls() | ||||
|                         } | ||||
|                         .setNegativeButton(android.R.string.cancel, null) | ||||
| @@ -592,12 +595,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | ||||
|                     dialog.getButton(AlertDialog.BUTTON_NEUTRAL) | ||||
|                         .setOnClickListener { | ||||
|                             val isChecked = !optionsArray[0] | ||||
|                             Settings.overlayPreferences.forEachIndexed { i, _ -> | ||||
|                             overlayControlData.forEachIndexed { i, _ -> | ||||
|                                 optionsArray[i] = isChecked | ||||
|                                 dialog.listView.setItemChecked(i, isChecked) | ||||
|                                 preferences.edit() | ||||
|                                     .putBoolean("buttonToggle$i", isChecked) | ||||
|                                     .apply() | ||||
|                                 overlayControlData[i].enabled = isChecked | ||||
|                             } | ||||
|                         } | ||||
|                     true | ||||
| @@ -605,26 +606,32 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | ||||
|  | ||||
|                 R.id.menu_show_overlay -> { | ||||
|                     it.isChecked = !it.isChecked | ||||
|                     EmulationMenuSettings.showOverlay = it.isChecked | ||||
|                     BooleanSetting.SHOW_INPUT_OVERLAY.setBoolean(it.isChecked) | ||||
|                     binding.surfaceInputOverlay.refreshControls() | ||||
|                     true | ||||
|                 } | ||||
|  | ||||
|                 R.id.menu_rel_stick_center -> { | ||||
|                     it.isChecked = !it.isChecked | ||||
|                     EmulationMenuSettings.joystickRelCenter = it.isChecked | ||||
|                     BooleanSetting.JOYSTICK_REL_CENTER.setBoolean(it.isChecked) | ||||
|                     true | ||||
|                 } | ||||
|  | ||||
|                 R.id.menu_dpad_slide -> { | ||||
|                     it.isChecked = !it.isChecked | ||||
|                     EmulationMenuSettings.dpadSlide = it.isChecked | ||||
|                     BooleanSetting.DPAD_SLIDE.setBoolean(it.isChecked) | ||||
|                     true | ||||
|                 } | ||||
|  | ||||
|                 R.id.menu_haptics -> { | ||||
|                     it.isChecked = !it.isChecked | ||||
|                     EmulationMenuSettings.hapticFeedback = it.isChecked | ||||
|                     BooleanSetting.HAPTIC_FEEDBACK.setBoolean(it.isChecked) | ||||
|                     true | ||||
|                 } | ||||
|  | ||||
|                 R.id.menu_touchscreen -> { | ||||
|                     it.isChecked = !it.isChecked | ||||
|                     BooleanSetting.TOUCHSCREEN.setBoolean(it.isChecked) | ||||
|                     true | ||||
|                 } | ||||
|  | ||||
| @@ -667,6 +674,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | ||||
|                 it.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED | ||||
|             } | ||||
|         } | ||||
|         NativeConfig.saveGlobalConfig() | ||||
|     } | ||||
|  | ||||
|     @SuppressLint("SetTextI18n") | ||||
| @@ -675,7 +683,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | ||||
|         adjustBinding.apply { | ||||
|             inputScaleSlider.apply { | ||||
|                 valueTo = 150F | ||||
|                 value = preferences.getInt(Settings.PREF_CONTROL_SCALE, 50).toFloat() | ||||
|                 value = IntSetting.OVERLAY_SCALE.getInt().toFloat() | ||||
|                 addOnChangeListener( | ||||
|                     Slider.OnChangeListener { _, value, _ -> | ||||
|                         inputScaleValue.text = "${value.toInt()}%" | ||||
| @@ -685,7 +693,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | ||||
|             } | ||||
|             inputOpacitySlider.apply { | ||||
|                 valueTo = 100F | ||||
|                 value = preferences.getInt(Settings.PREF_CONTROL_OPACITY, 100).toFloat() | ||||
|                 value = IntSetting.OVERLAY_OPACITY.getInt().toFloat() | ||||
|                 addOnChangeListener( | ||||
|                     Slider.OnChangeListener { _, value, _ -> | ||||
|                         inputOpacityValue.text = "${value.toInt()}%" | ||||
| @@ -709,16 +717,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | ||||
|     } | ||||
|  | ||||
|     private fun setControlScale(scale: Int) { | ||||
|         preferences.edit() | ||||
|             .putInt(Settings.PREF_CONTROL_SCALE, scale) | ||||
|             .apply() | ||||
|         IntSetting.OVERLAY_SCALE.setInt(scale) | ||||
|         binding.surfaceInputOverlay.refreshControls() | ||||
|     } | ||||
|  | ||||
|     private fun setControlOpacity(opacity: Int) { | ||||
|         preferences.edit() | ||||
|             .putInt(Settings.PREF_CONTROL_OPACITY, opacity) | ||||
|             .apply() | ||||
|         IntSetting.OVERLAY_OPACITY.setInt(opacity) | ||||
|         binding.surfaceInputOverlay.refreshControls() | ||||
|     } | ||||
|  | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -10,6 +10,7 @@ import android.graphics.Rect | ||||
| import android.graphics.drawable.BitmapDrawable | ||||
| import android.view.MotionEvent | ||||
| import org.yuzu.yuzu_emu.NativeLibrary.ButtonState | ||||
| import org.yuzu.yuzu_emu.overlay.model.OverlayControlData | ||||
|  | ||||
| /** | ||||
|  * Custom [BitmapDrawable] that is capable | ||||
| @@ -25,7 +26,7 @@ class InputOverlayDrawableButton( | ||||
|     defaultStateBitmap: Bitmap, | ||||
|     pressedStateBitmap: Bitmap, | ||||
|     val buttonId: Int, | ||||
|     val prefId: String | ||||
|     val overlayControlData: OverlayControlData | ||||
| ) { | ||||
|     // The ID value what motion event is tracking | ||||
|     var trackId: Int | ||||
|   | ||||
| @@ -14,7 +14,7 @@ import kotlin.math.cos | ||||
| import kotlin.math.sin | ||||
| import kotlin.math.sqrt | ||||
| import org.yuzu.yuzu_emu.NativeLibrary | ||||
| import org.yuzu.yuzu_emu.utils.EmulationMenuSettings | ||||
| import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting | ||||
|  | ||||
| /** | ||||
|  * Custom [BitmapDrawable] that is capable | ||||
| @@ -125,7 +125,7 @@ class InputOverlayDrawableJoystick( | ||||
|             pressedState = true | ||||
|             outerBitmap.alpha = 0 | ||||
|             boundsBoxBitmap.alpha = opacity | ||||
|             if (EmulationMenuSettings.joystickRelCenter) { | ||||
|             if (BooleanSetting.JOYSTICK_REL_CENTER.getBoolean()) { | ||||
|                 virtBounds.offset( | ||||
|                     xPosition - virtBounds.centerX(), | ||||
|                     yPosition - virtBounds.centerY() | ||||
|   | ||||
| @@ -0,0 +1,188 @@ | ||||
| // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| package org.yuzu.yuzu_emu.overlay.model | ||||
|  | ||||
| import androidx.annotation.IntegerRes | ||||
| import org.yuzu.yuzu_emu.R | ||||
| import org.yuzu.yuzu_emu.YuzuApplication | ||||
|  | ||||
| enum class OverlayControl( | ||||
|     val id: String, | ||||
|     val defaultVisibility: Boolean, | ||||
|     @IntegerRes val defaultLandscapePositionResources: Pair<Int, Int>, | ||||
|     @IntegerRes val defaultPortraitPositionResources: Pair<Int, Int>, | ||||
|     @IntegerRes val defaultFoldablePositionResources: Pair<Int, Int> | ||||
| ) { | ||||
|     BUTTON_A( | ||||
|         "button_a", | ||||
|         true, | ||||
|         Pair(R.integer.BUTTON_A_X, R.integer.BUTTON_A_Y), | ||||
|         Pair(R.integer.BUTTON_A_X_PORTRAIT, R.integer.BUTTON_A_Y_PORTRAIT), | ||||
|         Pair(R.integer.BUTTON_A_X_FOLDABLE, R.integer.BUTTON_A_Y_FOLDABLE) | ||||
|     ), | ||||
|     BUTTON_B( | ||||
|         "button_b", | ||||
|         true, | ||||
|         Pair(R.integer.BUTTON_B_X, R.integer.BUTTON_B_Y), | ||||
|         Pair(R.integer.BUTTON_B_X_PORTRAIT, R.integer.BUTTON_B_Y_PORTRAIT), | ||||
|         Pair(R.integer.BUTTON_B_X_FOLDABLE, R.integer.BUTTON_B_Y_FOLDABLE) | ||||
|     ), | ||||
|     BUTTON_X( | ||||
|         "button_x", | ||||
|         true, | ||||
|         Pair(R.integer.BUTTON_X_X, R.integer.BUTTON_X_Y), | ||||
|         Pair(R.integer.BUTTON_X_X_PORTRAIT, R.integer.BUTTON_X_Y_PORTRAIT), | ||||
|         Pair(R.integer.BUTTON_X_X_FOLDABLE, R.integer.BUTTON_X_Y_FOLDABLE) | ||||
|     ), | ||||
|     BUTTON_Y( | ||||
|         "button_y", | ||||
|         true, | ||||
|         Pair(R.integer.BUTTON_Y_X, R.integer.BUTTON_Y_Y), | ||||
|         Pair(R.integer.BUTTON_Y_X_PORTRAIT, R.integer.BUTTON_Y_Y_PORTRAIT), | ||||
|         Pair(R.integer.BUTTON_Y_X_FOLDABLE, R.integer.BUTTON_Y_Y_FOLDABLE) | ||||
|     ), | ||||
|     BUTTON_PLUS( | ||||
|         "button_plus", | ||||
|         true, | ||||
|         Pair(R.integer.BUTTON_PLUS_X, R.integer.BUTTON_PLUS_Y), | ||||
|         Pair(R.integer.BUTTON_PLUS_X_PORTRAIT, R.integer.BUTTON_PLUS_Y_PORTRAIT), | ||||
|         Pair(R.integer.BUTTON_PLUS_X_FOLDABLE, R.integer.BUTTON_PLUS_Y_FOLDABLE) | ||||
|     ), | ||||
|     BUTTON_MINUS( | ||||
|         "button_minus", | ||||
|         true, | ||||
|         Pair(R.integer.BUTTON_MINUS_X, R.integer.BUTTON_MINUS_Y), | ||||
|         Pair(R.integer.BUTTON_MINUS_X_PORTRAIT, R.integer.BUTTON_MINUS_Y_PORTRAIT), | ||||
|         Pair(R.integer.BUTTON_MINUS_X_FOLDABLE, R.integer.BUTTON_MINUS_Y_FOLDABLE) | ||||
|     ), | ||||
|     BUTTON_HOME( | ||||
|         "button_home", | ||||
|         false, | ||||
|         Pair(R.integer.BUTTON_HOME_X, R.integer.BUTTON_HOME_Y), | ||||
|         Pair(R.integer.BUTTON_HOME_X_PORTRAIT, R.integer.BUTTON_HOME_Y_PORTRAIT), | ||||
|         Pair(R.integer.BUTTON_HOME_X_FOLDABLE, R.integer.BUTTON_HOME_Y_FOLDABLE) | ||||
|     ), | ||||
|     BUTTON_CAPTURE( | ||||
|         "button_capture", | ||||
|         false, | ||||
|         Pair(R.integer.BUTTON_CAPTURE_X, R.integer.BUTTON_CAPTURE_Y), | ||||
|         Pair(R.integer.BUTTON_CAPTURE_X_PORTRAIT, R.integer.BUTTON_CAPTURE_Y_PORTRAIT), | ||||
|         Pair(R.integer.BUTTON_CAPTURE_X_FOLDABLE, R.integer.BUTTON_CAPTURE_Y_FOLDABLE) | ||||
|     ), | ||||
|     BUTTON_L( | ||||
|         "button_l", | ||||
|         true, | ||||
|         Pair(R.integer.BUTTON_L_X, R.integer.BUTTON_L_Y), | ||||
|         Pair(R.integer.BUTTON_L_X_PORTRAIT, R.integer.BUTTON_L_Y_PORTRAIT), | ||||
|         Pair(R.integer.BUTTON_L_X_FOLDABLE, R.integer.BUTTON_L_Y_FOLDABLE) | ||||
|     ), | ||||
|     BUTTON_R( | ||||
|         "button_r", | ||||
|         true, | ||||
|         Pair(R.integer.BUTTON_R_X, R.integer.BUTTON_R_Y), | ||||
|         Pair(R.integer.BUTTON_R_X_PORTRAIT, R.integer.BUTTON_R_Y_PORTRAIT), | ||||
|         Pair(R.integer.BUTTON_R_X_FOLDABLE, R.integer.BUTTON_R_Y_FOLDABLE) | ||||
|     ), | ||||
|     BUTTON_ZL( | ||||
|         "button_zl", | ||||
|         true, | ||||
|         Pair(R.integer.BUTTON_ZL_X, R.integer.BUTTON_ZL_Y), | ||||
|         Pair(R.integer.BUTTON_ZL_X_PORTRAIT, R.integer.BUTTON_ZL_Y_PORTRAIT), | ||||
|         Pair(R.integer.BUTTON_ZL_X_FOLDABLE, R.integer.BUTTON_ZL_Y_FOLDABLE) | ||||
|     ), | ||||
|     BUTTON_ZR( | ||||
|         "button_zr", | ||||
|         true, | ||||
|         Pair(R.integer.BUTTON_ZR_X, R.integer.BUTTON_ZR_Y), | ||||
|         Pair(R.integer.BUTTON_ZR_X_PORTRAIT, R.integer.BUTTON_ZR_Y_PORTRAIT), | ||||
|         Pair(R.integer.BUTTON_ZR_X_FOLDABLE, R.integer.BUTTON_ZR_Y_FOLDABLE) | ||||
|     ), | ||||
|     BUTTON_STICK_L( | ||||
|         "button_stick_l", | ||||
|         true, | ||||
|         Pair(R.integer.BUTTON_STICK_L_X, R.integer.BUTTON_STICK_L_Y), | ||||
|         Pair(R.integer.BUTTON_STICK_L_X_PORTRAIT, R.integer.BUTTON_STICK_L_Y_PORTRAIT), | ||||
|         Pair(R.integer.BUTTON_STICK_L_X_FOLDABLE, R.integer.BUTTON_STICK_L_Y_FOLDABLE) | ||||
|     ), | ||||
|     BUTTON_STICK_R( | ||||
|         "button_stick_r", | ||||
|         true, | ||||
|         Pair(R.integer.BUTTON_STICK_R_X, R.integer.BUTTON_STICK_R_Y), | ||||
|         Pair(R.integer.BUTTON_STICK_R_X_PORTRAIT, R.integer.BUTTON_STICK_R_Y_PORTRAIT), | ||||
|         Pair(R.integer.BUTTON_STICK_R_X_FOLDABLE, R.integer.BUTTON_STICK_R_Y_FOLDABLE) | ||||
|     ), | ||||
|     STICK_L( | ||||
|         "stick_l", | ||||
|         true, | ||||
|         Pair(R.integer.STICK_L_X, R.integer.STICK_L_Y), | ||||
|         Pair(R.integer.STICK_L_X_PORTRAIT, R.integer.STICK_L_Y_PORTRAIT), | ||||
|         Pair(R.integer.STICK_L_X_FOLDABLE, R.integer.STICK_L_Y_FOLDABLE) | ||||
|     ), | ||||
|     STICK_R( | ||||
|         "stick_r", | ||||
|         true, | ||||
|         Pair(R.integer.STICK_R_X, R.integer.STICK_R_Y), | ||||
|         Pair(R.integer.STICK_R_X_PORTRAIT, R.integer.STICK_R_Y_PORTRAIT), | ||||
|         Pair(R.integer.STICK_R_X_FOLDABLE, R.integer.STICK_R_Y_FOLDABLE) | ||||
|     ), | ||||
|     COMBINED_DPAD( | ||||
|         "combined_dpad", | ||||
|         true, | ||||
|         Pair(R.integer.COMBINED_DPAD_X, R.integer.COMBINED_DPAD_Y), | ||||
|         Pair(R.integer.COMBINED_DPAD_X_PORTRAIT, R.integer.COMBINED_DPAD_Y_PORTRAIT), | ||||
|         Pair(R.integer.COMBINED_DPAD_X_FOLDABLE, R.integer.COMBINED_DPAD_Y_FOLDABLE) | ||||
|     ); | ||||
|  | ||||
|     fun getDefaultPositionForLayout(layout: OverlayLayout): Pair<Double, Double> { | ||||
|         val rawResourcePair: Pair<Int, Int> | ||||
|         YuzuApplication.appContext.resources.apply { | ||||
|             rawResourcePair = when (layout) { | ||||
|                 OverlayLayout.Landscape -> { | ||||
|                     Pair( | ||||
|                         getInteger(this@OverlayControl.defaultLandscapePositionResources.first), | ||||
|                         getInteger(this@OverlayControl.defaultLandscapePositionResources.second) | ||||
|                     ) | ||||
|                 } | ||||
|  | ||||
|                 OverlayLayout.Portrait -> { | ||||
|                     Pair( | ||||
|                         getInteger(this@OverlayControl.defaultPortraitPositionResources.first), | ||||
|                         getInteger(this@OverlayControl.defaultPortraitPositionResources.second) | ||||
|                     ) | ||||
|                 } | ||||
|  | ||||
|                 OverlayLayout.Foldable -> { | ||||
|                     Pair( | ||||
|                         getInteger(this@OverlayControl.defaultFoldablePositionResources.first), | ||||
|                         getInteger(this@OverlayControl.defaultFoldablePositionResources.second) | ||||
|                     ) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return Pair( | ||||
|             rawResourcePair.first.toDouble() / 1000, | ||||
|             rawResourcePair.second.toDouble() / 1000 | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|     fun toOverlayControlData(): OverlayControlData = | ||||
|         OverlayControlData( | ||||
|             id, | ||||
|             defaultVisibility, | ||||
|             getDefaultPositionForLayout(OverlayLayout.Landscape), | ||||
|             getDefaultPositionForLayout(OverlayLayout.Portrait), | ||||
|             getDefaultPositionForLayout(OverlayLayout.Foldable) | ||||
|         ) | ||||
|  | ||||
|     companion object { | ||||
|         val map: HashMap<String, OverlayControl> by lazy { | ||||
|             val hashMap = hashMapOf<String, OverlayControl>() | ||||
|             entries.forEach { hashMap[it.id] = it } | ||||
|             hashMap | ||||
|         } | ||||
|  | ||||
|         fun from(id: String): OverlayControl? = map[id] | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,19 @@ | ||||
| // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| package org.yuzu.yuzu_emu.overlay.model | ||||
|  | ||||
| data class OverlayControlData( | ||||
|     val id: String, | ||||
|     var enabled: Boolean, | ||||
|     var landscapePosition: Pair<Double, Double>, | ||||
|     var portraitPosition: Pair<Double, Double>, | ||||
|     var foldablePosition: Pair<Double, Double> | ||||
| ) { | ||||
|     fun positionFromLayout(layout: OverlayLayout): Pair<Double, Double> = | ||||
|         when (layout) { | ||||
|             OverlayLayout.Landscape -> landscapePosition | ||||
|             OverlayLayout.Portrait -> portraitPosition | ||||
|             OverlayLayout.Foldable -> foldablePosition | ||||
|         } | ||||
| } | ||||
| @@ -0,0 +1,13 @@ | ||||
| // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| package org.yuzu.yuzu_emu.overlay.model | ||||
|  | ||||
| import androidx.annotation.IntegerRes | ||||
|  | ||||
| data class OverlayControlDefault( | ||||
|     val buttonId: String, | ||||
|     @IntegerRes val landscapePositionResource: Pair<Int, Int>, | ||||
|     @IntegerRes val portraitPositionResource: Pair<Int, Int>, | ||||
|     @IntegerRes val foldablePositionResource: Pair<Int, Int> | ||||
| ) | ||||
| @@ -0,0 +1,10 @@ | ||||
| // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| package org.yuzu.yuzu_emu.overlay.model | ||||
|  | ||||
| enum class OverlayLayout(val id: String) { | ||||
|     Landscape("Landscape"), | ||||
|     Portrait("Portrait"), | ||||
|     Foldable("Foldable") | ||||
| } | ||||
| @@ -3,9 +3,17 @@ | ||||
|  | ||||
| package org.yuzu.yuzu_emu.utils | ||||
|  | ||||
| import androidx.preference.PreferenceManager | ||||
| import java.io.IOException | ||||
| import org.yuzu.yuzu_emu.NativeLibrary | ||||
| import org.yuzu.yuzu_emu.YuzuApplication | ||||
| import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting | ||||
| import org.yuzu.yuzu_emu.features.settings.model.IntSetting | ||||
| import org.yuzu.yuzu_emu.features.settings.model.Settings | ||||
| import org.yuzu.yuzu_emu.overlay.model.OverlayControlData | ||||
| import org.yuzu.yuzu_emu.overlay.model.OverlayControl | ||||
| import org.yuzu.yuzu_emu.overlay.model.OverlayLayout | ||||
| import org.yuzu.yuzu_emu.utils.PreferenceUtil.migratePreference | ||||
|  | ||||
| object DirectoryInitialization { | ||||
|     private var userPath: String? = null | ||||
| @@ -17,6 +25,7 @@ object DirectoryInitialization { | ||||
|             initializeInternalStorage() | ||||
|             NativeLibrary.initializeSystem(false) | ||||
|             NativeConfig.initializeGlobalConfig() | ||||
|             migrateSettings() | ||||
|             areDirectoriesReady = true | ||||
|         } | ||||
|     } | ||||
| @@ -35,4 +44,170 @@ object DirectoryInitialization { | ||||
|             e.printStackTrace() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private fun migrateSettings() { | ||||
|         val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) | ||||
|         var saveConfig = false | ||||
|         val theme = preferences.migratePreference<Int>(Settings.PREF_THEME) | ||||
|         if (theme != null) { | ||||
|             IntSetting.THEME.setInt(theme) | ||||
|             saveConfig = true | ||||
|         } | ||||
|  | ||||
|         val themeMode = preferences.migratePreference<Int>(Settings.PREF_THEME_MODE) | ||||
|         if (themeMode != null) { | ||||
|             IntSetting.THEME_MODE.setInt(themeMode) | ||||
|             saveConfig = true | ||||
|         } | ||||
|  | ||||
|         val blackBackgrounds = | ||||
|             preferences.migratePreference<Boolean>(Settings.PREF_BLACK_BACKGROUNDS) | ||||
|         if (blackBackgrounds != null) { | ||||
|             BooleanSetting.BLACK_BACKGROUNDS.setBoolean(blackBackgrounds) | ||||
|             saveConfig = true | ||||
|         } | ||||
|  | ||||
|         val joystickRelCenter = | ||||
|             preferences.migratePreference<Boolean>(Settings.PREF_MENU_SETTINGS_JOYSTICK_REL_CENTER) | ||||
|         if (joystickRelCenter != null) { | ||||
|             BooleanSetting.JOYSTICK_REL_CENTER.setBoolean(joystickRelCenter) | ||||
|             saveConfig = true | ||||
|         } | ||||
|  | ||||
|         val dpadSlide = | ||||
|             preferences.migratePreference<Boolean>(Settings.PREF_MENU_SETTINGS_DPAD_SLIDE) | ||||
|         if (dpadSlide != null) { | ||||
|             BooleanSetting.DPAD_SLIDE.setBoolean(dpadSlide) | ||||
|             saveConfig = true | ||||
|         } | ||||
|  | ||||
|         val hapticFeedback = | ||||
|             preferences.migratePreference<Boolean>(Settings.PREF_MENU_SETTINGS_HAPTICS) | ||||
|         if (hapticFeedback != null) { | ||||
|             BooleanSetting.HAPTIC_FEEDBACK.setBoolean(hapticFeedback) | ||||
|             saveConfig = true | ||||
|         } | ||||
|  | ||||
|         val showPerformanceOverlay = | ||||
|             preferences.migratePreference<Boolean>(Settings.PREF_MENU_SETTINGS_SHOW_FPS) | ||||
|         if (showPerformanceOverlay != null) { | ||||
|             BooleanSetting.SHOW_PERFORMANCE_OVERLAY.setBoolean(showPerformanceOverlay) | ||||
|             saveConfig = true | ||||
|         } | ||||
|  | ||||
|         val showInputOverlay = | ||||
|             preferences.migratePreference<Boolean>(Settings.PREF_MENU_SETTINGS_SHOW_OVERLAY) | ||||
|         if (showInputOverlay != null) { | ||||
|             BooleanSetting.SHOW_INPUT_OVERLAY.setBoolean(showInputOverlay) | ||||
|             saveConfig = true | ||||
|         } | ||||
|  | ||||
|         val overlayOpacity = preferences.migratePreference<Int>(Settings.PREF_CONTROL_OPACITY) | ||||
|         if (overlayOpacity != null) { | ||||
|             IntSetting.OVERLAY_OPACITY.setInt(overlayOpacity) | ||||
|             saveConfig = true | ||||
|         } | ||||
|  | ||||
|         val overlayScale = preferences.migratePreference<Int>(Settings.PREF_CONTROL_SCALE) | ||||
|         if (overlayScale != null) { | ||||
|             IntSetting.OVERLAY_SCALE.setInt(overlayScale) | ||||
|             saveConfig = true | ||||
|         } | ||||
|  | ||||
|         var setOverlayData = false | ||||
|         val overlayControlData = NativeConfig.getOverlayControlData() | ||||
|         if (overlayControlData.isEmpty()) { | ||||
|             val overlayControlDataMap = | ||||
|                 NativeConfig.getOverlayControlData().associateBy { it.id }.toMutableMap() | ||||
|             for (button in Settings.overlayPreferences) { | ||||
|                 val buttonId = convertButtonId(button) | ||||
|                 var buttonEnabled = preferences.migratePreference<Boolean>(button) | ||||
|                 if (buttonEnabled == null) { | ||||
|                     buttonEnabled = OverlayControl.map[buttonId]?.defaultVisibility == true | ||||
|                 } | ||||
|  | ||||
|                 var landscapeXPosition = preferences.migratePreference<Float>( | ||||
|                     "$button-X${Settings.PREF_LANDSCAPE_SUFFIX}" | ||||
|                 )?.toDouble() | ||||
|                 var landscapeYPosition = preferences.migratePreference<Float>( | ||||
|                     "$button-Y${Settings.PREF_LANDSCAPE_SUFFIX}" | ||||
|                 )?.toDouble() | ||||
|                 if (landscapeXPosition == null || landscapeYPosition == null) { | ||||
|                     val landscapePosition = OverlayControl.map[buttonId] | ||||
|                         ?.getDefaultPositionForLayout(OverlayLayout.Landscape) ?: Pair(0.0, 0.0) | ||||
|                     landscapeXPosition = landscapePosition.first | ||||
|                     landscapeYPosition = landscapePosition.second | ||||
|                 } | ||||
|  | ||||
|                 var portraitXPosition = preferences.migratePreference<Float>( | ||||
|                     "$button-X${Settings.PREF_PORTRAIT_SUFFIX}" | ||||
|                 )?.toDouble() | ||||
|                 var portraitYPosition = preferences.migratePreference<Float>( | ||||
|                     "$button-Y${Settings.PREF_PORTRAIT_SUFFIX}" | ||||
|                 )?.toDouble() | ||||
|                 if (portraitXPosition == null || portraitYPosition == null) { | ||||
|                     val portraitPosition = OverlayControl.map[buttonId] | ||||
|                         ?.getDefaultPositionForLayout(OverlayLayout.Portrait) ?: Pair(0.0, 0.0) | ||||
|                     portraitXPosition = portraitPosition.first | ||||
|                     portraitYPosition = portraitPosition.second | ||||
|                 } | ||||
|  | ||||
|                 var foldableXPosition = preferences.migratePreference<Float>( | ||||
|                     "$button-X${Settings.PREF_FOLDABLE_SUFFIX}" | ||||
|                 )?.toDouble() | ||||
|                 var foldableYPosition = preferences.migratePreference<Float>( | ||||
|                     "$button-Y${Settings.PREF_FOLDABLE_SUFFIX}" | ||||
|                 )?.toDouble() | ||||
|                 if (foldableXPosition == null || foldableYPosition == null) { | ||||
|                     val foldablePosition = OverlayControl.map[buttonId] | ||||
|                         ?.getDefaultPositionForLayout(OverlayLayout.Foldable) ?: Pair(0.0, 0.0) | ||||
|                     foldableXPosition = foldablePosition.first | ||||
|                     foldableYPosition = foldablePosition.second | ||||
|                 } | ||||
|  | ||||
|                 val controlData = OverlayControlData( | ||||
|                     buttonId, | ||||
|                     buttonEnabled, | ||||
|                     Pair(landscapeXPosition, landscapeYPosition), | ||||
|                     Pair(portraitXPosition, portraitYPosition), | ||||
|                     Pair(foldableXPosition, foldableYPosition) | ||||
|                 ) | ||||
|                 overlayControlDataMap[buttonId] = controlData | ||||
|                 setOverlayData = true | ||||
|             } | ||||
|  | ||||
|             if (setOverlayData) { | ||||
|                 NativeConfig.setOverlayControlData( | ||||
|                     overlayControlDataMap.map { it.value }.toTypedArray() | ||||
|                 ) | ||||
|                 saveConfig = true | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (saveConfig) { | ||||
|             NativeConfig.saveGlobalConfig() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private fun convertButtonId(buttonId: String): String = | ||||
|         when (buttonId) { | ||||
|             Settings.PREF_BUTTON_A -> OverlayControl.BUTTON_A.id | ||||
|             Settings.PREF_BUTTON_B -> OverlayControl.BUTTON_B.id | ||||
|             Settings.PREF_BUTTON_X -> OverlayControl.BUTTON_X.id | ||||
|             Settings.PREF_BUTTON_Y -> OverlayControl.BUTTON_Y.id | ||||
|             Settings.PREF_BUTTON_L -> OverlayControl.BUTTON_L.id | ||||
|             Settings.PREF_BUTTON_R -> OverlayControl.BUTTON_R.id | ||||
|             Settings.PREF_BUTTON_ZL -> OverlayControl.BUTTON_ZL.id | ||||
|             Settings.PREF_BUTTON_ZR -> OverlayControl.BUTTON_ZR.id | ||||
|             Settings.PREF_BUTTON_PLUS -> OverlayControl.BUTTON_PLUS.id | ||||
|             Settings.PREF_BUTTON_MINUS -> OverlayControl.BUTTON_MINUS.id | ||||
|             Settings.PREF_BUTTON_DPAD -> OverlayControl.COMBINED_DPAD.id | ||||
|             Settings.PREF_STICK_L -> OverlayControl.STICK_L.id | ||||
|             Settings.PREF_STICK_R -> OverlayControl.STICK_R.id | ||||
|             Settings.PREF_BUTTON_HOME -> OverlayControl.BUTTON_HOME.id | ||||
|             Settings.PREF_BUTTON_SCREENSHOT -> OverlayControl.BUTTON_CAPTURE.id | ||||
|             Settings.PREF_BUTTON_STICK_L -> OverlayControl.BUTTON_STICK_L.id | ||||
|             Settings.PREF_BUTTON_STICK_R -> OverlayControl.BUTTON_STICK_R.id | ||||
|             else -> "" | ||||
|         } | ||||
| } | ||||
|   | ||||
| @@ -1,50 +0,0 @@ | ||||
| // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| package org.yuzu.yuzu_emu.utils | ||||
|  | ||||
| import androidx.preference.PreferenceManager | ||||
| import org.yuzu.yuzu_emu.YuzuApplication | ||||
| import org.yuzu.yuzu_emu.features.settings.model.Settings | ||||
|  | ||||
| object EmulationMenuSettings { | ||||
|     private val preferences = | ||||
|         PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) | ||||
|  | ||||
|     var joystickRelCenter: Boolean | ||||
|         get() = preferences.getBoolean(Settings.PREF_MENU_SETTINGS_JOYSTICK_REL_CENTER, true) | ||||
|         set(value) { | ||||
|             preferences.edit() | ||||
|                 .putBoolean(Settings.PREF_MENU_SETTINGS_JOYSTICK_REL_CENTER, value) | ||||
|                 .apply() | ||||
|         } | ||||
|     var dpadSlide: Boolean | ||||
|         get() = preferences.getBoolean(Settings.PREF_MENU_SETTINGS_DPAD_SLIDE, true) | ||||
|         set(value) { | ||||
|             preferences.edit() | ||||
|                 .putBoolean(Settings.PREF_MENU_SETTINGS_DPAD_SLIDE, value) | ||||
|                 .apply() | ||||
|         } | ||||
|     var hapticFeedback: Boolean | ||||
|         get() = preferences.getBoolean(Settings.PREF_MENU_SETTINGS_HAPTICS, false) | ||||
|         set(value) { | ||||
|             preferences.edit() | ||||
|                 .putBoolean(Settings.PREF_MENU_SETTINGS_HAPTICS, value) | ||||
|                 .apply() | ||||
|         } | ||||
|  | ||||
|     var showFps: Boolean | ||||
|         get() = preferences.getBoolean(Settings.PREF_MENU_SETTINGS_SHOW_FPS, false) | ||||
|         set(value) { | ||||
|             preferences.edit() | ||||
|                 .putBoolean(Settings.PREF_MENU_SETTINGS_SHOW_FPS, value) | ||||
|                 .apply() | ||||
|         } | ||||
|     var showOverlay: Boolean | ||||
|         get() = preferences.getBoolean(Settings.PREF_MENU_SETTINGS_SHOW_OVERLAY, true) | ||||
|         set(value) { | ||||
|             preferences.edit() | ||||
|                 .putBoolean(Settings.PREF_MENU_SETTINGS_SHOW_OVERLAY, value) | ||||
|                 .apply() | ||||
|         } | ||||
| } | ||||
| @@ -4,6 +4,7 @@ | ||||
| package org.yuzu.yuzu_emu.utils | ||||
|  | ||||
| import org.yuzu.yuzu_emu.model.GameDir | ||||
| import org.yuzu.yuzu_emu.overlay.model.OverlayControlData | ||||
|  | ||||
| object NativeConfig { | ||||
|     /** | ||||
| @@ -150,4 +151,21 @@ object NativeConfig { | ||||
|      */ | ||||
|     @Synchronized | ||||
|     external fun setDisabledAddons(programId: String, disabledAddons: Array<String>) | ||||
|  | ||||
|     /** | ||||
|      * Gets an array of [OverlayControlData] from settings | ||||
|      * | ||||
|      * @return An array of [OverlayControlData] | ||||
|      */ | ||||
|     @Synchronized | ||||
|     external fun getOverlayControlData(): Array<OverlayControlData> | ||||
|  | ||||
|     /** | ||||
|      * Clears the AndroidSettings::values.overlay_control_data array and replaces its values | ||||
|      * with [overlayControlData] | ||||
|      * | ||||
|      * @param overlayControlData Replacement array of [OverlayControlData] | ||||
|      */ | ||||
|     @Synchronized | ||||
|     external fun setOverlayControlData(overlayControlData: Array<OverlayControlData>) | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,37 @@ | ||||
| // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| package org.yuzu.yuzu_emu.utils | ||||
|  | ||||
| import android.content.SharedPreferences | ||||
|  | ||||
| object PreferenceUtil { | ||||
|     /** | ||||
|      * Retrieves a shared preference value and then deletes the value in storage. | ||||
|      * @param key Associated key for the value in this preferences instance | ||||
|      * @return Typed value associated with [key]. Null if no such key exists. | ||||
|      */ | ||||
|     inline fun <reified T> SharedPreferences.migratePreference(key: String): T? { | ||||
|         if (!this.contains(key)) { | ||||
|             return null | ||||
|         } | ||||
|  | ||||
|         val value: Any = when (T::class) { | ||||
|             String::class -> this.getString(key, "")!! | ||||
|  | ||||
|             Boolean::class -> this.getBoolean(key, false) | ||||
|  | ||||
|             Int::class -> this.getInt(key, 0) | ||||
|  | ||||
|             Float::class -> this.getFloat(key, 0f) | ||||
|  | ||||
|             Long::class -> this.getLong(key, 0) | ||||
|  | ||||
|             else -> throw IllegalStateException("Tried to migrate preference with invalid type!") | ||||
|         } | ||||
|         deletePreference(key) | ||||
|         return value as T | ||||
|     } | ||||
|  | ||||
|     fun SharedPreferences.deletePreference(key: String) = this.edit().remove(key).apply() | ||||
| } | ||||
| @@ -5,38 +5,38 @@ package org.yuzu.yuzu_emu.utils | ||||
|  | ||||
| import android.content.res.Configuration | ||||
| import android.graphics.Color | ||||
| import android.os.Build | ||||
| import androidx.annotation.ColorInt | ||||
| import androidx.appcompat.app.AppCompatActivity | ||||
| import androidx.appcompat.app.AppCompatDelegate | ||||
| import androidx.core.view.WindowCompat | ||||
| import androidx.core.view.WindowInsetsControllerCompat | ||||
| import androidx.preference.PreferenceManager | ||||
| import kotlin.math.roundToInt | ||||
| import org.yuzu.yuzu_emu.R | ||||
| import org.yuzu.yuzu_emu.YuzuApplication | ||||
| import org.yuzu.yuzu_emu.features.settings.model.Settings | ||||
| import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting | ||||
| import org.yuzu.yuzu_emu.features.settings.model.IntSetting | ||||
| import org.yuzu.yuzu_emu.ui.main.ThemeProvider | ||||
|  | ||||
| object ThemeHelper { | ||||
|     const val SYSTEM_BAR_ALPHA = 0.9f | ||||
|  | ||||
|     private const val DEFAULT = 0 | ||||
|     private const val MATERIAL_YOU = 1 | ||||
|  | ||||
|     fun setTheme(activity: AppCompatActivity) { | ||||
|         val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) | ||||
|         setThemeMode(activity) | ||||
|         when (preferences.getInt(Settings.PREF_THEME, 0)) { | ||||
|             DEFAULT -> activity.setTheme(R.style.Theme_Yuzu_Main) | ||||
|             MATERIAL_YOU -> activity.setTheme(R.style.Theme_Yuzu_Main_MaterialYou) | ||||
|         when (Theme.from(IntSetting.THEME.getInt())) { | ||||
|             Theme.Default -> activity.setTheme(R.style.Theme_Yuzu_Main) | ||||
|             Theme.MaterialYou -> { | ||||
|                 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { | ||||
|                     activity.setTheme(R.style.Theme_Yuzu_Main_MaterialYou) | ||||
|                 } else { | ||||
|                     activity.setTheme(R.style.Theme_Yuzu_Main) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Using a specific night mode check because this could apply incorrectly when using the | ||||
|         // light app mode, dark system mode, and black backgrounds. Launching the settings activity | ||||
|         // will then show light mode colors/navigation bars but with black backgrounds. | ||||
|         if (preferences.getBoolean(Settings.PREF_BLACK_BACKGROUNDS, false) && | ||||
|             isNightMode(activity) | ||||
|         ) { | ||||
|         if (BooleanSetting.BLACK_BACKGROUNDS.getBoolean() && isNightMode(activity)) { | ||||
|             activity.setTheme(R.style.ThemeOverlay_Yuzu_Dark) | ||||
|         } | ||||
|     } | ||||
| @@ -60,8 +60,7 @@ object ThemeHelper { | ||||
|     } | ||||
|  | ||||
|     fun setThemeMode(activity: AppCompatActivity) { | ||||
|         val themeMode = PreferenceManager.getDefaultSharedPreferences(activity.applicationContext) | ||||
|             .getInt(Settings.PREF_THEME_MODE, AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) | ||||
|         val themeMode = IntSetting.THEME_MODE.getInt() | ||||
|         activity.delegate.localNightMode = themeMode | ||||
|         val windowController = WindowCompat.getInsetsController( | ||||
|             activity.window, | ||||
| @@ -95,3 +94,12 @@ object ThemeHelper { | ||||
|         windowController.isAppearanceLightNavigationBars = false | ||||
|     } | ||||
| } | ||||
|  | ||||
| enum class Theme(val int: Int) { | ||||
|     Default(0), | ||||
|     MaterialYou(1); | ||||
|  | ||||
|     companion object { | ||||
|         fun from(int: Int): Theme = entries.firstOrNull { it.int == int } ?: Default | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -9,6 +9,7 @@ | ||||
| #include <jni.h> | ||||
|  | ||||
| #include "common/string_util.h" | ||||
| #include "jni/id_cache.h" | ||||
|  | ||||
| std::string GetJString(JNIEnv* env, jstring jstr) { | ||||
|     if (!jstr) { | ||||
| @@ -33,3 +34,11 @@ jstring ToJString(JNIEnv* env, std::string_view str) { | ||||
| jstring ToJString(JNIEnv* env, std::u16string_view str) { | ||||
|     return ToJString(env, Common::UTF16ToUTF8(str)); | ||||
| } | ||||
|  | ||||
| double GetJDouble(JNIEnv* env, jobject jdouble) { | ||||
|     return env->GetDoubleField(jdouble, IDCache::GetDoubleValueField()); | ||||
| } | ||||
|  | ||||
| jobject ToJDouble(JNIEnv* env, double value) { | ||||
|     return env->NewObject(IDCache::GetDoubleClass(), IDCache::GetDoubleConstructor(), value); | ||||
| } | ||||
|   | ||||
| @@ -10,3 +10,6 @@ | ||||
| std::string GetJString(JNIEnv* env, jstring jstr); | ||||
| jstring ToJString(JNIEnv* env, std::string_view str); | ||||
| jstring ToJString(JNIEnv* env, std::u16string_view str); | ||||
|  | ||||
| double GetJDouble(JNIEnv* env, jobject jdouble); | ||||
| jobject ToJDouble(JNIEnv* env, double value); | ||||
|   | ||||
| @@ -35,6 +35,7 @@ void AndroidConfig::ReadAndroidValues() { | ||||
|     if (global) { | ||||
|         ReadAndroidUIValues(); | ||||
|         ReadUIValues(); | ||||
|         ReadOverlayValues(); | ||||
|     } | ||||
|     ReadDriverValues(); | ||||
| } | ||||
| @@ -81,10 +82,42 @@ void AndroidConfig::ReadDriverValues() { | ||||
|     EndGroup(); | ||||
| } | ||||
|  | ||||
| void AndroidConfig::ReadOverlayValues() { | ||||
|     BeginGroup(Settings::TranslateCategory(Settings::Category::Overlay)); | ||||
|  | ||||
|     ReadCategory(Settings::Category::Overlay); | ||||
|  | ||||
|     AndroidSettings::values.overlay_control_data.clear(); | ||||
|     const int control_data_size = BeginArray("control_data"); | ||||
|     for (int i = 0; i < control_data_size; ++i) { | ||||
|         SetArrayIndex(i); | ||||
|         AndroidSettings::OverlayControlData control_data; | ||||
|         control_data.id = ReadStringSetting(std::string("id")); | ||||
|         control_data.enabled = ReadBooleanSetting(std::string("enabled")); | ||||
|         control_data.landscape_position.first = | ||||
|             ReadDoubleSetting(std::string("landscape\\x_position")); | ||||
|         control_data.landscape_position.second = | ||||
|             ReadDoubleSetting(std::string("landscape\\y_position")); | ||||
|         control_data.portrait_position.first = | ||||
|             ReadDoubleSetting(std::string("portrait\\x_position")); | ||||
|         control_data.portrait_position.second = | ||||
|             ReadDoubleSetting(std::string("portrait\\y_position")); | ||||
|         control_data.foldable_position.first = | ||||
|             ReadDoubleSetting(std::string("foldable\\x_position")); | ||||
|         control_data.foldable_position.second = | ||||
|             ReadDoubleSetting(std::string("foldable\\y_position")); | ||||
|         AndroidSettings::values.overlay_control_data.push_back(control_data); | ||||
|     } | ||||
|     EndArray(); | ||||
|  | ||||
|     EndGroup(); | ||||
| } | ||||
|  | ||||
| void AndroidConfig::SaveAndroidValues() { | ||||
|     if (global) { | ||||
|         SaveAndroidUIValues(); | ||||
|         SaveUIValues(); | ||||
|         SaveOverlayValues(); | ||||
|     } | ||||
|     SaveDriverValues(); | ||||
|  | ||||
| @@ -114,8 +147,9 @@ void AndroidConfig::SavePathValues() { | ||||
|     for (size_t i = 0; i < AndroidSettings::values.game_dirs.size(); ++i) { | ||||
|         SetArrayIndex(i); | ||||
|         const auto& game_dir = AndroidSettings::values.game_dirs[i]; | ||||
|         WriteSetting(std::string("path"), game_dir.path); | ||||
|         WriteSetting(std::string("deep_scan"), game_dir.deep_scan, std::make_optional(false)); | ||||
|         WriteStringSetting(std::string("path"), game_dir.path); | ||||
|         WriteBooleanSetting(std::string("deep_scan"), game_dir.deep_scan, | ||||
|                             std::make_optional(false)); | ||||
|     } | ||||
|     EndArray(); | ||||
|  | ||||
| @@ -130,6 +164,35 @@ void AndroidConfig::SaveDriverValues() { | ||||
|     EndGroup(); | ||||
| } | ||||
|  | ||||
| void AndroidConfig::SaveOverlayValues() { | ||||
|     BeginGroup(Settings::TranslateCategory(Settings::Category::Overlay)); | ||||
|  | ||||
|     WriteCategory(Settings::Category::Overlay); | ||||
|  | ||||
|     BeginArray("control_data"); | ||||
|     for (size_t i = 0; i < AndroidSettings::values.overlay_control_data.size(); ++i) { | ||||
|         SetArrayIndex(i); | ||||
|         const auto& control_data = AndroidSettings::values.overlay_control_data[i]; | ||||
|         WriteStringSetting(std::string("id"), control_data.id); | ||||
|         WriteBooleanSetting(std::string("enabled"), control_data.enabled); | ||||
|         WriteDoubleSetting(std::string("landscape\\x_position"), | ||||
|                            control_data.landscape_position.first); | ||||
|         WriteDoubleSetting(std::string("landscape\\y_position"), | ||||
|                            control_data.landscape_position.second); | ||||
|         WriteDoubleSetting(std::string("portrait\\x_position"), | ||||
|                            control_data.portrait_position.first); | ||||
|         WriteDoubleSetting(std::string("portrait\\y_position"), | ||||
|                            control_data.portrait_position.second); | ||||
|         WriteDoubleSetting(std::string("foldable\\x_position"), | ||||
|                            control_data.foldable_position.first); | ||||
|         WriteDoubleSetting(std::string("foldable\\y_position"), | ||||
|                            control_data.foldable_position.second); | ||||
|     } | ||||
|     EndArray(); | ||||
|  | ||||
|     EndGroup(); | ||||
| } | ||||
|  | ||||
| std::vector<Settings::BasicSetting*>& AndroidConfig::FindRelevantList(Settings::Category category) { | ||||
|     auto& map = Settings::values.linkage.by_category; | ||||
|     if (map.contains(category)) { | ||||
|   | ||||
| @@ -18,6 +18,7 @@ protected: | ||||
|     void ReadAndroidValues(); | ||||
|     void ReadAndroidUIValues(); | ||||
|     void ReadDriverValues(); | ||||
|     void ReadOverlayValues(); | ||||
|     void ReadHidbusValues() override {} | ||||
|     void ReadDebugControlValues() override {} | ||||
|     void ReadPathValues() override; | ||||
| @@ -30,6 +31,7 @@ protected: | ||||
|     void SaveAndroidValues(); | ||||
|     void SaveAndroidUIValues(); | ||||
|     void SaveDriverValues(); | ||||
|     void SaveOverlayValues(); | ||||
|     void SaveHidbusValues() override {} | ||||
|     void SaveDebugControlValues() override {} | ||||
|     void SavePathValues() override; | ||||
|   | ||||
| @@ -14,6 +14,14 @@ struct GameDir { | ||||
|     bool deep_scan = false; | ||||
| }; | ||||
|  | ||||
| struct OverlayControlData { | ||||
|     std::string id; | ||||
|     bool enabled; | ||||
|     std::pair<double, double> landscape_position; | ||||
|     std::pair<double, double> portrait_position; | ||||
|     std::pair<double, double> foldable_position; | ||||
| }; | ||||
|  | ||||
| struct Values { | ||||
|     Settings::Linkage linkage; | ||||
|  | ||||
| @@ -33,6 +41,28 @@ struct Values { | ||||
|  | ||||
|     Settings::SwitchableSetting<std::string, false> driver_path{linkage, "", "driver_path", | ||||
|                                                                 Settings::Category::GpuDriver}; | ||||
|  | ||||
|     Settings::Setting<s32> theme{linkage, 0, "theme", Settings::Category::Android}; | ||||
|     Settings::Setting<s32> theme_mode{linkage, -1, "theme_mode", Settings::Category::Android}; | ||||
|     Settings::Setting<bool> black_backgrounds{linkage, false, "black_backgrounds", | ||||
|                                               Settings::Category::Android}; | ||||
|  | ||||
|     // Input/performance overlay settings | ||||
|     std::vector<OverlayControlData> overlay_control_data; | ||||
|     Settings::Setting<s32> overlay_scale{linkage, 50, "control_scale", Settings::Category::Overlay}; | ||||
|     Settings::Setting<s32> overlay_opacity{linkage, 100, "control_opacity", | ||||
|                                            Settings::Category::Overlay}; | ||||
|  | ||||
|     Settings::Setting<bool> joystick_rel_center{linkage, true, "joystick_rel_center", | ||||
|                                                 Settings::Category::Overlay}; | ||||
|     Settings::Setting<bool> dpad_slide{linkage, true, "dpad_slide", Settings::Category::Overlay}; | ||||
|     Settings::Setting<bool> haptic_feedback{linkage, true, "haptic_feedback", | ||||
|                                             Settings::Category::Overlay}; | ||||
|     Settings::Setting<bool> show_performance_overlay{linkage, true, "show_performance_overlay", | ||||
|                                                      Settings::Category::Overlay}; | ||||
|     Settings::Setting<bool> show_input_overlay{linkage, true, "show_input_overlay", | ||||
|                                                Settings::Category::Overlay}; | ||||
|     Settings::Setting<bool> touchscreen{linkage, true, "touchscreen", Settings::Category::Overlay}; | ||||
| }; | ||||
|  | ||||
| extern Values values; | ||||
|   | ||||
| @@ -35,6 +35,18 @@ static jmethodID s_pair_constructor; | ||||
| static jfieldID s_pair_first_field; | ||||
| static jfieldID s_pair_second_field; | ||||
|  | ||||
| static jclass s_overlay_control_data_class; | ||||
| static jmethodID s_overlay_control_data_constructor; | ||||
| static jfieldID s_overlay_control_data_id_field; | ||||
| static jfieldID s_overlay_control_data_enabled_field; | ||||
| static jfieldID s_overlay_control_data_landscape_position_field; | ||||
| static jfieldID s_overlay_control_data_portrait_position_field; | ||||
| static jfieldID s_overlay_control_data_foldable_position_field; | ||||
|  | ||||
| static jclass s_double_class; | ||||
| static jmethodID s_double_constructor; | ||||
| static jfieldID s_double_value_field; | ||||
|  | ||||
| static constexpr jint JNI_VERSION = JNI_VERSION_1_6; | ||||
|  | ||||
| namespace IDCache { | ||||
| @@ -146,6 +158,46 @@ jfieldID GetPairSecondField() { | ||||
|     return s_pair_second_field; | ||||
| } | ||||
|  | ||||
| jclass GetOverlayControlDataClass() { | ||||
|     return s_overlay_control_data_class; | ||||
| } | ||||
|  | ||||
| jmethodID GetOverlayControlDataConstructor() { | ||||
|     return s_overlay_control_data_constructor; | ||||
| } | ||||
|  | ||||
| jfieldID GetOverlayControlDataIdField() { | ||||
|     return s_overlay_control_data_id_field; | ||||
| } | ||||
|  | ||||
| jfieldID GetOverlayControlDataEnabledField() { | ||||
|     return s_overlay_control_data_enabled_field; | ||||
| } | ||||
|  | ||||
| jfieldID GetOverlayControlDataLandscapePositionField() { | ||||
|     return s_overlay_control_data_landscape_position_field; | ||||
| } | ||||
|  | ||||
| jfieldID GetOverlayControlDataPortraitPositionField() { | ||||
|     return s_overlay_control_data_portrait_position_field; | ||||
| } | ||||
|  | ||||
| jfieldID GetOverlayControlDataFoldablePositionField() { | ||||
|     return s_overlay_control_data_foldable_position_field; | ||||
| } | ||||
|  | ||||
| jclass GetDoubleClass() { | ||||
|     return s_double_class; | ||||
| } | ||||
|  | ||||
| jmethodID GetDoubleConstructor() { | ||||
|     return s_double_constructor; | ||||
| } | ||||
|  | ||||
| jfieldID GetDoubleValueField() { | ||||
|     return s_double_value_field; | ||||
| } | ||||
|  | ||||
| } // namespace IDCache | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| @@ -207,6 +259,31 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) { | ||||
|     s_pair_second_field = env->GetFieldID(pair_class, "second", "Ljava/lang/Object;"); | ||||
|     env->DeleteLocalRef(pair_class); | ||||
|  | ||||
|     const jclass overlay_control_data_class = | ||||
|         env->FindClass("org/yuzu/yuzu_emu/overlay/model/OverlayControlData"); | ||||
|     s_overlay_control_data_class = | ||||
|         reinterpret_cast<jclass>(env->NewGlobalRef(overlay_control_data_class)); | ||||
|     s_overlay_control_data_constructor = | ||||
|         env->GetMethodID(overlay_control_data_class, "<init>", | ||||
|                          "(Ljava/lang/String;ZLkotlin/Pair;Lkotlin/Pair;Lkotlin/Pair;)V"); | ||||
|     s_overlay_control_data_id_field = | ||||
|         env->GetFieldID(overlay_control_data_class, "id", "Ljava/lang/String;"); | ||||
|     s_overlay_control_data_enabled_field = | ||||
|         env->GetFieldID(overlay_control_data_class, "enabled", "Z"); | ||||
|     s_overlay_control_data_landscape_position_field = | ||||
|         env->GetFieldID(overlay_control_data_class, "landscapePosition", "Lkotlin/Pair;"); | ||||
|     s_overlay_control_data_portrait_position_field = | ||||
|         env->GetFieldID(overlay_control_data_class, "portraitPosition", "Lkotlin/Pair;"); | ||||
|     s_overlay_control_data_foldable_position_field = | ||||
|         env->GetFieldID(overlay_control_data_class, "foldablePosition", "Lkotlin/Pair;"); | ||||
|     env->DeleteLocalRef(overlay_control_data_class); | ||||
|  | ||||
|     const jclass double_class = env->FindClass("java/lang/Double"); | ||||
|     s_double_class = reinterpret_cast<jclass>(env->NewGlobalRef(double_class)); | ||||
|     s_double_constructor = env->GetMethodID(double_class, "<init>", "(D)V"); | ||||
|     s_double_value_field = env->GetFieldID(double_class, "value", "D"); | ||||
|     env->DeleteLocalRef(double_class); | ||||
|  | ||||
|     // Initialize Android Storage | ||||
|     Common::FS::Android::RegisterCallbacks(env, s_native_library_class); | ||||
|  | ||||
| @@ -231,6 +308,8 @@ void JNI_OnUnload(JavaVM* vm, void* reserved) { | ||||
|     env->DeleteGlobalRef(s_game_class); | ||||
|     env->DeleteGlobalRef(s_string_class); | ||||
|     env->DeleteGlobalRef(s_pair_class); | ||||
|     env->DeleteGlobalRef(s_overlay_control_data_class); | ||||
|     env->DeleteGlobalRef(s_double_class); | ||||
|  | ||||
|     // UnInitialize applets | ||||
|     SoftwareKeyboard::CleanupJNI(env); | ||||
|   | ||||
| @@ -35,4 +35,16 @@ jmethodID GetPairConstructor(); | ||||
| jfieldID GetPairFirstField(); | ||||
| jfieldID GetPairSecondField(); | ||||
|  | ||||
| jclass GetOverlayControlDataClass(); | ||||
| jmethodID GetOverlayControlDataConstructor(); | ||||
| jfieldID GetOverlayControlDataIdField(); | ||||
| jfieldID GetOverlayControlDataEnabledField(); | ||||
| jfieldID GetOverlayControlDataLandscapePositionField(); | ||||
| jfieldID GetOverlayControlDataPortraitPositionField(); | ||||
| jfieldID GetOverlayControlDataFoldablePositionField(); | ||||
|  | ||||
| jclass GetDoubleClass(); | ||||
| jmethodID GetDoubleConstructor(); | ||||
| jfieldID GetDoubleValueField(); | ||||
|  | ||||
| } // namespace IDCache | ||||
|   | ||||
| @@ -344,4 +344,74 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setDisabledAddons(JNIEnv* env, j | ||||
|     Settings::values.disabled_addons[program_id] = disabled_addons; | ||||
| } | ||||
|  | ||||
| jobjectArray Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getOverlayControlData(JNIEnv* env, | ||||
|                                                                               jobject obj) { | ||||
|     jobjectArray joverlayControlDataArray = | ||||
|         env->NewObjectArray(AndroidSettings::values.overlay_control_data.size(), | ||||
|                             IDCache::GetOverlayControlDataClass(), nullptr); | ||||
|     for (size_t i = 0; i < AndroidSettings::values.overlay_control_data.size(); ++i) { | ||||
|         const auto& control_data = AndroidSettings::values.overlay_control_data[i]; | ||||
|         jobject jlandscapePosition = | ||||
|             env->NewObject(IDCache::GetPairClass(), IDCache::GetPairConstructor(), | ||||
|                            ToJDouble(env, control_data.landscape_position.first), | ||||
|                            ToJDouble(env, control_data.landscape_position.second)); | ||||
|         jobject jportraitPosition = | ||||
|             env->NewObject(IDCache::GetPairClass(), IDCache::GetPairConstructor(), | ||||
|                            ToJDouble(env, control_data.portrait_position.first), | ||||
|                            ToJDouble(env, control_data.portrait_position.second)); | ||||
|         jobject jfoldablePosition = | ||||
|             env->NewObject(IDCache::GetPairClass(), IDCache::GetPairConstructor(), | ||||
|                            ToJDouble(env, control_data.foldable_position.first), | ||||
|                            ToJDouble(env, control_data.foldable_position.second)); | ||||
|  | ||||
|         jobject jcontrolData = env->NewObject( | ||||
|             IDCache::GetOverlayControlDataClass(), IDCache::GetOverlayControlDataConstructor(), | ||||
|             ToJString(env, control_data.id), control_data.enabled, jlandscapePosition, | ||||
|             jportraitPosition, jfoldablePosition); | ||||
|         env->SetObjectArrayElement(joverlayControlDataArray, i, jcontrolData); | ||||
|     } | ||||
|     return joverlayControlDataArray; | ||||
| } | ||||
|  | ||||
| void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setOverlayControlData( | ||||
|     JNIEnv* env, jobject obj, jobjectArray joverlayControlDataArray) { | ||||
|     AndroidSettings::values.overlay_control_data.clear(); | ||||
|     int size = env->GetArrayLength(joverlayControlDataArray); | ||||
|  | ||||
|     if (size == 0) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     for (int i = 0; i < size; ++i) { | ||||
|         jobject joverlayControlData = env->GetObjectArrayElement(joverlayControlDataArray, i); | ||||
|         jstring jidString = static_cast<jstring>( | ||||
|             env->GetObjectField(joverlayControlData, IDCache::GetOverlayControlDataIdField())); | ||||
|         bool enabled = static_cast<bool>(env->GetBooleanField( | ||||
|             joverlayControlData, IDCache::GetOverlayControlDataEnabledField())); | ||||
|  | ||||
|         jobject jlandscapePosition = env->GetObjectField( | ||||
|             joverlayControlData, IDCache::GetOverlayControlDataLandscapePositionField()); | ||||
|         std::pair<double, double> landscape_position = std::make_pair( | ||||
|             GetJDouble(env, env->GetObjectField(jlandscapePosition, IDCache::GetPairFirstField())), | ||||
|             GetJDouble(env, | ||||
|                        env->GetObjectField(jlandscapePosition, IDCache::GetPairSecondField()))); | ||||
|  | ||||
|         jobject jportraitPosition = env->GetObjectField( | ||||
|             joverlayControlData, IDCache::GetOverlayControlDataPortraitPositionField()); | ||||
|         std::pair<double, double> portrait_position = std::make_pair( | ||||
|             GetJDouble(env, env->GetObjectField(jportraitPosition, IDCache::GetPairFirstField())), | ||||
|             GetJDouble(env, env->GetObjectField(jportraitPosition, IDCache::GetPairSecondField()))); | ||||
|  | ||||
|         jobject jfoldablePosition = env->GetObjectField( | ||||
|             joverlayControlData, IDCache::GetOverlayControlDataFoldablePositionField()); | ||||
|         std::pair<double, double> foldable_position = std::make_pair( | ||||
|             GetJDouble(env, env->GetObjectField(jfoldablePosition, IDCache::GetPairFirstField())), | ||||
|             GetJDouble(env, env->GetObjectField(jfoldablePosition, IDCache::GetPairSecondField()))); | ||||
|  | ||||
|         AndroidSettings::values.overlay_control_data.push_back(AndroidSettings::OverlayControlData{ | ||||
|             GetJString(env, jidString), enabled, landscape_position, portrait_position, | ||||
|             foldable_position}); | ||||
|     } | ||||
| } | ||||
|  | ||||
| } // extern "C" | ||||
|   | ||||
| @@ -38,6 +38,11 @@ | ||||
|         android:title="@string/emulation_haptics" | ||||
|         android:checkable="true" /> | ||||
|  | ||||
|     <item | ||||
|         android:id="@+id/menu_touchscreen" | ||||
|         android:title="@string/touchscreen" | ||||
|         android:checkable="true" /> | ||||
|  | ||||
|     <item | ||||
|         android:id="@+id/menu_reset_overlay" | ||||
|         android:title="@string/emulation_touch_overlay_reset" /> | ||||
|   | ||||
| @@ -212,19 +212,19 @@ | ||||
|         <item>B</item> | ||||
|         <item>X</item> | ||||
|         <item>Y</item> | ||||
|         <item>+</item> | ||||
|         <item>-</item> | ||||
|         <item>@string/gamepad_home</item> | ||||
|         <item>@string/gamepad_screenshot</item> | ||||
|         <item>L</item> | ||||
|         <item>R</item> | ||||
|         <item>ZL</item> | ||||
|         <item>ZR</item> | ||||
|         <item>+</item> | ||||
|         <item>-</item> | ||||
|         <item>@string/gamepad_d_pad</item> | ||||
|         <item>@string/gamepad_left_stick</item> | ||||
|         <item>@string/gamepad_right_stick</item> | ||||
|         <item>L3</item> | ||||
|         <item>R3</item> | ||||
|         <item>@string/gamepad_home</item> | ||||
|         <item>@string/gamepad_screenshot</item> | ||||
|         <item>@string/gamepad_d_pad</item> | ||||
|     </string-array> | ||||
|  | ||||
|     <string-array name="themeEntries"> | ||||
|   | ||||
| @@ -3,111 +3,111 @@ | ||||
|     <integer name="grid_columns">1</integer> | ||||
|  | ||||
|     <!-- Default SWITCH landscape layout --> | ||||
|     <integer name="SWITCH_BUTTON_A_X">760</integer> | ||||
|     <integer name="SWITCH_BUTTON_A_Y">790</integer> | ||||
|     <integer name="SWITCH_BUTTON_B_X">710</integer> | ||||
|     <integer name="SWITCH_BUTTON_B_Y">900</integer> | ||||
|     <integer name="SWITCH_BUTTON_X_X">710</integer> | ||||
|     <integer name="SWITCH_BUTTON_X_Y">680</integer> | ||||
|     <integer name="SWITCH_BUTTON_Y_X">660</integer> | ||||
|     <integer name="SWITCH_BUTTON_Y_Y">790</integer> | ||||
|     <integer name="SWITCH_STICK_L_X">100</integer> | ||||
|     <integer name="SWITCH_STICK_L_Y">670</integer> | ||||
|     <integer name="SWITCH_STICK_R_X">900</integer> | ||||
|     <integer name="SWITCH_STICK_R_Y">670</integer> | ||||
|     <integer name="SWITCH_TRIGGER_L_X">70</integer> | ||||
|     <integer name="SWITCH_TRIGGER_L_Y">220</integer> | ||||
|     <integer name="SWITCH_TRIGGER_R_X">930</integer> | ||||
|     <integer name="SWITCH_TRIGGER_R_Y">220</integer> | ||||
|     <integer name="SWITCH_TRIGGER_ZL_X">70</integer> | ||||
|     <integer name="SWITCH_TRIGGER_ZL_Y">90</integer> | ||||
|     <integer name="SWITCH_TRIGGER_ZR_X">930</integer> | ||||
|     <integer name="SWITCH_TRIGGER_ZR_Y">90</integer> | ||||
|     <integer name="SWITCH_BUTTON_MINUS_X">460</integer> | ||||
|     <integer name="SWITCH_BUTTON_MINUS_Y">950</integer> | ||||
|     <integer name="SWITCH_BUTTON_PLUS_X">540</integer> | ||||
|     <integer name="SWITCH_BUTTON_PLUS_Y">950</integer> | ||||
|     <integer name="SWITCH_BUTTON_HOME_X">600</integer> | ||||
|     <integer name="SWITCH_BUTTON_HOME_Y">950</integer> | ||||
|     <integer name="SWITCH_BUTTON_CAPTURE_X">400</integer> | ||||
|     <integer name="SWITCH_BUTTON_CAPTURE_Y">950</integer> | ||||
|     <integer name="SWITCH_BUTTON_DPAD_X">260</integer> | ||||
|     <integer name="SWITCH_BUTTON_DPAD_Y">790</integer> | ||||
|     <integer name="SWITCH_BUTTON_STICK_L_X">870</integer> | ||||
|     <integer name="SWITCH_BUTTON_STICK_L_Y">400</integer> | ||||
|     <integer name="SWITCH_BUTTON_STICK_R_X">960</integer> | ||||
|     <integer name="SWITCH_BUTTON_STICK_R_Y">430</integer> | ||||
|     <integer name="BUTTON_A_X">760</integer> | ||||
|     <integer name="BUTTON_A_Y">790</integer> | ||||
|     <integer name="BUTTON_B_X">710</integer> | ||||
|     <integer name="BUTTON_B_Y">900</integer> | ||||
|     <integer name="BUTTON_X_X">710</integer> | ||||
|     <integer name="BUTTON_X_Y">680</integer> | ||||
|     <integer name="BUTTON_Y_X">660</integer> | ||||
|     <integer name="BUTTON_Y_Y">790</integer> | ||||
|     <integer name="BUTTON_PLUS_X">540</integer> | ||||
|     <integer name="BUTTON_PLUS_Y">950</integer> | ||||
|     <integer name="BUTTON_MINUS_X">460</integer> | ||||
|     <integer name="BUTTON_MINUS_Y">950</integer> | ||||
|     <integer name="BUTTON_HOME_X">600</integer> | ||||
|     <integer name="BUTTON_HOME_Y">950</integer> | ||||
|     <integer name="BUTTON_CAPTURE_X">400</integer> | ||||
|     <integer name="BUTTON_CAPTURE_Y">950</integer> | ||||
|     <integer name="BUTTON_L_X">70</integer> | ||||
|     <integer name="BUTTON_L_Y">220</integer> | ||||
|     <integer name="BUTTON_R_X">930</integer> | ||||
|     <integer name="BUTTON_R_Y">220</integer> | ||||
|     <integer name="BUTTON_ZL_X">70</integer> | ||||
|     <integer name="BUTTON_ZL_Y">90</integer> | ||||
|     <integer name="BUTTON_ZR_X">930</integer> | ||||
|     <integer name="BUTTON_ZR_Y">90</integer> | ||||
|     <integer name="BUTTON_STICK_L_X">870</integer> | ||||
|     <integer name="BUTTON_STICK_L_Y">400</integer> | ||||
|     <integer name="BUTTON_STICK_R_X">960</integer> | ||||
|     <integer name="BUTTON_STICK_R_Y">430</integer> | ||||
|     <integer name="STICK_L_X">100</integer> | ||||
|     <integer name="STICK_L_Y">670</integer> | ||||
|     <integer name="STICK_R_X">900</integer> | ||||
|     <integer name="STICK_R_Y">670</integer> | ||||
|     <integer name="COMBINED_DPAD_X">260</integer> | ||||
|     <integer name="COMBINED_DPAD_Y">790</integer> | ||||
|  | ||||
|     <!-- Default SWITCH portrait layout --> | ||||
|     <integer name="SWITCH_BUTTON_A_X_PORTRAIT">840</integer> | ||||
|     <integer name="SWITCH_BUTTON_A_Y_PORTRAIT">840</integer> | ||||
|     <integer name="SWITCH_BUTTON_B_X_PORTRAIT">740</integer> | ||||
|     <integer name="SWITCH_BUTTON_B_Y_PORTRAIT">880</integer> | ||||
|     <integer name="SWITCH_BUTTON_X_X_PORTRAIT">740</integer> | ||||
|     <integer name="SWITCH_BUTTON_X_Y_PORTRAIT">800</integer> | ||||
|     <integer name="SWITCH_BUTTON_Y_X_PORTRAIT">640</integer> | ||||
|     <integer name="SWITCH_BUTTON_Y_Y_PORTRAIT">840</integer> | ||||
|     <integer name="SWITCH_STICK_L_X_PORTRAIT">180</integer> | ||||
|     <integer name="SWITCH_STICK_L_Y_PORTRAIT">660</integer> | ||||
|     <integer name="SWITCH_STICK_R_X_PORTRAIT">820</integer> | ||||
|     <integer name="SWITCH_STICK_R_Y_PORTRAIT">660</integer> | ||||
|     <integer name="SWITCH_TRIGGER_L_X_PORTRAIT">140</integer> | ||||
|     <integer name="SWITCH_TRIGGER_L_Y_PORTRAIT">260</integer> | ||||
|     <integer name="SWITCH_TRIGGER_R_X_PORTRAIT">860</integer> | ||||
|     <integer name="SWITCH_TRIGGER_R_Y_PORTRAIT">260</integer> | ||||
|     <integer name="SWITCH_TRIGGER_ZL_X_PORTRAIT">140</integer> | ||||
|     <integer name="SWITCH_TRIGGER_ZL_Y_PORTRAIT">200</integer> | ||||
|     <integer name="SWITCH_TRIGGER_ZR_X_PORTRAIT">860</integer> | ||||
|     <integer name="SWITCH_TRIGGER_ZR_Y_PORTRAIT">200</integer> | ||||
|     <integer name="SWITCH_BUTTON_MINUS_X_PORTRAIT">440</integer> | ||||
|     <integer name="SWITCH_BUTTON_MINUS_Y_PORTRAIT">950</integer> | ||||
|     <integer name="SWITCH_BUTTON_PLUS_X_PORTRAIT">560</integer> | ||||
|     <integer name="SWITCH_BUTTON_PLUS_Y_PORTRAIT">950</integer> | ||||
|     <integer name="SWITCH_BUTTON_HOME_X_PORTRAIT">680</integer> | ||||
|     <integer name="SWITCH_BUTTON_HOME_Y_PORTRAIT">950</integer> | ||||
|     <integer name="SWITCH_BUTTON_CAPTURE_X_PORTRAIT">320</integer> | ||||
|     <integer name="SWITCH_BUTTON_CAPTURE_Y_PORTRAIT">950</integer> | ||||
|     <integer name="SWITCH_BUTTON_DPAD_X_PORTRAIT">240</integer> | ||||
|     <integer name="SWITCH_BUTTON_DPAD_Y_PORTRAIT">840</integer> | ||||
|     <integer name="SWITCH_BUTTON_STICK_L_X_PORTRAIT">730</integer> | ||||
|     <integer name="SWITCH_BUTTON_STICK_L_Y_PORTRAIT">510</integer> | ||||
|     <integer name="SWITCH_BUTTON_STICK_R_X_PORTRAIT">900</integer> | ||||
|     <integer name="SWITCH_BUTTON_STICK_R_Y_PORTRAIT">540</integer> | ||||
|     <integer name="BUTTON_A_X_PORTRAIT">840</integer> | ||||
|     <integer name="BUTTON_A_Y_PORTRAIT">840</integer> | ||||
|     <integer name="BUTTON_B_X_PORTRAIT">740</integer> | ||||
|     <integer name="BUTTON_B_Y_PORTRAIT">880</integer> | ||||
|     <integer name="BUTTON_X_X_PORTRAIT">740</integer> | ||||
|     <integer name="BUTTON_X_Y_PORTRAIT">800</integer> | ||||
|     <integer name="BUTTON_Y_X_PORTRAIT">640</integer> | ||||
|     <integer name="BUTTON_Y_Y_PORTRAIT">840</integer> | ||||
|     <integer name="BUTTON_PLUS_Y_PORTRAIT">950</integer> | ||||
|     <integer name="BUTTON_MINUS_X_PORTRAIT">440</integer> | ||||
|     <integer name="BUTTON_MINUS_Y_PORTRAIT">950</integer> | ||||
|     <integer name="BUTTON_HOME_X_PORTRAIT">680</integer> | ||||
|     <integer name="BUTTON_HOME_Y_PORTRAIT">950</integer> | ||||
|     <integer name="BUTTON_CAPTURE_X_PORTRAIT">320</integer> | ||||
|     <integer name="BUTTON_CAPTURE_Y_PORTRAIT">950</integer> | ||||
|     <integer name="BUTTON_L_X_PORTRAIT">140</integer> | ||||
|     <integer name="BUTTON_L_Y_PORTRAIT">260</integer> | ||||
|     <integer name="BUTTON_R_X_PORTRAIT">860</integer> | ||||
|     <integer name="BUTTON_R_Y_PORTRAIT">260</integer> | ||||
|     <integer name="BUTTON_ZL_X_PORTRAIT">140</integer> | ||||
|     <integer name="BUTTON_ZL_Y_PORTRAIT">200</integer> | ||||
|     <integer name="BUTTON_ZR_X_PORTRAIT">860</integer> | ||||
|     <integer name="BUTTON_ZR_Y_PORTRAIT">200</integer> | ||||
|     <integer name="BUTTON_PLUS_X_PORTRAIT">560</integer> | ||||
|     <integer name="BUTTON_STICK_L_X_PORTRAIT">730</integer> | ||||
|     <integer name="BUTTON_STICK_L_Y_PORTRAIT">510</integer> | ||||
|     <integer name="BUTTON_STICK_R_X_PORTRAIT">900</integer> | ||||
|     <integer name="BUTTON_STICK_R_Y_PORTRAIT">540</integer> | ||||
|     <integer name="STICK_L_X_PORTRAIT">180</integer> | ||||
|     <integer name="STICK_L_Y_PORTRAIT">660</integer> | ||||
|     <integer name="STICK_R_X_PORTRAIT">820</integer> | ||||
|     <integer name="STICK_R_Y_PORTRAIT">660</integer> | ||||
|     <integer name="COMBINED_DPAD_X_PORTRAIT">240</integer> | ||||
|     <integer name="COMBINED_DPAD_Y_PORTRAIT">840</integer> | ||||
|  | ||||
|     <!-- Default SWITCH foldable layout --> | ||||
|     <integer name="SWITCH_BUTTON_A_X_FOLDABLE">840</integer> | ||||
|     <integer name="SWITCH_BUTTON_A_Y_FOLDABLE">390</integer> | ||||
|     <integer name="SWITCH_BUTTON_B_X_FOLDABLE">740</integer> | ||||
|     <integer name="SWITCH_BUTTON_B_Y_FOLDABLE">430</integer> | ||||
|     <integer name="SWITCH_BUTTON_X_X_FOLDABLE">740</integer> | ||||
|     <integer name="SWITCH_BUTTON_X_Y_FOLDABLE">350</integer> | ||||
|     <integer name="SWITCH_BUTTON_Y_X_FOLDABLE">640</integer> | ||||
|     <integer name="SWITCH_BUTTON_Y_Y_FOLDABLE">390</integer> | ||||
|     <integer name="SWITCH_STICK_L_X_FOLDABLE">180</integer> | ||||
|     <integer name="SWITCH_STICK_L_Y_FOLDABLE">250</integer> | ||||
|     <integer name="SWITCH_STICK_R_X_FOLDABLE">820</integer> | ||||
|     <integer name="SWITCH_STICK_R_Y_FOLDABLE">250</integer> | ||||
|     <integer name="SWITCH_TRIGGER_L_X_FOLDABLE">140</integer> | ||||
|     <integer name="SWITCH_TRIGGER_L_Y_FOLDABLE">130</integer> | ||||
|     <integer name="SWITCH_TRIGGER_R_X_FOLDABLE">860</integer> | ||||
|     <integer name="SWITCH_TRIGGER_R_Y_FOLDABLE">130</integer> | ||||
|     <integer name="SWITCH_TRIGGER_ZL_X_FOLDABLE">140</integer> | ||||
|     <integer name="SWITCH_TRIGGER_ZL_Y_FOLDABLE">70</integer> | ||||
|     <integer name="SWITCH_TRIGGER_ZR_X_FOLDABLE">860</integer> | ||||
|     <integer name="SWITCH_TRIGGER_ZR_Y_FOLDABLE">70</integer> | ||||
|     <integer name="SWITCH_BUTTON_MINUS_X_FOLDABLE">440</integer> | ||||
|     <integer name="SWITCH_BUTTON_MINUS_Y_FOLDABLE">470</integer> | ||||
|     <integer name="SWITCH_BUTTON_PLUS_X_FOLDABLE">560</integer> | ||||
|     <integer name="SWITCH_BUTTON_PLUS_Y_FOLDABLE">470</integer> | ||||
|     <integer name="SWITCH_BUTTON_HOME_X_FOLDABLE">680</integer> | ||||
|     <integer name="SWITCH_BUTTON_HOME_Y_FOLDABLE">470</integer> | ||||
|     <integer name="SWITCH_BUTTON_CAPTURE_X_FOLDABLE">320</integer> | ||||
|     <integer name="SWITCH_BUTTON_CAPTURE_Y_FOLDABLE">470</integer> | ||||
|     <integer name="SWITCH_BUTTON_DPAD_X_FOLDABLE">240</integer> | ||||
|     <integer name="SWITCH_BUTTON_DPAD_Y_FOLDABLE">390</integer> | ||||
|     <integer name="SWITCH_BUTTON_STICK_L_X_FOLDABLE">550</integer> | ||||
|     <integer name="SWITCH_BUTTON_STICK_L_Y_FOLDABLE">210</integer> | ||||
|     <integer name="SWITCH_BUTTON_STICK_R_X_FOLDABLE">550</integer> | ||||
|     <integer name="SWITCH_BUTTON_STICK_R_Y_FOLDABLE">280</integer> | ||||
|     <integer name="BUTTON_A_X_FOLDABLE">840</integer> | ||||
|     <integer name="BUTTON_A_Y_FOLDABLE">390</integer> | ||||
|     <integer name="BUTTON_B_X_FOLDABLE">740</integer> | ||||
|     <integer name="BUTTON_B_Y_FOLDABLE">430</integer> | ||||
|     <integer name="BUTTON_X_X_FOLDABLE">740</integer> | ||||
|     <integer name="BUTTON_X_Y_FOLDABLE">350</integer> | ||||
|     <integer name="BUTTON_Y_X_FOLDABLE">640</integer> | ||||
|     <integer name="BUTTON_Y_Y_FOLDABLE">390</integer> | ||||
|     <integer name="BUTTON_PLUS_X_FOLDABLE">560</integer> | ||||
|     <integer name="BUTTON_PLUS_Y_FOLDABLE">470</integer> | ||||
|     <integer name="BUTTON_MINUS_X_FOLDABLE">440</integer> | ||||
|     <integer name="BUTTON_MINUS_Y_FOLDABLE">470</integer> | ||||
|     <integer name="BUTTON_HOME_X_FOLDABLE">680</integer> | ||||
|     <integer name="BUTTON_HOME_Y_FOLDABLE">470</integer> | ||||
|     <integer name="BUTTON_CAPTURE_X_FOLDABLE">320</integer> | ||||
|     <integer name="BUTTON_CAPTURE_Y_FOLDABLE">470</integer> | ||||
|     <integer name="BUTTON_L_X_FOLDABLE">140</integer> | ||||
|     <integer name="BUTTON_L_Y_FOLDABLE">130</integer> | ||||
|     <integer name="BUTTON_R_X_FOLDABLE">860</integer> | ||||
|     <integer name="BUTTON_R_Y_FOLDABLE">130</integer> | ||||
|     <integer name="BUTTON_ZL_X_FOLDABLE">140</integer> | ||||
|     <integer name="BUTTON_ZL_Y_FOLDABLE">70</integer> | ||||
|     <integer name="BUTTON_ZR_X_FOLDABLE">860</integer> | ||||
|     <integer name="BUTTON_ZR_Y_FOLDABLE">70</integer> | ||||
|     <integer name="BUTTON_STICK_L_X_FOLDABLE">550</integer> | ||||
|     <integer name="BUTTON_STICK_L_Y_FOLDABLE">210</integer> | ||||
|     <integer name="BUTTON_STICK_R_X_FOLDABLE">550</integer> | ||||
|     <integer name="BUTTON_STICK_R_Y_FOLDABLE">280</integer> | ||||
|     <integer name="STICK_L_X_FOLDABLE">180</integer> | ||||
|     <integer name="STICK_L_Y_FOLDABLE">250</integer> | ||||
|     <integer name="STICK_R_X_FOLDABLE">820</integer> | ||||
|     <integer name="STICK_R_Y_FOLDABLE">250</integer> | ||||
|     <integer name="COMBINED_DPAD_X_FOLDABLE">240</integer> | ||||
|     <integer name="COMBINED_DPAD_Y_FOLDABLE">390</integer> | ||||
|  | ||||
| </resources> | ||||
|   | ||||
| @@ -366,6 +366,7 @@ | ||||
|     <string name="emulation_pause">Pause emulation</string> | ||||
|     <string name="emulation_unpause">Unpause emulation</string> | ||||
|     <string name="emulation_input_overlay">Overlay options</string> | ||||
|     <string name="touchscreen">Touchscreen</string> | ||||
|  | ||||
|     <string name="load_settings">Loading settings…</string> | ||||
|  | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
| plugins { | ||||
|     id("com.android.application") version "8.1.2" apply false | ||||
|     id("com.android.library") version "8.1.2" apply false | ||||
|     id("org.jetbrains.kotlin.android") version "1.8.21" apply false | ||||
|     id("org.jetbrains.kotlin.android") version "1.9.20" apply false | ||||
| } | ||||
|  | ||||
| tasks.register("clean").configure { | ||||
|   | ||||
| @@ -199,6 +199,8 @@ const char* TranslateCategory(Category category) { | ||||
|     case Category::CpuDebug: | ||||
|     case Category::CpuUnsafe: | ||||
|         return "Cpu"; | ||||
|     case Category::Overlay: | ||||
|         return "Overlay"; | ||||
|     case Category::Renderer: | ||||
|     case Category::RendererAdvanced: | ||||
|     case Category::RendererDebug: | ||||
|   | ||||
| @@ -18,6 +18,7 @@ enum class Category : u32 { | ||||
|     Cpu, | ||||
|     CpuDebug, | ||||
|     CpuUnsafe, | ||||
|     Overlay, | ||||
|     Renderer, | ||||
|     RendererAdvanced, | ||||
|     RendererDebug, | ||||
|   | ||||
| @@ -403,59 +403,63 @@ void Config::SavePlayerValues(const std::size_t player_index) { | ||||
|             // No custom profile selected | ||||
|             return; | ||||
|         } | ||||
|         WriteSetting(std::string(player_prefix).append("profile_name"), player.profile_name, | ||||
|                      std::make_optional(std::string(""))); | ||||
|         WriteStringSetting(std::string(player_prefix).append("profile_name"), player.profile_name, | ||||
|                            std::make_optional(std::string(""))); | ||||
|     } | ||||
|  | ||||
|     WriteSetting(std::string(player_prefix).append("type"), static_cast<u8>(player.controller_type), | ||||
|                  std::make_optional(static_cast<u8>(Settings::ControllerType::ProController))); | ||||
|     WriteIntegerSetting( | ||||
|         std::string(player_prefix).append("type"), static_cast<u8>(player.controller_type), | ||||
|         std::make_optional(static_cast<u8>(Settings::ControllerType::ProController))); | ||||
|  | ||||
|     if (!player_prefix.empty() || !Settings::IsConfiguringGlobal()) { | ||||
|         WriteSetting(std::string(player_prefix).append("connected"), player.connected, | ||||
|                      std::make_optional(player_index == 0)); | ||||
|         WriteSetting(std::string(player_prefix).append("vibration_enabled"), | ||||
|                      player.vibration_enabled, std::make_optional(true)); | ||||
|         WriteSetting(std::string(player_prefix).append("vibration_strength"), | ||||
|                      player.vibration_strength, std::make_optional(100)); | ||||
|         WriteSetting(std::string(player_prefix).append("body_color_left"), player.body_color_left, | ||||
|                      std::make_optional(Settings::JOYCON_BODY_NEON_BLUE)); | ||||
|         WriteSetting(std::string(player_prefix).append("body_color_right"), player.body_color_right, | ||||
|                      std::make_optional(Settings::JOYCON_BODY_NEON_RED)); | ||||
|         WriteSetting(std::string(player_prefix).append("button_color_left"), | ||||
|                      player.button_color_left, | ||||
|                      std::make_optional(Settings::JOYCON_BUTTONS_NEON_BLUE)); | ||||
|         WriteSetting(std::string(player_prefix).append("button_color_right"), | ||||
|                      player.button_color_right, | ||||
|                      std::make_optional(Settings::JOYCON_BUTTONS_NEON_RED)); | ||||
|         WriteBooleanSetting(std::string(player_prefix).append("connected"), player.connected, | ||||
|                             std::make_optional(player_index == 0)); | ||||
|         WriteIntegerSetting(std::string(player_prefix).append("vibration_enabled"), | ||||
|                             player.vibration_enabled, std::make_optional(true)); | ||||
|         WriteIntegerSetting(std::string(player_prefix).append("vibration_strength"), | ||||
|                             player.vibration_strength, std::make_optional(100)); | ||||
|         WriteIntegerSetting(std::string(player_prefix).append("body_color_left"), | ||||
|                             player.body_color_left, | ||||
|                             std::make_optional(Settings::JOYCON_BODY_NEON_BLUE)); | ||||
|         WriteIntegerSetting(std::string(player_prefix).append("body_color_right"), | ||||
|                             player.body_color_right, | ||||
|                             std::make_optional(Settings::JOYCON_BODY_NEON_RED)); | ||||
|         WriteIntegerSetting(std::string(player_prefix).append("button_color_left"), | ||||
|                             player.button_color_left, | ||||
|                             std::make_optional(Settings::JOYCON_BUTTONS_NEON_BLUE)); | ||||
|         WriteIntegerSetting(std::string(player_prefix).append("button_color_right"), | ||||
|                             player.button_color_right, | ||||
|                             std::make_optional(Settings::JOYCON_BUTTONS_NEON_RED)); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void Config::SaveTouchscreenValues() { | ||||
|     const auto& touchscreen = Settings::values.touchscreen; | ||||
|  | ||||
|     WriteSetting(std::string("touchscreen_enabled"), touchscreen.enabled, std::make_optional(true)); | ||||
|     WriteBooleanSetting(std::string("touchscreen_enabled"), touchscreen.enabled, | ||||
|                         std::make_optional(true)); | ||||
|  | ||||
|     WriteSetting(std::string("touchscreen_angle"), touchscreen.rotation_angle, | ||||
|                  std::make_optional(static_cast<u32>(0))); | ||||
|     WriteSetting(std::string("touchscreen_diameter_x"), touchscreen.diameter_x, | ||||
|                  std::make_optional(static_cast<u32>(15))); | ||||
|     WriteSetting(std::string("touchscreen_diameter_y"), touchscreen.diameter_y, | ||||
|                  std::make_optional(static_cast<u32>(15))); | ||||
|     WriteIntegerSetting(std::string("touchscreen_angle"), touchscreen.rotation_angle, | ||||
|                         std::make_optional(static_cast<u32>(0))); | ||||
|     WriteIntegerSetting(std::string("touchscreen_diameter_x"), touchscreen.diameter_x, | ||||
|                         std::make_optional(static_cast<u32>(15))); | ||||
|     WriteIntegerSetting(std::string("touchscreen_diameter_y"), touchscreen.diameter_y, | ||||
|                         std::make_optional(static_cast<u32>(15))); | ||||
| } | ||||
|  | ||||
| void Config::SaveMotionTouchValues() { | ||||
|     BeginArray(std::string("touch_from_button_maps")); | ||||
|     for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) { | ||||
|         SetArrayIndex(static_cast<int>(p)); | ||||
|         WriteSetting(std::string("name"), Settings::values.touch_from_button_maps[p].name, | ||||
|                      std::make_optional(std::string("default"))); | ||||
|         WriteStringSetting(std::string("name"), Settings::values.touch_from_button_maps[p].name, | ||||
|                            std::make_optional(std::string("default"))); | ||||
|  | ||||
|         BeginArray(std::string("entries")); | ||||
|         for (std::size_t q = 0; q < Settings::values.touch_from_button_maps[p].buttons.size(); | ||||
|              ++q) { | ||||
|             SetArrayIndex(static_cast<int>(q)); | ||||
|             WriteSetting(std::string("bind"), | ||||
|                          Settings::values.touch_from_button_maps[p].buttons[q]); | ||||
|             WriteStringSetting(std::string("bind"), | ||||
|                                Settings::values.touch_from_button_maps[p].buttons[q]); | ||||
|         } | ||||
|         EndArray(); // entries | ||||
|     } | ||||
| @@ -520,16 +524,16 @@ void Config::SaveCoreValues() { | ||||
| void Config::SaveDataStorageValues() { | ||||
|     BeginGroup(Settings::TranslateCategory(Settings::Category::DataStorage)); | ||||
|  | ||||
|     WriteSetting(std::string("nand_directory"), FS::GetYuzuPathString(FS::YuzuPath::NANDDir), | ||||
|                  std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::NANDDir))); | ||||
|     WriteSetting(std::string("sdmc_directory"), FS::GetYuzuPathString(FS::YuzuPath::SDMCDir), | ||||
|                  std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::SDMCDir))); | ||||
|     WriteSetting(std::string("load_directory"), FS::GetYuzuPathString(FS::YuzuPath::LoadDir), | ||||
|                  std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::LoadDir))); | ||||
|     WriteSetting(std::string("dump_directory"), FS::GetYuzuPathString(FS::YuzuPath::DumpDir), | ||||
|                  std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::DumpDir))); | ||||
|     WriteSetting(std::string("tas_directory"), FS::GetYuzuPathString(FS::YuzuPath::TASDir), | ||||
|                  std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::TASDir))); | ||||
|     WriteStringSetting(std::string("nand_directory"), FS::GetYuzuPathString(FS::YuzuPath::NANDDir), | ||||
|                        std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::NANDDir))); | ||||
|     WriteStringSetting(std::string("sdmc_directory"), FS::GetYuzuPathString(FS::YuzuPath::SDMCDir), | ||||
|                        std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::SDMCDir))); | ||||
|     WriteStringSetting(std::string("load_directory"), FS::GetYuzuPathString(FS::YuzuPath::LoadDir), | ||||
|                        std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::LoadDir))); | ||||
|     WriteStringSetting(std::string("dump_directory"), FS::GetYuzuPathString(FS::YuzuPath::DumpDir), | ||||
|                        std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::DumpDir))); | ||||
|     WriteStringSetting(std::string("tas_directory"), FS::GetYuzuPathString(FS::YuzuPath::TASDir), | ||||
|                        std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::TASDir))); | ||||
|  | ||||
|     WriteCategory(Settings::Category::DataStorage); | ||||
|  | ||||
| @@ -540,7 +544,7 @@ void Config::SaveDebuggingValues() { | ||||
|     BeginGroup(Settings::TranslateCategory(Settings::Category::Debugging)); | ||||
|  | ||||
|     // Intentionally not using the QT default setting as this is intended to be changed in the ini | ||||
|     WriteSetting(std::string("record_frame_times"), Settings::values.record_frame_times); | ||||
|     WriteBooleanSetting(std::string("record_frame_times"), Settings::values.record_frame_times); | ||||
|  | ||||
|     WriteCategory(Settings::Category::Debugging); | ||||
|     WriteCategory(Settings::Category::DebuggingGraphics); | ||||
| @@ -564,11 +568,13 @@ void Config::SaveDisabledAddOnValues() { | ||||
|     BeginArray(std::string("")); | ||||
|     for (const auto& elem : Settings::values.disabled_addons) { | ||||
|         SetArrayIndex(i); | ||||
|         WriteSetting(std::string("title_id"), elem.first, std::make_optional(static_cast<u64>(0))); | ||||
|         WriteIntegerSetting(std::string("title_id"), elem.first, | ||||
|                             std::make_optional(static_cast<u64>(0))); | ||||
|         BeginArray(std::string("disabled")); | ||||
|         for (std::size_t j = 0; j < elem.second.size(); ++j) { | ||||
|             SetArrayIndex(static_cast<int>(j)); | ||||
|             WriteSetting(std::string("d"), elem.second[j], std::make_optional(std::string(""))); | ||||
|             WriteStringSetting(std::string("d"), elem.second[j], | ||||
|                                std::make_optional(std::string(""))); | ||||
|         } | ||||
|         EndArray(); // disabled | ||||
|         ++i; | ||||
| @@ -609,8 +615,8 @@ void Config::SaveRendererValues() { | ||||
| void Config::SaveScreenshotValues() { | ||||
|     BeginGroup(Settings::TranslateCategory(Settings::Category::Screenshots)); | ||||
|  | ||||
|     WriteSetting(std::string("screenshot_path"), | ||||
|                  FS::GetYuzuPathString(FS::YuzuPath::ScreenshotsDir)); | ||||
|     WriteStringSetting(std::string("screenshot_path"), | ||||
|                        FS::GetYuzuPathString(FS::YuzuPath::ScreenshotsDir)); | ||||
|     WriteCategory(Settings::Category::Screenshots); | ||||
|  | ||||
|     EndGroup(); | ||||
| @@ -746,46 +752,70 @@ bool Config::Exists(const std::string& section, const std::string& key) const { | ||||
|     return !value.empty(); | ||||
| } | ||||
|  | ||||
| template <typename Type> | ||||
| void Config::WriteSetting(const std::string& key, const Type& value, | ||||
|                           const std::optional<Type>& default_value, | ||||
|                           const std::optional<bool>& use_global) { | ||||
|     std::string full_key = GetFullKey(key, false); | ||||
|  | ||||
|     std::string saved_value; | ||||
|     std::string string_default; | ||||
|     if constexpr (std::is_same_v<Type, std::string>) { | ||||
|         saved_value.append(AdjustOutputString(value)); | ||||
|         if (default_value.has_value()) { | ||||
|             string_default.append(AdjustOutputString(default_value.value())); | ||||
|         } | ||||
|     } else { | ||||
|         saved_value.append(AdjustOutputString(ToString(value))); | ||||
|         if (default_value.has_value()) { | ||||
|             string_default.append(ToString(default_value.value())); | ||||
|         } | ||||
| void Config::WriteBooleanSetting(const std::string& key, const bool& value, | ||||
|                                  const std::optional<bool>& default_value, | ||||
|                                  const std::optional<bool>& use_global) { | ||||
|     std::optional<std::string> string_default = std::nullopt; | ||||
|     if (default_value.has_value()) { | ||||
|         string_default = std::make_optional(ToString(default_value.value())); | ||||
|     } | ||||
|     WritePreparedSetting(key, AdjustOutputString(ToString(value)), string_default, use_global); | ||||
| } | ||||
|  | ||||
|     if (default_value.has_value() && use_global.has_value()) { | ||||
| template <typename T> | ||||
| std::enable_if_t<std::is_integral_v<T>> Config::WriteIntegerSetting( | ||||
|     const std::string& key, const T& value, const std::optional<T>& default_value, | ||||
|     const std::optional<bool>& use_global) { | ||||
|     std::optional<std::string> string_default = std::nullopt; | ||||
|     if (default_value.has_value()) { | ||||
|         string_default = std::make_optional(ToString(default_value.value())); | ||||
|     } | ||||
|     WritePreparedSetting(key, AdjustOutputString(ToString(value)), string_default, use_global); | ||||
| } | ||||
|  | ||||
| void Config::WriteDoubleSetting(const std::string& key, const double& value, | ||||
|                                 const std::optional<double>& default_value, | ||||
|                                 const std::optional<bool>& use_global) { | ||||
|     std::optional<std::string> string_default = std::nullopt; | ||||
|     if (default_value.has_value()) { | ||||
|         string_default = std::make_optional(ToString(default_value.value())); | ||||
|     } | ||||
|     WritePreparedSetting(key, AdjustOutputString(ToString(value)), string_default, use_global); | ||||
| } | ||||
|  | ||||
| void Config::WriteStringSetting(const std::string& key, const std::string& value, | ||||
|                                 const std::optional<std::string>& default_value, | ||||
|                                 const std::optional<bool>& use_global) { | ||||
|     std::optional string_default = default_value; | ||||
|     if (default_value.has_value()) { | ||||
|         string_default.value().append(AdjustOutputString(default_value.value())); | ||||
|     } | ||||
|     WritePreparedSetting(key, AdjustOutputString(value), string_default, use_global); | ||||
| } | ||||
|  | ||||
| void Config::WritePreparedSetting(const std::string& key, const std::string& adjusted_value, | ||||
|                                   const std::optional<std::string>& adjusted_default_value, | ||||
|                                   const std::optional<bool>& use_global) { | ||||
|     std::string full_key = GetFullKey(key, false); | ||||
|     if (adjusted_default_value.has_value() && use_global.has_value()) { | ||||
|         if (!global) { | ||||
|             WriteSettingInternal(std::string(full_key).append("\\global"), | ||||
|                                  ToString(use_global.value())); | ||||
|             WriteString(std::string(full_key).append("\\global"), ToString(use_global.value())); | ||||
|         } | ||||
|         if (global || use_global.value() == false) { | ||||
|             WriteSettingInternal(std::string(full_key).append("\\default"), | ||||
|                                  ToString(string_default == saved_value)); | ||||
|             WriteSettingInternal(full_key, saved_value); | ||||
|             WriteString(std::string(full_key).append("\\default"), | ||||
|                         ToString(adjusted_default_value == adjusted_value)); | ||||
|             WriteString(full_key, adjusted_value); | ||||
|         } | ||||
|     } else if (default_value.has_value() && !use_global.has_value()) { | ||||
|         WriteSettingInternal(std::string(full_key).append("\\default"), | ||||
|                              ToString(string_default == saved_value)); | ||||
|         WriteSettingInternal(full_key, saved_value); | ||||
|     } else if (adjusted_default_value.has_value() && !use_global.has_value()) { | ||||
|         WriteString(std::string(full_key).append("\\default"), | ||||
|                     ToString(adjusted_default_value == adjusted_value)); | ||||
|         WriteString(full_key, adjusted_value); | ||||
|     } else { | ||||
|         WriteSettingInternal(full_key, saved_value); | ||||
|         WriteString(full_key, adjusted_value); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void Config::WriteSettingInternal(const std::string& key, const std::string& value) { | ||||
| void Config::WriteString(const std::string& key, const std::string& value) { | ||||
|     config->SetValue(GetSection().c_str(), key.c_str(), value.c_str()); | ||||
| } | ||||
|  | ||||
| @@ -861,17 +891,17 @@ void Config::WriteSettingGeneric(const Settings::BasicSetting* const setting) { | ||||
|     std::string key = AdjustKey(setting->GetLabel()); | ||||
|     if (setting->Switchable()) { | ||||
|         if (!global) { | ||||
|             WriteSetting(std::string(key).append("\\use_global"), setting->UsingGlobal()); | ||||
|             WriteBooleanSetting(std::string(key).append("\\use_global"), setting->UsingGlobal()); | ||||
|         } | ||||
|         if (global || !setting->UsingGlobal()) { | ||||
|             WriteSetting(std::string(key).append("\\default"), | ||||
|                          setting->ToString() == setting->DefaultToString()); | ||||
|             WriteSetting(key, setting->ToString()); | ||||
|             WriteBooleanSetting(std::string(key).append("\\default"), | ||||
|                                 setting->ToString() == setting->DefaultToString()); | ||||
|             WriteStringSetting(key, setting->ToString()); | ||||
|         } | ||||
|     } else if (global) { | ||||
|         WriteSetting(std::string(key).append("\\default"), | ||||
|                      setting->ToString() == setting->DefaultToString()); | ||||
|         WriteSetting(key, setting->ToString()); | ||||
|         WriteBooleanSetting(std::string(key).append("\\default"), | ||||
|                             setting->ToString() == setting->DefaultToString()); | ||||
|         WriteStringSetting(key, setting->ToString()); | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -154,11 +154,20 @@ protected: | ||||
|      * @param use_global Specifies if the custom or global config should be in use, for custom | ||||
|      * configs | ||||
|      */ | ||||
|     template <typename Type = int> | ||||
|     void WriteSetting(const std::string& key, const Type& value, | ||||
|                       const std::optional<Type>& default_value = std::nullopt, | ||||
|                       const std::optional<bool>& use_global = std::nullopt); | ||||
|     void WriteSettingInternal(const std::string& key, const std::string& value); | ||||
|     void WriteBooleanSetting(const std::string& key, const bool& value, | ||||
|                              const std::optional<bool>& default_value = std::nullopt, | ||||
|                              const std::optional<bool>& use_global = std::nullopt); | ||||
|     template <typename T> | ||||
|     std::enable_if_t<std::is_integral_v<T>> WriteIntegerSetting( | ||||
|         const std::string& key, const T& value, | ||||
|         const std::optional<T>& default_value = std::nullopt, | ||||
|         const std::optional<bool>& use_global = std::nullopt); | ||||
|     void WriteDoubleSetting(const std::string& key, const double& value, | ||||
|                             const std::optional<double>& default_value = std::nullopt, | ||||
|                             const std::optional<bool>& use_global = std::nullopt); | ||||
|     void WriteStringSetting(const std::string& key, const std::string& value, | ||||
|                             const std::optional<std::string>& default_value = std::nullopt, | ||||
|                             const std::optional<bool>& use_global = std::nullopt); | ||||
|  | ||||
|     void ReadCategory(Settings::Category category); | ||||
|     void WriteCategory(Settings::Category category); | ||||
| @@ -175,8 +184,10 @@ protected: | ||||
|             return value_ ? "true" : "false"; | ||||
|         } else if constexpr (std::is_same_v<T, u64>) { | ||||
|             return std::to_string(static_cast<u64>(value_)); | ||||
|         } else { | ||||
|         } else if constexpr (std::is_same_v<T, s64>) { | ||||
|             return std::to_string(static_cast<s64>(value_)); | ||||
|         } else { | ||||
|             return std::to_string(value_); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -197,9 +208,13 @@ protected: | ||||
|     const bool global; | ||||
|  | ||||
| private: | ||||
|     inline static std::array<char, 19> special_characters = {'!', '#', '$',  '%',  '^', '&', '*', | ||||
|                                                              '|', ';', '\'', '\"', ',', '<', '.', | ||||
|                                                              '>', '?', '`',  '~',  '='}; | ||||
|     void WritePreparedSetting(const std::string& key, const std::string& adjusted_value, | ||||
|                               const std::optional<std::string>& adjusted_default_value, | ||||
|                               const std::optional<bool>& use_global); | ||||
|     void WriteString(const std::string& key, const std::string& value); | ||||
|  | ||||
|     inline static std::array<char, 18> special_characters = { | ||||
|         '!', '#', '$', '%', '^', '&', '*', '|', ';', '\'', '\"', ',', '<', '>', '?', '`', '~', '='}; | ||||
|  | ||||
|     struct ConfigArray { | ||||
|         std::string name; | ||||
|   | ||||
| @@ -348,43 +348,45 @@ void QtConfig::SaveQtPlayerValues(const std::size_t player_index) { | ||||
|  | ||||
|     for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { | ||||
|         const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); | ||||
|         WriteSetting(std::string(player_prefix).append(Settings::NativeButton::mapping[i]), | ||||
|                      player.buttons[i], std::make_optional(default_param)); | ||||
|         WriteStringSetting(std::string(player_prefix).append(Settings::NativeButton::mapping[i]), | ||||
|                            player.buttons[i], std::make_optional(default_param)); | ||||
|     } | ||||
|     for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | ||||
|         const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | ||||
|             default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], | ||||
|             default_analogs[i][3], default_stick_mod[i], 0.5f); | ||||
|         WriteSetting(std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), | ||||
|                      player.analogs[i], std::make_optional(default_param)); | ||||
|         WriteStringSetting(std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), | ||||
|                            player.analogs[i], std::make_optional(default_param)); | ||||
|     } | ||||
|     for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { | ||||
|         const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); | ||||
|         WriteSetting(std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), | ||||
|                      player.motions[i], std::make_optional(default_param)); | ||||
|         WriteStringSetting(std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), | ||||
|                            player.motions[i], std::make_optional(default_param)); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void QtConfig::SaveDebugControlValues() { | ||||
|     for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { | ||||
|         const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); | ||||
|         WriteSetting(std::string("debug_pad_").append(Settings::NativeButton::mapping[i]), | ||||
|                      Settings::values.debug_pad_buttons[i], std::make_optional(default_param)); | ||||
|         WriteStringSetting(std::string("debug_pad_").append(Settings::NativeButton::mapping[i]), | ||||
|                            Settings::values.debug_pad_buttons[i], | ||||
|                            std::make_optional(default_param)); | ||||
|     } | ||||
|     for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | ||||
|         const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | ||||
|             default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], | ||||
|             default_analogs[i][3], default_stick_mod[i], 0.5f); | ||||
|         WriteSetting(std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]), | ||||
|                      Settings::values.debug_pad_analogs[i], std::make_optional(default_param)); | ||||
|         WriteStringSetting(std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]), | ||||
|                            Settings::values.debug_pad_analogs[i], | ||||
|                            std::make_optional(default_param)); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void QtConfig::SaveHidbusValues() { | ||||
|     const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | ||||
|         0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); | ||||
|     WriteSetting(std::string("ring_controller"), Settings::values.ringcon_analogs, | ||||
|                  std::make_optional(default_param)); | ||||
|     WriteStringSetting(std::string("ring_controller"), Settings::values.ringcon_analogs, | ||||
|                        std::make_optional(default_param)); | ||||
| } | ||||
|  | ||||
| void QtConfig::SaveQtControlValues() { | ||||
| @@ -409,19 +411,20 @@ void QtConfig::SavePathValues() { | ||||
|  | ||||
|     WriteCategory(Settings::Category::Paths); | ||||
|  | ||||
|     WriteSetting(std::string("romsPath"), UISettings::values.roms_path); | ||||
|     WriteStringSetting(std::string("romsPath"), UISettings::values.roms_path); | ||||
|     BeginArray(std::string("gamedirs")); | ||||
|     for (int i = 0; i < UISettings::values.game_dirs.size(); ++i) { | ||||
|         SetArrayIndex(i); | ||||
|         const auto& game_dir = UISettings::values.game_dirs[i]; | ||||
|         WriteSetting(std::string("path"), game_dir.path); | ||||
|         WriteSetting(std::string("deep_scan"), game_dir.deep_scan, std::make_optional(false)); | ||||
|         WriteSetting(std::string("expanded"), game_dir.expanded, std::make_optional(true)); | ||||
|         WriteStringSetting(std::string("path"), game_dir.path); | ||||
|         WriteBooleanSetting(std::string("deep_scan"), game_dir.deep_scan, | ||||
|                             std::make_optional(false)); | ||||
|         WriteBooleanSetting(std::string("expanded"), game_dir.expanded, std::make_optional(true)); | ||||
|     } | ||||
|     EndArray(); | ||||
|  | ||||
|     WriteSetting(std::string("recentFiles"), | ||||
|                  UISettings::values.recent_files.join(QStringLiteral(", ")).toStdString()); | ||||
|     WriteStringSetting(std::string("recentFiles"), | ||||
|                        UISettings::values.recent_files.join(QStringLiteral(", ")).toStdString()); | ||||
|  | ||||
|     EndGroup(); | ||||
| } | ||||
| @@ -438,14 +441,14 @@ void QtConfig::SaveShortcutValues() { | ||||
|         BeginGroup(group); | ||||
|         BeginGroup(name); | ||||
|  | ||||
|         WriteSetting(std::string("KeySeq"), shortcut.keyseq, | ||||
|                      std::make_optional(default_hotkey.keyseq)); | ||||
|         WriteSetting(std::string("Controller_KeySeq"), shortcut.controller_keyseq, | ||||
|                      std::make_optional(default_hotkey.controller_keyseq)); | ||||
|         WriteSetting(std::string("Context"), shortcut.context, | ||||
|                      std::make_optional(default_hotkey.context)); | ||||
|         WriteSetting(std::string("Repeat"), shortcut.repeat, | ||||
|                      std::make_optional(default_hotkey.repeat)); | ||||
|         WriteStringSetting(std::string("KeySeq"), shortcut.keyseq, | ||||
|                            std::make_optional(default_hotkey.keyseq)); | ||||
|         WriteStringSetting(std::string("Controller_KeySeq"), shortcut.controller_keyseq, | ||||
|                            std::make_optional(default_hotkey.controller_keyseq)); | ||||
|         WriteIntegerSetting(std::string("Context"), shortcut.context, | ||||
|                             std::make_optional(default_hotkey.context)); | ||||
|         WriteBooleanSetting(std::string("Repeat"), shortcut.repeat, | ||||
|                             std::make_optional(default_hotkey.repeat)); | ||||
|  | ||||
|         EndGroup(); // name | ||||
|         EndGroup(); // group | ||||
| @@ -460,9 +463,10 @@ void QtConfig::SaveUIValues() { | ||||
|     WriteCategory(Settings::Category::Ui); | ||||
|     WriteCategory(Settings::Category::UiGeneral); | ||||
|  | ||||
|     WriteSetting(std::string("theme"), UISettings::values.theme, | ||||
|                  std::make_optional(std::string( | ||||
|                      UISettings::themes[static_cast<size_t>(UISettings::default_theme)].second))); | ||||
|     WriteStringSetting( | ||||
|         std::string("theme"), UISettings::values.theme, | ||||
|         std::make_optional(std::string( | ||||
|             UISettings::themes[static_cast<size_t>(UISettings::default_theme)].second))); | ||||
|  | ||||
|     SaveUIGamelistValues(); | ||||
|     SaveUILayoutValues(); | ||||
| @@ -482,7 +486,7 @@ void QtConfig::SaveUIGamelistValues() { | ||||
|     BeginArray(std::string("favorites")); | ||||
|     for (int i = 0; i < UISettings::values.favorited_ids.size(); i++) { | ||||
|         SetArrayIndex(i); | ||||
|         WriteSetting(std::string("program_id"), UISettings::values.favorited_ids[i]); | ||||
|         WriteIntegerSetting(std::string("program_id"), UISettings::values.favorited_ids[i]); | ||||
|     } | ||||
|     EndArray(); // favorites | ||||
|  | ||||
| @@ -506,14 +510,15 @@ void QtConfig::SaveMultiplayerValues() { | ||||
|     BeginArray(std::string("username_ban_list")); | ||||
|     for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.first.size(); ++i) { | ||||
|         SetArrayIndex(static_cast<int>(i)); | ||||
|         WriteSetting(std::string("username"), UISettings::values.multiplayer_ban_list.first[i]); | ||||
|         WriteStringSetting(std::string("username"), | ||||
|                            UISettings::values.multiplayer_ban_list.first[i]); | ||||
|     } | ||||
|     EndArray(); // username_ban_list | ||||
|  | ||||
|     BeginArray(std::string("ip_ban_list")); | ||||
|     for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.second.size(); ++i) { | ||||
|         SetArrayIndex(static_cast<int>(i)); | ||||
|         WriteSetting(std::string("ip"), UISettings::values.multiplayer_ban_list.second[i]); | ||||
|         WriteStringSetting(std::string("ip"), UISettings::values.multiplayer_ban_list.second[i]); | ||||
|     } | ||||
|     EndArray(); // ip_ban_list | ||||
|  | ||||
|   | ||||
| @@ -213,43 +213,45 @@ void SdlConfig::SaveSdlPlayerValues(const std::size_t player_index) { | ||||
|  | ||||
|     for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { | ||||
|         const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); | ||||
|         WriteSetting(std::string(player_prefix).append(Settings::NativeButton::mapping[i]), | ||||
|                      player.buttons[i], std::make_optional(default_param)); | ||||
|         WriteStringSetting(std::string(player_prefix).append(Settings::NativeButton::mapping[i]), | ||||
|                            player.buttons[i], std::make_optional(default_param)); | ||||
|     } | ||||
|     for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | ||||
|         const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | ||||
|             default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], | ||||
|             default_analogs[i][3], default_stick_mod[i], 0.5f); | ||||
|         WriteSetting(std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), | ||||
|                      player.analogs[i], std::make_optional(default_param)); | ||||
|         WriteStringSetting(std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), | ||||
|                            player.analogs[i], std::make_optional(default_param)); | ||||
|     } | ||||
|     for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { | ||||
|         const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); | ||||
|         WriteSetting(std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), | ||||
|                      player.motions[i], std::make_optional(default_param)); | ||||
|         WriteStringSetting(std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), | ||||
|                            player.motions[i], std::make_optional(default_param)); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void SdlConfig::SaveDebugControlValues() { | ||||
|     for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { | ||||
|         const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); | ||||
|         WriteSetting(std::string("debug_pad_").append(Settings::NativeButton::mapping[i]), | ||||
|                      Settings::values.debug_pad_buttons[i], std::make_optional(default_param)); | ||||
|         WriteStringSetting(std::string("debug_pad_").append(Settings::NativeButton::mapping[i]), | ||||
|                            Settings::values.debug_pad_buttons[i], | ||||
|                            std::make_optional(default_param)); | ||||
|     } | ||||
|     for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | ||||
|         const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | ||||
|             default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], | ||||
|             default_analogs[i][3], default_stick_mod[i], 0.5f); | ||||
|         WriteSetting(std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]), | ||||
|                      Settings::values.debug_pad_analogs[i], std::make_optional(default_param)); | ||||
|         WriteStringSetting(std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]), | ||||
|                            Settings::values.debug_pad_analogs[i], | ||||
|                            std::make_optional(default_param)); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void SdlConfig::SaveHidbusValues() { | ||||
|     const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | ||||
|         0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); | ||||
|     WriteSetting(std::string("ring_controller"), Settings::values.ringcon_analogs, | ||||
|                  std::make_optional(default_param)); | ||||
|     WriteStringSetting(std::string("ring_controller"), Settings::values.ringcon_analogs, | ||||
|                        std::make_optional(default_param)); | ||||
| } | ||||
|  | ||||
| std::vector<Settings::BasicSetting*>& SdlConfig::FindRelevantList(Settings::Category category) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user