From 5d93a10c60f25acd4f9045234156fd68720b1a87 Mon Sep 17 00:00:00 2001 From: zackhow Date: Sun, 26 Aug 2018 18:27:27 -0400 Subject: [PATCH] Android: Add game specific gc/wii controller settings --- .../app/src/main/assets/WiimoteProfile.ini | 135 ++++++ .../dolphinemu/dolphinemu/NativeLibrary.java | 3 + .../dolphinemu/adapters/GameAdapter.java | 49 +-- .../dolphinemu/adapters/GameRowPresenter.java | 72 +--- .../dialogs/GameSettingsDialog.java | 98 +++++ .../features/settings/model/Settings.java | 8 +- .../model/view/InputBindingSetting.java | 11 +- .../settings/model/view/SettingsItem.java | 3 +- .../features/settings/ui/SettingsAdapter.java | 30 +- .../ui/SettingsFragmentPresenter.java | 391 ++++++++++-------- .../InputBindingSettingViewHolder.java | 5 +- .../features/settings/utils/SettingsFile.java | 75 +++- .../utils/DirectoryInitialization.java | 30 ++ .../app/src/main/res/values/arrays.xml | 10 +- Source/Android/jni/ButtonManager.cpp | 36 +- Source/Android/jni/ButtonManager.h | 2 +- Source/Android/jni/MainAndroid.cpp | 28 +- 17 files changed, 704 insertions(+), 282 deletions(-) create mode 100644 Source/Android/app/src/main/assets/WiimoteProfile.ini create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GameSettingsDialog.java diff --git a/Source/Android/app/src/main/assets/WiimoteProfile.ini b/Source/Android/app/src/main/assets/WiimoteProfile.ini new file mode 100644 index 0000000000..6c036c1a37 --- /dev/null +++ b/Source/Android/app/src/main/assets/WiimoteProfile.ini @@ -0,0 +1,135 @@ +[Profile] +Device = Android/4/Touchscreen +Buttons/A = `Button 100` +Buttons/B = `Button 101` +Buttons/- = `Button 102` +Buttons/+ = `Button 103` +Buttons/Home = `Button 104` +Buttons/1 = `Button 105` +Buttons/2 = `Button 106` +D-Pad/Up = `Button 107` +D-Pad/Down = `Button 108` +D-Pad/Left = `Button 109` +D-Pad/Right = `Button 110` +IR/Up = `Axis 112` +IR/Down = `Axis 113` +IR/Left = `Axis 114` +IR/Right = `Axis 115` +IR/Forward = `Axis 116` +IR/Backward = `Axis 117` +IR/Hide = `Button 118` +Swing/Up = `Axis 120` +Swing/Down = `Axis 121` +Swing/Left = `Axis 122` +Swing/Right = `Axis 123` +Swing/Forward = `Axis 124` +Swing/Backward = `Axis 125` +Tilt/Forward = `Axis 127` +Tilt/Backward = `Axis 128` +Tilt/Left = `Axis 129` +Tilt/Right = `Axis 130` +Tilt/Modifier = `Button 131` +Tilt/Modifier/Range = 50,000000 +Shake/X = `Button 132` +Shake/Y = `Button 133` +Shake/Z = `Button 134` +Extension = Nunchuk +Nunchuk/Buttons/C = `Button 200` +Nunchuk/Buttons/Z = `Button 201` +Nunchuk/Stick/Up = `Axis 203` +Nunchuk/Stick/Down = `Axis 204` +Nunchuk/Stick/Left = `Axis 205` +Nunchuk/Stick/Right = `Axis 206` +Nunchuk/Stick/Radius = 100,000000 +Nunchuk/Swing/Up = `Axis 208` +Nunchuk/Swing/Down = `Axis 209` +Nunchuk/Swing/Left = `Axis 210` +Nunchuk/Swing/Right = `Axis 211` +Nunchuk/Swing/Forward = `Axis 212` +Nunchuk/Swing/Backward = `Axis 213` +Nunchuk/Tilt/Forward = `Axis 215` +Nunchuk/Tilt/Backward = `Axis 216` +Nunchuk/Tilt/Left = `Axis 217` +Nunchuk/Tilt/Right = `Axis 218` +Nunchuk/Tilt/Modifier = `Button 219` +Nunchuk/Tilt/Modifier/Range = 50,000000 +Nunchuk/Shake/X = `Button 220` +Nunchuk/Shake/Y = `Button 221` +Nunchuk/Shake/Z = `Button 222` +Classic/Buttons/A = `Button 300` +Classic/Buttons/B = `Button 301` +Classic/Buttons/X = `Button 302` +Classic/Buttons/Y = `Button 303` +Classic/Buttons/- = `Button 304` +Classic/Buttons/+ = `Button 305` +Classic/Buttons/Home = `Button 306` +Classic/Buttons/ZL = `Button 307` +Classic/Buttons/ZR = `Button 308` +Classic/D-Pad/Up = `Button 309` +Classic/D-Pad/Down = `Button 310` +Classic/D-Pad/Left = `Button 311` +Classic/D-Pad/Right = `Button 312` +Classic/Left Stick/Up = `Axis 314` +Classic/Left Stick/Down = `Axis 315` +Classic/Left Stick/Left = `Axis 316` +Classic/Left Stick/Right = `Axis 317` +Classic/Left Stick/Radius = 100,000000 +Classic/Right Stick/Up = `Axis 319` +Classic/Right Stick/Down = `Axis 320` +Classic/Right Stick/Left = `Axis 321` +Classic/Right Stick/Right = `Axis 322` +Classic/Right Stick/Radius = 100,000000 +Classic/Triggers/L = `Axis 323` +Classic/Triggers/R = `Axis 324` +Classic/Triggers/Threshold = 90,000000 +Guitar/Buttons/- = `Button 400` +Guitar/Buttons/+ = `Button 401` +Guitar/Frets/Green = `Button 402` +Guitar/Frets/Red = `Button 403` +Guitar/Frets/Yellow = `Button 404` +Guitar/Frets/Blue = `Button 405` +Guitar/Frets/Orange = `Button 406` +Guitar/Strum/Up = `Button 407` +Guitar/Strum/Down = `Button 408` +Guitar/Stick/Up = `Axis 410` +Guitar/Stick/Down = `Axis 411` +Guitar/Stick/Left = `Axis 412` +Guitar/Stick/Right = `Axis 413` +Guitar/Stick/Radius = 100,000000 +Guitar/Whammy/Bar = `Axis = 414` +Drums/Buttons/- = `Button 500` +Drums/Buttons/+ = `Button 501` +Drums/Pads/Red = `Button 502` +Drums/Pads/Yellow = `Button 503` +Drums/Pads/Blue = `Button 504` +Drums/Pads/Green = `Button 505` +Drums/Pads/Orange = `Button 506` +Drums/Pads/Bass = `Button 507` +Drums/Stick/Up = `Axis 509` +Drums/Stick/Down = `Axis 510` +Drums/Stick/Left = `Axis 511` +Drums/Stick/Right = `Axis 512` +Drums/Stick/Radius = 100,000000 +Turntable/Buttons/Green Left = `Button 600` +Turntable/Buttons/Red Left = `Button 601` +Turntable/Buttons/Blue Left = `Button 602` +Turntable/Buttons/Green Right = `Button 603` +Turntable/Buttons/Red Right = `Button 604` +Turntable/Buttons/Blue Right = `Button 605` +Turntable/Buttons/- = `Button 606` +Turntable/Buttons/+ = `Button 607` +Turntable/Buttons/Home = `Button 608` +Turntable/Buttons/Euphoria = `Button 609` +Turntable/Table Left/Left = `Axis 611` +Turntable/Table Left/Right = `Axis 612` +Turntable/Table Right/Left = `Axis 614` +Turntable/Table Right/Right = `Axis 615` +Turntable/Stick/Up = `Axis 617` +Turntable/Stick/Down = `Axis 618` +Turntable/Stick/Left = `Axis 619` +Turntable/Stick/Right = `Axis 620` +Turntable/Stick/Radius = 100,000000 +Turntable/Effect/Dial = `Axis 621` +Turntable/Crossfade/Left = `Axis 623` +Turntable/Crossfade/Right = `Axis 624` +Rumble/Motor = `Rumble 700` \ No newline at end of file diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java index 3536a17776..933ba04285 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java @@ -248,6 +248,9 @@ public final class NativeLibrary public static native void SetUserSetting(String gameID, String Section, String Key, String Value); + public static native void SetProfileSetting(String profile, String Section, String Key, + String Value); + public static native void InitGameIni(String gameID); /** diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java index 67b6b77e7a..52312b29f9 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java @@ -12,10 +12,12 @@ import android.widget.Toast; import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.activities.EmulationActivity; +import org.dolphinemu.dolphinemu.dialogs.GameSettingsDialog; import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag; import org.dolphinemu.dolphinemu.features.settings.ui.SettingsActivity; import org.dolphinemu.dolphinemu.model.GameFile; import org.dolphinemu.dolphinemu.utils.DirectoryInitialization; +import org.dolphinemu.dolphinemu.ui.platform.Platform; import org.dolphinemu.dolphinemu.utils.PicassoUtils; import org.dolphinemu.dolphinemu.viewholders.GameViewHolder; @@ -147,49 +149,10 @@ public final class GameAdapter extends RecyclerView.Adapter impl return true; } - AlertDialog.Builder builder = new AlertDialog.Builder(activity); - builder.setTitle("Game Settings") - .setItems(R.array.gameSettingsMenus, new DialogInterface.OnClickListener() - { - public void onClick(DialogInterface dialog, int which) - { - switch (which) - { - case 0: - SettingsActivity.launch(activity, MenuTag.CONFIG, gameId); - break; - case 1: - SettingsActivity.launch(activity, MenuTag.GRAPHICS, gameId); - break; - case 2: - String path = - DirectoryInitialization.getUserDirectory() + "/GameSettings/" + - gameId + ".ini"; - File gameSettingsFile = new File(path); - if (gameSettingsFile.exists()) - { - if (gameSettingsFile.delete()) - { - Toast.makeText(view.getContext(), "Cleared settings for " + gameId, - Toast.LENGTH_SHORT).show(); - } - else - { - Toast.makeText(view.getContext(), "Unable to clear settings for " + gameId, - Toast.LENGTH_SHORT).show(); - } - } - else - { - Toast.makeText(view.getContext(), "No game settings to delete", - Toast.LENGTH_SHORT).show(); - } - break; - } - } - }); - - builder.show(); + GameSettingsDialog fragment = + GameSettingsDialog.newInstance(gameId, holder.gameFile.getPlatform()); + ((FragmentActivity) view.getContext()).getSupportFragmentManager().beginTransaction() + .add(fragment, GameSettingsDialog.TAG).commit(); return true; } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameRowPresenter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameRowPresenter.java index 2cf23080b1..8047a438e8 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameRowPresenter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameRowPresenter.java @@ -14,6 +14,7 @@ import android.widget.ImageView; import android.widget.Toast; import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.dialogs.GameSettingsDialog; import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag; import org.dolphinemu.dolphinemu.features.settings.ui.SettingsActivity; import org.dolphinemu.dolphinemu.model.GameFile; @@ -80,73 +81,30 @@ public final class GameRowPresenter extends Presenter Context context = holder.cardParent.getContext(); Drawable background = ContextCompat.getDrawable(context, backgroundId); holder.cardParent.setInfoAreaBackground(background); - holder.cardParent.setOnLongClickListener(new View.OnLongClickListener() + holder.cardParent.setOnLongClickListener((view) -> { - @Override - public boolean onLongClick(View view) + FragmentActivity activity = (FragmentActivity) view.getContext(); + String gameId = gameFile.getGameId(); + + if (gameId.isEmpty()) { - FragmentActivity activity = (FragmentActivity) view.getContext(); - String gameId = gameFile.getGameId(); - - if (gameId.isEmpty()) - { - AlertDialog.Builder builder = new AlertDialog.Builder(activity); - builder.setTitle("Game Settings"); - builder.setMessage("Files without game IDs don't support game-specific settings."); - - builder.show(); - return true; - } - AlertDialog.Builder builder = new AlertDialog.Builder(activity); - builder.setTitle("Game Settings") - .setItems(R.array.gameSettingsMenus, new DialogInterface.OnClickListener() - { - public void onClick(DialogInterface dialog, int which) - { - switch (which) - { - case 0: - SettingsActivity.launch(activity, MenuTag.CONFIG, gameId); - break; - case 1: - SettingsActivity.launch(activity, MenuTag.GRAPHICS, gameId); - break; - case 2: - String path = DirectoryInitialization.getUserDirectory() + - "/GameSettings/" + gameId + ".ini"; - File gameSettingsFile = new File(path); - if (gameSettingsFile.exists()) - { - if (gameSettingsFile.delete()) - { - Toast.makeText(view.getContext(), "Cleared settings for " + gameId, - Toast.LENGTH_SHORT).show(); - } - else - { - Toast.makeText(view.getContext(), - "Unable to clear settings for " + gameId, Toast.LENGTH_SHORT) - .show(); - } - } - else - { - Toast.makeText(view.getContext(), "No game settings to delete", - Toast.LENGTH_SHORT).show(); - } - break; - } - } - }); + builder.setTitle("Game Settings"); + builder.setMessage("Files without game IDs don't support game-specific settings."); builder.show(); return true; } + + GameSettingsDialog fragment = + GameSettingsDialog.newInstance(gameId, holder.gameFile.getPlatform()); + ((FragmentActivity) view.getContext()).getSupportFragmentManager().beginTransaction() + .add(fragment, GameSettingsDialog.TAG).commit(); + + return true; }); } - @Override public void onUnbindViewHolder(ViewHolder viewHolder) { diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GameSettingsDialog.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GameSettingsDialog.java new file mode 100644 index 0000000000..5639897d62 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GameSettingsDialog.java @@ -0,0 +1,98 @@ +package org.dolphinemu.dolphinemu.dialogs; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.os.Bundle; +import android.support.v4.app.DialogFragment; +import android.widget.Toast; + +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag; +import org.dolphinemu.dolphinemu.features.settings.ui.SettingsActivity; +import org.dolphinemu.dolphinemu.ui.platform.Platform; +import org.dolphinemu.dolphinemu.utils.DirectoryInitialization; + +import java.io.File; + +public class GameSettingsDialog extends DialogFragment +{ + public static final String TAG = "GameSettingsDialog"; + public static final String ARG_GAMEID = "game_id"; + public static final String ARG_PLATFORM = "platform"; + + public static GameSettingsDialog newInstance(String gameId, int platform) + { + GameSettingsDialog fragment = new GameSettingsDialog(); + + Bundle arguments = new Bundle(); + arguments.putString(ARG_GAMEID, gameId); + arguments.putInt(ARG_PLATFORM, platform); + fragment.setArguments(arguments); + + return fragment; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) + { + AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + + String gameId = getArguments().getString(ARG_GAMEID); + int platform = getArguments().getInt(ARG_PLATFORM); + + builder.setTitle(getActivity().getString(R.string.preferences_game_settings)) + .setItems(platform == Platform.GAMECUBE.toInt() ? + R.array.gameSettingsMenusGC : + R.array.gameSettingsMenusWii, (dialog, which) -> + { + switch (which) + { + case 0: + SettingsActivity.launch(getContext(), MenuTag.CONFIG, gameId); + break; + case 1: + SettingsActivity.launch(getContext(), MenuTag.GRAPHICS, gameId); + break; + case 2: + SettingsActivity.launch(getContext(), MenuTag.GCPAD_TYPE, gameId); + break; + case 3: + // Clear option for GC, Wii controls for else + if (platform == Platform.GAMECUBE.toInt()) + clearGameSettings(gameId); + else + SettingsActivity.launch(getActivity(), MenuTag.WIIMOTE, gameId); + break; + case 4: + clearGameSettings(gameId); + break; + } + }); + return builder.create(); + } + + + private void clearGameSettings(String gameId) + { + String path = + DirectoryInitialization.getUserDirectory() + "/GameSettings/" + gameId + ".ini"; + File gameSettingsFile = new File(path); + if (gameSettingsFile.exists()) + { + if (gameSettingsFile.delete()) + { + Toast.makeText(getContext(), "Cleared settings for " + gameId, Toast.LENGTH_SHORT) + .show(); + } + else + { + Toast.makeText(getContext(), "Unable to clear settings for " + gameId, + Toast.LENGTH_SHORT).show(); + } + } + else + { + Toast.makeText(getContext(), "No game settings to delete", Toast.LENGTH_SHORT).show(); + } + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/Settings.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/Settings.java index d945512069..0f3ff9d717 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/Settings.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/Settings.java @@ -26,6 +26,8 @@ public class Settings public static final String SECTION_WIIMOTE = "Wiimote"; public static final String SECTION_BINDINGS = "Android"; + public static final String SECTION_CONTROLS = "Controls"; + public static final String SECTION_PROFILE = "Profile"; public static final String SECTION_ANALYTICS = "Analytics"; @@ -134,6 +136,11 @@ public class Settings mergeSections(SettingsFile.readCustomGameSettings(gameId, view)); } + public void loadWiimoteProfile(String gameId, String padId) + { + mergeSections(SettingsFile.readWiimoteProfile(gameId, padId)); + } + private void mergeSections(HashMap updatedSections) { for (Map.Entry entry : updatedSections.entrySet()) @@ -182,6 +189,5 @@ public class Settings view.showToastMessage("Saved settings for " + gameId); SettingsFile.saveCustomGameSettings(gameId, sections); } - } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/InputBindingSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/InputBindingSetting.java index e3850cb447..0c6a3bc314 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/InputBindingSetting.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/InputBindingSetting.java @@ -11,9 +11,13 @@ import org.dolphinemu.dolphinemu.features.settings.model.StringSetting; public class InputBindingSetting extends SettingsItem { - public InputBindingSetting(String key, String section, int titleId, Setting setting) + private String gameId; + + public InputBindingSetting(String key, String section, int titleId, Setting setting, + String gameId) { super(key, section, setting, titleId, 0); + this.gameId = gameId; } public String getValue() @@ -98,4 +102,9 @@ public class InputBindingSetting extends SettingsItem { return TYPE_INPUT_BINDING; } + + public String getGameId() + { + return gameId; + } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/SettingsItem.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/SettingsItem.java index e3c798521f..48df22fc45 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/SettingsItem.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/SettingsItem.java @@ -1,7 +1,7 @@ package org.dolphinemu.dolphinemu.features.settings.model.view; -import org.dolphinemu.dolphinemu.features.settings.model.Setting; import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter; +import org.dolphinemu.dolphinemu.features.settings.model.Setting; /** * ViewModel abstraction for an Item in the RecyclerView powering SettingsFragments. @@ -39,6 +39,7 @@ public abstract class SettingsItem * @param nameId Resource ID for a text string to be displayed as this setting's name. * @param descriptionId Resource ID for a text string to be displayed as this setting's description. */ + public SettingsItem(String key, String section, Setting setting, int nameId, int descriptionId) { mKey = key; diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsAdapter.java index a2392caefc..7d903ddd0a 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsAdapter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsAdapter.java @@ -292,7 +292,14 @@ public final class SettingsAdapter extends RecyclerView.Adapter readWiimoteProfile(final String gameId, + final String padId) + { + String profile = gameId + "_Wii" + padId; + return readFile(getWiiProfile(profile, padId), true, null); + } /** * Saves a Settings HashMap to a given .ini file on disk. If unsuccessful, outputs an error @@ -435,13 +446,43 @@ public final class SettingsFile for (String settingKey : sortedKeySet) { Setting setting = settings.get(settingKey); - NativeLibrary - .SetUserSetting(gameId, mapSectionNameFromIni(section.getName()), setting.getKey(), - setting.getValueAsString()); + // Special case. Extension gets saved into a controller profile + if (settingKey.contains(SettingsFile.KEY_WIIMOTE_EXTENSION)) + { + saveCustomWiimoteSetting(gameId, setting); + } + else + { + NativeLibrary.SetUserSetting(gameId, mapSectionNameFromIni(section.getName()), + setting.getKey(), setting.getValueAsString()); + } } } } + /** + * Saves the extension value in a profile and enables that profile. Extension is the only + * controller setting that is not saved in the main config. + * + * @param gameId + * @param setting + */ + public static void saveCustomWiimoteSetting(final String gameId, final Setting setting) + { + if (setting.getSection().equals(Settings.SECTION_PROFILE)) + return; + String padId = + setting.getKey().substring(setting.getKey().length() - 1, setting.getKey().length()); + String profile = gameId + "_Wii" + padId; + + NativeLibrary.SetProfileSetting(profile, Settings.SECTION_PROFILE, KEY_WIIMOTE_EXTENSION, + setting.getValueAsString()); + + // Enable the profile + NativeLibrary.SetUserSetting(gameId, Settings.SECTION_CONTROLS, + KEY_WIIMOTE_PROFILE + (Integer.valueOf(padId) + 1), profile); + } + private static String mapSectionNameFromIni(String generalSectionName) { if (sectionsMap.getForward(generalSectionName) != null) @@ -487,10 +528,32 @@ public final class SettingsFile private static File getCustomGameSettingsFile(String gameId) { + return new File( DirectoryInitialization.getUserDirectory() + "/GameSettings/" + gameId + ".ini"); } + private static File getWiiProfile(String profile, String padId) + { + String wiiConfigPath = + DirectoryInitialization.getUserDirectory() + "/Config/Profiles/Wiimote/" + + profile + ".ini"; + + File wiiProfile = new File(wiiConfigPath); + // If it doesn't exist, create it + if (!wiiProfile.exists()) + { + String defautlWiiProfilePath = + DirectoryInitialization.getUserDirectory() + + "/Config/Profiles/Wiimote/WiimoteProfile.ini"; + DirectoryInitialization.copyFile(defautlWiiProfilePath, wiiConfigPath); + + NativeLibrary.SetProfileSetting(profile, Settings.SECTION_PROFILE, "Device", + "Android/" + (Integer.valueOf(padId) + 4) + "/Touchscreen"); + } + return wiiProfile; + } + private static SettingSection sectionFromLine(String line, boolean isCustomGame) { String sectionName = line.substring(1, line.length() - 1); @@ -626,4 +689,10 @@ public final class SettingsFile { return setting.getKey() + " = " + setting.getValueAsString(); } + + private static String customWiimoteExtSettingAsString(Setting setting) + { + return setting.getKey().substring(0, setting.getKey().length() - 1) + " = " + + setting.getValueAsString(); + } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java index b0132c215f..c8b54b36f0 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java @@ -16,6 +16,7 @@ import android.support.v4.content.LocalBroadcastManager; import org.dolphinemu.dolphinemu.NativeLibrary; import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -139,8 +140,14 @@ public final class DirectoryInitialization // // TODO: Redo the Android controller system so that we don't have to extract these INIs. String configDirectory = NativeLibrary.GetUserDirectory() + File.separator + "Config"; + String profileDirectory = + NativeLibrary.GetUserDirectory() + File.separator + "Config/Profiles/Wiimote/"; + createWiimoteProfileDirectory(profileDirectory); + copyAsset("GCPadNew.ini", new File(configDirectory, "GCPadNew.ini"), true, context); copyAsset("WiimoteNew.ini", new File(configDirectory, "WiimoteNew.ini"), false, context); + copyAsset("WiimoteProfile.ini", new File(profileDirectory, "WiimoteProfile.ini"), true, + context); } private static void deleteDirectoryRecursively(File file) @@ -247,6 +254,20 @@ public final class DirectoryInitialization } } + public static void copyFile(String from, String to) + { + try + { + InputStream in = new FileInputStream(from); + OutputStream out = new FileOutputStream(to); + copyFile(in, out); + } + catch (IOException e) + { + + } + } + private static void copyFile(InputStream in, OutputStream out) throws IOException { byte[] buffer = new byte[1024]; @@ -258,6 +279,15 @@ public final class DirectoryInitialization } } + private static void createWiimoteProfileDirectory(String directory) + { + File wiiPath = new File(directory); + if (!wiiPath.isDirectory()) + { + wiiPath.mkdirs(); + } + } + private static native void CreateUserDirectories(); private static native void SetSysDirectory(String path); diff --git a/Source/Android/app/src/main/res/values/arrays.xml b/Source/Android/app/src/main/res/values/arrays.xml index 21a5c4f7b3..403e27b2b1 100644 --- a/Source/Android/app/src/main/res/values/arrays.xml +++ b/Source/Android/app/src/main/res/values/arrays.xml @@ -306,9 +306,17 @@ Right Stick - + Core Settings GFX Settings + GameCube Controller Settings + Clear Game Settings + + + Core Settings + GFX Settings + GameCube Controller Settings + Wii Controller Settings Clear Game Settings diff --git a/Source/Android/jni/ButtonManager.cpp b/Source/Android/jni/ButtonManager.cpp index 637b23b3da..251c754968 100644 --- a/Source/Android/jni/ButtonManager.cpp +++ b/Source/Android/jni/ButtonManager.cpp @@ -335,7 +335,7 @@ static void AddBind(const std::string& dev, sBind* bind) m_controllers[dev]->AddBind(bind); } -void Init() +void Init(const std::string& gameId) { // Initialize our touchScreenKey buttons for (int a = 0; a < 8; ++a) @@ -592,6 +592,40 @@ void Init() new sBind(padID, configTypes[a], type, bindnum, modifier == '-' ? -1.0f : 1.0f)); } } + + ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + std::string(gameId + ".ini")); + for (u32 a = 0; a < configStrings.size(); ++a) + { + for (int padID = 0; padID < 8; ++padID) + { + std::ostringstream config; + config << configStrings[a] << "_" << padID; + BindType type; + int bindnum; + char dev[128]; + bool hasbind = false; + char modifier = '+'; + std::string value; + ini.GetOrCreateSection("Android")->Get(config.str(), &value, "None"); + if (value == "None") + continue; + if (std::string::npos != value.find("Axis")) + { + hasbind = true; + type = BIND_AXIS; + sscanf(value.c_str(), "Device '%127[^\']'-Axis %d%c", dev, &bindnum, &modifier); + } + else if (std::string::npos != value.find("Button")) + { + hasbind = true; + type = BIND_BUTTON; + sscanf(value.c_str(), "Device '%127[^\']'-Button %d", dev, &bindnum); + } + if (hasbind) + AddBind(std::string(dev), + new sBind(padID, configTypes[a], type, bindnum, modifier == '-' ? -1.0f : 1.0f)); + } + } } bool GetButtonPressed(int padID, ButtonType button) diff --git a/Source/Android/jni/ButtonManager.h b/Source/Android/jni/ButtonManager.h index b9744f516c..82f64e6d4d 100644 --- a/Source/Android/jni/ButtonManager.h +++ b/Source/Android/jni/ButtonManager.h @@ -250,7 +250,7 @@ public: float AxisValue(int padID, ButtonType axis); }; -void Init(); +void Init(const std::string&); bool GetButtonPressed(int padID, ButtonType button); float GetAxisValue(int padID, ButtonType axis); bool GamepadEvent(const std::string& dev, int button, int action); diff --git a/Source/Android/jni/MainAndroid.cpp b/Source/Android/jni/MainAndroid.cpp index 34e2b06c5e..f74ae67788 100644 --- a/Source/Android/jni/MainAndroid.cpp +++ b/Source/Android/jni/MainAndroid.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include "Common/AndroidAnalytics.h" #include "Common/CPUDetect.h" @@ -250,8 +251,10 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetProfiling jboolean enable); JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_WriteProfileResults(JNIEnv* env, jobject obj); + JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run__Ljava_lang_String_2Z( JNIEnv* env, jobject obj, jstring jFile, jboolean jfirstOpen); + JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run__Ljava_lang_String_2Ljava_lang_String_2Z( JNIEnv* env, jobject obj, jstring jFile, jstring jSavestate, jboolean jDeleteSavestate); @@ -381,6 +384,29 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetUserSetti ini.Save(File::GetUserPath(D_GAMESETTINGS_IDX) + gameid + ".ini"); } +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetProfileSetting( + JNIEnv* env, jobject obj, jstring jProfile, jstring jSection, jstring jKey, jstring jValue) +{ + IniFile ini; + std::string profile = GetJString(env, jProfile); + std::string section = GetJString(env, jSection); + std::string key = GetJString(env, jKey); + std::string val = GetJString(env, jValue); + + ini.Load(File::GetUserPath(D_CONFIG_IDX) + "Profiles/Wiimote/" + profile + ".ini"); + + if (val != "-1") + { + ini.GetOrCreateSection(section)->Set(key, val); + } + else + { + ini.GetOrCreateSection(section)->Delete(key); + } + + ini.Save(File::GetUserPath(D_CONFIG_IDX) + "Profiles/Wiimote/" + profile + ".ini"); +} + JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetConfig( JNIEnv* env, jobject obj, jstring jFile, jstring jSection, jstring jKey, jstring jDefault) { @@ -539,7 +565,6 @@ static void Run(const std::string& path, bool first_open, __android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Running : %s", path.c_str()); // Install our callbacks - OSD::AddCallback(OSD::CallbackType::Initialization, ButtonManager::Init); OSD::AddCallback(OSD::CallbackType::Shutdown, ButtonManager::Shutdown); RegisterMsgAlertHandler(&MsgAlert); @@ -563,6 +588,7 @@ static void Run(const std::string& path, bool first_open, WindowSystemInfo wsi(WindowSystemType::Android, nullptr, s_surf); if (BootManager::BootCore(std::move(boot), wsi)) { + ButtonManager::Init(SConfig::GetInstance().GetGameID()); static constexpr int TIMEOUT = 10000; static constexpr int WAIT_STEP = 25; int time_waited = 0;