Android: support DualSHockUDPClient for input

This commit is contained in:
PlayXboxtion963 2025-12-14 08:57:02 +08:00
parent 04f71e5e6d
commit 3ffa9f3ba7
7 changed files with 82 additions and 16 deletions

View File

@ -931,6 +931,13 @@ enum class BooleanSetting(
Settings.SECTION_ACHIEVEMENTS, Settings.SECTION_ACHIEVEMENTS,
"ProgressEnabled", "ProgressEnabled",
true true
),
SERVERS_ENABLED(
Settings.FILE_DUALSHOCKUDPCLIENT,
Settings.SECTION_INI_SERVER,
key = "Enabled",
false
); );
override val isOverridden: Boolean override val isOverridden: Boolean

View File

@ -106,6 +106,7 @@ class Settings : Closeable {
const val FILE_WIIMOTE = "WiimoteNew" const val FILE_WIIMOTE = "WiimoteNew"
const val FILE_ACHIEVEMENTS = "RetroAchievements" const val FILE_ACHIEVEMENTS = "RetroAchievements"
const val FILE_GAME_SETTINGS_ONLY = "GameSettingsOnly" const val FILE_GAME_SETTINGS_ONLY = "GameSettingsOnly"
const val FILE_DUALSHOCKUDPCLIENT = "DualShockUDPClient"
const val SECTION_INI_ANDROID = "Android" const val SECTION_INI_ANDROID = "Android"
const val SECTION_INI_ANDROID_OVERLAY_BUTTONS = "AndroidOverlayButtons" const val SECTION_INI_ANDROID_OVERLAY_BUTTONS = "AndroidOverlayButtons"
const val SECTION_INI_GENERAL = "General" const val SECTION_INI_GENERAL = "General"
@ -124,5 +125,6 @@ class Settings : Closeable {
const val SECTION_STEREOSCOPY = "Stereoscopy" const val SECTION_STEREOSCOPY = "Stereoscopy"
const val SECTION_ANALYTICS = "Analytics" const val SECTION_ANALYTICS = "Analytics"
const val SECTION_ACHIEVEMENTS = "Achievements" const val SECTION_ACHIEVEMENTS = "Achievements"
const val SECTION_INI_SERVER = "Server"
} }
} }

View File

@ -92,6 +92,13 @@ enum class StringSetting(
Settings.SECTION_ACHIEVEMENTS, Settings.SECTION_ACHIEVEMENTS,
"ApiToken", "ApiToken",
"" ""
),
SERVERS(
Settings.FILE_DUALSHOCKUDPCLIENT,
Settings.SECTION_INI_SERVER,
"Entries",
""
); );
override val isOverridden: Boolean override val isOverridden: Boolean

View File

@ -502,16 +502,16 @@ class SettingsFragmentPresenter(
override val isOverridden: Boolean override val isOverridden: Boolean
get() = BooleanSetting.MAIN_DSP_HLE.isOverridden || get() = BooleanSetting.MAIN_DSP_HLE.isOverridden ||
BooleanSetting.MAIN_DSP_JIT.isOverridden BooleanSetting.MAIN_DSP_JIT.isOverridden
override val isRuntimeEditable: Boolean override val isRuntimeEditable: Boolean
get() = BooleanSetting.MAIN_DSP_HLE.isRuntimeEditable && get() = BooleanSetting.MAIN_DSP_HLE.isRuntimeEditable &&
BooleanSetting.MAIN_DSP_JIT.isRuntimeEditable BooleanSetting.MAIN_DSP_JIT.isRuntimeEditable
override fun delete(settings: Settings): Boolean { override fun delete(settings: Settings): Boolean {
// Not short circuiting // Not short circuiting
return BooleanSetting.MAIN_DSP_HLE.delete(settings) and return BooleanSetting.MAIN_DSP_HLE.delete(settings) and
BooleanSetting.MAIN_DSP_JIT.delete(settings) BooleanSetting.MAIN_DSP_JIT.delete(settings)
} }
} }
@ -962,8 +962,8 @@ class SettingsFragmentPresenter(
0, 0,
false false
) { ) {
fragmentView.showDialogFragment(LoginDialog(this)) fragmentView.showDialogFragment(LoginDialog(this))
loadSettingsList() loadSettingsList()
}) })
} else { } else {
sl.add( sl.add(
@ -975,8 +975,8 @@ class SettingsFragmentPresenter(
0, 0,
false false
) { ) {
logout() logout()
loadSettingsList() loadSettingsList()
}) })
} }
sl.add( sl.add(
@ -1073,16 +1073,16 @@ class SettingsFragmentPresenter(
override val isOverridden: Boolean override val isOverridden: Boolean
get() = BooleanSetting.MAIN_SYNC_ON_SKIP_IDLE.isOverridden || get() = BooleanSetting.MAIN_SYNC_ON_SKIP_IDLE.isOverridden ||
BooleanSetting.MAIN_SYNC_GPU.isOverridden BooleanSetting.MAIN_SYNC_GPU.isOverridden
override val isRuntimeEditable: Boolean override val isRuntimeEditable: Boolean
get() = BooleanSetting.MAIN_SYNC_ON_SKIP_IDLE.isRuntimeEditable && get() = BooleanSetting.MAIN_SYNC_ON_SKIP_IDLE.isRuntimeEditable &&
BooleanSetting.MAIN_SYNC_GPU.isRuntimeEditable BooleanSetting.MAIN_SYNC_GPU.isRuntimeEditable
override fun delete(settings: Settings): Boolean { override fun delete(settings: Settings): Boolean {
// Not short circuiting // Not short circuiting
return BooleanSetting.MAIN_SYNC_ON_SKIP_IDLE.delete(settings) and return BooleanSetting.MAIN_SYNC_ON_SKIP_IDLE.delete(settings) and
BooleanSetting.MAIN_SYNC_GPU.delete(settings) BooleanSetting.MAIN_SYNC_GPU.delete(settings)
} }
} }
@ -1422,6 +1422,32 @@ class SettingsFragmentPresenter(
IntSetting.WIIMOTE_BB_SOURCE.setInt(settings, if (newValue) 2 else 0) IntSetting.WIIMOTE_BB_SOURCE.setInt(settings, if (newValue) 2 else 0)
} }
}, R.string.real_balance_board, 0)) }, R.string.real_balance_board, 0))
sl.add(SwitchSetting(context, object : AbstractBooleanSetting {
override val isOverridden: Boolean = BooleanSetting.SERVERS_ENABLED.isOverridden
override val isRuntimeEditable: Boolean =
BooleanSetting.SERVERS_ENABLED.isRuntimeEditable
override fun delete(settings: Settings): Boolean {
return BooleanSetting.SERVERS_ENABLED.delete(settings)
}
override val boolean: Boolean get() = BooleanSetting.SERVERS_ENABLED.boolean;
override fun setBoolean(settings: Settings, newValue: Boolean) {
BooleanSetting.SERVERS_ENABLED.setBoolean(settings, if (newValue) true else false);
}
}, R.string.dualshockudp_client, R.string.dualshockudp_client_description))
sl.add(
InputStringSetting(
context,
StringSetting.SERVERS,
R.string.dualshockudp_entries,
R.string.dualshockudp_entries_description
)
)
} }
private fun addGraphicsSettings(sl: ArrayList<SettingsItem>) { private fun addGraphicsSettings(sl: ArrayList<SettingsItem>) {
@ -2189,7 +2215,7 @@ class SettingsFragmentPresenter(
BooleanSetting.MAIN_DEBUG_JIT_ENABLE_PROFILING, BooleanSetting.MAIN_DEBUG_JIT_ENABLE_PROFILING,
R.string.debug_jit_enable_block_profiling, R.string.debug_jit_enable_block_profiling,
0 0
) )
) )
sl.add( sl.add(
RunRunnable( RunRunnable(
@ -2355,6 +2381,7 @@ class SettingsFragmentPresenter(
addControllerMappingSettings(sl, gcPad, null) addControllerMappingSettings(sl, gcPad, null)
} }
} }
7 -> { 7 -> {
// Emulated keyboard controller // Emulated keyboard controller
val gcKeyboard = EmulatedController.getGcKeyboard(gcPadNumber) val gcKeyboard = EmulatedController.getGcKeyboard(gcPadNumber)
@ -2367,6 +2394,7 @@ class SettingsFragmentPresenter(
addControllerMappingSettings(sl, gcKeyboard, null) addControllerMappingSettings(sl, gcKeyboard, null)
} }
} }
12 -> { 12 -> {
// Adapter // Adapter
sl.add( sl.add(
@ -2585,11 +2613,11 @@ class SettingsFragmentPresenter(
* @param groupTypeFilter If this is non-null, only groups whose types match this are considered. * @param groupTypeFilter If this is non-null, only groups whose types match this are considered.
*/ */
private fun addControllerMappingSettings( private fun addControllerMappingSettings(
sl: ArrayList<SettingsItem>, sl: ArrayList<SettingsItem>,
controller: EmulatedController, controller: EmulatedController,
groupTypeFilter: Set<Int>? groupTypeFilter: Set<Int>?
) { ) {
addContainerMappingSettings(sl, controller, controller, groupTypeFilter) addContainerMappingSettings(sl, controller, controller, groupTypeFilter)
} }
/** /**
@ -2684,7 +2712,7 @@ class SettingsFragmentPresenter(
val defaultDevice = controller.getDefaultDevice() val defaultDevice = controller.getDefaultDevice()
hasOldControllerSettings = defaultDevice.startsWith("Android/") && hasOldControllerSettings = defaultDevice.startsWith("Android/") &&
defaultDevice.endsWith("/Touchscreen") defaultDevice.endsWith("/Touchscreen")
fragmentView.setOldControllerSettingsWarningVisibility(hasOldControllerSettings) fragmentView.setOldControllerSettingsWarningVisibility(hasOldControllerSettings)
} }

View File

@ -24,6 +24,10 @@
<string name="wiimote_extension_3">Wii Remote Extension 4</string> <string name="wiimote_extension_3">Wii Remote Extension 4</string>
<string name="real_balance_board">Real Balance Board</string> <string name="real_balance_board">Real Balance Board</string>
<string name="dualshockudp_client">DualshockUDP Client (Background Input)</string>
<string name="dualshockudp_entries">DualshockUDP Server Info (Alternate Input Source)</string>
<string name="dualshockudp_entries_description">Description:IP:Port;</string>
<string name="wiimote">Wii Remote</string> <string name="wiimote">Wii Remote</string>
<string name="wiimote_general">Buttons</string> <string name="wiimote_general">Buttons</string>
@ -120,6 +124,7 @@
<string name="wiimote_scanning_description">Leave this on if you are using a DolphinBar for real Wii Remote support.</string> <string name="wiimote_scanning_description">Leave this on if you are using a DolphinBar for real Wii Remote support.</string>
<string name="wiimote_speaker">Wii Remote Speaker</string> <string name="wiimote_speaker">Wii Remote Speaker</string>
<string name="wiimote_speaker_description">Enable sound output through the speaker on a real Wii Remote (DolphinBar required).</string> <string name="wiimote_speaker_description">Enable sound output through the speaker on a real Wii Remote (DolphinBar required).</string>
<string name="dualshockudp_client_description">DSU protocol enables the use of input and motion data from compatible sources, like PlayStation, Nintendo Switch and Steam controllers.</string>
<string name="override_region_settings">Allow Mismatched Region Settings</string> <string name="override_region_settings">Allow Mismatched Region Settings</string>
<string name="auto_disc_change">Change Discs Automatically</string> <string name="auto_disc_change">Change Discs Automatically</string>
<string name="fallback_region">Fallback Region</string> <string name="fallback_region">Fallback Region</string>

View File

@ -52,6 +52,10 @@ static Config::Location GetLocation(JNIEnv* env, jstring file, jstring section,
{ {
system = Config::System::Achievements; system = Config::System::Achievements;
} }
else if (decoded_file == "DualShockUDPClient")
{
system = Config::System::DualShockUDPClient;
}
else else
{ {
ASSERT(false); ASSERT(false);

View File

@ -57,6 +57,8 @@
#include "DiscIO/Volume.h" #include "DiscIO/Volume.h"
#include "InputCommon/GCAdapter.h" #include "InputCommon/GCAdapter.h"
#include "InputCommon/ControllerInterface/ControllerInterface.h"
#include "UICommon/GameFile.h" #include "UICommon/GameFile.h"
#include "UICommon/UICommon.h" #include "UICommon/UICommon.h"
@ -562,6 +564,17 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Initialize(J
UICommon::InitControllers(WindowSystemInfo(WindowSystemType::Android, nullptr, nullptr, nullptr)); UICommon::InitControllers(WindowSystemInfo(WindowSystemType::Android, nullptr, nullptr, nullptr));
AchievementManager::GetInstance().Init(nullptr); AchievementManager::GetInstance().Init(nullptr);
// Start a background thread to periodically update controller input (every 10ms).
// This ensures Android keeps controller state updated even without a dedicated input loop.
std::thread([]() {
while (true)
{
g_controller_interface.SetCurrentInputChannel(ciface::InputChannel::Host);
g_controller_interface.UpdateInput();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}).detach();
} }
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ReportStartToAnalytics(JNIEnv*, JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ReportStartToAnalytics(JNIEnv*,