mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2026-05-09 12:24:04 -05:00
Enables, GBA on android. links to games, can be played on its own.
This commit is contained in:
parent
c0e0b685f3
commit
34af99ad26
|
|
@ -13,11 +13,13 @@ import androidx.core.content.ContextCompat
|
|||
import androidx.core.util.Pair
|
||||
import org.dolphinemu.dolphinemu.activities.EmulationActivity
|
||||
import org.dolphinemu.dolphinemu.dialogs.AlertMessage
|
||||
import org.dolphinemu.dolphinemu.features.gba.GbaRenderManager
|
||||
import org.dolphinemu.dolphinemu.utils.CompressCallback
|
||||
import org.dolphinemu.dolphinemu.utils.Log
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.concurrent.Semaphore
|
||||
|
||||
|
||||
/**
|
||||
* Class which contains methods that interact
|
||||
* with the native side of the Dolphin code.
|
||||
|
|
@ -366,11 +368,11 @@ object NativeLibrary {
|
|||
@JvmStatic
|
||||
external fun StopEmulation()
|
||||
|
||||
/**
|
||||
* Ensures that IsRunning will return true from now on until emulation exits.
|
||||
* (If this is not called, IsRunning will start returning true at some point
|
||||
* after calling Run.)
|
||||
*/
|
||||
/**
|
||||
* Ensures that IsRunning will return true from now on until emulation exits.
|
||||
* (If this is not called, IsRunning will start returning true at some point
|
||||
* after calling Run.)
|
||||
*/
|
||||
@JvmStatic
|
||||
external fun SetIsBooting()
|
||||
|
||||
|
|
@ -450,6 +452,25 @@ object NativeLibrary {
|
|||
@JvmStatic
|
||||
external fun GetGameAspectRatio(): Float
|
||||
|
||||
@JvmStatic
|
||||
external fun copyGBAFramebuffer(slot: Int, buffer: java.nio.ByteBuffer):
|
||||
Boolean
|
||||
|
||||
@JvmStatic
|
||||
external fun resetGBACore(slot: Int)
|
||||
|
||||
@JvmStatic
|
||||
external fun getGBAGameTitle(slot: Int): String
|
||||
|
||||
@JvmStatic
|
||||
external fun getGBAGameCode(slot: Int): String
|
||||
|
||||
@Keep
|
||||
@JvmStatic
|
||||
fun onGBAFrame(slot: Int) {
|
||||
GbaRenderManager.onFrame(slot)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun IsEmulatingWii(): Boolean {
|
||||
checkGameMetadataValid()
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
package org.dolphinemu.dolphinemu.activities
|
||||
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.graphics.Rect
|
||||
|
|
@ -14,13 +15,17 @@ import android.util.SparseIntArray
|
|||
import android.view.KeyEvent
|
||||
import android.view.MenuItem
|
||||
import android.view.MotionEvent
|
||||
import android.view.ScaleGestureDetector
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewGroup.MarginLayoutParams
|
||||
import android.view.WindowManager
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.core.view.doOnLayout
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
|
|
@ -36,12 +41,15 @@ import org.dolphinemu.dolphinemu.R
|
|||
import org.dolphinemu.dolphinemu.databinding.ActivityEmulationBinding
|
||||
import org.dolphinemu.dolphinemu.databinding.DialogInputAdjustBinding
|
||||
import org.dolphinemu.dolphinemu.databinding.DialogNfcFiguresManagerBinding
|
||||
import org.dolphinemu.dolphinemu.features.gba.GBAOverlayView
|
||||
import org.dolphinemu.dolphinemu.features.gba.GbaRenderManager
|
||||
import org.dolphinemu.dolphinemu.features.infinitybase.InfinityConfig
|
||||
import org.dolphinemu.dolphinemu.features.infinitybase.model.Figure
|
||||
import org.dolphinemu.dolphinemu.features.infinitybase.ui.FigureSlot
|
||||
import org.dolphinemu.dolphinemu.features.infinitybase.ui.FigureSlotAdapter
|
||||
import org.dolphinemu.dolphinemu.features.input.model.ControllerInterface
|
||||
import org.dolphinemu.dolphinemu.features.input.model.DolphinSensorEventListener
|
||||
import org.dolphinemu.dolphinemu.features.input.model.InputOverrider
|
||||
import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting
|
||||
import org.dolphinemu.dolphinemu.features.settings.model.IntSetting
|
||||
import org.dolphinemu.dolphinemu.features.settings.model.Settings
|
||||
|
|
@ -72,6 +80,12 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider {
|
|||
|
||||
private lateinit var settings: Settings
|
||||
|
||||
private val gbaViews = mutableListOf<GBAOverlayView>()
|
||||
|
||||
private val lastGbaTapTimes = mutableMapOf<Int, Long>()
|
||||
|
||||
private var isGbaLocked = false
|
||||
|
||||
override var themeId = 0
|
||||
|
||||
private var menuVisible = false
|
||||
|
|
@ -186,6 +200,12 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider {
|
|||
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
//gba overlay setup, also clean up views from previous launch to prevent stacking
|
||||
GbaRenderManager.detach()
|
||||
gbaViews.forEach { binding.root.removeView(it) }
|
||||
gbaViews.clear()
|
||||
lastGbaTapTimes.clear()
|
||||
|
||||
MainPresenter.skipRescanningLibrary()
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
|
|
@ -211,6 +231,38 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider {
|
|||
binding = ActivityEmulationBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
//Read snap state before creating new views
|
||||
val globalGbaPrefs = getSharedPreferences("gba_overlay", Context.MODE_PRIVATE)
|
||||
isGbaLocked = globalGbaPrefs.getBoolean("gba_locked", false)
|
||||
|
||||
for (slot in 0 until 4) {
|
||||
if (IntSetting.getSettingForSIDevice(slot).int != 13) continue
|
||||
val view = GBAOverlayView(this)
|
||||
view.gbaSlot = slot
|
||||
val slotPrefs = getSharedPreferences("gba_overlay_${'$'}slot", Context.MODE_PRIVATE)
|
||||
val sw = slotPrefs.getFloat("gba_width", 480f).coerceIn(120f, 960f)
|
||||
val sh = slotPrefs.getFloat("gba_height", 320f).coerceIn(80f, 640f)
|
||||
val screenW = resources.displayMetrics.widthPixels.toFloat()
|
||||
val screenH = resources.displayMetrics.heightPixels.toFloat()
|
||||
var sx = slotPrefs.getFloat("gba_x", 16f + slot * 20f)
|
||||
var sy = slotPrefs.getFloat("gba_y", screenH - sh - 16f - slot * 20f)
|
||||
if (sx < 0 || sx > screenW) sx = 16f + slot * 20f
|
||||
if (sy < 0 || sy > screenH) sy = screenH - sh - 16f
|
||||
val params = FrameLayout.LayoutParams(sw.toInt(), sh.toInt())
|
||||
binding.root.addView(view, 0, params)
|
||||
view.x = sx;
|
||||
view.y = sy
|
||||
view.visibility = android.view.View.VISIBLE
|
||||
InputOverrider.registerGBA(slot)
|
||||
attachGbaTouchListener(view, slot, slotPrefs)
|
||||
gbaViews.add(view)
|
||||
}
|
||||
|
||||
if (gbaViews.isNotEmpty() && NativeLibrary.IsGameMetadataValid()) {
|
||||
GbaRenderManager.attach(gbaViews)
|
||||
binding.root.doOnLayout { applyGbaLayout() }
|
||||
}
|
||||
|
||||
setInsets()
|
||||
|
||||
// Find or create the EmulationFragment
|
||||
|
|
@ -332,6 +384,25 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider {
|
|||
emulationFragment?.refreshInputOverlay()
|
||||
|
||||
updateDisplaySettings()
|
||||
|
||||
val activeSlots = (0 until 4).filter {
|
||||
IntSetting.getSettingForSIDevice(it).int == 13
|
||||
}
|
||||
gbaViews.forEachIndexed { index, view ->
|
||||
if (index < activeSlots.size) {
|
||||
view.gbaSlot = activeSlots[index]
|
||||
view.visibility = android.view.View.VISIBLE
|
||||
InputOverrider.registerGBA(activeSlots[index])
|
||||
} else view.visibility = android.view.View.GONE
|
||||
}
|
||||
if (gbaViews.isNotEmpty()) {
|
||||
if (GbaRenderManager.isAttached()) {
|
||||
GbaRenderManager.updateViews(gbaViews)
|
||||
} else {
|
||||
GbaRenderManager.attach(gbaViews)
|
||||
}
|
||||
binding.root.post { applyGbaLayout() }
|
||||
}
|
||||
} catch (_: IllegalStateException) {
|
||||
// Most likely the core delivered an onTitleChanged while emulation was shutting down.
|
||||
// Let's just ignore it, since we're about to shut down anyway.
|
||||
|
|
@ -340,9 +411,41 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider {
|
|||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
GbaRenderManager.detach()
|
||||
for (slot in 0 until 4) {
|
||||
InputOverrider.unregisterGBA(slot)
|
||||
}
|
||||
gbaViews.forEach { binding.root.removeView(it) }
|
||||
gbaViews.clear()
|
||||
settings.close()
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfig: android.content.res.Configuration) {
|
||||
super.onConfigurationChanged(newConfig)
|
||||
if (gbaViews.isNotEmpty()) {
|
||||
GbaRenderManager.updateViews(gbaViews)
|
||||
binding.root.post { applyGbaLayout() }
|
||||
|
||||
} else {
|
||||
//no gba - restore game to full screen to try stop portrait squish into landscape
|
||||
binding.frameEmulationFragment.x = 0f
|
||||
binding.frameEmulationFragment.layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
binding.frameEmulationFragment.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
binding.frameEmulationFragment.requestLayout()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setGbaViewsTouchable(touchable: Boolean) {
|
||||
gbaViews.forEach { view ->
|
||||
view.isClickable = touchable
|
||||
view.isFocusable = touchable
|
||||
view.isFocusableInTouchMode = touchable
|
||||
if (!touchable) {
|
||||
view.setOnTouchListener(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
if (!closeSubmenu()) {
|
||||
toggleMenu()
|
||||
|
|
@ -361,7 +464,8 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider {
|
|||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
WindowInsetsControllerCompat(window, window.decorView).let { controller ->
|
||||
controller.hide(WindowInsetsCompat.Type.systemBars())
|
||||
controller.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||
controller.systemBarsBehavior =
|
||||
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -443,6 +547,7 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider {
|
|||
menu.findItem(R.id.menu_emulation_ir_recenter).isChecked =
|
||||
BooleanSetting.MAIN_IR_ALWAYS_RECENTER.boolean
|
||||
}
|
||||
menu.findItem(R.id.menu_emulation_gba_snap)?.isChecked = isGbaLocked
|
||||
popup.setOnMenuItemClickListener { item: MenuItem -> onOptionsItemSelected(item) }
|
||||
popup.show()
|
||||
}
|
||||
|
|
@ -471,6 +576,11 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider {
|
|||
item.isChecked = !item.isChecked
|
||||
toggleRecenter(item.isChecked)
|
||||
}
|
||||
|
||||
MENU_ACTION_GBA_SNAP -> {
|
||||
item.isChecked = !item.isChecked
|
||||
toggleGBASnap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -518,6 +628,13 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider {
|
|||
MENU_ACTION_SKYLANDERS -> showSkylanderPortalSettings()
|
||||
MENU_ACTION_INFINITY_BASE -> showInfinityBaseSettings()
|
||||
MENU_ACTION_EXIT -> emulationFragment!!.stopEmulation()
|
||||
MENU_ACTION_GBA_SNAP -> toggleGBASnap()
|
||||
MENU_ACTION_GBA_RESET -> {
|
||||
isGbaLocked = false; resetGBAScreens();
|
||||
binding.root.post { applyGbaLayout() }
|
||||
}
|
||||
|
||||
MENU_ACTION_GBA_RESET_CORE -> resetGBACore()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -533,9 +650,21 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider {
|
|||
private fun editControlsPlacement() {
|
||||
if (emulationFragment!!.isConfiguringControls) {
|
||||
emulationFragment?.stopConfiguringControls()
|
||||
setGbaViewsTouchable(true)
|
||||
if (!isGbaLocked) {
|
||||
gbaViews.forEachIndexed { _, view ->
|
||||
val slot = view.gbaSlot
|
||||
val slotPrefs = getSharedPreferences(
|
||||
"gba_overlay_${'$'}slot",
|
||||
Context.MODE_PRIVATE
|
||||
)
|
||||
attachGbaTouchListener(view, slot, slotPrefs)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
closeSubmenu()
|
||||
closeMenu()
|
||||
setGbaViewsTouchable(false)
|
||||
emulationFragment?.startConfiguringControls()
|
||||
}
|
||||
}
|
||||
|
|
@ -571,12 +700,14 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider {
|
|||
emulationFragment?.refreshInputOverlay()
|
||||
}
|
||||
}
|
||||
|
||||
InputOverlay.OVERLAY_WIIMOTE_CLASSIC -> {
|
||||
val wiiClassicLatchingButtons = BooleanArray(11)
|
||||
val classicSettingBase = "MAIN_BUTTON_LATCHING_CLASSIC_"
|
||||
|
||||
for (i in wiiClassicLatchingButtons.indices) {
|
||||
wiiClassicLatchingButtons[i] = BooleanSetting.valueOf(classicSettingBase + i).boolean
|
||||
wiiClassicLatchingButtons[i] =
|
||||
BooleanSetting.valueOf(classicSettingBase + i).boolean
|
||||
}
|
||||
builder.setMultiChoiceItems(
|
||||
R.array.classicLatchableButtons, wiiClassicLatchingButtons
|
||||
|
|
@ -586,6 +717,7 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider {
|
|||
emulationFragment?.refreshInputOverlay()
|
||||
}
|
||||
}
|
||||
|
||||
InputOverlay.OVERLAY_WIIMOTE_NUNCHUK -> {
|
||||
val nunchukLatchingButtons = BooleanArray(9)
|
||||
val nunchukSettingBase = "MAIN_BUTTON_LATCHING_WII_"
|
||||
|
|
@ -603,21 +735,27 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider {
|
|||
builder.setMultiChoiceItems(
|
||||
R.array.nunchukLatchableButtons, nunchukLatchingButtons
|
||||
) { _: DialogInterface?, indexSelected: Int, isChecked: Boolean ->
|
||||
BooleanSetting.valueOf(nunchukSettingBase + translateToSettingsIndex(indexSelected))
|
||||
BooleanSetting.valueOf(
|
||||
nunchukSettingBase + translateToSettingsIndex(
|
||||
indexSelected
|
||||
)
|
||||
)
|
||||
.setBoolean(settings, isChecked)
|
||||
emulationFragment?.refreshInputOverlay()
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
val wiimoteLatchingButtons = BooleanArray(7)
|
||||
val wiimoteSettingBase = "MAIN_BUTTON_LATCHING_WII_"
|
||||
|
||||
for (i in wiimoteLatchingButtons.indices) {
|
||||
wiimoteLatchingButtons[i] = BooleanSetting.valueOf(wiimoteSettingBase + i).boolean
|
||||
wiimoteLatchingButtons[i] =
|
||||
BooleanSetting.valueOf(wiimoteSettingBase + i).boolean
|
||||
}
|
||||
|
||||
builder.setMultiChoiceItems(
|
||||
R.array.wiimoteLatchableButtons, wiimoteLatchingButtons
|
||||
R.array.wiimoteLatchableButtons, wiimoteLatchingButtons
|
||||
) { _: DialogInterface?, indexSelected: Int, isChecked: Boolean ->
|
||||
BooleanSetting.valueOf(wiimoteSettingBase + indexSelected)
|
||||
.setBoolean(settings, isChecked)
|
||||
|
|
@ -932,7 +1070,9 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider {
|
|||
when (position) {
|
||||
0 -> infinityFigures[position].label = getString(R.string.infinity_hexagon_label)
|
||||
1 -> infinityFigures[position].label = getString(R.string.infinity_power_hex_two_label)
|
||||
2 -> infinityFigures[position].label = getString(R.string.infinity_power_hex_three_label)
|
||||
2 -> infinityFigures[position].label =
|
||||
getString(R.string.infinity_power_hex_three_label)
|
||||
|
||||
3 -> infinityFigures[position].label = getString(R.string.infinity_p1_label)
|
||||
4 -> infinityFigures[position].label = getString(R.string.infinity_p1a1_label)
|
||||
5 -> infinityFigures[position].label = getString(R.string.infinity_p1a2_label)
|
||||
|
|
@ -975,6 +1115,20 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider {
|
|||
if (anyMenuClosed)
|
||||
return true
|
||||
}
|
||||
// gbas were not dragable this fixes it, but once touched they appear over the menus
|
||||
if (!isGbaLocked && gbaViews.isNotEmpty()) {
|
||||
val loc = IntArray(2)
|
||||
for (gbaView in gbaViews) {
|
||||
gbaView.getLocationOnScreen(loc)
|
||||
val bounds = android.graphics.Rect(
|
||||
loc[0], loc[1],
|
||||
loc[0] + gbaView.width, loc[1] + gbaView.height
|
||||
)
|
||||
if (bounds.contains(event.rawX.toInt(), event.rawY.toInt())) {
|
||||
return gbaView.dispatchTouchEvent(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.dispatchTouchEvent(event)
|
||||
}
|
||||
|
||||
|
|
@ -1016,6 +1170,249 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider {
|
|||
this.themeId = themeId
|
||||
}
|
||||
|
||||
//gba touch for scale/drag listener while in unlocked gba mode.
|
||||
private fun attachGbaTouchListener(
|
||||
view: GBAOverlayView,
|
||||
slot: Int,
|
||||
slotPrefs: android.content.SharedPreferences
|
||||
) {
|
||||
var dragX = 0f
|
||||
var dragY = 0f
|
||||
|
||||
// Initial dimensions for scaling math
|
||||
val params = view.layoutParams as FrameLayout.LayoutParams
|
||||
var cw = params.width.toFloat()
|
||||
var ch = params.height.toFloat()
|
||||
|
||||
val scaleDetector = ScaleGestureDetector(
|
||||
this,
|
||||
object : ScaleGestureDetector.SimpleOnScaleGestureListener() {
|
||||
override fun onScale(d: ScaleGestureDetector): Boolean {
|
||||
if (isGbaLocked) return true
|
||||
val sf = d.scaleFactor
|
||||
val ow = cw
|
||||
val oh = ch
|
||||
|
||||
// Scale width and maintain 3:2 aspect ratio
|
||||
cw = (cw * sf).coerceIn(120f, 960f)
|
||||
ch = cw * (2f / 3f)
|
||||
|
||||
// Center the scaling transformation
|
||||
view.x += (ow - cw) / 2f
|
||||
view.y += (oh - ch) / 2f
|
||||
|
||||
val p = view.layoutParams as FrameLayout.LayoutParams
|
||||
p.width = cw.toInt()
|
||||
p.height = ch.toInt()
|
||||
view.layoutParams = p
|
||||
|
||||
slotPrefs.edit()
|
||||
.putFloat("gba_width", cw)
|
||||
.putFloat("gba_height", ch)
|
||||
.putFloat("gba_x", view.x)
|
||||
.putFloat("gba_y", view.y)
|
||||
.apply()
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
view.setOnTouchListener { v, event ->
|
||||
// Prevent interaction if Snap Mode (Locked) is active
|
||||
if (isGbaLocked) return@setOnTouchListener false
|
||||
|
||||
// Let the scale detector handle pinch gestures first
|
||||
scaleDetector.onTouchEvent(event)
|
||||
|
||||
// If the user is currently pinching/scaling, stop the dragging logic
|
||||
if (scaleDetector.isInProgress) return@setOnTouchListener true
|
||||
|
||||
when (event.actionMasked) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
// Store the offset so the window doesn't "jump" to the finger center
|
||||
dragX = event.rawX - v.x
|
||||
dragY = event.rawY - v.y
|
||||
|
||||
// Bring the window to the top layer
|
||||
v.bringToFront()
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
// Update the view's position as the finger moves
|
||||
v.x = event.rawX - dragX
|
||||
v.y = event.rawY - dragY
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_UP -> {
|
||||
// Double tap detection for visibility toggle
|
||||
val now = System.currentTimeMillis()
|
||||
val last = lastGbaTapTimes[slot] ?: 0L
|
||||
if (now - last < 300) {
|
||||
view.onDoubleTap()
|
||||
}
|
||||
lastGbaTapTimes[slot] = now
|
||||
|
||||
slotPrefs.edit()
|
||||
.putFloat("gba_x", v.x)
|
||||
.putFloat("gba_y", v.y)
|
||||
.apply()
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
//Android Gba layout
|
||||
private fun applyGbaLayout() {
|
||||
if (gbaViews.isEmpty())
|
||||
return
|
||||
val tw = binding.root.width
|
||||
val th = binding.root.height
|
||||
val count = gbaViews.size
|
||||
val isLandscape =
|
||||
resources.configuration.orientation == android.content.res.Configuration.ORIENTATION_LANDSCAPE
|
||||
|
||||
binding.frameEmulationFragment.x = 0f
|
||||
binding.frameEmulationFragment.layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
binding.frameEmulationFragment.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
binding.frameEmulationFragment.requestLayout()
|
||||
|
||||
if (isGbaLocked) {
|
||||
if (isLandscape) {
|
||||
val slotH = th / count
|
||||
val maxW = (tw * 0.45f).toInt()
|
||||
// Set point for landscape height
|
||||
val maxH = 300
|
||||
|
||||
gbaViews.forEachIndexed { i, v ->
|
||||
v.setOnTouchListener(null)
|
||||
val p = v.layoutParams as FrameLayout.LayoutParams
|
||||
|
||||
// Calculate height first, then width based on 3:2 ratio
|
||||
var targetH = slotH.coerceAtMost(maxH)
|
||||
var targetW = (targetH * 3f / 2f).toInt()
|
||||
|
||||
// If it's too wide for the sidebar, scale down based on width
|
||||
if (targetW > maxW) {
|
||||
targetW = maxW
|
||||
targetH = (targetW * 2f / 3f).toInt()
|
||||
}
|
||||
|
||||
p.width = targetW
|
||||
p.height = targetH
|
||||
v.layoutParams = p
|
||||
|
||||
// Re-snapping: Force X to 0 and calculate centered Y within the slot
|
||||
v.x = 0f
|
||||
v.y = (i * slotH).toFloat() + (slotH - targetH) / 2f
|
||||
v.visibility = android.view.View.VISIBLE
|
||||
}
|
||||
} else {
|
||||
// Portrait Logic
|
||||
val gih = (tw * 3f / 4f).toInt()
|
||||
val topBar = (th - gih) / 2
|
||||
val gbaY = topBar + gih
|
||||
val availH = th - gbaY
|
||||
// Set point for portrait height
|
||||
val maxH = 400
|
||||
|
||||
when (count) {
|
||||
1 -> {
|
||||
val targetH = (tw * 2f / 3f).toInt().coerceAtMost(availH).coerceAtMost(maxH)
|
||||
val targetW = (targetH * 3f / 2f).toInt()
|
||||
|
||||
with(gbaViews[0]) {
|
||||
setOnTouchListener(null)
|
||||
val p = layoutParams as FrameLayout.LayoutParams
|
||||
p.width = targetW; p.height = targetH; layoutParams = p
|
||||
x = (tw - targetW) / 2f
|
||||
y = gbaY.toFloat() + (availH - targetH) / 2f
|
||||
visibility = android.view.View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
// Multi-screen grid (2, 3, or 4)
|
||||
val cols = if (count <= 2) count else 2
|
||||
val rows = if (count <= 2) 1 else 2
|
||||
val slotW = tw / cols
|
||||
val slotH = availH / rows
|
||||
|
||||
val targetH =
|
||||
(slotW * 2f / 3f).toInt().coerceAtMost(slotH).coerceAtMost(maxH)
|
||||
val targetW = (targetH * 3f / 2f).toInt()
|
||||
|
||||
gbaViews.forEachIndexed { i, v ->
|
||||
v.setOnTouchListener(null)
|
||||
val p = v.layoutParams as FrameLayout.LayoutParams
|
||||
p.width = targetW; p.height = targetH; v.layoutParams = p
|
||||
|
||||
val col = i % cols
|
||||
val row = i / cols
|
||||
|
||||
v.x = (col * slotW).toFloat() + (slotW - targetW) / 2f
|
||||
v.y = gbaY.toFloat() + (row * slotH).toFloat() + (slotH - targetH) / 2f
|
||||
v.visibility = android.view.View.VISIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
gbaViews.forEachIndexed { i, view ->
|
||||
val slot = view.gbaSlot
|
||||
val sp2 = getSharedPreferences("gba_overlay_${slot}", Context.MODE_PRIVATE)
|
||||
val sw = sp2.getFloat("gba_width", 480f).coerceIn(120f, 960f)
|
||||
val sh = sp2.getFloat("gba_height", 320f).coerceIn(80f, 640f)
|
||||
val screenW = resources.displayMetrics.widthPixels.toFloat()
|
||||
val screenH = resources.displayMetrics.heightPixels.toFloat()
|
||||
var sx = sp2.getFloat("gba_x", 16f + i * 20f)
|
||||
var sy = sp2.getFloat("gba_y", screenH - sh - 16f - i * 20f)
|
||||
if (sx < 0 || sx > screenW) sx = 16f + i * 20f
|
||||
if (sy < 0 || sy > screenH) sy = screenH - sh - 16f
|
||||
val p = view.layoutParams as FrameLayout.LayoutParams
|
||||
p.width = sw.toInt(); p.height = sh.toInt(); view.layoutParams = p
|
||||
view.x = sx; view.y = sy
|
||||
attachGbaTouchListener(view, slot, sp2)
|
||||
}
|
||||
}
|
||||
getSharedPreferences("gba_overlay", Context.MODE_PRIVATE).edit()
|
||||
.putBoolean("gba_locked", isGbaLocked).apply()
|
||||
}
|
||||
|
||||
private fun toggleGBASnap() {
|
||||
isGbaLocked = !isGbaLocked
|
||||
if (!isGbaLocked) {
|
||||
NativeLibrary.SetObscuredPixelsLeft(0)
|
||||
}
|
||||
binding.root.post { applyGbaLayout() }
|
||||
|
||||
}
|
||||
|
||||
private fun resetGBAScreens() {
|
||||
if (gbaViews.isEmpty()) return
|
||||
runOnUiThread {
|
||||
val screenH = resources.displayMetrics.heightPixels.toFloat()
|
||||
gbaViews.forEachIndexed { i, view ->
|
||||
val slot = view.gbaSlot
|
||||
val dx = 16f + i * 20f
|
||||
val dy = screenH - 320f - 16f - i * 20f
|
||||
getSharedPreferences("gba_overlay_${slot}", Context.MODE_PRIVATE).edit()
|
||||
.putFloat("gba_x", dx).putFloat("gba_y", dy).putFloat("gba_width", 480f)
|
||||
.putFloat("gba_height", 320f).apply()
|
||||
val p = view.layoutParams as? FrameLayout.LayoutParams ?: return@forEachIndexed
|
||||
p.width = 480; p.height = 320; view.layoutParams = p
|
||||
view.x = dx; view.y = dy
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun resetGBACore() {
|
||||
for (slot in 0 until 4) {
|
||||
if (IntSetting.getSettingForSIDevice(slot).int == 13)
|
||||
NativeLibrary.resetGBACore(slot)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
private const val BACKSTACK_NAME_MENU = "menu"
|
||||
private const val BACKSTACK_NAME_SUBMENU = "submenu"
|
||||
|
|
@ -1077,6 +1474,9 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider {
|
|||
const val MENU_ACTION_SKYLANDERS = 36
|
||||
const val MENU_ACTION_INFINITY_BASE = 37
|
||||
const val MENU_ACTION_LATCHING_CONTROLS = 38
|
||||
const val MENU_ACTION_GBA_SNAP = 39
|
||||
const val MENU_ACTION_GBA_RESET = 40
|
||||
const val MENU_ACTION_GBA_RESET_CORE = 41
|
||||
|
||||
init {
|
||||
buttonsActionsMap.apply {
|
||||
|
|
@ -1090,19 +1490,38 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider {
|
|||
append(R.id.menu_emulation_ir_recenter, MENU_SET_IR_RECENTER)
|
||||
append(R.id.menu_emulation_set_ir_mode, MENU_SET_IR_MODE)
|
||||
append(R.id.menu_emulation_choose_doubletap, MENU_ACTION_CHOOSE_DOUBLETAP)
|
||||
append(R.id.menu_emulation_gba_snap, MENU_ACTION_GBA_SNAP)
|
||||
append(R.id.menu_emulation_gba_reset, MENU_ACTION_GBA_RESET)
|
||||
append(R.id.menu_emulation_gba_reset_core, MENU_ACTION_GBA_RESET_CORE)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun launch(activity: FragmentActivity, filePaths: Array<String>, riivolution: Boolean, fromIntent: Boolean = false) {
|
||||
fun launch(
|
||||
activity: FragmentActivity,
|
||||
filePaths: Array<String>,
|
||||
riivolution: Boolean,
|
||||
fromIntent: Boolean = false
|
||||
) {
|
||||
if (ignoreLaunchRequests)
|
||||
return
|
||||
|
||||
performLaunchChecks(activity, fromIntent) { launchWithoutChecks(activity, filePaths, riivolution) }
|
||||
performLaunchChecks(activity, fromIntent) {
|
||||
launchWithoutChecks(
|
||||
activity,
|
||||
filePaths,
|
||||
riivolution
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun launch(activity: FragmentActivity, filePath: String, riivolution: Boolean, fromIntent: Boolean = false) =
|
||||
fun launch(
|
||||
activity: FragmentActivity,
|
||||
filePath: String,
|
||||
riivolution: Boolean,
|
||||
fromIntent: Boolean = false
|
||||
) =
|
||||
launch(activity, arrayOf(filePath), riivolution, fromIntent)
|
||||
|
||||
private fun launchWithoutChecks(
|
||||
|
|
@ -1117,7 +1536,11 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider {
|
|||
activity.startActivity(launcher)
|
||||
}
|
||||
|
||||
private fun performLaunchChecks(activity: FragmentActivity, fromIntent: Boolean, continueCallback: Runnable) {
|
||||
private fun performLaunchChecks(
|
||||
activity: FragmentActivity,
|
||||
fromIntent: Boolean,
|
||||
continueCallback: Runnable
|
||||
) {
|
||||
AfterDirectoryInitializationRunner().runWithLifecycle(activity) {
|
||||
if (fromIntent) {
|
||||
activity.finish()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
package org.dolphinemu.dolphinemu.features.gba
|
||||
|
||||
import android.content.Context
|
||||
import android.view.SurfaceHolder
|
||||
import android.view.SurfaceView
|
||||
import android.graphics.*
|
||||
|
||||
//Passive surfaceview displaying one gba screen
|
||||
//Rendering is driven by GbaRenderManager
|
||||
|
||||
class GBAOverlayView(context: Context) : SurfaceView(context),
|
||||
SurfaceHolder.Callback {
|
||||
var renderManager: GbaRenderManager? = null
|
||||
var gbaSlot: Int = 0
|
||||
var isScreenVisible = true
|
||||
var needsBorderRedraw = false
|
||||
var surfaceReady = false
|
||||
|
||||
private val paint = Paint().apply { isFilterBitmap = true }
|
||||
private val destRect = Rect()
|
||||
private val borderPaint = Paint().apply {
|
||||
color = Color.argb(120, 255, 255, 255); style = Paint.Style.STROKE
|
||||
strokeWidth = 2f; isAntiAlias = true
|
||||
}
|
||||
private val borderFillPaint = Paint().apply {
|
||||
color = Color.argb(0, 0, 0, 0); style = Paint.Style.FILL
|
||||
}
|
||||
private val borderTextPaint = Paint().apply {
|
||||
color = Color.argb(120, 255, 255, 255); textSize = 20f
|
||||
isAntiAlias = true; typeface = Typeface.DEFAULT_BOLD
|
||||
textAlign = Paint.Align.CENTER
|
||||
}
|
||||
|
||||
init {
|
||||
holder.setFormat(PixelFormat.TRANSLUCENT)
|
||||
setZOrderMediaOverlay(true)
|
||||
holder.addCallback(this)
|
||||
}
|
||||
|
||||
fun drawFrame(bitmap: Bitmap) {
|
||||
if (!holder.surface.isValid) return
|
||||
if (!isScreenVisible) {
|
||||
if (needsBorderRedraw) {
|
||||
needsBorderRedraw = false
|
||||
val canvas = holder.lockCanvas() ?: return
|
||||
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
|
||||
val rect = RectF(2f, 2f, width - 2f, height - 2f)
|
||||
canvas.drawRoundRect(rect, 12f, 12f, borderFillPaint)
|
||||
canvas.drawRoundRect(rect, 12f, 12f, borderPaint)
|
||||
canvas.drawText("GBA", width / 2f, height / 2f + 8f, borderTextPaint)
|
||||
holder.unlockCanvasAndPost(canvas)
|
||||
}
|
||||
return
|
||||
}
|
||||
val canvas = holder.lockCanvas() ?: return
|
||||
destRect.set(0, 0, width, height)
|
||||
canvas.drawColor(Color.BLACK)
|
||||
canvas.drawBitmap(bitmap, null, destRect, paint)
|
||||
holder.unlockCanvasAndPost(canvas)
|
||||
}
|
||||
|
||||
fun onDoubleTap() {
|
||||
isScreenVisible = !isScreenVisible
|
||||
if (!isScreenVisible) needsBorderRedraw = true
|
||||
}
|
||||
|
||||
override fun surfaceCreated(h: SurfaceHolder) {
|
||||
surfaceReady = false
|
||||
}
|
||||
|
||||
override fun surfaceChanged(h: SurfaceHolder, f: Int, w: Int, h2: Int) {
|
||||
surfaceReady = true
|
||||
post { renderManager?.requestRedraw(gbaSlot) }
|
||||
}
|
||||
|
||||
override fun surfaceDestroyed(h: SurfaceHolder) {
|
||||
surfaceReady = false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
package org.dolphinemu.dolphinemu.features.gba
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import org.dolphinemu.dolphinemu.NativeLibrary
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
object GbaRenderManager {
|
||||
|
||||
private val buffers = Array(4) { ByteBuffer.allocateDirect(240 * 160 * 4) }
|
||||
private val bitmaps = Array(4) { Bitmap.createBitmap(240, 160, Bitmap.Config.ARGB_8888) }
|
||||
private val renderThread = HandlerThread("GBA_RENDER").apply { start() }
|
||||
private val handler = Handler(renderThread.looper)
|
||||
|
||||
@Volatile
|
||||
private var activeViews: List<GBAOverlayView> = emptyList()
|
||||
|
||||
@Volatile
|
||||
private var attached = false
|
||||
|
||||
fun isAttached() = attached
|
||||
|
||||
fun onFrame(slot: Int) {
|
||||
if (!attached || slot < 0 || slot >= 4) return
|
||||
handler.post { renderFrame(slot, forceRedraw = false) }
|
||||
}
|
||||
|
||||
private fun renderFrame(slot: Int, forceRedraw: Boolean = false) {
|
||||
val view = activeViews.firstOrNull { it.gbaSlot == slot } ?: return
|
||||
if (!view.holder.surface.isValid) return
|
||||
val buffer = buffers[slot]
|
||||
buffer.rewind()
|
||||
if (NativeLibrary.copyGBAFramebuffer(slot, buffer)) {
|
||||
buffer.rewind()
|
||||
bitmaps[slot].copyPixelsFromBuffer(buffer)
|
||||
view.drawFrame(bitmaps[slot])
|
||||
} else if (forceRedraw) {
|
||||
view.drawFrame(bitmaps[slot])
|
||||
}
|
||||
}
|
||||
|
||||
fun requestRedraw(slot: Int) {
|
||||
if (!attached || slot < 0 || slot >= 4) return
|
||||
handler.post { renderFrame(slot, forceRedraw = true) }
|
||||
}
|
||||
|
||||
fun attach(views: List<GBAOverlayView>) {
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
attached = true
|
||||
activeViews = views
|
||||
views.forEach {
|
||||
it.renderManager = this
|
||||
if (it.surfaceReady) requestRedraw(it.gbaSlot)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateViews(views: List<GBAOverlayView>) {
|
||||
activeViews = views
|
||||
views.forEach { it.renderManager = this }
|
||||
views.forEach { if (it.surfaceReady) requestRedraw(it.gbaSlot) }
|
||||
}
|
||||
|
||||
fun detach() {
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
//renderThread.quitSafely()
|
||||
activeViews = emptyList()
|
||||
attached = false
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,10 @@ object InputOverrider {
|
|||
|
||||
external fun unregisterWii(controllerIndex: Int)
|
||||
|
||||
external fun registerGBA(controllerIndex: Int)
|
||||
|
||||
external fun unregisterGBA(controllerIndex: Int)
|
||||
|
||||
external fun setControlState(controllerIndex: Int, control: Int, state: Double)
|
||||
|
||||
external fun clearControlState(controllerIndex: Int, control: Int)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,12 @@ enum class BooleanSetting(
|
|||
MAIN_DSP_HLE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "DSPHLE", true),
|
||||
MAIN_FASTMEM(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "Fastmem", true),
|
||||
MAIN_FASTMEM_ARENA(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "FastmemArena", true),
|
||||
MAIN_LARGE_ENTRY_POINTS_MAP(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "LargeEntryPointsMap", true),
|
||||
MAIN_LARGE_ENTRY_POINTS_MAP(
|
||||
Settings.FILE_DOLPHIN,
|
||||
Settings.SECTION_INI_CORE,
|
||||
"LargeEntryPointsMap",
|
||||
true
|
||||
),
|
||||
MAIN_CPU_THREAD(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "CPUThread", true),
|
||||
MAIN_SYNC_ON_SKIP_IDLE(
|
||||
Settings.FILE_DOLPHIN,
|
||||
|
|
@ -31,7 +36,12 @@ enum class BooleanSetting(
|
|||
false
|
||||
),
|
||||
MAIN_AUDIO_FILL_GAPS(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "AudioFillGaps", true),
|
||||
MAIN_AUDIO_PRESERVE_PITCH(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "AudioPreservePitch", false),
|
||||
MAIN_AUDIO_PRESERVE_PITCH(
|
||||
Settings.FILE_DOLPHIN,
|
||||
Settings.SECTION_INI_CORE,
|
||||
"AudioPreservePitch",
|
||||
false
|
||||
),
|
||||
MAIN_BBA_XLINK_CHAT_OSD(
|
||||
Settings.FILE_DOLPHIN,
|
||||
Settings.SECTION_INI_CORE,
|
||||
|
|
@ -137,7 +147,12 @@ enum class BooleanSetting(
|
|||
"EnableSaveStates",
|
||||
false
|
||||
),
|
||||
MAIN_WII_WIILINK_ENABLE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "EnableWiiLink", false),
|
||||
MAIN_WII_WIILINK_ENABLE(
|
||||
Settings.FILE_DOLPHIN,
|
||||
Settings.SECTION_INI_CORE,
|
||||
"EnableWiiLink",
|
||||
false
|
||||
),
|
||||
MAIN_DSP_JIT(Settings.FILE_DOLPHIN, Settings.SECTION_INI_DSP, "EnableJIT", true),
|
||||
MAIN_TIME_TRACKING(
|
||||
Settings.FILE_DOLPHIN,
|
||||
|
|
|
|||
|
|
@ -72,6 +72,10 @@ enum class StringSetting(
|
|||
MAIN_GBA_BIOS_PATH(Settings.FILE_DOLPHIN, Settings.SECTION_INI_GBA, "BIOS", ""),
|
||||
MAIN_GB_PLAYER_ROM(Settings.FILE_DOLPHIN, Settings.SECTION_INI_GBA, "GBPlayerRom", ""),
|
||||
MAIN_GBA_SAVES_PATH(Settings.FILE_DOLPHIN, Settings.SECTION_INI_GBA, "SavesPath", ""),
|
||||
MAIN_GBA_ROM_PATH_1(Settings.FILE_DOLPHIN, Settings.SECTION_INI_GBA, "Rom1", ""),
|
||||
MAIN_GBA_ROM_PATH_2(Settings.FILE_DOLPHIN, Settings.SECTION_INI_GBA, "Rom2", ""),
|
||||
MAIN_GBA_ROM_PATH_3(Settings.FILE_DOLPHIN, Settings.SECTION_INI_GBA, "Rom3", ""),
|
||||
MAIN_GBA_ROM_PATH_4(Settings.FILE_DOLPHIN, Settings.SECTION_INI_GBA, "Rom4", ""),
|
||||
MAIN_TRIFORCE_IP_REDIRECTIONS(
|
||||
Settings.FILE_DOLPHIN,
|
||||
Settings.SECTION_INI_CORE,
|
||||
|
|
@ -137,6 +141,14 @@ enum class StringSetting(
|
|||
MAIN_GFX_BACKEND
|
||||
)
|
||||
|
||||
fun getGBARomPath(slot: Int): StringSetting = when (slot) {
|
||||
0 -> MAIN_GBA_ROM_PATH_1
|
||||
1 -> MAIN_GBA_ROM_PATH_2
|
||||
2 -> MAIN_GBA_ROM_PATH_3
|
||||
3 -> MAIN_GBA_ROM_PATH_4
|
||||
else -> MAIN_GBA_ROM_PATH_1
|
||||
}
|
||||
|
||||
private val NOT_RUNTIME_EDITABLE: Set<StringSetting> =
|
||||
HashSet(listOf(*NOT_RUNTIME_EDITABLE_ARRAY))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,47 +71,58 @@ class SettingsAdapter(
|
|||
ListItemHeaderBinding.inflate(inflater, parent, false),
|
||||
this
|
||||
)
|
||||
|
||||
SettingsItem.TYPE_SWITCH -> SwitchSettingViewHolder(
|
||||
ListItemSettingSwitchBinding.inflate(inflater, parent, false),
|
||||
this
|
||||
)
|
||||
|
||||
SettingsItem.TYPE_STRING_SINGLE_CHOICE,
|
||||
SettingsItem.TYPE_SINGLE_CHOICE_DYNAMIC_DESCRIPTIONS,
|
||||
SettingsItem.TYPE_SINGLE_CHOICE -> SingleChoiceViewHolder(
|
||||
ListItemSettingBinding.inflate(inflater, parent, false),
|
||||
this
|
||||
)
|
||||
|
||||
SettingsItem.TYPE_SLIDER -> SliderViewHolder(
|
||||
ListItemSettingBinding.inflate(inflater, parent, false),
|
||||
this,
|
||||
context
|
||||
)
|
||||
|
||||
SettingsItem.TYPE_SUBMENU -> SubmenuViewHolder(
|
||||
ListItemSubmenuBinding.inflate(inflater, parent, false),
|
||||
this
|
||||
)
|
||||
|
||||
SettingsItem.TYPE_INPUT_MAPPING_CONTROL -> InputMappingControlSettingViewHolder(
|
||||
ListItemMappingBinding.inflate(inflater, parent, false),
|
||||
this
|
||||
)
|
||||
|
||||
SettingsItem.TYPE_FILE_PICKER,
|
||||
SettingsItem.TYPE_DIRECTORY_PICKER -> FilePickerViewHolder(
|
||||
ListItemSettingBinding.inflate(inflater, parent, false),
|
||||
this
|
||||
)
|
||||
|
||||
SettingsItem.TYPE_RUN_RUNNABLE -> RunRunnableViewHolder(
|
||||
ListItemSettingBinding.inflate(inflater, parent, false),
|
||||
this, context
|
||||
)
|
||||
|
||||
SettingsItem.TYPE_STRING -> InputStringSettingViewHolder(
|
||||
ListItemSettingBinding.inflate(inflater, parent, false), this
|
||||
)
|
||||
|
||||
SettingsItem.TYPE_HYPERLINK_HEADER -> HeaderHyperLinkViewHolder(
|
||||
ListItemHeaderBinding.inflate(inflater, parent, false), this
|
||||
)
|
||||
|
||||
SettingsItem.TYPE_DATETIME_CHOICE -> DateTimeSettingViewHolder(
|
||||
ListItemSettingBinding.inflate(inflater, parent, false), this
|
||||
)
|
||||
|
||||
else -> throw IllegalArgumentException("Invalid view type: $viewType")
|
||||
}
|
||||
}
|
||||
|
|
@ -251,6 +262,7 @@ class SettingsAdapter(
|
|||
slider.valueTo = item.max
|
||||
slider.stepSize = item.stepSize
|
||||
}
|
||||
|
||||
is IntSliderSetting -> {
|
||||
slider.valueFrom = item.min.toFloat()
|
||||
slider.valueTo = item.max.toFloat()
|
||||
|
|
@ -446,6 +458,17 @@ class SettingsAdapter(
|
|||
fun onFilePickerConfirmation(selectedFile: String) {
|
||||
val filePicker = clickedItem as FilePicker
|
||||
|
||||
if (selectedFile.startsWith("content://")) {
|
||||
try {
|
||||
val uri = android.net.Uri.parse(selectedFile)
|
||||
fragmentActivity.contentResolver.takePersistableUriPermission(
|
||||
uri,
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
)
|
||||
} catch (e: SecurityException) {
|
||||
}
|
||||
}
|
||||
|
||||
if (filePicker.getSelectedValue() != selectedFile) {
|
||||
notifyItemChanged(clickedPosition)
|
||||
fragmentView.onSettingChanged()
|
||||
|
|
@ -476,6 +499,7 @@ class SettingsAdapter(
|
|||
|
||||
closeDialog()
|
||||
}
|
||||
|
||||
is SingleChoiceSettingDynamicDescriptions -> {
|
||||
val scSetting = clickedItem as SingleChoiceSettingDynamicDescriptions
|
||||
|
||||
|
|
@ -486,6 +510,7 @@ class SettingsAdapter(
|
|||
|
||||
closeDialog()
|
||||
}
|
||||
|
||||
is StringSingleChoiceSetting -> {
|
||||
val scSetting = clickedItem as StringSingleChoiceSetting
|
||||
|
||||
|
|
@ -496,6 +521,7 @@ class SettingsAdapter(
|
|||
|
||||
closeDialog()
|
||||
}
|
||||
|
||||
is IntSliderSetting -> {
|
||||
val sliderSetting = clickedItem as IntSliderSetting
|
||||
if (sliderSetting.selectedValue != seekbarProgress.toInt()) {
|
||||
|
|
@ -504,6 +530,7 @@ class SettingsAdapter(
|
|||
sliderSetting.setSelectedValue(settings!!, seekbarProgress.toInt())
|
||||
closeDialog()
|
||||
}
|
||||
|
||||
is FloatSliderSetting -> {
|
||||
val sliderSetting = clickedItem as FloatSliderSetting
|
||||
|
||||
|
|
|
|||
|
|
@ -502,16 +502,16 @@ class SettingsFragmentPresenter(
|
|||
|
||||
override val isOverridden: Boolean
|
||||
get() = BooleanSetting.MAIN_DSP_HLE.isOverridden ||
|
||||
BooleanSetting.MAIN_DSP_JIT.isOverridden
|
||||
BooleanSetting.MAIN_DSP_JIT.isOverridden
|
||||
|
||||
override val isRuntimeEditable: Boolean
|
||||
get() = BooleanSetting.MAIN_DSP_HLE.isRuntimeEditable &&
|
||||
BooleanSetting.MAIN_DSP_JIT.isRuntimeEditable
|
||||
BooleanSetting.MAIN_DSP_JIT.isRuntimeEditable
|
||||
|
||||
override fun delete(settings: Settings): Boolean {
|
||||
// Not short circuiting
|
||||
return BooleanSetting.MAIN_DSP_HLE.delete(settings) and
|
||||
BooleanSetting.MAIN_DSP_JIT.delete(settings)
|
||||
BooleanSetting.MAIN_DSP_JIT.delete(settings)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1002,8 +1002,8 @@ class SettingsFragmentPresenter(
|
|||
0,
|
||||
false
|
||||
) {
|
||||
fragmentView.showDialogFragment(LoginDialog(this))
|
||||
loadSettingsList()
|
||||
fragmentView.showDialogFragment(LoginDialog(this))
|
||||
loadSettingsList()
|
||||
})
|
||||
} else {
|
||||
sl.add(
|
||||
|
|
@ -1015,8 +1015,8 @@ class SettingsFragmentPresenter(
|
|||
0,
|
||||
false
|
||||
) {
|
||||
logout()
|
||||
loadSettingsList()
|
||||
logout()
|
||||
loadSettingsList()
|
||||
})
|
||||
}
|
||||
sl.add(
|
||||
|
|
@ -1113,16 +1113,16 @@ class SettingsFragmentPresenter(
|
|||
|
||||
override val isOverridden: Boolean
|
||||
get() = BooleanSetting.MAIN_SYNC_ON_SKIP_IDLE.isOverridden ||
|
||||
BooleanSetting.MAIN_SYNC_GPU.isOverridden
|
||||
BooleanSetting.MAIN_SYNC_GPU.isOverridden
|
||||
|
||||
override val isRuntimeEditable: Boolean
|
||||
get() = BooleanSetting.MAIN_SYNC_ON_SKIP_IDLE.isRuntimeEditable &&
|
||||
BooleanSetting.MAIN_SYNC_GPU.isRuntimeEditable
|
||||
BooleanSetting.MAIN_SYNC_GPU.isRuntimeEditable
|
||||
|
||||
override fun delete(settings: Settings): Boolean {
|
||||
// Not short circuiting
|
||||
return BooleanSetting.MAIN_SYNC_ON_SKIP_IDLE.delete(settings) and
|
||||
BooleanSetting.MAIN_SYNC_GPU.delete(settings)
|
||||
BooleanSetting.MAIN_SYNC_GPU.delete(settings)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2239,7 +2239,7 @@ class SettingsFragmentPresenter(
|
|||
BooleanSetting.MAIN_DEBUG_JIT_ENABLE_PROFILING,
|
||||
R.string.debug_jit_enable_block_profiling,
|
||||
0
|
||||
)
|
||||
)
|
||||
)
|
||||
sl.add(
|
||||
RunRunnable(
|
||||
|
|
@ -2405,6 +2405,7 @@ class SettingsFragmentPresenter(
|
|||
addControllerMappingSettings(sl, gcPad, null)
|
||||
}
|
||||
}
|
||||
|
||||
7 -> {
|
||||
// Emulated keyboard controller
|
||||
val gcKeyboard = EmulatedController.getGcKeyboard(gcPadNumber)
|
||||
|
|
@ -2417,6 +2418,7 @@ class SettingsFragmentPresenter(
|
|||
addControllerMappingSettings(sl, gcKeyboard, null)
|
||||
}
|
||||
}
|
||||
|
||||
12 -> {
|
||||
// Adapter
|
||||
sl.add(
|
||||
|
|
@ -2436,6 +2438,21 @@ class SettingsFragmentPresenter(
|
|||
)
|
||||
)
|
||||
}
|
||||
|
||||
13 -> {
|
||||
//GBA emulator
|
||||
sl.add(HeaderSetting(context, R.string.gba_settings, 0))
|
||||
sl.add(
|
||||
FilePicker(
|
||||
context,
|
||||
StringSetting.getGBARomPath(gcPadNumber),
|
||||
R.string.gba_rom_path,
|
||||
R.string.gba_rom_path_description,
|
||||
fragmentView.activityResultLaunchers.requestGbaRomFile,
|
||||
null
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2635,11 +2652,11 @@ class SettingsFragmentPresenter(
|
|||
* @param groupTypeFilter If this is non-null, only groups whose types match this are considered.
|
||||
*/
|
||||
private fun addControllerMappingSettings(
|
||||
sl: ArrayList<SettingsItem>,
|
||||
controller: EmulatedController,
|
||||
groupTypeFilter: Set<Int>?
|
||||
sl: ArrayList<SettingsItem>,
|
||||
controller: EmulatedController,
|
||||
groupTypeFilter: Set<Int>?
|
||||
) {
|
||||
addContainerMappingSettings(sl, controller, controller, groupTypeFilter)
|
||||
addContainerMappingSettings(sl, controller, controller, groupTypeFilter)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2734,7 +2751,7 @@ class SettingsFragmentPresenter(
|
|||
val defaultDevice = controller.getDefaultDevice()
|
||||
|
||||
hasOldControllerSettings = defaultDevice.startsWith("Android/") &&
|
||||
defaultDevice.endsWith("/Touchscreen")
|
||||
defaultDevice.endsWith("/Touchscreen")
|
||||
|
||||
fragmentView.setOldControllerSettingsWarningVisibility(hasOldControllerSettings)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,11 +51,17 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
|
|||
private var isFirstRun = true
|
||||
private val gcPadRegistered = BooleanArray(4)
|
||||
private val wiimoteRegistered = BooleanArray(4)
|
||||
private val gbaRegistered = BooleanArray(4)
|
||||
private val gbaOverlayButtons: MutableSet<InputOverlayDrawableButton> = HashSet()
|
||||
private val gbaOverlayDpads: MutableSet<InputOverlayDrawableDpad> = HashSet()
|
||||
private var gbaControllerIndex = -1
|
||||
var editMode = false
|
||||
private var controllerType = -1
|
||||
private var controllerIndex = 0
|
||||
private var buttonBeingConfigured: InputOverlayDrawableButton? = null
|
||||
private var dpadBeingConfigured: InputOverlayDrawableDpad? = null
|
||||
private var gbaButtonBeingConfigured: InputOverlayDrawableButton? = null
|
||||
private var gbaDpadBeingConfigured: InputOverlayDrawableDpad? = null
|
||||
private var joystickBeingConfigured: InputOverlayDrawableJoystick? = null
|
||||
|
||||
private val preferences: SharedPreferences
|
||||
|
|
@ -129,6 +135,35 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
|
|||
for (joystick in overlayJoysticks) {
|
||||
joystick.draw(canvas)
|
||||
}
|
||||
|
||||
for (button in gbaOverlayButtons) {
|
||||
button.draw(canvas)
|
||||
drawGBABadge(canvas, button.bounds)
|
||||
}
|
||||
|
||||
for (dpad in gbaOverlayDpads) {
|
||||
dpad.draw(canvas)
|
||||
drawGBABadge(canvas, dpad.bounds)
|
||||
}
|
||||
}
|
||||
|
||||
//draws gba badge on controlls for gba controller, to not get confused with the GC pad buttons
|
||||
private fun drawGBABadge(canvas: Canvas, bounds: android.graphics.Rect) {
|
||||
val bp = android.graphics.Paint().apply {
|
||||
isAntiAlias = true; color = android.graphics.Color.argb(200, 98, 0, 238)
|
||||
style = android.graphics.Paint.Style.FILL
|
||||
}
|
||||
val tp = android.graphics.Paint().apply {
|
||||
isAntiAlias = true; color = android.graphics.Color.WHITE; textSize = 18f
|
||||
typeface = android.graphics.Typeface.DEFAULT_BOLD
|
||||
textAlign = android.graphics.Paint.Align.CENTER
|
||||
}
|
||||
val r = android.graphics.RectF(
|
||||
bounds.left.toFloat(), bounds.top.toFloat(),
|
||||
bounds.left + 36f, bounds.top + 18f
|
||||
)
|
||||
canvas.drawRoundRect(r, 6f, 6f, bp)
|
||||
canvas.drawText("GBA", r.left + 18f, r.top + 14f, tp)
|
||||
}
|
||||
|
||||
override fun onTouch(v: View, event: MotionEvent): Boolean {
|
||||
|
|
@ -138,7 +173,7 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
|
|||
|
||||
val action = event.actionMasked
|
||||
val firstPointer = action != MotionEvent.ACTION_POINTER_DOWN &&
|
||||
action != MotionEvent.ACTION_POINTER_UP
|
||||
action != MotionEvent.ACTION_POINTER_UP
|
||||
val pointerIndex = if (firstPointer) 0 else event.actionIndex
|
||||
// Tracks if any button/joystick is pressed down
|
||||
var pressed = false
|
||||
|
|
@ -157,7 +192,11 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
|
|||
button.setPressedState(if (button.latching) !button.getPressedState() else true)
|
||||
button.trackId = event.getPointerId(pointerIndex)
|
||||
pressed = true
|
||||
InputOverrider.setControlState(controllerIndex, button.control, if (button.getPressedState()) 1.0 else 0.0)
|
||||
InputOverrider.setControlState(
|
||||
controllerIndex,
|
||||
button.control,
|
||||
if (button.getPressedState()) 1.0 else 0.0
|
||||
)
|
||||
|
||||
val analogControl = getAnalogControlForTrigger(button.control)
|
||||
if (analogControl >= 0)
|
||||
|
|
@ -175,7 +214,11 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
|
|||
if (button.trackId == event.getPointerId(pointerIndex)) {
|
||||
if (!button.latching)
|
||||
button.setPressedState(false)
|
||||
InputOverrider.setControlState(controllerIndex, button.control, if (button.getPressedState()) 1.0 else 0.0)
|
||||
InputOverrider.setControlState(
|
||||
controllerIndex,
|
||||
button.control,
|
||||
if (button.getPressedState()) 1.0 else 0.0
|
||||
)
|
||||
|
||||
val analogControl = getAnalogControlForTrigger(button.control)
|
||||
if (analogControl >= 0)
|
||||
|
|
@ -301,6 +344,118 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
|
|||
)
|
||||
}
|
||||
|
||||
//gba touch handling
|
||||
if (gbaControllerIndex >= 0) {
|
||||
for (button in gbaOverlayButtons) {
|
||||
when (action) {
|
||||
MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN -> {
|
||||
if (button.bounds.contains(
|
||||
event.getX(pointerIndex).toInt(),
|
||||
event.getY(pointerIndex).toInt()
|
||||
)
|
||||
) {
|
||||
button.setPressedState(if (button.latching) !button.getPressedState() else true)
|
||||
button.trackId = event.getPointerId(pointerIndex)
|
||||
pressed = true
|
||||
InputOverrider.setControlState(
|
||||
gbaControllerIndex,
|
||||
button.control,
|
||||
if (button.getPressedState()) 1.0 else 0.0
|
||||
)
|
||||
val analog = getAnalogControlForTrigger(button.control)
|
||||
if (analog >= 0)
|
||||
InputOverrider.setControlState(gbaControllerIndex, analog, 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_UP, MotionEvent.ACTION_POINTER_UP -> {
|
||||
if (button.trackId == event.getPointerId(pointerIndex)) {
|
||||
if (!button.latching)
|
||||
button.setPressedState(false)
|
||||
InputOverrider.setControlState(
|
||||
gbaControllerIndex,
|
||||
button.control,
|
||||
if (button.getPressedState()) 1.0 else 0.0
|
||||
)
|
||||
val analog = getAnalogControlForTrigger(button.control)
|
||||
if (analog >= 0)
|
||||
InputOverrider.setControlState(gbaControllerIndex, analog, 0.0)
|
||||
button.trackId = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (dpad in gbaOverlayDpads) {
|
||||
when (action) {
|
||||
MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN -> {
|
||||
if (dpad.bounds.contains(
|
||||
event.getX(pointerIndex).toInt(),
|
||||
event.getY(pointerIndex).toInt()
|
||||
)
|
||||
) {
|
||||
dpad.trackId = event.getPointerId(pointerIndex)
|
||||
pressed = true
|
||||
}
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
if (dpad.trackId == event.getPointerId(pointerIndex)) {
|
||||
val up = event.getY(pointerIndex) < dpad.bounds.centerY()
|
||||
val down = event.getY(pointerIndex) > dpad.bounds.centerY()
|
||||
val left = event.getX(pointerIndex) < dpad.bounds.centerX()
|
||||
val right = event.getX(pointerIndex) > dpad.bounds.centerX()
|
||||
setDpadState(dpad, up, down, left, right)
|
||||
InputOverrider.setControlState(
|
||||
gbaControllerIndex,
|
||||
ControlId.GCPAD_DPAD_UP, if (up) 1.0 else 0.0
|
||||
)
|
||||
InputOverrider.setControlState(
|
||||
gbaControllerIndex,
|
||||
ControlId.GCPAD_DPAD_DOWN, if (down) 1.0 else 0.0
|
||||
)
|
||||
InputOverrider.setControlState(
|
||||
gbaControllerIndex,
|
||||
ControlId.GCPAD_DPAD_LEFT, if (left) 1.0 else 0.0
|
||||
)
|
||||
InputOverrider.setControlState(
|
||||
gbaControllerIndex,
|
||||
ControlId.GCPAD_DPAD_RIGHT, if (right) 1.0 else 0.0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_UP, MotionEvent.ACTION_POINTER_UP -> {
|
||||
if (dpad.trackId == event.getPointerId(pointerIndex)) {
|
||||
dpad.trackId = -1
|
||||
dpad.setState(InputOverlayDrawableDpad.STATE_DEFAULT)
|
||||
InputOverrider.setControlState(
|
||||
gbaControllerIndex,
|
||||
ControlId.GCPAD_DPAD_UP,
|
||||
0.0
|
||||
)
|
||||
InputOverrider.setControlState(
|
||||
gbaControllerIndex,
|
||||
ControlId.GCPAD_DPAD_DOWN,
|
||||
0.0
|
||||
)
|
||||
InputOverrider.setControlState(
|
||||
gbaControllerIndex,
|
||||
ControlId.GCPAD_DPAD_LEFT,
|
||||
0.0
|
||||
)
|
||||
InputOverrider.setControlState(
|
||||
gbaControllerIndex,
|
||||
ControlId.GCPAD_DPAD_RIGHT,
|
||||
0.0
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
invalidate()
|
||||
|
||||
return true
|
||||
|
|
@ -425,6 +580,76 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
|
|||
}
|
||||
}
|
||||
}
|
||||
for (button in gbaOverlayButtons) {
|
||||
when (event.action and MotionEvent.ACTION_MASK) {
|
||||
MotionEvent.ACTION_DOWN,
|
||||
MotionEvent.ACTION_POINTER_DOWN -> {
|
||||
if (gbaButtonBeingConfigured == null &&
|
||||
button.bounds.contains(fingerPositionX, fingerPositionY)
|
||||
) {
|
||||
gbaButtonBeingConfigured = button
|
||||
gbaButtonBeingConfigured?.onConfigureTouch(event)
|
||||
}
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
if (gbaButtonBeingConfigured != null) {
|
||||
gbaButtonBeingConfigured?.onConfigureTouch(event)
|
||||
invalidate()
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_UP,
|
||||
MotionEvent.ACTION_POINTER_UP -> {
|
||||
if (gbaButtonBeingConfigured == button) {
|
||||
saveControlPosition(
|
||||
gbaButtonBeingConfigured!!.legacyId,
|
||||
gbaButtonBeingConfigured!!.bounds.left,
|
||||
gbaButtonBeingConfigured!!.bounds.top,
|
||||
orientation
|
||||
)
|
||||
gbaButtonBeingConfigured = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (dpad in gbaOverlayDpads) {
|
||||
when (event.action and MotionEvent.ACTION_MASK) {
|
||||
MotionEvent.ACTION_DOWN,
|
||||
MotionEvent.ACTION_POINTER_DOWN -> {
|
||||
if (gbaDpadBeingConfigured == null && dpad.bounds.contains(
|
||||
fingerPositionX,
|
||||
fingerPositionY
|
||||
)
|
||||
) {
|
||||
gbaDpadBeingConfigured = dpad
|
||||
gbaDpadBeingConfigured?.onConfigureTouch(event)
|
||||
}
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
if (gbaDpadBeingConfigured != null) {
|
||||
gbaDpadBeingConfigured?.onConfigureTouch(event)
|
||||
invalidate()
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_UP,
|
||||
MotionEvent.ACTION_POINTER_UP -> {
|
||||
if (gbaDpadBeingConfigured == dpad) {
|
||||
saveControlPosition(
|
||||
gbaDpadBeingConfigured!!.legacyId,
|
||||
gbaDpadBeingConfigured!!.bounds.left,
|
||||
gbaDpadBeingConfigured!!.bounds.top,
|
||||
orientation
|
||||
)
|
||||
gbaDpadBeingConfigured = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
@ -443,8 +668,16 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
|
|||
InputOverrider.unregisterWii(i)
|
||||
}
|
||||
|
||||
for (i in gbaRegistered.indices) {
|
||||
if (gbaRegistered[i]) InputOverrider.unregisterGBA(i)
|
||||
}
|
||||
|
||||
Arrays.fill(gcPadRegistered, false)
|
||||
Arrays.fill(wiimoteRegistered, false)
|
||||
Arrays.fill(gbaRegistered, false)
|
||||
gbaOverlayButtons.clear()
|
||||
gbaOverlayDpads.clear()
|
||||
gbaControllerIndex = -1
|
||||
}
|
||||
|
||||
private fun getAnalogControlForTrigger(control: Int): Int = when (control) {
|
||||
|
|
@ -640,6 +873,70 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
|
|||
}
|
||||
}
|
||||
|
||||
private fun addGBAOverlayControls(orientation: String) {
|
||||
gbaOverlayButtons.add(
|
||||
initializeOverlayButton(
|
||||
context, R.drawable.gcpad_a, R.drawable.gcpad_a_pressed,
|
||||
ButtonType.BUTTON_A + GBA_BUTTON_ID_OFFSET,
|
||||
ControlId.GCPAD_A_BUTTON, orientation, false
|
||||
)
|
||||
)
|
||||
|
||||
gbaOverlayButtons.add(
|
||||
initializeOverlayButton(
|
||||
context, R.drawable.gcpad_b, R.drawable.gcpad_b_pressed,
|
||||
ButtonType.BUTTON_B + GBA_BUTTON_ID_OFFSET,
|
||||
ControlId.GCPAD_B_BUTTON, orientation, false
|
||||
)
|
||||
)
|
||||
|
||||
gbaOverlayButtons.add(
|
||||
initializeOverlayButton(
|
||||
context,
|
||||
R.drawable.gcpad_start,
|
||||
R.drawable.gcpad_start_pressed,
|
||||
ButtonType.BUTTON_START + GBA_BUTTON_ID_OFFSET,
|
||||
ControlId.GCPAD_START_BUTTON,
|
||||
orientation,
|
||||
false
|
||||
)
|
||||
)
|
||||
|
||||
gbaOverlayButtons.add(
|
||||
initializeOverlayButton(
|
||||
context, R.drawable.gcpad_z, R.drawable.gcpad_z_pressed,
|
||||
ButtonType.BUTTON_Z + GBA_BUTTON_ID_OFFSET,
|
||||
ControlId.GCPAD_Z_BUTTON, orientation, false
|
||||
)
|
||||
)
|
||||
|
||||
gbaOverlayButtons.add(
|
||||
initializeOverlayButton(
|
||||
context, R.drawable.gcpad_l, R.drawable.gcpad_l_pressed,
|
||||
ButtonType.TRIGGER_L + GBA_BUTTON_ID_OFFSET,
|
||||
ControlId.GCPAD_L_DIGITAL, orientation, false
|
||||
)
|
||||
)
|
||||
|
||||
gbaOverlayButtons.add(
|
||||
initializeOverlayButton(
|
||||
context, R.drawable.gcpad_r, R.drawable.gcpad_r_pressed,
|
||||
ButtonType.TRIGGER_R + GBA_BUTTON_ID_OFFSET,
|
||||
ControlId.GCPAD_R_DIGITAL, orientation, false
|
||||
)
|
||||
)
|
||||
|
||||
gbaOverlayDpads.add(
|
||||
initializeOverlayDpad(
|
||||
context, R.drawable.gcwii_dpad, R.drawable.gcwii_dpad_pressed_one_direction,
|
||||
R.drawable.gcwii_dpad_pressed_two_directions,
|
||||
ButtonType.BUTTON_UP + GBA_BUTTON_ID_OFFSET,
|
||||
ControlId.GCPAD_DPAD_UP, ControlId.GCPAD_DPAD_DOWN,
|
||||
ControlId.GCPAD_DPAD_LEFT, ControlId.GCPAD_DPAD_RIGHT, orientation
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun addWiimoteOverlayControls(orientation: String) {
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_0.boolean) {
|
||||
overlayButtons.add(
|
||||
|
|
@ -1047,6 +1344,23 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
|
|||
|
||||
OVERLAY_NONE -> {}
|
||||
}
|
||||
//add GBA controls on top of primary, GC controller always visible
|
||||
gbaOverlayButtons.clear()
|
||||
gbaOverlayDpads.clear()
|
||||
gbaControllerIndex = -1
|
||||
|
||||
for (i in 0 until 4) {
|
||||
if (getSettingForSIDevice(i).int == EMULATED_GBA_CONTROLLER) {
|
||||
if (gbaControllerIndex < 0) gbaControllerIndex = i
|
||||
if (!gbaRegistered[i]) {
|
||||
InputOverrider.registerGBA(i)
|
||||
gbaRegistered[i] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if (gbaControllerIndex >= 0) {
|
||||
addGBAOverlayControls(orientation)
|
||||
}
|
||||
}
|
||||
|
||||
isFirstRun = false
|
||||
|
|
@ -1085,6 +1399,7 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
|
|||
wiiOnlyPortraitDefaultOverlay()
|
||||
}
|
||||
}
|
||||
if (isLandscape) gbaDefaultOverlay() else gbaPortraitDefaultOverlay()
|
||||
refreshControls()
|
||||
}
|
||||
|
||||
|
|
@ -1401,6 +1716,22 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
|
|||
) {
|
||||
wiiClassicPortraitDefaultOverlay()
|
||||
}
|
||||
|
||||
// GBA controls android
|
||||
if (preferences.getFloat(
|
||||
(ButtonType.BUTTON_A + GBA_BUTTON_ID_OFFSET)
|
||||
.toString() + "-X", 0f
|
||||
) == 0f
|
||||
) {
|
||||
gbaDefaultOverlay()
|
||||
}
|
||||
if (preferences.getFloat(
|
||||
(ButtonType.BUTTON_A + GBA_BUTTON_ID_OFFSET)
|
||||
.toString() + "-Portrait" + "-X", 0f
|
||||
) == 0f
|
||||
) {
|
||||
gbaPortraitDefaultOverlay()
|
||||
}
|
||||
}
|
||||
|
||||
if (!preferences.getBoolean("OverlayInitV3", false)) {
|
||||
|
|
@ -2276,6 +2607,112 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
|
|||
.apply()
|
||||
}
|
||||
|
||||
private fun gbaDefaultOverlay() {
|
||||
val dm = resources.displayMetrics
|
||||
var maxX = dm.heightPixels.toFloat()
|
||||
var maxY = dm.widthPixels.toFloat()
|
||||
if (maxY > maxX) {
|
||||
val tmp = maxX;
|
||||
maxX = maxY;
|
||||
maxY = tmp
|
||||
}
|
||||
|
||||
preferences.edit()
|
||||
.putFloat((ButtonType.BUTTON_A + GBA_BUTTON_ID_OFFSET).toString() + "-X", 0.82f * maxX)
|
||||
.putFloat((ButtonType.BUTTON_A + GBA_BUTTON_ID_OFFSET).toString() + "-Y", 0.60f * maxY)
|
||||
.putFloat((ButtonType.BUTTON_B + GBA_BUTTON_ID_OFFSET).toString() + "-X", 0.73f * maxX)
|
||||
.putFloat((ButtonType.BUTTON_B + GBA_BUTTON_ID_OFFSET).toString() + "-Y", 0.70f * maxY)
|
||||
.putFloat((ButtonType.TRIGGER_L + GBA_BUTTON_ID_OFFSET).toString() + "-X", 0.08f * maxX)
|
||||
.putFloat((ButtonType.TRIGGER_L + GBA_BUTTON_ID_OFFSET).toString() + "-Y", 0.25f * maxY)
|
||||
.putFloat((ButtonType.TRIGGER_R + GBA_BUTTON_ID_OFFSET).toString() + "-X", 0.78f * maxX)
|
||||
.putFloat((ButtonType.TRIGGER_R + GBA_BUTTON_ID_OFFSET).toString() + "-Y", 0.25f * maxY)
|
||||
.putFloat(
|
||||
(ButtonType.BUTTON_START + GBA_BUTTON_ID_OFFSET).toString() + "-X",
|
||||
0.60f * maxX
|
||||
)
|
||||
.putFloat(
|
||||
(ButtonType.BUTTON_START + GBA_BUTTON_ID_OFFSET).toString() + "-Y",
|
||||
0.80f * maxY
|
||||
)
|
||||
.putFloat((ButtonType.BUTTON_Z + GBA_BUTTON_ID_OFFSET).toString() + "-X", 0.45f * maxX)
|
||||
.putFloat((ButtonType.BUTTON_Z + GBA_BUTTON_ID_OFFSET).toString() + "-Y", 0.80f * maxY)
|
||||
.putFloat((ButtonType.BUTTON_UP + GBA_BUTTON_ID_OFFSET).toString() + "-X", 0.12f * maxX)
|
||||
.putFloat((ButtonType.BUTTON_UP + GBA_BUTTON_ID_OFFSET).toString() + "-Y", 0.55f * maxY)
|
||||
.apply()
|
||||
}
|
||||
|
||||
private fun gbaPortraitDefaultOverlay() {
|
||||
val dm = resources.displayMetrics
|
||||
var maxX = dm.heightPixels.toFloat()
|
||||
var maxY = dm.widthPixels.toFloat()
|
||||
if (maxY < maxX) {
|
||||
val tmp = maxX;
|
||||
maxX = maxY;
|
||||
maxY = tmp
|
||||
}
|
||||
val portrait = "-Portrait"
|
||||
|
||||
preferences.edit()
|
||||
.putFloat(
|
||||
(ButtonType.BUTTON_A + GBA_BUTTON_ID_OFFSET).toString() + portrait + "-X",
|
||||
0.82f * maxX
|
||||
)
|
||||
.putFloat(
|
||||
(ButtonType.BUTTON_A + GBA_BUTTON_ID_OFFSET).toString() + portrait + "-Y",
|
||||
0.72f * maxY
|
||||
)
|
||||
.putFloat(
|
||||
(ButtonType.BUTTON_B + GBA_BUTTON_ID_OFFSET).toString() + portrait + "-X",
|
||||
0.68f * maxX
|
||||
)
|
||||
.putFloat(
|
||||
(ButtonType.BUTTON_B + GBA_BUTTON_ID_OFFSET).toString() + portrait + "-Y",
|
||||
0.80f * maxY
|
||||
)
|
||||
.putFloat(
|
||||
(ButtonType.TRIGGER_L + GBA_BUTTON_ID_OFFSET).toString() + portrait + "-X",
|
||||
0.04f * maxX
|
||||
)
|
||||
.putFloat(
|
||||
(ButtonType.TRIGGER_L + GBA_BUTTON_ID_OFFSET).toString() + portrait + "-Y",
|
||||
0.55f * maxY
|
||||
)
|
||||
.putFloat(
|
||||
(ButtonType.TRIGGER_R + GBA_BUTTON_ID_OFFSET).toString() + portrait + "-X",
|
||||
0.78f * maxX
|
||||
)
|
||||
.putFloat(
|
||||
(ButtonType.TRIGGER_R + GBA_BUTTON_ID_OFFSET).toString() + portrait + "-Y",
|
||||
0.55f * maxY
|
||||
)
|
||||
.putFloat(
|
||||
(ButtonType.BUTTON_START + GBA_BUTTON_ID_OFFSET).toString() + portrait + "-X",
|
||||
0.62f * maxX
|
||||
)
|
||||
.putFloat(
|
||||
(ButtonType.BUTTON_START + GBA_BUTTON_ID_OFFSET).toString() + portrait + "-Y",
|
||||
0.90f * maxY
|
||||
)
|
||||
.putFloat(
|
||||
(ButtonType.BUTTON_Z + GBA_BUTTON_ID_OFFSET).toString() + portrait + "-X",
|
||||
0.42f * maxX
|
||||
)
|
||||
.putFloat(
|
||||
(ButtonType.BUTTON_Z + GBA_BUTTON_ID_OFFSET).toString() + portrait + "-Y",
|
||||
0.90f * maxY
|
||||
)
|
||||
.putFloat(
|
||||
(ButtonType.BUTTON_UP + GBA_BUTTON_ID_OFFSET).toString() + portrait + "-X",
|
||||
0.10f * maxX
|
||||
)
|
||||
.putFloat(
|
||||
(ButtonType.BUTTON_UP + GBA_BUTTON_ID_OFFSET).toString() + portrait + "-Y",
|
||||
0.72f * maxY
|
||||
)
|
||||
.apply()
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
const val OVERLAY_GAMECUBE = 0
|
||||
const val OVERLAY_WIIMOTE = 1
|
||||
|
|
@ -2287,6 +2724,10 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
|
|||
private const val EMULATED_GAMECUBE_CONTROLLER = 6
|
||||
private const val EMULATED_AM_BASEBOARD = 11
|
||||
private const val GAMECUBE_ADAPTER = 12
|
||||
private const val EMULATED_GBA_CONTROLLER = 13
|
||||
|
||||
//avoid ID collision with GC buttons
|
||||
private const val GBA_BUTTON_ID_OFFSET = 1000
|
||||
|
||||
// Buttons that have special positions in Wiimote only
|
||||
private val WIIMOTE_H_BUTTONS = ArrayList<Int>()
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@ import java.util.Set;
|
|||
public final class FileBrowserHelper
|
||||
{
|
||||
public static final HashSet<String> GAME_EXTENSIONS = new HashSet<>(Arrays.asList(
|
||||
"gcm", "tgc", "bin", "iso", "ciso", "gcz", "wbfs", "wia", "rvz", "nfs", "wad", "dol",
|
||||
"elf", "json"));
|
||||
"gcm", "tgc", "bin", "iso", "ciso", "gcz", "wbfs", "wia", "rvz", "nfs", "wad", "dol",
|
||||
"elf", "json"));
|
||||
|
||||
public static final HashSet<String> GAME_LIKE_EXTENSIONS = new HashSet<>(GAME_EXTENSIONS);
|
||||
|
||||
|
|
@ -40,19 +40,19 @@ public final class FileBrowserHelper
|
|||
}
|
||||
|
||||
public static final HashSet<String> GBA_ROM_EXTENSIONS = new HashSet<>(Arrays.asList(
|
||||
"gba", "gbc", "gb", "agb", "mb", "rom", "bin"));
|
||||
"gba", "gbc", "gb", "agb", "mb", "rom", "bin"));
|
||||
|
||||
public static final HashSet<String> BIN_EXTENSION = new HashSet<>(Collections.singletonList(
|
||||
"bin"));
|
||||
"bin"));
|
||||
|
||||
public static final HashSet<String> RAW_EXTENSION = new HashSet<>(Collections.singletonList(
|
||||
"raw"));
|
||||
"raw"));
|
||||
|
||||
public static final HashSet<String> WAD_EXTENSION = new HashSet<>(Collections.singletonList(
|
||||
"wad"));
|
||||
"wad"));
|
||||
|
||||
public static Intent createDirectoryPickerIntent(FragmentActivity activity,
|
||||
HashSet<String> extensions)
|
||||
HashSet<String> extensions)
|
||||
{
|
||||
Intent i = new Intent(activity, CustomFilePickerActivity.class);
|
||||
|
||||
|
|
@ -60,7 +60,7 @@ public final class FileBrowserHelper
|
|||
i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, false);
|
||||
i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR);
|
||||
i.putExtra(FilePickerActivity.EXTRA_START_PATH,
|
||||
Environment.getExternalStorageDirectory().getPath());
|
||||
Environment.getExternalStorageDirectory().getPath());
|
||||
i.putExtra(CustomFilePickerActivity.EXTRA_EXTENSIONS, extensions);
|
||||
|
||||
return i;
|
||||
|
|
@ -98,7 +98,7 @@ public final class FileBrowserHelper
|
|||
}
|
||||
|
||||
public static void runAfterExtensionCheck(Context context, Uri uri, Set<String> validExtensions,
|
||||
Runnable runnable)
|
||||
Runnable runnable)
|
||||
{
|
||||
String extension = null;
|
||||
|
||||
|
|
@ -123,18 +123,18 @@ public final class FileBrowserHelper
|
|||
else
|
||||
{
|
||||
int messageId = validExtensions.size() == 1 ?
|
||||
R.string.wrong_file_extension_single : R.string.wrong_file_extension_multiple;
|
||||
R.string.wrong_file_extension_single : R.string.wrong_file_extension_multiple;
|
||||
|
||||
message = context.getString(messageId, extension,
|
||||
setToSortedDelimitedString(validExtensions));
|
||||
setToSortedDelimitedString(validExtensions));
|
||||
}
|
||||
|
||||
new MaterialAlertDialogBuilder(context)
|
||||
.setMessage(message)
|
||||
.setPositiveButton(R.string.yes, (dialogInterface, i) -> runnable.run())
|
||||
.setNegativeButton(R.string.no, null)
|
||||
.setCancelable(false)
|
||||
.show();
|
||||
.setMessage(message)
|
||||
.setPositiveButton(R.string.yes, (dialogInterface, i) -> runnable.run())
|
||||
.setNegativeButton(R.string.no, null)
|
||||
.setCancelable(false)
|
||||
.show();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@
|
|||
<SurfaceView
|
||||
android:id="@+id/surface_emulation"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_gravity="start"
|
||||
android:layout_marginStart="0dp"
|
||||
android:focusable="false"
|
||||
android:focusableInTouchMode="false" />
|
||||
|
||||
|
|
|
|||
|
|
@ -30,4 +30,15 @@
|
|||
<item
|
||||
android:id="@+id/menu_emulation_reset_overlay"
|
||||
android:title="@string/emulation_touch_overlay_reset"/>
|
||||
|
||||
<item android:id="@+id/menu_emulation_gba_snap"
|
||||
android:checkable="true"
|
||||
android:title="Snap Gba Layout"/>
|
||||
|
||||
|
||||
<item android:id="@+id/menu_emulation_gba_reset"
|
||||
android:title="Reset Gba Screens"/>
|
||||
|
||||
<item android:id="@+id/menu_emulation_gba_reset_core"
|
||||
android:title="Reset Gba"/>
|
||||
</menu>
|
||||
|
|
|
|||
|
|
@ -2,78 +2,37 @@
|
|||
|
||||
<!-- All lists for ListPreference keys/values are placed here -->
|
||||
<resources>
|
||||
<string-array name="regionEntries">
|
||||
<item>NTSC-J</item>
|
||||
<item>NTSC-U</item>
|
||||
<item>PAL</item>
|
||||
<item>NTSC-K</item>
|
||||
</string-array>
|
||||
<integer-array name="regionValues">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- UI CPU Core selection -->
|
||||
<string-array name="emuCoresEntriesX86_64">
|
||||
<item>@string/jit_recompiler_x86</item>
|
||||
<item>@string/cached_interpreter_slower</item>
|
||||
<item>@string/interpreter_slowest</item>
|
||||
</string-array>
|
||||
<integer-array name="emuCoresValuesX86_64">
|
||||
<item>1</item>
|
||||
<item>5</item>
|
||||
<item>0</item>
|
||||
</integer-array>
|
||||
<string-array name="emuCoresEntriesARM64">
|
||||
<item>@string/jit_recompiler_arm64</item>
|
||||
<item>@string/cached_interpreter_slower</item>
|
||||
<item>@string/interpreter_slowest</item>
|
||||
</string-array>
|
||||
|
||||
<!-- UI CPU Core selection -->
|
||||
<integer-array name="emuCoresValuesARM64">
|
||||
<item>4</item>
|
||||
<item>5</item>
|
||||
<item>0</item>
|
||||
</integer-array>
|
||||
<string-array name="emuCoresEntriesGeneric">
|
||||
<item>@string/cached_interpreter</item>
|
||||
<item>@string/interpreter</item>
|
||||
</string-array>
|
||||
<integer-array name="emuCoresValuesGeneric">
|
||||
<item>5</item>
|
||||
<item>0</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- DSP Emulation Engine -->
|
||||
<string-array name="dspEngineEntriesX86_64">
|
||||
<item>@string/dsp_hle</item>
|
||||
<item>@string/dsp_lle_recompiler</item>
|
||||
<item>@string/dsp_lle_interpreter</item>
|
||||
</string-array>
|
||||
<integer-array name="dspEngineValuesX86_64">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
</integer-array>
|
||||
<string-array name="dspEngineEntriesGeneric">
|
||||
<item>@string/dsp_hle</item>
|
||||
<item>@string/dsp_lle_interpreter</item>
|
||||
</string-array>
|
||||
<integer-array name="dspEngineValuesGeneric">
|
||||
<item>0</item>
|
||||
<item>2</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- GameCube System Languages -->
|
||||
<string-array name="gameCubeSystemLanguageEntries">
|
||||
<item>@string/language_english</item>
|
||||
<item>@string/language_german</item>
|
||||
<item>@string/language_french</item>
|
||||
<item>@string/language_spanish</item>
|
||||
<item>@string/language_italian</item>
|
||||
<item>@string/language_dutch</item>
|
||||
</string-array>
|
||||
<integer-array name="gameCubeSystemLanguageValues">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
|
|
@ -82,14 +41,6 @@
|
|||
<item>4</item>
|
||||
<item>5</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- Slot A & B Device selection -->
|
||||
<string-array name="slotDeviceEntries">
|
||||
<item>@string/device_nothing</item>
|
||||
<item>@string/device_dummy</item>
|
||||
<item>@string/device_memory_card</item>
|
||||
<item>@string/device_gci_folder</item>
|
||||
</string-array>
|
||||
<integer-array name="slotDeviceValues">
|
||||
<item>255</item>
|
||||
<item>0</item>
|
||||
|
|
@ -97,16 +48,7 @@
|
|||
<item>8</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- Slot SP1 Device selection -->
|
||||
<string-array name="serialPort1DeviceEntries">
|
||||
<item>@string/device_nothing</item>
|
||||
<item>@string/device_dummy</item>
|
||||
<item>@string/broadband_adapter_xlink</item>
|
||||
<item>@string/broadband_adapter_hle</item>
|
||||
<item>@string/broadband_adapter_tapserver</item>
|
||||
<item>@string/modem_adapter_tapserver</item>
|
||||
<item>@string/sp1_am_baseboard</item>
|
||||
</string-array>
|
||||
<!-- DSP Emulation Engine -->
|
||||
<integer-array name="serialPort1DeviceValues">
|
||||
<item>255</item>
|
||||
<item>0</item>
|
||||
|
|
@ -116,20 +58,6 @@
|
|||
<item>13</item>
|
||||
<item>6</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- Wii System Languages -->
|
||||
<string-array name="wiiSystemLanguageEntries">
|
||||
<item>@string/language_japanese</item>
|
||||
<item>@string/language_english</item>
|
||||
<item>@string/language_german</item>
|
||||
<item>@string/language_french</item>
|
||||
<item>@string/language_spanish</item>
|
||||
<item>@string/language_italian</item>
|
||||
<item>@string/language_dutch</item>
|
||||
<item>@string/language_simplified_chinese</item>
|
||||
<item>@string/language_traditional_chinese</item>
|
||||
<item>@string/language_korean</item>
|
||||
</string-array>
|
||||
<integer-array name="wiiSystemLanguageValues">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
|
|
@ -142,49 +70,23 @@
|
|||
<item>8</item>
|
||||
<item>9</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- Sound Mode -->
|
||||
<string-array name="soundModeEntries">
|
||||
<item>@string/sound_mode_mono</item>
|
||||
<item>@string/sound_mode_stereo</item>
|
||||
<item>@string/sound_mode_surround</item>
|
||||
</string-array>
|
||||
<integer-array name="soundModeValues">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- Sensor Bar Position -->
|
||||
<string-array name="sensorBarPositionEntries">
|
||||
<item>@string/sensor_position_top</item>
|
||||
<item>@string/sensor_position_bottom</item>
|
||||
</string-array>
|
||||
<integer-array name="sensorBarPositionValues">
|
||||
<item>1</item>
|
||||
<item>0</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- Log Verbosity selection based on LogLevel in Common/Logging/Log.h -->
|
||||
<string-array name="logVerbosityEntriesMaxLevelInfo">
|
||||
<item>@string/log_notice</item>
|
||||
<item>@string/log_error</item>
|
||||
<item>@string/log_warning</item>
|
||||
<item>@string/log_info</item>
|
||||
</string-array>
|
||||
<!-- GameCube System Languages -->
|
||||
<integer-array name="logVerbosityValuesMaxLevelInfo">
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
</integer-array>
|
||||
<string-array name="logVerbosityEntriesMaxLevelDebug">
|
||||
<item>@string/log_notice</item>
|
||||
<item>@string/log_error</item>
|
||||
<item>@string/log_warning</item>
|
||||
<item>@string/log_info</item>
|
||||
<item>@string/log_debug</item>
|
||||
</string-array>
|
||||
<integer-array name="logVerbosityValuesMaxLevelDebug">
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
|
|
@ -193,29 +95,7 @@
|
|||
<item>5</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- Video backend selection -->
|
||||
<string-array name="videoBackendEntries">
|
||||
<item>@string/backend_opengl</item>
|
||||
<item>@string/backend_vulkan</item>
|
||||
<item>@string/backend_software</item>
|
||||
<item>@string/backend_null</item>
|
||||
</string-array>
|
||||
<string-array name="videoBackendValues">
|
||||
<item>OGL</item>
|
||||
<item>Vulkan</item>
|
||||
<item>Software Renderer</item>
|
||||
<item>Null</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Wii Remote extensions -->
|
||||
<string-array name="wiimoteExtensionsEntries">
|
||||
<item>@string/extension_none</item>
|
||||
<item>@string/extension_nunchuk</item>
|
||||
<item>@string/extension_classic</item>
|
||||
<item>@string/extension_guitar</item>
|
||||
<item>@string/extension_drums</item>
|
||||
<item>@string/extension_turntable</item>
|
||||
</string-array>
|
||||
<!-- Slot A & B Device selection -->
|
||||
<integer-array name="wiimoteExtensionsValues">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
|
|
@ -224,40 +104,19 @@
|
|||
<item>4</item>
|
||||
<item>5</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- Texture Cache Accuracy Preference -->
|
||||
<string-array name="textureCacheAccuracyEntries">
|
||||
<item>@string/accuracy_fast</item>
|
||||
<item>@string/accuracy_medium</item>
|
||||
<item>@string/accuracy_safe</item>
|
||||
</string-array>
|
||||
<integer-array name="textureCacheAccuracyValues">
|
||||
<item>128</item>
|
||||
<item>512</item>
|
||||
<item>0</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- Shader Compilation Mode Preference -->
|
||||
<string-array name="shaderCompilationModeEntries">
|
||||
<item>@string/shader_compilation_specialized</item>
|
||||
<item>@string/shader_compilation_exclusive_ubershaders</item>
|
||||
<item>@string/shader_compilation_hybrid_ubershaders</item>
|
||||
<item>@string/shader_compilation_skip_drawing</item>
|
||||
</string-array>
|
||||
<!-- Slot SP1 Device selection -->
|
||||
<integer-array name="shaderCompilationModeValues">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- Shader Compilation Mode Dynamic Descriptions -->
|
||||
<string-array name="shaderCompilationDescriptionEntries">
|
||||
<item>@string/shader_compilation_specialized_description</item>
|
||||
<item>@string/shader_compilation_exclusive_ubershaders_description</item>
|
||||
<item>@string/shader_compilation_hybrid_ubershaders_description</item>
|
||||
<item>@string/shader_compilation_skip_drawing_description</item>
|
||||
</string-array>
|
||||
<integer-array name="shaderCompilationDescriptionValues">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
|
|
@ -265,15 +124,7 @@
|
|||
<item>3</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- Internal Resolution Preference -->
|
||||
<string-array name="internalResolutionEntries">
|
||||
<item>@string/resolution_one_native</item>
|
||||
<item>@string/resolution_two_native</item>
|
||||
<item>@string/resolution_three_native</item>
|
||||
<item>@string/resolution_four_native</item>
|
||||
<item>@string/resolution_five_native</item>
|
||||
<item>@string/resolution_six_native</item>
|
||||
</string-array>
|
||||
<!-- Wii System Languages -->
|
||||
<integer-array name="internalResolutionValues">
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
|
|
@ -282,14 +133,6 @@
|
|||
<item>5</item>
|
||||
<item>6</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- FSAA Preference -->
|
||||
<string-array name="FSAAEntries" translatable="false">
|
||||
<item>@string/multiple_off</item>
|
||||
<item>@string/multiple_two</item>
|
||||
<item>@string/multiple_four</item>
|
||||
<item>@string/multiple_eight</item>
|
||||
</string-array>
|
||||
<integer-array name="FSAAValues" translatable="false">
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
|
|
@ -297,14 +140,7 @@
|
|||
<item>8</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- Anisotropic Filtering Preference -->
|
||||
<string-array name="anisotropicFilteringEntries">
|
||||
<item>@string/filtering_default</item>
|
||||
<item>@string/multiple_two</item>
|
||||
<item>@string/multiple_four</item>
|
||||
<item>@string/multiple_eight</item>
|
||||
<item>@string/multiple_sixteen</item>
|
||||
</string-array>
|
||||
<!-- Sound Mode -->
|
||||
<integer-array name="anisotropicFilteringValues">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
|
|
@ -312,40 +148,19 @@
|
|||
<item>3</item>
|
||||
<item>4</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- Texture Filtering Preference -->
|
||||
<string-array name="textureFilteringEntries">
|
||||
<item>@string/filtering_default</item>
|
||||
<item>@string/filtering_nearest</item>
|
||||
<item>@string/filtering_linear</item>
|
||||
</string-array>
|
||||
<integer-array name="textureFilteringValues">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- Stereoscopy Preference -->
|
||||
<string-array name="stereoscopyEntries">
|
||||
<item>@string/stereoscopy_off</item>
|
||||
<item>@string/stereoscopy_side_by_side</item>
|
||||
<item>@string/stereoscopy_top_and_bottom</item>
|
||||
<item>@string/stereoscopy_anaglyph</item>
|
||||
</string-array>
|
||||
<!-- Sensor Bar Position -->
|
||||
<integer-array name="stereoscopyValues">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- Aspect Ratio Preference -->
|
||||
<string-array name="aspectRatioEntries">
|
||||
<item>@string/aspect_ratio_auto</item>
|
||||
<item>@string/aspect_ratio_force_sixteen_by_nine</item>
|
||||
<item>@string/aspect_ratio_force_four_by_three</item>
|
||||
<item>@string/aspect_ratio_stretch</item>
|
||||
</string-array>
|
||||
<integer-array name="aspectRatioValues">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
|
|
@ -353,6 +168,329 @@
|
|||
<item>3</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- Log Verbosity selection based on LogLevel in Common/Logging/Log.h -->
|
||||
<integer-array name="gcpadTypeValues">
|
||||
<item>0</item>
|
||||
<item>6</item>
|
||||
<item>7</item>
|
||||
<item>8</item>
|
||||
<item>9</item>
|
||||
<item>10</item>
|
||||
<item>11</item>
|
||||
<item>12</item>
|
||||
<item>13</item>
|
||||
</integer-array>
|
||||
<integer-array name="wiimoteTypeValues">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
</integer-array>
|
||||
<integer-array name="orientationValues">
|
||||
<item>0</item>
|
||||
<item>8</item>
|
||||
<item>1</item>
|
||||
<item>-1</item>
|
||||
</integer-array>
|
||||
<integer-array name="themeValues">
|
||||
<item>0</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- Video backend selection -->
|
||||
<integer-array name="themeValuesA12">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
</integer-array>
|
||||
<integer-array name="themeModeValues">
|
||||
<item>-1</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- Wii Remote extensions -->
|
||||
<integer-array name="synchronizeGpuThreadValues">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
</integer-array>
|
||||
<integer-array name="convertFormatValues">
|
||||
<item>0</item>
|
||||
<item>3</item>
|
||||
<item>7</item>
|
||||
<item>8</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- Texture Cache Accuracy Preference -->
|
||||
<integer-array name="convertBlockSizeGczValues">
|
||||
<item>32768</item>
|
||||
</integer-array>
|
||||
<integer-array name="convertBlockSizeWiaValues">
|
||||
<item>2097152</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- Shader Compilation Mode Preference -->
|
||||
<integer-array name="convertBlockSizeRvzValues">
|
||||
<item>32768</item>
|
||||
<item>65536</item>
|
||||
<item>131072</item>
|
||||
<item>262144</item>
|
||||
<item>524288</item>
|
||||
<item>1048576</item>
|
||||
<item>2097152</item>
|
||||
</integer-array>
|
||||
<integer-array name="convertCompressionGczValues">
|
||||
<item>0</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- Shader Compilation Mode Dynamic Descriptions -->
|
||||
<integer-array name="convertCompressionWiaValues">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
</integer-array>
|
||||
<integer-array name="convertCompressionRvzValues">
|
||||
<item>0</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
<item>5</item>
|
||||
<item>6</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- Internal Resolution Preference -->
|
||||
<integer-array name="convertCompressionLevelValues">
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
<item>5</item>
|
||||
<item>6</item>
|
||||
<item>7</item>
|
||||
<item>8</item>
|
||||
<item>9</item>
|
||||
</integer-array>
|
||||
<integer-array name="convertCompressionLevelZstdValues">
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
<item>5</item>
|
||||
<item>6</item>
|
||||
<item>7</item>
|
||||
<item>8</item>
|
||||
<item>9</item>
|
||||
<item>10</item>
|
||||
<item>11</item>
|
||||
<item>12</item>
|
||||
<item>13</item>
|
||||
<item>14</item>
|
||||
<item>15</item>
|
||||
<item>16</item>
|
||||
<item>17</item>
|
||||
<item>18</item>
|
||||
<item>19</item>
|
||||
<item>20</item>
|
||||
<item>21</item>
|
||||
<item>22</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- FSAA Preference -->
|
||||
<integer-array name="colorSpaceValues">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
</integer-array>
|
||||
<string-array name="regionEntries">
|
||||
<item>NTSC-J</item>
|
||||
<item>NTSC-U</item>
|
||||
<item>PAL</item>
|
||||
<item>NTSC-K</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Anisotropic Filtering Preference -->
|
||||
<string-array name="emuCoresEntriesX86_64">
|
||||
<item>@string/jit_recompiler_x86</item>
|
||||
<item>@string/cached_interpreter_slower</item>
|
||||
<item>@string/interpreter_slowest</item>
|
||||
</string-array>
|
||||
<string-array name="emuCoresEntriesARM64">
|
||||
<item>@string/jit_recompiler_arm64</item>
|
||||
<item>@string/cached_interpreter_slower</item>
|
||||
<item>@string/interpreter_slowest</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Texture Filtering Preference -->
|
||||
<string-array name="emuCoresEntriesGeneric">
|
||||
<item>@string/cached_interpreter</item>
|
||||
<item>@string/interpreter</item>
|
||||
</string-array>
|
||||
<string-array name="dspEngineEntriesX86_64">
|
||||
<item>@string/dsp_hle</item>
|
||||
<item>@string/dsp_lle_recompiler</item>
|
||||
<item>@string/dsp_lle_interpreter</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Stereoscopy Preference -->
|
||||
<string-array name="dspEngineEntriesGeneric">
|
||||
<item>@string/dsp_hle</item>
|
||||
<item>@string/dsp_lle_interpreter</item>
|
||||
</string-array>
|
||||
<string-array name="gameCubeSystemLanguageEntries">
|
||||
<item>@string/language_english</item>
|
||||
<item>@string/language_german</item>
|
||||
<item>@string/language_french</item>
|
||||
<item>@string/language_spanish</item>
|
||||
<item>@string/language_italian</item>
|
||||
<item>@string/language_dutch</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Aspect Ratio Preference -->
|
||||
<string-array name="slotDeviceEntries">
|
||||
<item>@string/device_nothing</item>
|
||||
<item>@string/device_dummy</item>
|
||||
<item>@string/device_memory_card</item>
|
||||
<item>@string/device_gci_folder</item>
|
||||
</string-array>
|
||||
<string-array name="serialPort1DeviceEntries">
|
||||
<item>@string/device_nothing</item>
|
||||
<item>@string/device_dummy</item>
|
||||
<item>@string/broadband_adapter_xlink</item>
|
||||
<item>@string/broadband_adapter_hle</item>
|
||||
<item>@string/broadband_adapter_tapserver</item>
|
||||
<item>@string/modem_adapter_tapserver</item>
|
||||
<item>@string/sp1_am_baseboard</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="wiiSystemLanguageEntries">
|
||||
<item>@string/language_japanese</item>
|
||||
<item>@string/language_english</item>
|
||||
<item>@string/language_german</item>
|
||||
<item>@string/language_french</item>
|
||||
<item>@string/language_spanish</item>
|
||||
<item>@string/language_italian</item>
|
||||
<item>@string/language_dutch</item>
|
||||
<item>@string/language_simplified_chinese</item>
|
||||
<item>@string/language_traditional_chinese</item>
|
||||
<item>@string/language_korean</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="soundModeEntries">
|
||||
<item>@string/sound_mode_mono</item>
|
||||
<item>@string/sound_mode_stereo</item>
|
||||
<item>@string/sound_mode_surround</item>
|
||||
</string-array>
|
||||
<string-array name="sensorBarPositionEntries">
|
||||
<item>@string/sensor_position_top</item>
|
||||
<item>@string/sensor_position_bottom</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="logVerbosityEntriesMaxLevelInfo">
|
||||
<item>@string/log_notice</item>
|
||||
<item>@string/log_error</item>
|
||||
<item>@string/log_warning</item>
|
||||
<item>@string/log_info</item>
|
||||
</string-array>
|
||||
<string-array name="logVerbosityEntriesMaxLevelDebug">
|
||||
<item>@string/log_notice</item>
|
||||
<item>@string/log_error</item>
|
||||
<item>@string/log_warning</item>
|
||||
<item>@string/log_info</item>
|
||||
<item>@string/log_debug</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="videoBackendEntries">
|
||||
<item>@string/backend_opengl</item>
|
||||
<item>@string/backend_vulkan</item>
|
||||
<item>@string/backend_software</item>
|
||||
<item>@string/backend_null</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="videoBackendValues">
|
||||
<item>OGL</item>
|
||||
<item>Vulkan</item>
|
||||
<item>Software Renderer</item>
|
||||
<item>Null</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="wiimoteExtensionsEntries">
|
||||
<item>@string/extension_none</item>
|
||||
<item>@string/extension_nunchuk</item>
|
||||
<item>@string/extension_classic</item>
|
||||
<item>@string/extension_guitar</item>
|
||||
<item>@string/extension_drums</item>
|
||||
<item>@string/extension_turntable</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="textureCacheAccuracyEntries">
|
||||
<item>@string/accuracy_fast</item>
|
||||
<item>@string/accuracy_medium</item>
|
||||
<item>@string/accuracy_safe</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="shaderCompilationModeEntries">
|
||||
<item>@string/shader_compilation_specialized</item>
|
||||
<item>@string/shader_compilation_exclusive_ubershaders</item>
|
||||
<item>@string/shader_compilation_hybrid_ubershaders</item>
|
||||
<item>@string/shader_compilation_skip_drawing</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="shaderCompilationDescriptionEntries">
|
||||
<item>@string/shader_compilation_specialized_description</item>
|
||||
<item>@string/shader_compilation_exclusive_ubershaders_description</item>
|
||||
<item>@string/shader_compilation_hybrid_ubershaders_description</item>
|
||||
<item>@string/shader_compilation_skip_drawing_description</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="internalResolutionEntries">
|
||||
<item>@string/resolution_one_native</item>
|
||||
<item>@string/resolution_two_native</item>
|
||||
<item>@string/resolution_three_native</item>
|
||||
<item>@string/resolution_four_native</item>
|
||||
<item>@string/resolution_five_native</item>
|
||||
<item>@string/resolution_six_native</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="FSAAEntries" translatable="false">
|
||||
<item>@string/multiple_off</item>
|
||||
<item>@string/multiple_two</item>
|
||||
<item>@string/multiple_four</item>
|
||||
<item>@string/multiple_eight</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="anisotropicFilteringEntries">
|
||||
<item>@string/filtering_default</item>
|
||||
<item>@string/multiple_two</item>
|
||||
<item>@string/multiple_four</item>
|
||||
<item>@string/multiple_eight</item>
|
||||
<item>@string/multiple_sixteen</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="textureFilteringEntries">
|
||||
<item>@string/filtering_default</item>
|
||||
<item>@string/filtering_nearest</item>
|
||||
<item>@string/filtering_linear</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="stereoscopyEntries">
|
||||
<item>@string/stereoscopy_off</item>
|
||||
<item>@string/stereoscopy_side_by_side</item>
|
||||
<item>@string/stereoscopy_top_and_bottom</item>
|
||||
<item>@string/stereoscopy_anaglyph</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="aspectRatioEntries">
|
||||
<item>@string/aspect_ratio_auto</item>
|
||||
<item>@string/aspect_ratio_force_sixteen_by_nine</item>
|
||||
<item>@string/aspect_ratio_force_four_by_three</item>
|
||||
<item>@string/aspect_ratio_stretch</item>
|
||||
</string-array>
|
||||
<string-array name="countryNames">
|
||||
<item>@string/country_europe</item>
|
||||
<item>@string/country_japan</item>
|
||||
|
|
@ -370,6 +508,7 @@
|
|||
<item>@string/country_unknown</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Monet must always have a value exclusive to >= API 31 -->
|
||||
<string-array name="gcpadTypeEntries">
|
||||
<item>@string/gcpad_disabled</item>
|
||||
<item>@string/gcpad_emulated</item>
|
||||
|
|
@ -379,29 +518,13 @@
|
|||
<item>@string/gcpad_taru_konga</item>
|
||||
<item>@string/gcpad_am_baseboard</item>
|
||||
<item>@string/gcpad_gc_adapter</item>
|
||||
<item>GBA</item>
|
||||
</string-array>
|
||||
<integer-array name="gcpadTypeValues">
|
||||
<item>0</item>
|
||||
<item>6</item>
|
||||
<item>7</item>
|
||||
<item>8</item>
|
||||
<item>9</item>
|
||||
<item>10</item>
|
||||
<item>11</item>
|
||||
<item>12</item>
|
||||
</integer-array>
|
||||
|
||||
<string-array name="wiimoteTypeEntries">
|
||||
<item>@string/wiimote_disabled</item>
|
||||
<item>@string/wiimote_emulated</item>
|
||||
<item>@string/wiimote_real</item>
|
||||
</string-array>
|
||||
<integer-array name="wiimoteTypeValues">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
</integer-array>
|
||||
|
||||
<string-array name="gcpadButtons">
|
||||
<item>A</item>
|
||||
<item>B</item>
|
||||
|
|
@ -415,7 +538,6 @@
|
|||
<item>@string/gamepad_main_stick</item>
|
||||
<item>@string/gamepad_c_stick</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="gcpadLatchableButtons">
|
||||
<item>A</item>
|
||||
<item>B</item>
|
||||
|
|
@ -437,7 +559,6 @@
|
|||
<item>@string/gamepad_home</item>
|
||||
<item>@string/gamepad_d_pad</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="wiimoteLatchableButtons">
|
||||
<item>A</item>
|
||||
<item>B</item>
|
||||
|
|
@ -461,7 +582,6 @@
|
|||
<item>Z</item>
|
||||
<item>@string/gamepad_nunchuk_stick</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="nunchukLatchableButtons">
|
||||
<item>A</item>
|
||||
<item>B</item>
|
||||
|
|
@ -504,7 +624,6 @@
|
|||
<item>ZL</item>
|
||||
<item>ZR</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="irModeEntries">
|
||||
<item>@string/ir_disabled</item>
|
||||
<item>@string/ir_follow</item>
|
||||
|
|
@ -516,7 +635,6 @@
|
|||
<item>@string/double_tap_b</item>
|
||||
<item>@string/double_tap_2</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="doubleTapWithClassic">
|
||||
<item>@string/double_tap_a</item>
|
||||
<item>@string/double_tap_b</item>
|
||||
|
|
@ -530,26 +648,13 @@
|
|||
<item>@string/orientation_portrait</item>
|
||||
<item>@string/orientation_auto</item>
|
||||
</string-array>
|
||||
<integer-array name="orientationValues">
|
||||
<item>0</item>
|
||||
<item>8</item>
|
||||
<item>1</item>
|
||||
<item>-1</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- Monet must always have a value exclusive to >= API 31 -->
|
||||
<string-array name="themeEntries">
|
||||
<item>@string/theme_default</item>
|
||||
<item>@string/theme_material_default</item>
|
||||
<item>@string/theme_green</item>
|
||||
<item>@string/theme_pink</item>
|
||||
</string-array>
|
||||
<integer-array name="themeValues">
|
||||
<item>0</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
</integer-array>
|
||||
|
||||
<string-array name="themeEntriesA12">
|
||||
<item>@string/theme_default</item>
|
||||
<item>@string/theme_material_you</item>
|
||||
|
|
@ -557,36 +662,17 @@
|
|||
<item>@string/theme_green</item>
|
||||
<item>@string/theme_pink</item>
|
||||
</string-array>
|
||||
<integer-array name="themeValuesA12">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
</integer-array>
|
||||
|
||||
<string-array name="themeModeEntries">
|
||||
<item>@string/theme_mode_follow_system</item>
|
||||
<item>@string/theme_mode_light</item>
|
||||
<item>@string/theme_mode_dark</item>
|
||||
</string-array>
|
||||
<integer-array name="themeModeValues">
|
||||
<item>-1</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
</integer-array>
|
||||
|
||||
<string-array name="synchronizeGpuThreadEntries">
|
||||
<item>@string/sync_gpu_never</item>
|
||||
<item>@string/sync_gpu_idle</item>
|
||||
<item>@string/sync_gpu_always</item>
|
||||
</string-array>
|
||||
<integer-array name="synchronizeGpuThreadValues">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
</integer-array>
|
||||
|
||||
<string-array name="motionControlsEntries">
|
||||
<item>@string/motion_device_with_pointer</item>
|
||||
<item>@string/motion_device_without_pointer</item>
|
||||
|
|
@ -599,27 +685,13 @@
|
|||
<item>WIA</item>
|
||||
<item>RVZ</item>
|
||||
</string-array>
|
||||
<integer-array name="convertFormatValues">
|
||||
<item>0</item>
|
||||
<item>3</item>
|
||||
<item>7</item>
|
||||
<item>8</item>
|
||||
</integer-array>
|
||||
|
||||
<string-array name="convertBlockSizeGczEntries">
|
||||
<item>@string/block_size_32_kib</item>
|
||||
</string-array>
|
||||
<integer-array name="convertBlockSizeGczValues">
|
||||
<item>32768</item>
|
||||
</integer-array>
|
||||
|
||||
<string-array name="convertBlockSizeWiaEntries">
|
||||
<item>@string/block_size_2_mib</item>
|
||||
</string-array>
|
||||
<integer-array name="convertBlockSizeWiaValues">
|
||||
<item>2097152</item>
|
||||
</integer-array>
|
||||
|
||||
<string-array name="convertBlockSizeRvzEntries">
|
||||
<item>@string/block_size_32_kib</item>
|
||||
<item>@string/block_size_64_kib</item>
|
||||
|
|
@ -629,23 +701,10 @@
|
|||
<item>@string/block_size_1_mib</item>
|
||||
<item>@string/block_size_2_mib</item>
|
||||
</string-array>
|
||||
<integer-array name="convertBlockSizeRvzValues">
|
||||
<item>32768</item>
|
||||
<item>65536</item>
|
||||
<item>131072</item>
|
||||
<item>262144</item>
|
||||
<item>524288</item>
|
||||
<item>1048576</item>
|
||||
<item>2097152</item>
|
||||
</integer-array>
|
||||
|
||||
<string-array name="convertCompressionGczEntries">
|
||||
<item>@string/compression_deflate</item>
|
||||
</string-array>
|
||||
<integer-array name="convertCompressionGczValues">
|
||||
<item>0</item>
|
||||
</integer-array>
|
||||
|
||||
<string-array name="convertCompressionWiaEntries">
|
||||
<item>@string/compression_none</item>
|
||||
<item>@string/compression_purge</item>
|
||||
|
|
@ -653,13 +712,6 @@
|
|||
<item>@string/compression_lzma</item>
|
||||
<item>@string/compression_lzma2</item>
|
||||
</string-array>
|
||||
<integer-array name="convertCompressionWiaValues">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
</integer-array>
|
||||
|
||||
<string-array name="convertCompressionRvzEntries">
|
||||
<item>@string/compression_none</item>
|
||||
|
|
@ -668,15 +720,6 @@
|
|||
<item>@string/compression_lzma2</item>
|
||||
<item>@string/compression_zstandard</item>
|
||||
</string-array>
|
||||
<integer-array name="convertCompressionRvzValues">
|
||||
<item>0</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
<item>5</item>
|
||||
<item>6</item>
|
||||
</integer-array>
|
||||
|
||||
<string-array name="convertCompressionLevelEntries">
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
|
|
@ -688,17 +731,6 @@
|
|||
<item>8</item>
|
||||
<item>9</item>
|
||||
</string-array>
|
||||
<integer-array name="convertCompressionLevelValues">
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
<item>5</item>
|
||||
<item>6</item>
|
||||
<item>7</item>
|
||||
<item>8</item>
|
||||
<item>9</item>
|
||||
</integer-array>
|
||||
|
||||
<string-array name="convertCompressionLevelZstdEntries">
|
||||
<item>1</item>
|
||||
|
|
@ -724,39 +756,9 @@
|
|||
<item>21</item>
|
||||
<item>22</item>
|
||||
</string-array>
|
||||
<integer-array name="convertCompressionLevelZstdValues">
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
<item>5</item>
|
||||
<item>6</item>
|
||||
<item>7</item>
|
||||
<item>8</item>
|
||||
<item>9</item>
|
||||
<item>10</item>
|
||||
<item>11</item>
|
||||
<item>12</item>
|
||||
<item>13</item>
|
||||
<item>14</item>
|
||||
<item>15</item>
|
||||
<item>16</item>
|
||||
<item>17</item>
|
||||
<item>18</item>
|
||||
<item>19</item>
|
||||
<item>20</item>
|
||||
<item>21</item>
|
||||
<item>22</item>
|
||||
</integer-array>
|
||||
|
||||
<string-array name="colorSpaceEntries">
|
||||
<item>@string/ntscm_space</item>
|
||||
<item>@string/ntscj_space</item>
|
||||
<item>@string/pal_space</item>
|
||||
</string-array>
|
||||
<integer-array name="colorSpaceValues">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
</integer-array>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -89,6 +89,8 @@
|
|||
<string name="gba_bios_path">BIOS</string>
|
||||
<string name="gb_player_rom">Game Boy Player ROM</string>
|
||||
<string name="gba_saves_path">Saves</string>
|
||||
<string name="gba_rom_path">GBA ROM Path</string>
|
||||
<string name="gba_rom_path_description">Rom to load for this slot. Long-press to clear</string>
|
||||
<string name="wii_submenu">Wii</string>
|
||||
<string name="wii_misc_settings">Misc Settings</string>
|
||||
<string name="wii_sd_card_settings">SD Card Settings</string>
|
||||
|
|
|
|||
|
|
@ -150,6 +150,11 @@ JNIEnv* GetEnvForThread()
|
|||
return owned.env;
|
||||
}
|
||||
|
||||
JavaVM* GetJavaVM()
|
||||
{
|
||||
return s_java_vm;
|
||||
}
|
||||
|
||||
jclass GetStringClass()
|
||||
{
|
||||
return s_string_class;
|
||||
|
|
@ -574,12 +579,12 @@ jmethodID GetAudioUtilsGetFramesPerBuffer()
|
|||
{
|
||||
return s_audio_utils_get_frames_per_buffer;
|
||||
}
|
||||
|
||||
} // namespace IDCache
|
||||
|
||||
extern "C" {
|
||||
|
||||
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
|
||||
|
||||
{
|
||||
s_java_vm = vm;
|
||||
|
||||
|
|
|
|||
|
|
@ -124,4 +124,6 @@ jclass GetAudioUtilsClass();
|
|||
jmethodID GetAudioUtilsGetSampleRate();
|
||||
jmethodID GetAudioUtilsGetFramesPerBuffer();
|
||||
|
||||
JavaVM* GetJavaVM();
|
||||
|
||||
} // namespace IDCache
|
||||
|
|
|
|||
|
|
@ -35,6 +35,20 @@ Java_org_dolphinemu_dolphinemu_features_input_model_InputOverrider_unregisterWii
|
|||
{
|
||||
ciface::Touch::UnregisterWiiInputOverrider(controller_index);
|
||||
}
|
||||
// Android GBA emu.
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_dolphinemu_dolphinemu_features_input_model_InputOverrider_registerGBA(JNIEnv*, jclass,
|
||||
int controller_index)
|
||||
{
|
||||
ciface::Touch::RegisterGBAInputOverrider(controller_index);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_dolphinemu_dolphinemu_features_input_model_InputOverrider_unregisterGBA(
|
||||
JNIEnv*, jclass, int controller_index)
|
||||
{
|
||||
ciface::Touch::UnregisterGBAInputOverrider(controller_index);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_dolphinemu_dolphinemu_features_input_model_InputOverrider_setControlState(
|
||||
|
|
|
|||
|
|
@ -69,6 +69,14 @@
|
|||
#include "jni/AndroidCommon/IDCache.h"
|
||||
#include "jni/Host.h"
|
||||
|
||||
#include <shared_mutex>
|
||||
#ifdef HAS_LIBMGBA
|
||||
#include "Core/HW/GBACore.h"
|
||||
#include "Core/HW/SI/SI.h"
|
||||
#include "Core/HW/SI/SI_Device.h"
|
||||
#include "Core/HW/SI/SI_DeviceGBAEmu.h"
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr char DOLPHIN_TAG[] = "DolphinEmuNative";
|
||||
|
|
@ -815,4 +823,52 @@ Java_org_dolphinemu_dolphinemu_NativeLibrary_GetCurrentTitleDescriptionUnchecked
|
|||
|
||||
return ToJString(env, description);
|
||||
}
|
||||
// Android Gba Emulation.
|
||||
JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_copyGBAFramebuffer(
|
||||
JNIEnv* env, jclass, jint slot, jobject byte_buffer)
|
||||
{
|
||||
#ifdef HAS_LIBMGBA
|
||||
if (slot < 0 || slot >= 4)
|
||||
return JNI_FALSE;
|
||||
auto core = Core::System::GetInstance().GetSerialInterface().GetGBACore(slot);
|
||||
if (!core)
|
||||
return JNI_FALSE;
|
||||
std::shared_lock<std::shared_mutex> lock(core->GetVideoBufferMutex());
|
||||
const auto buffer = core->GetVideoBuffer();
|
||||
if (buffer.empty())
|
||||
return JNI_FALSE;
|
||||
void* dst = env->GetDirectBufferAddress(byte_buffer);
|
||||
if (!dst)
|
||||
return JNI_FALSE;
|
||||
jlong capacity = env->GetDirectBufferCapacity(byte_buffer);
|
||||
if (static_cast<size_t>(capacity) < buffer.size() * sizeof(u32))
|
||||
return JNI_FALSE;
|
||||
memcpy(dst, buffer.data(), buffer.size() * sizeof(u32));
|
||||
return JNI_TRUE;
|
||||
#else
|
||||
return JNI_FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_resetGBACore(JNIEnv*, jclass,
|
||||
jint slot)
|
||||
{
|
||||
#ifdef HAS_LIBMGBA
|
||||
Core::System::GetInstance().GetSerialInterface().ResetGBACore(slot);
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_getGBAGameTitle(JNIEnv* env,
|
||||
jclass,
|
||||
jint slot)
|
||||
{
|
||||
return ToJString(env, Core::System::GetInstance().GetSerialInterface().GetGBAGameTitle(slot));
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_getGBAGameCode(JNIEnv* env,
|
||||
jclass,
|
||||
jint slot)
|
||||
{
|
||||
return ToJString(env, Core::System::GetInstance().GetSerialInterface().GetGBAGameCode(slot));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
|
||||
#ifdef ANDROID
|
||||
#include "jni/AndroidCommon/AndroidCommon.h"
|
||||
#include "jni/AndroidCommon/IDCache.h"
|
||||
#endif
|
||||
|
||||
namespace HW::GBA
|
||||
|
|
@ -245,6 +246,8 @@ bool Core::Start(u64 gc_ticks)
|
|||
mGameInfo info;
|
||||
m_core->getGameInfo(m_core, &info);
|
||||
m_game_title = info.title;
|
||||
// android region code furture use.
|
||||
m_game_code = std::string(info.code, 4);
|
||||
|
||||
m_save_path = NetPlay::IsNetPlayRunning() ? NetPlay::GetGBASavePath(m_device_number) :
|
||||
GetSavePath(m_rom_path, m_device_number);
|
||||
|
|
@ -295,6 +298,9 @@ void Core::Stop()
|
|||
m_save_path = {};
|
||||
m_rom_hash = {};
|
||||
m_game_title = {};
|
||||
// android future use, game code match.
|
||||
m_game_title = {};
|
||||
m_game_code = {};
|
||||
}
|
||||
|
||||
void Core::Reset()
|
||||
|
|
@ -374,12 +380,18 @@ bool Core::LoadBIOS(const char* bios_path)
|
|||
bool Core::LoadSave(const char* save_path)
|
||||
{
|
||||
VFile* vf = VFileOpen(save_path, O_CREAT | O_RDWR);
|
||||
std::string path_str = save_path;
|
||||
if (!vf)
|
||||
{
|
||||
PanicAlertFmtT("Error: GBA{0} failed to open the save in {1}", m_device_number + 1, save_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
if (path_str.starts_with("content://"))
|
||||
vf = VFileFromFD(OpenAndroidContent(save_path, "rw"));
|
||||
#endif
|
||||
|
||||
if (!m_core->loadSave(m_core, vf))
|
||||
{
|
||||
PanicAlertFmtT("Error: GBA{0} failed to load the save in {1}", m_device_number + 1, save_path);
|
||||
|
|
@ -445,6 +457,75 @@ void Core::SetAudioBufferSize()
|
|||
m_core->setAudioBufferSize(m_core, AUDIO_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
// Android GBAcore emu
|
||||
#ifdef ANDROID
|
||||
#include <atomic>
|
||||
namespace
|
||||
{
|
||||
static std::atomic<jmethodID> s_on_gba_frame{nullptr};
|
||||
struct GBAThreadJNI
|
||||
{
|
||||
JNIEnv* env = nullptr;
|
||||
bool attached = false;
|
||||
|
||||
GBAThreadJNI()
|
||||
{
|
||||
JavaVM* vm = IDCache::GetJavaVM();
|
||||
if (!vm)
|
||||
return;
|
||||
jint rc = vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
|
||||
if (rc == JNI_EDETACHED)
|
||||
{
|
||||
if (vm->AttachCurrentThread(&env, nullptr) != JNI_OK)
|
||||
env = nullptr;
|
||||
else
|
||||
attached = true;
|
||||
}
|
||||
else if (rc != JNI_OK)
|
||||
{
|
||||
env = nullptr;
|
||||
return;
|
||||
}
|
||||
if (s_on_gba_frame.load() == nullptr)
|
||||
{
|
||||
jclass cls = IDCache::GetNativeLibraryClass();
|
||||
if (cls)
|
||||
{
|
||||
jmethodID mid = env->GetStaticMethodID(cls, "onGBAFrame", "(I)V");
|
||||
if (mid)
|
||||
{
|
||||
s_on_gba_frame.store(mid);
|
||||
}
|
||||
else
|
||||
{
|
||||
env->ExceptionClear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
#endif
|
||||
static void GBACore_PushFrameReady(int slot)
|
||||
{
|
||||
#ifdef ANDROID
|
||||
|
||||
thread_local GBAThreadJNI tls;
|
||||
|
||||
jmethodID methodId = s_on_gba_frame.load();
|
||||
if (!tls.env || !methodId)
|
||||
return;
|
||||
tls.env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), s_on_gba_frame,
|
||||
static_cast<jint>(slot));
|
||||
|
||||
if (tls.env->ExceptionCheck())
|
||||
{
|
||||
tls.env->ExceptionDescribe();
|
||||
tls.env->ExceptionClear();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Core::AddCallbacks()
|
||||
{
|
||||
mCoreCallbacks callbacks{};
|
||||
|
|
@ -455,8 +536,12 @@ void Core::AddCallbacks()
|
|||
};
|
||||
callbacks.videoFrameEnded = [](void* context) {
|
||||
auto core = static_cast<Core*>(context);
|
||||
if (auto host = core->m_host.lock())
|
||||
host->FrameEnded(core->m_video_buffer);
|
||||
{
|
||||
std::unique_lock<std::shared_mutex> lock(core->m_video_buffer_mutex);
|
||||
if (auto host = core->m_host.lock())
|
||||
host->FrameEnded(core->m_video_buffer);
|
||||
}
|
||||
GBACore_PushFrameReady(core->m_device_number);
|
||||
};
|
||||
m_core->addCoreCallbacks(m_core, &callbacks);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <shared_mutex>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
|
@ -90,6 +91,10 @@ public:
|
|||
|
||||
mAudioBuffer* GetAudioBuffer() { return m_core->getAudioBuffer(m_core); }
|
||||
std::span<const u32> GetVideoBuffer() const { return m_video_buffer; }
|
||||
// Android game code future use.
|
||||
std::string GetGameCode() const { return m_game_code; }
|
||||
// android video bufffer mutex.
|
||||
std::shared_mutex& GetVideoBufferMutex() { return m_video_buffer_mutex; }
|
||||
|
||||
mPlatform GetPlatform() const { return m_core->platform(m_core); }
|
||||
u32 GetAudioSampleRate() const { return m_core->audioSampleRate(m_core); }
|
||||
|
|
@ -139,6 +144,10 @@ private:
|
|||
std::string m_save_path;
|
||||
std::array<u8, 20> m_rom_hash{};
|
||||
std::string m_game_title;
|
||||
// android game code future use.
|
||||
std::string m_game_code;
|
||||
// guard for m_video_buffer vulkan
|
||||
mutable std::shared_mutex m_video_buffer_mutex;
|
||||
|
||||
mCore* m_core{};
|
||||
mCoreSync m_core_sync{};
|
||||
|
|
|
|||
|
|
@ -31,6 +31,11 @@
|
|||
|
||||
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
||||
|
||||
#ifdef HAS_LIBMGBA
|
||||
#include "Core/HW/GBACore.h"
|
||||
#include "Core/HW/SI/SI_DeviceGBAEmu.h"
|
||||
#endif
|
||||
|
||||
namespace SerialInterface
|
||||
{
|
||||
// SI Internal Hardware Addresses
|
||||
|
|
@ -597,5 +602,52 @@ u32 SerialInterfaceManager::GetPollXLines()
|
|||
{
|
||||
return m_poll.X;
|
||||
}
|
||||
// Android GBA emulation.
|
||||
std::shared_ptr<HW::GBA::Core> SerialInterfaceManager::GetGBACore(int channel) const
|
||||
{
|
||||
#ifdef HAS_LIBMGBA
|
||||
if (channel < 0 || channel >= MAX_SI_CHANNELS)
|
||||
return nullptr;
|
||||
auto* dev = m_channel[channel].device.get();
|
||||
if (dev && dev->GetDeviceType() == SIDEVICE_GC_GBA_EMULATED)
|
||||
return static_cast<CSIDevice_GBAEmu*>(dev)->GetCore();
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SerialInterfaceManager::ResetGBACore(int channel)
|
||||
{
|
||||
#ifdef HAS_LIBMGBA
|
||||
if (channel < 0 || channel >= MAX_SI_CHANNELS)
|
||||
return;
|
||||
auto* dev = m_channel[channel].device.get();
|
||||
if (dev && dev->GetDeviceType() == SIDEVICE_GC_GBA_EMULATED)
|
||||
static_cast<CSIDevice_GBAEmu*>(dev)->GetCore()->Reset();
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string SerialInterfaceManager::GetGBAGameTitle(int channel) const
|
||||
{
|
||||
#ifdef HAS_LIBMGBA
|
||||
if (channel < 0 || channel >= MAX_SI_CHANNELS)
|
||||
return "";
|
||||
auto* dev = m_channel[channel].device.get();
|
||||
if (dev && dev->GetDeviceType() == SIDEVICE_GC_GBA_EMULATED)
|
||||
return static_cast<CSIDevice_GBAEmu*>(dev)->GetGBAGameTitle();
|
||||
#endif
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string SerialInterfaceManager::GetGBAGameCode(int channel) const
|
||||
{
|
||||
#ifdef HAS_LIBMGBA
|
||||
if (channel < 0 || channel >= MAX_SI_CHANNELS)
|
||||
return "";
|
||||
auto* dev = m_channel[channel].device.get();
|
||||
if (dev && dev->GetDeviceType() == SIDEVICE_GC_GBA_EMULATED)
|
||||
return static_cast<CSIDevice_GBAEmu*>(dev)->GetGBAGameCode();
|
||||
#endif
|
||||
return "";
|
||||
}
|
||||
|
||||
} // namespace SerialInterface
|
||||
|
|
|
|||
|
|
@ -24,6 +24,11 @@ namespace MMIO
|
|||
{
|
||||
class Mapping;
|
||||
}
|
||||
// Android GBA
|
||||
namespace HW::GBA
|
||||
{
|
||||
class Core;
|
||||
}
|
||||
|
||||
namespace SerialInterface
|
||||
{
|
||||
|
|
@ -68,6 +73,11 @@ public:
|
|||
|
||||
u32 GetPollXLines();
|
||||
|
||||
std::shared_ptr<HW::GBA::Core> GetGBACore(int channel) const;
|
||||
void ResetGBACore(int channel);
|
||||
std::string GetGBAGameTitle(int channel) const;
|
||||
std::string GetGBAGameCode(int channel) const;
|
||||
|
||||
static constexpr u32 BUFFER_SIZE = 128;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -172,5 +172,14 @@ void CSIDevice_GBAEmu::OnEvent(u64 userdata, s64 cycles_late)
|
|||
const auto num_cycles = userdata + GetSyncInterval(m_system.GetSystemTimers());
|
||||
m_system.GetSerialInterface().ScheduleEvent(m_device_number, num_cycles);
|
||||
}
|
||||
// android gameID furture use
|
||||
std::string CSIDevice_GBAEmu::GetGBAGameTitle() const
|
||||
{
|
||||
return m_core ? m_core->GetCoreInfo().game_title : "";
|
||||
}
|
||||
std::string CSIDevice_GBAEmu::GetGBAGameCode() const
|
||||
{
|
||||
return m_core ? m_core->GetGameCode() : "";
|
||||
}
|
||||
} // namespace SerialInterface
|
||||
#endif // HAS_LIBMGBA
|
||||
|
|
|
|||
|
|
@ -31,6 +31,11 @@ public:
|
|||
void SendCommand(u32 command, u8 poll) override;
|
||||
void DoState(PointerWrap& p) override;
|
||||
void OnEvent(u64 userdata, s64 cycles_late) override;
|
||||
// android gba core
|
||||
std::shared_ptr<HW::GBA::Core> GetCore() const { return m_core; }
|
||||
// android gamecode match for future use.
|
||||
std::string GetGBAGameTitle() const;
|
||||
std::string GetGBAGameCode() const;
|
||||
|
||||
private:
|
||||
enum class NextAction
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@
|
|||
|
||||
#include "Common/Assert.h"
|
||||
|
||||
#include "Core/HW/GBAPad.h"
|
||||
#include "Core/HW/GBAPadEmu.h"
|
||||
#include "Core/HW/GCPad.h"
|
||||
#include "Core/HW/GCPadEmu.h"
|
||||
#include "Core/HW/Wiimote.h"
|
||||
|
|
@ -144,6 +146,19 @@ const ControlsMap s_classic_controls_map = {{
|
|||
{{WiimoteEmu::Classic::RIGHT_STICK_GROUP, ControllerEmu::ReshapableInput::Y_INPUT_OVERRIDE},
|
||||
ControlID::CLASSIC_RIGHT_STICK_Y},
|
||||
}};
|
||||
// android GBA controls map
|
||||
static const ControlsMap s_gbapad_controls_map = {{
|
||||
{{GBAPad::BUTTONS_GROUP, GBAPad::A_BUTTON}, ControlID::GCPAD_A_BUTTON},
|
||||
{{GBAPad::BUTTONS_GROUP, GBAPad::B_BUTTON}, ControlID::GCPAD_B_BUTTON},
|
||||
{{GBAPad::BUTTONS_GROUP, GBAPad::L_BUTTON}, ControlID::GCPAD_L_DIGITAL},
|
||||
{{GBAPad::BUTTONS_GROUP, GBAPad::R_BUTTON}, ControlID::GCPAD_R_DIGITAL},
|
||||
{{GBAPad::BUTTONS_GROUP, GBAPad::START_BUTTON}, ControlID::GCPAD_START_BUTTON},
|
||||
{{GBAPad::BUTTONS_GROUP, GBAPad::SELECT_BUTTON}, ControlID::GCPAD_Z_BUTTON},
|
||||
{{GBAPad::DPAD_GROUP, DIRECTION_UP}, ControlID::GCPAD_DPAD_UP},
|
||||
{{GBAPad::DPAD_GROUP, DIRECTION_DOWN}, ControlID::GCPAD_DPAD_DOWN},
|
||||
{{GBAPad::DPAD_GROUP, DIRECTION_LEFT}, ControlID::GCPAD_DPAD_LEFT},
|
||||
{{GBAPad::DPAD_GROUP, DIRECTION_RIGHT}, ControlID::GCPAD_DPAD_RIGHT},
|
||||
}};
|
||||
|
||||
ControllerEmu::InputOverrideFunction GetInputOverrideFunction(const ControlsMap& controls_map,
|
||||
size_t i)
|
||||
|
|
@ -220,6 +235,20 @@ void UnregisterWiiInputOverrider(int controller_index)
|
|||
for (size_t i = ControlID::FIRST_WII_CONTROL; i <= ControlID::LAST_WII_CONTROL; ++i)
|
||||
s_state_arrays[controller_index][i].overriding = false;
|
||||
}
|
||||
// android gba overrider
|
||||
void RegisterGBAInputOverrider(int controller_index)
|
||||
{
|
||||
Pad::GetGBAConfig()
|
||||
->GetController(controller_index)
|
||||
->SetInputOverrideFunction(GetInputOverrideFunction(s_gbapad_controls_map, controller_index));
|
||||
}
|
||||
|
||||
void UnregisterGBAInputOverrider(int controller_index)
|
||||
{
|
||||
Pad::GetGBAConfig()->GetController(controller_index)->ClearInputOverrideFunction();
|
||||
for (size_t i = ControlID::FIRST_GC_CONTROL; i <= ControlID::LAST_GC_CONTROL; ++i)
|
||||
s_state_arrays[controller_index][i].overriding = false;
|
||||
}
|
||||
|
||||
void SetControlState(int controller_index, ControlID control, double state)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -80,6 +80,8 @@ void RegisterGameCubeInputOverrider(int controller_index);
|
|||
void RegisterWiiInputOverrider(int controller_index);
|
||||
void UnregisterGameCubeInputOverrider(int controller_index);
|
||||
void UnregisterWiiInputOverrider(int controller_index);
|
||||
void RegisterGBAInputOverrider(int controller_index);
|
||||
void UnregisterGBAInputOverrider(int controller_index);
|
||||
|
||||
void SetControlState(int controller_index, ControlID control, double state);
|
||||
void ClearControlState(int controller_index, ControlID control);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user