summaryrefslogtreecommitdiffstats
path: root/src/android/app
diff options
context:
space:
mode:
authort895 <clombardo169@gmail.com>2023-12-24 21:42:28 +0100
committert895 <clombardo169@gmail.com>2023-12-30 21:11:36 +0100
commitd163b182081401dbdcc5fc92c1692ff3209f2353 (patch)
treee5ed8e3c24c03966f4544d5433a7f4c553c28b40 /src/android/app
parentfrontend_common: config: Refactor WriteSetting to stricter types (diff)
downloadyuzu-d163b182081401dbdcc5fc92c1692ff3209f2353.tar
yuzu-d163b182081401dbdcc5fc92c1692ff3209f2353.tar.gz
yuzu-d163b182081401dbdcc5fc92c1692ff3209f2353.tar.bz2
yuzu-d163b182081401dbdcc5fc92c1692ff3209f2353.tar.lz
yuzu-d163b182081401dbdcc5fc92c1692ff3209f2353.tar.xz
yuzu-d163b182081401dbdcc5fc92c1692ff3209f2353.tar.zst
yuzu-d163b182081401dbdcc5fc92c1692ff3209f2353.zip
Diffstat (limited to 'src/android/app')
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt6
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt8
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt4
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt39
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt89
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt984
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableButton.kt3
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableJoystick.kt4
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayControl.kt188
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayControlData.kt19
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayControlDefault.kt13
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayLayout.kt10
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt142
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/EmulationMenuSettings.kt50
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NativeConfig.kt18
-rw-r--r--src/android/app/src/main/jni/android_common/android_common.cpp9
-rw-r--r--src/android/app/src/main/jni/android_common/android_common.h3
-rw-r--r--src/android/app/src/main/jni/android_config.cpp62
-rw-r--r--src/android/app/src/main/jni/android_config.h2
-rw-r--r--src/android/app/src/main/jni/android_settings.h25
-rw-r--r--src/android/app/src/main/jni/id_cache.cpp79
-rw-r--r--src/android/app/src/main/jni/id_cache.h12
-rw-r--r--src/android/app/src/main/jni/native_config.cpp70
-rw-r--r--src/android/app/src/main/res/values/arrays.xml10
-rw-r--r--src/android/app/src/main/res/values/integers.xml204
25 files changed, 1206 insertions, 847 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt
index 9b08f008d..93c8ce922 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt
@@ -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) {
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt
index 110d15f1c..86bd33672 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt
@@ -19,7 +19,13 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
RENDERER_DEBUG("debug"),
PICTURE_IN_PICTURE("picture_in_picture"),
USE_CUSTOM_RTC("custom_rtc_enabled"),
- BLACK_BACKGROUNDS("black_backgrounds");
+ 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)
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt
index b0193d83e..16fb87614 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt
@@ -21,7 +21,9 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
AUDIO_OUTPUT_ENGINE("output_engine"),
MAX_ANISOTROPY("max_anisotropy"),
THEME("theme"),
- THEME_MODE("theme_mode");
+ THEME_MODE("theme_mode"),
+ OVERLAY_SCALE("control_scale"),
+ OVERLAY_OPACITY("control_opacity");
override fun getInt(needsGlobal: Boolean): Int = NativeConfig.getInt(key, needsGlobal)
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt
index 360bdaf3e..43caac989 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt
@@ -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,24 +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"
-
- // Deprecated theme preference keys
- 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,
@@ -84,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
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
index d7b38f62d..6e5dd1dba 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
@@ -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,21 @@ 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()
}
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 +563,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 +577,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 +594,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 +605,26 @@ 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
}
@@ -667,6 +667,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
it.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
}
}
+ NativeConfig.saveGlobalConfig()
}
@SuppressLint("SetTextI18n")
@@ -675,7 +676,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 +686,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 +710,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()
}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt
index a13faf3c7..bb69b8bd5 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt
@@ -21,7 +21,6 @@ import android.view.View
import android.view.View.OnTouchListener
import android.view.WindowInsets
import androidx.core.content.ContextCompat
-import androidx.preference.PreferenceManager
import androidx.window.layout.WindowMetricsCalculator
import kotlin.math.max
import kotlin.math.min
@@ -29,9 +28,13 @@ import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.NativeLibrary.ButtonType
import org.yuzu.yuzu_emu.NativeLibrary.StickType
import org.yuzu.yuzu_emu.R
-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.utils.EmulationMenuSettings
+import org.yuzu.yuzu_emu.overlay.model.OverlayControl
+import org.yuzu.yuzu_emu.overlay.model.OverlayControlData
+import org.yuzu.yuzu_emu.overlay.model.OverlayLayout
+import org.yuzu.yuzu_emu.utils.NativeConfig
/**
* Draws the interactive input overlay on top of the
@@ -51,23 +54,18 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
private lateinit var windowInsets: WindowInsets
- var layout = LANDSCAPE
+ var layout = OverlayLayout.Landscape
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
windowInsets = rootWindowInsets
- val overlayVersion = preferences.getInt(Settings.PREF_OVERLAY_VERSION, 0)
- if (overlayVersion != OVERLAY_VERSION) {
- resetAllLayouts()
+ val overlayControlData = NativeConfig.getOverlayControlData()
+ if (overlayControlData.isEmpty()) {
+ populateDefaultConfig()
} else {
- val layoutIndex = overlayLayouts.indexOf(layout)
- val currentLayoutVersion =
- preferences.getInt(Settings.overlayLayoutPrefs[layoutIndex], 0)
- if (currentLayoutVersion != overlayLayoutVersions[layoutIndex]) {
- resetCurrentLayout()
- }
+ checkForNewControls(overlayControlData)
}
// Load the controls.
@@ -123,7 +121,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
}
for (dpad in overlayDpads) {
- if (!dpad.updateStatus(event, EmulationMenuSettings.dpadSlide)) {
+ if (!dpad.updateStatus(event, BooleanSetting.DPAD_SLIDE.getBoolean())) {
continue
}
NativeLibrary.onGamePadButtonEvent(
@@ -174,7 +172,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
invalidate()
}
- if (!preferences.getBoolean(Settings.PREF_TOUCH_ENABLED, true)) {
+ if (!BooleanSetting.TOUCHSCREEN.getBoolean()) {
return true
}
@@ -211,7 +209,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
}
private fun playHaptics(event: MotionEvent) {
- if (EmulationMenuSettings.hapticFeedback) {
+ if (BooleanSetting.HAPTIC_FEEDBACK.getBoolean()) {
when (event.actionMasked) {
MotionEvent.ACTION_DOWN,
MotionEvent.ACTION_POINTER_DOWN ->
@@ -255,10 +253,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
MotionEvent.ACTION_POINTER_DOWN ->
// If no button is being moved now, remember the currently touched button to move.
if (buttonBeingConfigured == null &&
- button.bounds.contains(
- fingerPositionX,
- fingerPositionY
- )
+ button.bounds.contains(fingerPositionX, fingerPositionY)
) {
buttonBeingConfigured = button
buttonBeingConfigured!!.onConfigureTouch(event)
@@ -274,7 +269,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
MotionEvent.ACTION_POINTER_UP -> if (buttonBeingConfigured === button) {
// Persist button position by saving new place.
saveControlPosition(
- buttonBeingConfigured!!.prefId,
+ buttonBeingConfigured!!.overlayControlData.id,
buttonBeingConfigured!!.bounds.centerX(),
buttonBeingConfigured!!.bounds.centerY(),
layout
@@ -321,10 +316,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
when (event.action) {
MotionEvent.ACTION_DOWN,
MotionEvent.ACTION_POINTER_DOWN -> if (joystickBeingConfigured == null &&
- joystick.bounds.contains(
- fingerPositionX,
- fingerPositionY
- )
+ joystick.bounds.contains(fingerPositionX, fingerPositionY)
) {
joystickBeingConfigured = joystick
joystickBeingConfigured!!.onConfigureTouch(event)
@@ -351,231 +343,257 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
return true
}
- private fun addOverlayControls(layout: String) {
+ private fun addOverlayControls(layout: OverlayLayout) {
val windowSize = getSafeScreenSize(context, Pair(measuredWidth, measuredHeight))
- if (preferences.getBoolean(Settings.PREF_BUTTON_A, true)) {
- overlayButtons.add(
- initializeOverlayButton(
- context,
- windowSize,
- R.drawable.facebutton_a,
- R.drawable.facebutton_a_depressed,
- ButtonType.BUTTON_A,
- Settings.PREF_BUTTON_A,
- layout
- )
- )
- }
- if (preferences.getBoolean(Settings.PREF_BUTTON_B, true)) {
- overlayButtons.add(
- initializeOverlayButton(
- context,
- windowSize,
- R.drawable.facebutton_b,
- R.drawable.facebutton_b_depressed,
- ButtonType.BUTTON_B,
- Settings.PREF_BUTTON_B,
- layout
- )
- )
- }
- if (preferences.getBoolean(Settings.PREF_BUTTON_X, true)) {
- overlayButtons.add(
- initializeOverlayButton(
- context,
- windowSize,
- R.drawable.facebutton_x,
- R.drawable.facebutton_x_depressed,
- ButtonType.BUTTON_X,
- Settings.PREF_BUTTON_X,
- layout
- )
- )
- }
- if (preferences.getBoolean(Settings.PREF_BUTTON_Y, true)) {
- overlayButtons.add(
- initializeOverlayButton(
- context,
- windowSize,
- R.drawable.facebutton_y,
- R.drawable.facebutton_y_depressed,
- ButtonType.BUTTON_Y,
- Settings.PREF_BUTTON_Y,
- layout
- )
- )
- }
- if (preferences.getBoolean(Settings.PREF_BUTTON_L, true)) {
- overlayButtons.add(
- initializeOverlayButton(
- context,
- windowSize,
- R.drawable.l_shoulder,
- R.drawable.l_shoulder_depressed,
- ButtonType.TRIGGER_L,
- Settings.PREF_BUTTON_L,
- layout
- )
- )
- }
- if (preferences.getBoolean(Settings.PREF_BUTTON_R, true)) {
- overlayButtons.add(
- initializeOverlayButton(
- context,
- windowSize,
- R.drawable.r_shoulder,
- R.drawable.r_shoulder_depressed,
- ButtonType.TRIGGER_R,
- Settings.PREF_BUTTON_R,
- layout
- )
- )
- }
- if (preferences.getBoolean(Settings.PREF_BUTTON_ZL, true)) {
- overlayButtons.add(
- initializeOverlayButton(
- context,
- windowSize,
- R.drawable.zl_trigger,
- R.drawable.zl_trigger_depressed,
- ButtonType.TRIGGER_ZL,
- Settings.PREF_BUTTON_ZL,
- layout
- )
- )
- }
- if (preferences.getBoolean(Settings.PREF_BUTTON_ZR, true)) {
- overlayButtons.add(
- initializeOverlayButton(
- context,
- windowSize,
- R.drawable.zr_trigger,
- R.drawable.zr_trigger_depressed,
- ButtonType.TRIGGER_ZR,
- Settings.PREF_BUTTON_ZR,
- layout
- )
- )
- }
- if (preferences.getBoolean(Settings.PREF_BUTTON_PLUS, true)) {
- overlayButtons.add(
- initializeOverlayButton(
- context,
- windowSize,
- R.drawable.facebutton_plus,
- R.drawable.facebutton_plus_depressed,
- ButtonType.BUTTON_PLUS,
- Settings.PREF_BUTTON_PLUS,
- layout
- )
- )
- }
- if (preferences.getBoolean(Settings.PREF_BUTTON_MINUS, true)) {
- overlayButtons.add(
- initializeOverlayButton(
- context,
- windowSize,
- R.drawable.facebutton_minus,
- R.drawable.facebutton_minus_depressed,
- ButtonType.BUTTON_MINUS,
- Settings.PREF_BUTTON_MINUS,
- layout
- )
- )
- }
- if (preferences.getBoolean(Settings.PREF_BUTTON_DPAD, true)) {
- overlayDpads.add(
- initializeOverlayDpad(
- context,
- windowSize,
- R.drawable.dpad_standard,
- R.drawable.dpad_standard_cardinal_depressed,
- R.drawable.dpad_standard_diagonal_depressed,
- layout
- )
- )
- }
- if (preferences.getBoolean(Settings.PREF_STICK_L, true)) {
- overlayJoysticks.add(
- initializeOverlayJoystick(
- context,
- windowSize,
- R.drawable.joystick_range,
- R.drawable.joystick,
- R.drawable.joystick_depressed,
- StickType.STICK_L,
- ButtonType.STICK_L,
- Settings.PREF_STICK_L,
- layout
- )
- )
- }
- if (preferences.getBoolean(Settings.PREF_STICK_R, true)) {
- overlayJoysticks.add(
- initializeOverlayJoystick(
- context,
- windowSize,
- R.drawable.joystick_range,
- R.drawable.joystick,
- R.drawable.joystick_depressed,
- StickType.STICK_R,
- ButtonType.STICK_R,
- Settings.PREF_STICK_R,
- layout
- )
- )
- }
- if (preferences.getBoolean(Settings.PREF_BUTTON_HOME, false)) {
- overlayButtons.add(
- initializeOverlayButton(
- context,
- windowSize,
- R.drawable.facebutton_home,
- R.drawable.facebutton_home_depressed,
- ButtonType.BUTTON_HOME,
- Settings.PREF_BUTTON_HOME,
- layout
- )
- )
- }
- if (preferences.getBoolean(Settings.PREF_BUTTON_SCREENSHOT, false)) {
- overlayButtons.add(
- initializeOverlayButton(
- context,
- windowSize,
- R.drawable.facebutton_screenshot,
- R.drawable.facebutton_screenshot_depressed,
- ButtonType.BUTTON_CAPTURE,
- Settings.PREF_BUTTON_SCREENSHOT,
- layout
- )
- )
- }
- if (preferences.getBoolean(Settings.PREF_BUTTON_STICK_L, true)) {
- overlayButtons.add(
- initializeOverlayButton(
- context,
- windowSize,
- R.drawable.button_l3,
- R.drawable.button_l3_depressed,
- ButtonType.STICK_L,
- Settings.PREF_BUTTON_STICK_L,
- layout
- )
- )
- }
- if (preferences.getBoolean(Settings.PREF_BUTTON_STICK_R, true)) {
- overlayButtons.add(
- initializeOverlayButton(
- context,
- windowSize,
- R.drawable.button_r3,
- R.drawable.button_r3_depressed,
- ButtonType.STICK_R,
- Settings.PREF_BUTTON_STICK_R,
- layout
- )
- )
+ val overlayControlData = NativeConfig.getOverlayControlData()
+ for (data in overlayControlData) {
+ if (!data.enabled) {
+ continue
+ }
+
+ val position = data.positionFromLayout(layout)
+ when (data.id) {
+ OverlayControl.BUTTON_A.id -> {
+ overlayButtons.add(
+ initializeOverlayButton(
+ context,
+ windowSize,
+ R.drawable.facebutton_a,
+ R.drawable.facebutton_a_depressed,
+ ButtonType.BUTTON_A,
+ data,
+ position
+ )
+ )
+ }
+
+ OverlayControl.BUTTON_B.id -> {
+ overlayButtons.add(
+ initializeOverlayButton(
+ context,
+ windowSize,
+ R.drawable.facebutton_b,
+ R.drawable.facebutton_b_depressed,
+ ButtonType.BUTTON_B,
+ data,
+ position
+ )
+ )
+ }
+
+ OverlayControl.BUTTON_X.id -> {
+ overlayButtons.add(
+ initializeOverlayButton(
+ context,
+ windowSize,
+ R.drawable.facebutton_x,
+ R.drawable.facebutton_x_depressed,
+ ButtonType.BUTTON_X,
+ data,
+ position
+ )
+ )
+ }
+
+ OverlayControl.BUTTON_Y.id -> {
+ overlayButtons.add(
+ initializeOverlayButton(
+ context,
+ windowSize,
+ R.drawable.facebutton_y,
+ R.drawable.facebutton_y_depressed,
+ ButtonType.BUTTON_Y,
+ data,
+ position
+ )
+ )
+ }
+
+ OverlayControl.BUTTON_PLUS.id -> {
+ overlayButtons.add(
+ initializeOverlayButton(
+ context,
+ windowSize,
+ R.drawable.facebutton_plus,
+ R.drawable.facebutton_plus_depressed,
+ ButtonType.BUTTON_PLUS,
+ data,
+ position
+ )
+ )
+ }
+
+ OverlayControl.BUTTON_MINUS.id -> {
+ overlayButtons.add(
+ initializeOverlayButton(
+ context,
+ windowSize,
+ R.drawable.facebutton_minus,
+ R.drawable.facebutton_minus_depressed,
+ ButtonType.BUTTON_MINUS,
+ data,
+ position
+ )
+ )
+ }
+
+ OverlayControl.BUTTON_HOME.id -> {
+ overlayButtons.add(
+ initializeOverlayButton(
+ context,
+ windowSize,
+ R.drawable.facebutton_home,
+ R.drawable.facebutton_home_depressed,
+ ButtonType.BUTTON_HOME,
+ data,
+ position
+ )
+ )
+ }
+
+ OverlayControl.BUTTON_CAPTURE.id -> {
+ overlayButtons.add(
+ initializeOverlayButton(
+ context,
+ windowSize,
+ R.drawable.facebutton_screenshot,
+ R.drawable.facebutton_screenshot_depressed,
+ ButtonType.BUTTON_CAPTURE,
+ data,
+ position
+ )
+ )
+ }
+
+ OverlayControl.BUTTON_L.id -> {
+ overlayButtons.add(
+ initializeOverlayButton(
+ context,
+ windowSize,
+ R.drawable.l_shoulder,
+ R.drawable.l_shoulder_depressed,
+ ButtonType.TRIGGER_L,
+ data,
+ position
+ )
+ )
+ }
+
+ OverlayControl.BUTTON_R.id -> {
+ overlayButtons.add(
+ initializeOverlayButton(
+ context,
+ windowSize,
+ R.drawable.r_shoulder,
+ R.drawable.r_shoulder_depressed,
+ ButtonType.TRIGGER_R,
+ data,
+ position
+ )
+ )
+ }
+
+ OverlayControl.BUTTON_ZL.id -> {
+ overlayButtons.add(
+ initializeOverlayButton(
+ context,
+ windowSize,
+ R.drawable.zl_trigger,
+ R.drawable.zl_trigger_depressed,
+ ButtonType.TRIGGER_ZL,
+ data,
+ position
+ )
+ )
+ }
+
+ OverlayControl.BUTTON_ZR.id -> {
+ overlayButtons.add(
+ initializeOverlayButton(
+ context,
+ windowSize,
+ R.drawable.zr_trigger,
+ R.drawable.zr_trigger_depressed,
+ ButtonType.TRIGGER_ZR,
+ data,
+ position
+ )
+ )
+ }
+
+ OverlayControl.BUTTON_STICK_L.id -> {
+ overlayButtons.add(
+ initializeOverlayButton(
+ context,
+ windowSize,
+ R.drawable.button_l3,
+ R.drawable.button_l3_depressed,
+ ButtonType.STICK_L,
+ data,
+ position
+ )
+ )
+ }
+
+ OverlayControl.BUTTON_STICK_R.id -> {
+ overlayButtons.add(
+ initializeOverlayButton(
+ context,
+ windowSize,
+ R.drawable.button_r3,
+ R.drawable.button_r3_depressed,
+ ButtonType.STICK_R,
+ data,
+ position
+ )
+ )
+ }
+
+ OverlayControl.STICK_L.id -> {
+ overlayJoysticks.add(
+ initializeOverlayJoystick(
+ context,
+ windowSize,
+ R.drawable.joystick_range,
+ R.drawable.joystick,
+ R.drawable.joystick_depressed,
+ StickType.STICK_L,
+ ButtonType.STICK_L,
+ data,
+ position
+ )
+ )
+ }
+
+ OverlayControl.STICK_R.id -> {
+ overlayJoysticks.add(
+ initializeOverlayJoystick(
+ context,
+ windowSize,
+ R.drawable.joystick_range,
+ R.drawable.joystick,
+ R.drawable.joystick_depressed,
+ StickType.STICK_R,
+ ButtonType.STICK_R,
+ data,
+ position
+ )
+ )
+ }
+
+ OverlayControl.COMBINED_DPAD.id -> {
+ overlayDpads.add(
+ initializeOverlayDpad(
+ context,
+ windowSize,
+ R.drawable.dpad_standard,
+ R.drawable.dpad_standard_cardinal_depressed,
+ R.drawable.dpad_standard_diagonal_depressed,
+ position
+ )
+ )
+ }
+ }
}
}
@@ -586,313 +604,87 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
overlayJoysticks.clear()
// Add all the enabled overlay items back to the HashSet.
- if (EmulationMenuSettings.showOverlay) {
+ if (BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean()) {
addOverlayControls(layout)
}
invalidate()
}
- private fun saveControlPosition(prefId: String, x: Int, y: Int, layout: String) {
+ private fun saveControlPosition(id: String, x: Int, y: Int, layout: OverlayLayout) {
val windowSize = getSafeScreenSize(context, Pair(measuredWidth, measuredHeight))
val min = windowSize.first
val max = windowSize.second
- PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext).edit()
- .putFloat("$prefId-X$layout", (x - min.x).toFloat() / max.x)
- .putFloat("$prefId-Y$layout", (y - min.y).toFloat() / max.y)
- .apply()
+ val overlayControlData = NativeConfig.getOverlayControlData()
+ val data = overlayControlData.firstOrNull { it.id == id }
+ val newPosition = Pair((x - min.x).toDouble() / max.x, (y - min.y).toDouble() / max.y)
+ when (layout) {
+ OverlayLayout.Landscape -> data?.landscapePosition = newPosition
+ OverlayLayout.Portrait -> data?.portraitPosition = newPosition
+ OverlayLayout.Foldable -> data?.foldablePosition = newPosition
+ }
+ NativeConfig.setOverlayControlData(overlayControlData)
}
fun setIsInEditMode(editMode: Boolean) {
inEditMode = editMode
}
- private fun resetCurrentLayout() {
- defaultOverlayByLayout(layout)
- val layoutIndex = overlayLayouts.indexOf(layout)
- preferences.edit()
- .putInt(Settings.overlayLayoutPrefs[layoutIndex], overlayLayoutVersions[layoutIndex])
- .apply()
+ /**
+ * Applies and saves all default values for the overlay
+ */
+ private fun populateDefaultConfig() {
+ val newConfig = OverlayControl.entries.map { it.toOverlayControlData() }
+ NativeConfig.setOverlayControlData(newConfig.toTypedArray())
+ NativeConfig.saveGlobalConfig()
}
- private fun resetAllLayouts() {
- val editor = preferences.edit()
- overlayLayouts.forEachIndexed { i, layout ->
- defaultOverlayByLayout(layout)
- editor.putInt(Settings.overlayLayoutPrefs[i], overlayLayoutVersions[i])
+ /**
+ * Checks if any new controls were added to OverlayControl that do not exist within deserialized
+ * config and adds / saves them if necessary
+ *
+ * @param overlayControlData Overlay control data from [NativeConfig.getOverlayControlData]
+ */
+ private fun checkForNewControls(overlayControlData: Array<OverlayControlData>) {
+ val missingControls = mutableListOf<OverlayControlData>()
+ OverlayControl.entries.forEach { defaultControl ->
+ val controlData = overlayControlData.firstOrNull { it.id == defaultControl.id }
+ if (controlData == null) {
+ missingControls.add(defaultControl.toOverlayControlData())
+ }
+ }
+
+ if (missingControls.isNotEmpty()) {
+ NativeConfig.setOverlayControlData(
+ arrayOf(*overlayControlData, *(missingControls.toTypedArray()))
+ )
+ NativeConfig.saveGlobalConfig()
}
- editor.putInt(Settings.PREF_OVERLAY_VERSION, OVERLAY_VERSION)
- editor.apply()
}
fun resetLayoutVisibilityAndPlacement() {
- defaultOverlayByLayout(layout)
- val editor = preferences.edit()
- Settings.overlayPreferences.forEachIndexed { _, pref ->
- editor.remove(pref)
+ defaultOverlayPositionByLayout(layout)
+
+ val overlayControlData = NativeConfig.getOverlayControlData()
+ overlayControlData.forEach {
+ it.enabled = OverlayControl.from(it.id)?.defaultVisibility == false
}
- editor.apply()
+ NativeConfig.setOverlayControlData(overlayControlData)
+
refreshControls()
}
- private val landscapeResources = arrayOf(
- R.integer.SWITCH_BUTTON_A_X,
- R.integer.SWITCH_BUTTON_A_Y,
- R.integer.SWITCH_BUTTON_B_X,
- R.integer.SWITCH_BUTTON_B_Y,
- R.integer.SWITCH_BUTTON_X_X,
- R.integer.SWITCH_BUTTON_X_Y,
- R.integer.SWITCH_BUTTON_Y_X,
- R.integer.SWITCH_BUTTON_Y_Y,
- R.integer.SWITCH_TRIGGER_ZL_X,
- R.integer.SWITCH_TRIGGER_ZL_Y,
- R.integer.SWITCH_TRIGGER_ZR_X,
- R.integer.SWITCH_TRIGGER_ZR_Y,
- R.integer.SWITCH_BUTTON_DPAD_X,
- R.integer.SWITCH_BUTTON_DPAD_Y,
- R.integer.SWITCH_TRIGGER_L_X,
- R.integer.SWITCH_TRIGGER_L_Y,
- R.integer.SWITCH_TRIGGER_R_X,
- R.integer.SWITCH_TRIGGER_R_Y,
- R.integer.SWITCH_BUTTON_PLUS_X,
- R.integer.SWITCH_BUTTON_PLUS_Y,
- R.integer.SWITCH_BUTTON_MINUS_X,
- R.integer.SWITCH_BUTTON_MINUS_Y,
- R.integer.SWITCH_BUTTON_HOME_X,
- R.integer.SWITCH_BUTTON_HOME_Y,
- R.integer.SWITCH_BUTTON_CAPTURE_X,
- R.integer.SWITCH_BUTTON_CAPTURE_Y,
- R.integer.SWITCH_STICK_R_X,
- R.integer.SWITCH_STICK_R_Y,
- R.integer.SWITCH_STICK_L_X,
- R.integer.SWITCH_STICK_L_Y,
- R.integer.SWITCH_BUTTON_STICK_L_X,
- R.integer.SWITCH_BUTTON_STICK_L_Y,
- R.integer.SWITCH_BUTTON_STICK_R_X,
- R.integer.SWITCH_BUTTON_STICK_R_Y
- )
-
- private val portraitResources = arrayOf(
- R.integer.SWITCH_BUTTON_A_X_PORTRAIT,
- R.integer.SWITCH_BUTTON_A_Y_PORTRAIT,
- R.integer.SWITCH_BUTTON_B_X_PORTRAIT,
- R.integer.SWITCH_BUTTON_B_Y_PORTRAIT,
- R.integer.SWITCH_BUTTON_X_X_PORTRAIT,
- R.integer.SWITCH_BUTTON_X_Y_PORTRAIT,
- R.integer.SWITCH_BUTTON_Y_X_PORTRAIT,
- R.integer.SWITCH_BUTTON_Y_Y_PORTRAIT,
- R.integer.SWITCH_TRIGGER_ZL_X_PORTRAIT,
- R.integer.SWITCH_TRIGGER_ZL_Y_PORTRAIT,
- R.integer.SWITCH_TRIGGER_ZR_X_PORTRAIT,
- R.integer.SWITCH_TRIGGER_ZR_Y_PORTRAIT,
- R.integer.SWITCH_BUTTON_DPAD_X_PORTRAIT,
- R.integer.SWITCH_BUTTON_DPAD_Y_PORTRAIT,
- R.integer.SWITCH_TRIGGER_L_X_PORTRAIT,
- R.integer.SWITCH_TRIGGER_L_Y_PORTRAIT,
- R.integer.SWITCH_TRIGGER_R_X_PORTRAIT,
- R.integer.SWITCH_TRIGGER_R_Y_PORTRAIT,
- R.integer.SWITCH_BUTTON_PLUS_X_PORTRAIT,
- R.integer.SWITCH_BUTTON_PLUS_Y_PORTRAIT,
- R.integer.SWITCH_BUTTON_MINUS_X_PORTRAIT,
- R.integer.SWITCH_BUTTON_MINUS_Y_PORTRAIT,
- R.integer.SWITCH_BUTTON_HOME_X_PORTRAIT,
- R.integer.SWITCH_BUTTON_HOME_Y_PORTRAIT,
- R.integer.SWITCH_BUTTON_CAPTURE_X_PORTRAIT,
- R.integer.SWITCH_BUTTON_CAPTURE_Y_PORTRAIT,
- R.integer.SWITCH_STICK_R_X_PORTRAIT,
- R.integer.SWITCH_STICK_R_Y_PORTRAIT,
- R.integer.SWITCH_STICK_L_X_PORTRAIT,
- R.integer.SWITCH_STICK_L_Y_PORTRAIT,
- R.integer.SWITCH_BUTTON_STICK_L_X_PORTRAIT,
- R.integer.SWITCH_BUTTON_STICK_L_Y_PORTRAIT,
- R.integer.SWITCH_BUTTON_STICK_R_X_PORTRAIT,
- R.integer.SWITCH_BUTTON_STICK_R_Y_PORTRAIT
- )
-
- private val foldableResources = arrayOf(
- R.integer.SWITCH_BUTTON_A_X_FOLDABLE,
- R.integer.SWITCH_BUTTON_A_Y_FOLDABLE,
- R.integer.SWITCH_BUTTON_B_X_FOLDABLE,
- R.integer.SWITCH_BUTTON_B_Y_FOLDABLE,
- R.integer.SWITCH_BUTTON_X_X_FOLDABLE,
- R.integer.SWITCH_BUTTON_X_Y_FOLDABLE,
- R.integer.SWITCH_BUTTON_Y_X_FOLDABLE,
- R.integer.SWITCH_BUTTON_Y_Y_FOLDABLE,
- R.integer.SWITCH_TRIGGER_ZL_X_FOLDABLE,
- R.integer.SWITCH_TRIGGER_ZL_Y_FOLDABLE,
- R.integer.SWITCH_TRIGGER_ZR_X_FOLDABLE,
- R.integer.SWITCH_TRIGGER_ZR_Y_FOLDABLE,
- R.integer.SWITCH_BUTTON_DPAD_X_FOLDABLE,
- R.integer.SWITCH_BUTTON_DPAD_Y_FOLDABLE,
- R.integer.SWITCH_TRIGGER_L_X_FOLDABLE,
- R.integer.SWITCH_TRIGGER_L_Y_FOLDABLE,
- R.integer.SWITCH_TRIGGER_R_X_FOLDABLE,
- R.integer.SWITCH_TRIGGER_R_Y_FOLDABLE,
- R.integer.SWITCH_BUTTON_PLUS_X_FOLDABLE,
- R.integer.SWITCH_BUTTON_PLUS_Y_FOLDABLE,
- R.integer.SWITCH_BUTTON_MINUS_X_FOLDABLE,
- R.integer.SWITCH_BUTTON_MINUS_Y_FOLDABLE,
- R.integer.SWITCH_BUTTON_HOME_X_FOLDABLE,
- R.integer.SWITCH_BUTTON_HOME_Y_FOLDABLE,
- R.integer.SWITCH_BUTTON_CAPTURE_X_FOLDABLE,
- R.integer.SWITCH_BUTTON_CAPTURE_Y_FOLDABLE,
- R.integer.SWITCH_STICK_R_X_FOLDABLE,
- R.integer.SWITCH_STICK_R_Y_FOLDABLE,
- R.integer.SWITCH_STICK_L_X_FOLDABLE,
- R.integer.SWITCH_STICK_L_Y_FOLDABLE,
- R.integer.SWITCH_BUTTON_STICK_L_X_FOLDABLE,
- R.integer.SWITCH_BUTTON_STICK_L_Y_FOLDABLE,
- R.integer.SWITCH_BUTTON_STICK_R_X_FOLDABLE,
- R.integer.SWITCH_BUTTON_STICK_R_Y_FOLDABLE
- )
-
- private fun getResourceValue(layout: String, position: Int): Float {
- return when (layout) {
- PORTRAIT -> resources.getInteger(portraitResources[position]).toFloat() / 1000
- FOLDABLE -> resources.getInteger(foldableResources[position]).toFloat() / 1000
- else -> resources.getInteger(landscapeResources[position]).toFloat() / 1000
+ private fun defaultOverlayPositionByLayout(layout: OverlayLayout) {
+ val overlayControlData = NativeConfig.getOverlayControlData()
+ for (data in overlayControlData) {
+ val defaultControlData = OverlayControl.from(data.id) ?: continue
+ val position = defaultControlData.getDefaultPositionForLayout(layout)
+ when (layout) {
+ OverlayLayout.Landscape -> data.landscapePosition = position
+ OverlayLayout.Portrait -> data.portraitPosition = position
+ OverlayLayout.Foldable -> data.foldablePosition = position
+ }
}
- }
-
- private fun defaultOverlayByLayout(layout: String) {
- // Each value represents the position of the button in relation to the screen size without insets.
- preferences.edit()
- .putFloat(
- "${Settings.PREF_BUTTON_A}-X$layout",
- getResourceValue(layout, 0)
- )
- .putFloat(
- "${Settings.PREF_BUTTON_A}-Y$layout",
- getResourceValue(layout, 1)
- )
- .putFloat(
- "${Settings.PREF_BUTTON_B}-X$layout",
- getResourceValue(layout, 2)
- )
- .putFloat(
- "${Settings.PREF_BUTTON_B}-Y$layout",
- getResourceValue(layout, 3)
- )
- .putFloat(
- "${Settings.PREF_BUTTON_X}-X$layout",
- getResourceValue(layout, 4)
- )
- .putFloat(
- "${Settings.PREF_BUTTON_X}-Y$layout",
- getResourceValue(layout, 5)
- )
- .putFloat(
- "${Settings.PREF_BUTTON_Y}-X$layout",
- getResourceValue(layout, 6)
- )
- .putFloat(
- "${Settings.PREF_BUTTON_Y}-Y$layout",
- getResourceValue(layout, 7)
- )
- .putFloat(
- "${Settings.PREF_BUTTON_ZL}-X$layout",
- getResourceValue(layout, 8)
- )
- .putFloat(
- "${Settings.PREF_BUTTON_ZL}-Y$layout",
- getResourceValue(layout, 9)
- )
- .putFloat(
- "${Settings.PREF_BUTTON_ZR}-X$layout",
- getResourceValue(layout, 10)
- )
- .putFloat(
- "${Settings.PREF_BUTTON_ZR}-Y$layout",
- getResourceValue(layout, 11)
- )
- .putFloat(
- "${Settings.PREF_BUTTON_DPAD}-X$layout",
- getResourceValue(layout, 12)
- )
- .putFloat(
- "${Settings.PREF_BUTTON_DPAD}-Y$layout",
- getResourceValue(layout, 13)
- )
- .putFloat(
- "${Settings.PREF_BUTTON_L}-X$layout",
- getResourceValue(layout, 14)
- )
- .putFloat(
- "${Settings.PREF_BUTTON_L}-Y$layout",
- getResourceValue(layout, 15)
- )
- .putFloat(
- "${Settings.PREF_BUTTON_R}-X$layout",
- getResourceValue(layout, 16)
- )
- .putFloat(
- "${Settings.PREF_BUTTON_R}-Y$layout",
- getResourceValue(layout, 17)
- )
- .putFloat(
- "${Settings.PREF_BUTTON_PLUS}-X$layout",
- getResourceValue(layout, 18)
- )
- .putFloat(
- "${Settings.PREF_BUTTON_PLUS}-Y$layout",
- getResourceValue(layout, 19)
- )
- .putFloat(
- "${Settings.PREF_BUTTON_MINUS}-X$layout",
- getResourceValue(layout, 20)
- )
- .putFloat(
- "${Settings.PREF_BUTTON_MINUS}-Y$layout",
- getResourceValue(layout, 21)
- )
- .putFloat(
- "${Settings.PREF_BUTTON_HOME}-X$layout",
- getResourceValue(layout, 22)
- )
- .putFloat(
- "${Settings.PREF_BUTTON_HOME}-Y$layout",
- getResourceValue(layout, 23)
- )
- .putFloat(
- "${Settings.PREF_BUTTON_SCREENSHOT}-X$layout",
- getResourceValue(layout, 24)
- )
- .putFloat(
- "${Settings.PREF_BUTTON_SCREENSHOT}-Y$layout",
- getResourceValue(layout, 25)
- )
- .putFloat(
- "${Settings.PREF_STICK_R}-X$layout",
- getResourceValue(layout, 26)
- )
- .putFloat(
- "${Settings.PREF_STICK_R}-Y$layout",
- getResourceValue(layout, 27)
- )
- .putFloat(
- "${Settings.PREF_STICK_L}-X$layout",
- getResourceValue(layout, 28)
- )
- .putFloat(
- "${Settings.PREF_STICK_L}-Y$layout",
- getResourceValue(layout, 29)
- )
- .putFloat(
- "${Settings.PREF_BUTTON_STICK_L}-X$layout",
- getResourceValue(layout, 30)
- )
- .putFloat(
- "${Settings.PREF_BUTTON_STICK_L}-Y$layout",
- getResourceValue(layout, 31)
- )
- .putFloat(
- "${Settings.PREF_BUTTON_STICK_R}-X$layout",
- getResourceValue(layout, 32)
- )
- .putFloat(
- "${Settings.PREF_BUTTON_STICK_R}-Y$layout",
- getResourceValue(layout, 33)
- )
- .apply()
+ NativeConfig.setOverlayControlData(overlayControlData)
}
override fun isInEditMode(): Boolean {
@@ -913,18 +705,6 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
FOLDABLE_OVERLAY_VERSION
)
- private val preferences: SharedPreferences =
- PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
-
- const val LANDSCAPE = "_Landscape"
- const val PORTRAIT = "_Portrait"
- const val FOLDABLE = "_Foldable"
- val overlayLayouts = listOf(
- LANDSCAPE,
- PORTRAIT,
- FOLDABLE
- )
-
/**
* Resizes a [Bitmap] by a given scale factor
*
@@ -1036,29 +816,19 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
* In the input overlay configuration menu,
* once a touch event begins and then ends (ie. Organizing the buttons to one's own liking for the overlay).
* the X and Y coordinates of the button at the END of its touch event
- * (when you remove your finger/stylus from the touchscreen) are then stored
- * within a SharedPreferences instance so that those values can be retrieved here.
- *
- *
- * This has a few benefits over the conventional way of storing the values
- * (ie. within the yuzu ini file).
- *
- * * No native calls
- * * Keeps Android-only values inside the Android environment
- *
- *
+ * (when you remove your finger/stylus from the touchscreen) are then stored in a native .
*
* Technically no modifications should need to be performed on the returned
* InputOverlayDrawableButton. Simply add it to the HashSet of overlay items and wait
* for Android to call the onDraw method.
*
- * @param context The current [Context].
- * @param windowSize The size of the window to draw the overlay on.
- * @param defaultResId The resource ID of the [Drawable] to get the [Bitmap] of (Default State).
- * @param pressedResId The resource ID of the [Drawable] to get the [Bitmap] of (Pressed State).
- * @param buttonId Identifier for determining what type of button the initialized InputOverlayDrawableButton represents.
- * @param prefId Identifier for determining where a button appears on screen.
- * @param layout The current screen layout as determined by [LANDSCAPE], [PORTRAIT], or [FOLDABLE].
+ * @param context The current [Context].
+ * @param windowSize The size of the window to draw the overlay on.
+ * @param defaultResId The resource ID of the [Drawable] to get the [Bitmap] of (Default State).
+ * @param pressedResId The resource ID of the [Drawable] to get the [Bitmap] of (Pressed State).
+ * @param buttonId Identifier for determining what type of button the initialized InputOverlayDrawableButton represents.
+ * @param overlayControlData Identifier for determining where a button appears on screen.
+ * @param position The position on screen as represented by an x and y value between 0 and 1.
* @return An [InputOverlayDrawableButton] with the correct drawing bounds set.
*/
private fun initializeOverlayButton(
@@ -1067,33 +837,30 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
defaultResId: Int,
pressedResId: Int,
buttonId: Int,
- prefId: String,
- layout: String
+ overlayControlData: OverlayControlData,
+ position: Pair<Double, Double>
): InputOverlayDrawableButton {
// Resources handle for fetching the initial Drawable resource.
val res = context.resources
- // SharedPreference to retrieve the X and Y coordinates for the InputOverlayDrawableButton.
- val sPrefs = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
-
// Decide scale based on button preference ID and user preference
- var scale: Float = when (prefId) {
- Settings.PREF_BUTTON_HOME,
- Settings.PREF_BUTTON_SCREENSHOT,
- Settings.PREF_BUTTON_PLUS,
- Settings.PREF_BUTTON_MINUS -> 0.07f
+ var scale: Float = when (overlayControlData.id) {
+ OverlayControl.BUTTON_HOME.id,
+ OverlayControl.BUTTON_CAPTURE.id,
+ OverlayControl.BUTTON_PLUS.id,
+ OverlayControl.BUTTON_MINUS.id -> 0.07f
- Settings.PREF_BUTTON_L,
- Settings.PREF_BUTTON_R,
- Settings.PREF_BUTTON_ZL,
- Settings.PREF_BUTTON_ZR -> 0.26f
+ OverlayControl.BUTTON_L.id,
+ OverlayControl.BUTTON_R.id,
+ OverlayControl.BUTTON_ZL.id,
+ OverlayControl.BUTTON_ZR.id -> 0.26f
- Settings.PREF_BUTTON_STICK_L,
- Settings.PREF_BUTTON_STICK_R -> 0.155f
+ OverlayControl.BUTTON_STICK_L.id,
+ OverlayControl.BUTTON_STICK_R.id -> 0.155f
else -> 0.11f
}
- scale *= (sPrefs.getInt(Settings.PREF_CONTROL_SCALE, 50) + 50).toFloat()
+ scale *= (IntSetting.OVERLAY_SCALE.getInt() + 50).toFloat()
scale /= 100f
// Initialize the InputOverlayDrawableButton.
@@ -1104,7 +871,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
defaultStateBitmap,
pressedStateBitmap,
buttonId,
- prefId
+ overlayControlData
)
// Get the minimum and maximum coordinates of the screen where the button can be placed.
@@ -1113,12 +880,8 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
// The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay.
// These were set in the input overlay configuration menu.
- val xKey = "$prefId-X$layout"
- val yKey = "$prefId-Y$layout"
- val drawableXPercent = sPrefs.getFloat(xKey, 0f)
- val drawableYPercent = sPrefs.getFloat(yKey, 0f)
- val drawableX = (drawableXPercent * max.x + min.x).toInt()
- val drawableY = (drawableYPercent * max.y + min.y).toInt()
+ val drawableX = (position.first * max.x + min.x).toInt()
+ val drawableY = (position.second * max.y + min.y).toInt()
val width = overlayDrawable.width
val height = overlayDrawable.height
@@ -1136,8 +899,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
drawableX - (width / 2),
drawableY - (height / 2)
)
- val savedOpacity = preferences.getInt(Settings.PREF_CONTROL_OPACITY, 100)
- overlayDrawable.setOpacity(savedOpacity * 255 / 100)
+ overlayDrawable.setOpacity(IntSetting.OVERLAY_OPACITY.getInt() * 255 / 100)
return overlayDrawable
}
@@ -1149,7 +911,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
* @param defaultResId The [Bitmap] resource ID of the default state.
* @param pressedOneDirectionResId The [Bitmap] resource ID of the pressed state in one direction.
* @param pressedTwoDirectionsResId The [Bitmap] resource ID of the pressed state in two directions.
- * @param layout The current screen layout as determined by [LANDSCAPE], [PORTRAIT], or [FOLDABLE].
+ * @param position The position on screen as represented by an x and y value between 0 and 1.
* @return The initialized [InputOverlayDrawableDpad]
*/
private fun initializeOverlayDpad(
@@ -1158,17 +920,14 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
defaultResId: Int,
pressedOneDirectionResId: Int,
pressedTwoDirectionsResId: Int,
- layout: String
+ position: Pair<Double, Double>
): InputOverlayDrawableDpad {
// Resources handle for fetching the initial Drawable resource.
val res = context.resources
- // SharedPreference to retrieve the X and Y coordinates for the InputOverlayDrawableDpad.
- val sPrefs = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
-
// Decide scale based on button ID and user preference
var scale = 0.25f
- scale *= (sPrefs.getInt(Settings.PREF_CONTROL_SCALE, 50) + 50).toFloat()
+ scale *= (IntSetting.OVERLAY_SCALE.getInt() + 50).toFloat()
scale /= 100f
// Initialize the InputOverlayDrawableDpad.
@@ -1195,10 +954,8 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
// The X and Y coordinates of the InputOverlayDrawableDpad on the InputOverlay.
// These were set in the input overlay configuration menu.
- val drawableXPercent = sPrefs.getFloat("${Settings.PREF_BUTTON_DPAD}-X$layout", 0f)
- val drawableYPercent = sPrefs.getFloat("${Settings.PREF_BUTTON_DPAD}-Y$layout", 0f)
- val drawableX = (drawableXPercent * max.x + min.x).toInt()
- val drawableY = (drawableYPercent * max.y + min.y).toInt()
+ val drawableX = (position.first * max.x + min.x).toInt()
+ val drawableY = (position.second * max.y + min.y).toInt()
val width = overlayDrawable.width
val height = overlayDrawable.height
@@ -1213,8 +970,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
// Need to set the image's position
overlayDrawable.setPosition(drawableX - (width / 2), drawableY - (height / 2))
- val savedOpacity = preferences.getInt(Settings.PREF_CONTROL_OPACITY, 100)
- overlayDrawable.setOpacity(savedOpacity * 255 / 100)
+ overlayDrawable.setOpacity(IntSetting.OVERLAY_OPACITY.getInt() * 255 / 100)
return overlayDrawable
}
@@ -1227,9 +983,9 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
* @param defaultResInner Resource ID for the default inner image of the joystick (the one you actually move around).
* @param pressedResInner Resource ID for the pressed inner image of the joystick.
* @param joystick Identifier for which joystick this is.
- * @param button Identifier for which joystick button this is.
- * @param prefId Identifier for determining where a button appears on screen.
- * @param layout The current screen layout as determined by [LANDSCAPE], [PORTRAIT], or [FOLDABLE].
+ * @param buttonId Identifier for which joystick button this is.
+ * @param overlayControlData Identifier for determining where a button appears on screen.
+ * @param position The position on screen as represented by an x and y value between 0 and 1.
* @return The initialized [InputOverlayDrawableJoystick].
*/
private fun initializeOverlayJoystick(
@@ -1239,19 +995,16 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
defaultResInner: Int,
pressedResInner: Int,
joystick: Int,
- button: Int,
- prefId: String,
- layout: String
+ buttonId: Int,
+ overlayControlData: OverlayControlData,
+ position: Pair<Double, Double>
): InputOverlayDrawableJoystick {
// Resources handle for fetching the initial Drawable resource.
val res = context.resources
- // SharedPreference to retrieve the X and Y coordinates for the InputOverlayDrawableJoystick.
- val sPrefs = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
-
// Decide scale based on user preference
var scale = 0.3f
- scale *= (sPrefs.getInt(Settings.PREF_CONTROL_SCALE, 50) + 50).toFloat()
+ scale *= (IntSetting.OVERLAY_SCALE.getInt() + 50).toFloat()
scale /= 100f
// Initialize the InputOverlayDrawableJoystick.
@@ -1265,10 +1018,8 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
// The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay.
// These were set in the input overlay configuration menu.
- val drawableXPercent = sPrefs.getFloat("$prefId-X$layout", 0f)
- val drawableYPercent = sPrefs.getFloat("$prefId-Y$layout", 0f)
- val drawableX = (drawableXPercent * max.x + min.x).toInt()
- val drawableY = (drawableYPercent * max.y + min.y).toInt()
+ val drawableX = (position.first * max.x + min.x).toInt()
+ val drawableY = (position.second * max.y + min.y).toInt()
val outerScale = 1.66f
// Now set the bounds for the InputOverlayDrawableJoystick.
@@ -1292,14 +1043,13 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
outerRect,
innerRect,
joystick,
- button,
- prefId
+ buttonId,
+ overlayControlData.id
)
// Need to set the image's position
overlayDrawable.setPosition(drawableX, drawableY)
- val savedOpacity = preferences.getInt(Settings.PREF_CONTROL_OPACITY, 100)
- overlayDrawable.setOpacity(savedOpacity * 255 / 100)
+ overlayDrawable.setOpacity(IntSetting.OVERLAY_OPACITY.getInt() * 255 / 100)
return overlayDrawable
}
}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableButton.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableButton.kt
index 2c28dda88..b14a4f96e 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableButton.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableButton.kt
@@ -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
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableJoystick.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableJoystick.kt
index 518b1e783..113bf7c24 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableJoystick.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableJoystick.kt
@@ -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()
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayControl.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayControl.kt
new file mode 100644
index 000000000..a0eeadf4b
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayControl.kt
@@ -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]
+ }
+}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayControlData.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayControlData.kt
new file mode 100644
index 000000000..26cfeb1db
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayControlData.kt
@@ -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
+ }
+}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayControlDefault.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayControlDefault.kt
new file mode 100644
index 000000000..6bd74c82f
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayControlDefault.kt
@@ -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>
+)
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayLayout.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayLayout.kt
new file mode 100644
index 000000000..d728164e5
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayLayout.kt
@@ -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")
+}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt
index d4a9da06f..de0794a17 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt
@@ -10,6 +10,9 @@ 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 {
@@ -64,8 +67,147 @@ object DirectoryInitialization {
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 -> ""
+ }
}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/EmulationMenuSettings.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/EmulationMenuSettings.kt
deleted file mode 100644
index 7e8f058c1..000000000
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/EmulationMenuSettings.kt
+++ /dev/null
@@ -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()
- }
-}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NativeConfig.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NativeConfig.kt
index 7512d5eed..a4c14b3a7 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NativeConfig.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NativeConfig.kt
@@ -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>)
}
diff --git a/src/android/app/src/main/jni/android_common/android_common.cpp b/src/android/app/src/main/jni/android_common/android_common.cpp
index 52d8ecfeb..1e884ffdd 100644
--- a/src/android/app/src/main/jni/android_common/android_common.cpp
+++ b/src/android/app/src/main/jni/android_common/android_common.cpp
@@ -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);
+}
diff --git a/src/android/app/src/main/jni/android_common/android_common.h b/src/android/app/src/main/jni/android_common/android_common.h
index ccb0c06f7..8eb803e1b 100644
--- a/src/android/app/src/main/jni/android_common/android_common.h
+++ b/src/android/app/src/main/jni/android_common/android_common.h
@@ -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);
diff --git a/src/android/app/src/main/jni/android_config.cpp b/src/android/app/src/main/jni/android_config.cpp
index fb17ab6f6..c86aa1c39 100644
--- a/src/android/app/src/main/jni/android_config.cpp
+++ b/src/android/app/src/main/jni/android_config.cpp
@@ -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();
@@ -131,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)) {
diff --git a/src/android/app/src/main/jni/android_config.h b/src/android/app/src/main/jni/android_config.h
index 2c12874e1..d83852de9 100644
--- a/src/android/app/src/main/jni/android_config.h
+++ b/src/android/app/src/main/jni/android_config.h
@@ -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;
diff --git a/src/android/app/src/main/jni/android_settings.h b/src/android/app/src/main/jni/android_settings.h
index 1e4906b9a..559ae83eb 100644
--- a/src/android/app/src/main/jni/android_settings.h
+++ b/src/android/app/src/main/jni/android_settings.h
@@ -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;
@@ -38,6 +46,23 @@ struct Values {
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;
diff --git a/src/android/app/src/main/jni/id_cache.cpp b/src/android/app/src/main/jni/id_cache.cpp
index e7a86d3fd..c79ad7d76 100644
--- a/src/android/app/src/main/jni/id_cache.cpp
+++ b/src/android/app/src/main/jni/id_cache.cpp
@@ -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);
diff --git a/src/android/app/src/main/jni/id_cache.h b/src/android/app/src/main/jni/id_cache.h
index 24030be42..784d1412f 100644
--- a/src/android/app/src/main/jni/id_cache.h
+++ b/src/android/app/src/main/jni/id_cache.h
@@ -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
diff --git a/src/android/app/src/main/jni/native_config.cpp b/src/android/app/src/main/jni/native_config.cpp
index 324d9e9cd..535902483 100644
--- a/src/android/app/src/main/jni/native_config.cpp
+++ b/src/android/app/src/main/jni/native_config.cpp
@@ -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"
diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml
index c882a8e62..45d57c3ea 100644
--- a/src/android/app/src/main/res/values/arrays.xml
+++ b/src/android/app/src/main/res/values/arrays.xml
@@ -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">
diff --git a/src/android/app/src/main/res/values/integers.xml b/src/android/app/src/main/res/values/integers.xml
index dc527965c..1c6f5db93 100644
--- a/src/android/app/src/main/res/values/integers.xml
+++ b/src/android/app/src/main/res/values/integers.xml
@@ -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>