From a5483910d593810c5c4e158d61382a8ec9b26504 Mon Sep 17 00:00:00 2001 From: SSimco <37044560+SSimco@users.noreply.github.com> Date: Fri, 1 Nov 2024 22:04:26 +0200 Subject: [PATCH] Refactored input gui code --- src/android/app/src/main/cpp/NativeInput.cpp | 18 + .../Cemu/nativeinterface/NativeInput.java | 4 + .../input/ControllerInputsDataProvider.java | 184 -------- .../input/ControllerInputsFragment.java | 413 ++++++++++++++++-- .../res/layout/layout_controller_input.xml | 4 +- .../app/src/main/res/values/strings.xml | 2 + 6 files changed, 394 insertions(+), 231 deletions(-) delete mode 100644 src/android/app/src/main/java/info/cemu/Cemu/settings/input/ControllerInputsDataProvider.java diff --git a/src/android/app/src/main/cpp/NativeInput.cpp b/src/android/app/src/main/cpp/NativeInput.cpp index df4231f3..8e38656f 100644 --- a/src/android/app/src/main/cpp/NativeInput.cpp +++ b/src/android/app/src/main/cpp/NativeInput.cpp @@ -91,6 +91,24 @@ Java_info_cemu_Cemu_nativeinterface_NativeInput_getVPADControllersCount([[maybe_ return vpadCount; } +extern "C" [[maybe_unused]] JNIEXPORT void JNICALL +Java_info_cemu_Cemu_nativeinterface_NativeInput_setVPADScreenToggle([[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jint index, jboolean enabled) +{ + auto emulatedController = AndroidEmulatedController::getAndroidEmulatedController(index).getEmulatedController(); + if (emulatedController == nullptr || emulatedController->type() != EmulatedController::Type::VPAD) + throw std::runtime_error(fmt::format("Invalid controller type for controller {}, expected VPAD", index)); + static_cast(emulatedController.get())->set_screen_toggle(enabled); +} + +extern "C" [[maybe_unused]] JNIEXPORT jboolean JNICALL +Java_info_cemu_Cemu_nativeinterface_NativeInput_getVPADScreenToggle([[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jint index) +{ + auto emulatedController = AndroidEmulatedController::getAndroidEmulatedController(index).getEmulatedController(); + if (emulatedController == nullptr || emulatedController->type() != EmulatedController::Type::VPAD) + throw std::runtime_error(fmt::format("Invalid controller type for controller {}, expected VPAD", index)); + return static_cast(emulatedController.get())->is_screen_active_toggle(); +} + extern "C" [[maybe_unused]] JNIEXPORT jboolean JNICALL Java_info_cemu_Cemu_nativeinterface_NativeInput_isControllerDisabled([[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jint index) { diff --git a/src/android/app/src/main/java/info/cemu/Cemu/nativeinterface/NativeInput.java b/src/android/app/src/main/java/info/cemu/Cemu/nativeinterface/NativeInput.java index 88eb8eed..f15595af 100644 --- a/src/android/app/src/main/java/info/cemu/Cemu/nativeinterface/NativeInput.java +++ b/src/android/app/src/main/java/info/cemu/Cemu/nativeinterface/NativeInput.java @@ -146,6 +146,10 @@ public class NativeInput { public static native int getVPADControllersCount(); + public static native void setVPADScreenToggle(int index, boolean enabled); + + public static native boolean getVPADScreenToggle(int index); + public static native void setControllerMapping(String deviceDescriptor, String deviceName, int index, int mappingId, int buttonId); public static native void clearControllerMapping(int index, int mappingId); diff --git a/src/android/app/src/main/java/info/cemu/Cemu/settings/input/ControllerInputsDataProvider.java b/src/android/app/src/main/java/info/cemu/Cemu/settings/input/ControllerInputsDataProvider.java deleted file mode 100644 index a69f7c2c..00000000 --- a/src/android/app/src/main/java/info/cemu/Cemu/settings/input/ControllerInputsDataProvider.java +++ /dev/null @@ -1,184 +0,0 @@ -package info.cemu.Cemu.settings.input; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import info.cemu.Cemu.R; -import info.cemu.Cemu.nativeinterface.NativeInput; - -public class ControllerInputsDataProvider { - private int getButtonResourceIdName(int controllerType, int buttonId) { - if (controllerType == NativeInput.EMULATED_CONTROLLER_TYPE_VPAD) { - return switch (buttonId) { - case NativeInput.VPAD_BUTTON_A -> R.string.button_a; - case NativeInput.VPAD_BUTTON_B -> R.string.button_b; - case NativeInput.VPAD_BUTTON_X -> R.string.button_x; - case NativeInput.VPAD_BUTTON_Y -> R.string.button_y; - case NativeInput.VPAD_BUTTON_L -> R.string.button_l; - case NativeInput.VPAD_BUTTON_R -> R.string.button_r; - case NativeInput.VPAD_BUTTON_ZL -> R.string.button_zl; - case NativeInput.VPAD_BUTTON_ZR -> R.string.button_zr; - case NativeInput.VPAD_BUTTON_PLUS -> R.string.button_plus; - case NativeInput.VPAD_BUTTON_MINUS -> R.string.button_minus; - case NativeInput.VPAD_BUTTON_UP -> R.string.button_up; - case NativeInput.VPAD_BUTTON_DOWN -> R.string.button_down; - case NativeInput.VPAD_BUTTON_LEFT -> R.string.button_left; - case NativeInput.VPAD_BUTTON_RIGHT -> R.string.button_right; - case NativeInput.VPAD_BUTTON_STICKL -> R.string.button_stickl; - case NativeInput.VPAD_BUTTON_STICKR -> R.string.button_stickr; - case NativeInput.VPAD_BUTTON_STICKL_UP -> R.string.button_stickl_up; - case NativeInput.VPAD_BUTTON_STICKL_DOWN -> R.string.button_stickl_down; - case NativeInput.VPAD_BUTTON_STICKL_LEFT -> R.string.button_stickl_left; - case NativeInput.VPAD_BUTTON_STICKL_RIGHT -> R.string.button_stickl_right; - case NativeInput.VPAD_BUTTON_STICKR_UP -> R.string.button_stickr_up; - case NativeInput.VPAD_BUTTON_STICKR_DOWN -> R.string.button_stickr_down; - case NativeInput.VPAD_BUTTON_STICKR_LEFT -> R.string.button_stickr_left; - case NativeInput.VPAD_BUTTON_STICKR_RIGHT -> R.string.button_stickr_right; - case NativeInput.VPAD_BUTTON_MIC -> R.string.button_mic; - case NativeInput.VPAD_BUTTON_SCREEN -> R.string.button_screen; - case NativeInput.VPAD_BUTTON_HOME -> R.string.button_home; - default -> throw new IllegalArgumentException("Invalid buttonId " + buttonId + " for controllerType " + controllerType); - }; - } - if (controllerType == NativeInput.EMULATED_CONTROLLER_TYPE_PRO) { - return switch (buttonId) { - case NativeInput.PRO_BUTTON_A -> R.string.button_a; - case NativeInput.PRO_BUTTON_B -> R.string.button_b; - case NativeInput.PRO_BUTTON_X -> R.string.button_x; - case NativeInput.PRO_BUTTON_Y -> R.string.button_y; - case NativeInput.PRO_BUTTON_L -> R.string.button_l; - case NativeInput.PRO_BUTTON_R -> R.string.button_r; - case NativeInput.PRO_BUTTON_ZL -> R.string.button_zl; - case NativeInput.PRO_BUTTON_ZR -> R.string.button_zr; - case NativeInput.PRO_BUTTON_PLUS -> R.string.button_plus; - case NativeInput.PRO_BUTTON_MINUS -> R.string.button_minus; - case NativeInput.PRO_BUTTON_HOME -> R.string.button_home; - case NativeInput.PRO_BUTTON_UP -> R.string.button_up; - case NativeInput.PRO_BUTTON_DOWN -> R.string.button_down; - case NativeInput.PRO_BUTTON_LEFT -> R.string.button_left; - case NativeInput.PRO_BUTTON_RIGHT -> R.string.button_right; - case NativeInput.PRO_BUTTON_STICKL -> R.string.button_stickl; - case NativeInput.PRO_BUTTON_STICKR -> R.string.button_stickr; - case NativeInput.PRO_BUTTON_STICKL_UP -> R.string.button_stickl_up; - case NativeInput.PRO_BUTTON_STICKL_DOWN -> R.string.button_stickl_down; - case NativeInput.PRO_BUTTON_STICKL_LEFT -> R.string.button_stickl_left; - case NativeInput.PRO_BUTTON_STICKL_RIGHT -> R.string.button_stickl_right; - case NativeInput.PRO_BUTTON_STICKR_UP -> R.string.button_stickr_up; - case NativeInput.PRO_BUTTON_STICKR_DOWN -> R.string.button_stickr_down; - case NativeInput.PRO_BUTTON_STICKR_LEFT -> R.string.button_stickr_left; - case NativeInput.PRO_BUTTON_STICKR_RIGHT -> R.string.button_stickr_right; - default -> throw new IllegalArgumentException("Invalid buttonId " + buttonId + " for controllerType " + controllerType); - }; - } - if (controllerType == NativeInput.EMULATED_CONTROLLER_TYPE_CLASSIC) { - return switch (buttonId) { - case NativeInput.CLASSIC_BUTTON_A -> R.string.button_a; - case NativeInput.CLASSIC_BUTTON_B -> R.string.button_b; - case NativeInput.CLASSIC_BUTTON_X -> R.string.button_x; - case NativeInput.CLASSIC_BUTTON_Y -> R.string.button_y; - case NativeInput.CLASSIC_BUTTON_L -> R.string.button_l; - case NativeInput.CLASSIC_BUTTON_R -> R.string.button_r; - case NativeInput.CLASSIC_BUTTON_ZL -> R.string.button_zl; - case NativeInput.CLASSIC_BUTTON_ZR -> R.string.button_zr; - case NativeInput.CLASSIC_BUTTON_PLUS -> R.string.button_plus; - case NativeInput.CLASSIC_BUTTON_MINUS -> R.string.button_minus; - case NativeInput.CLASSIC_BUTTON_HOME -> R.string.button_home; - case NativeInput.CLASSIC_BUTTON_UP -> R.string.button_up; - case NativeInput.CLASSIC_BUTTON_DOWN -> R.string.button_down; - case NativeInput.CLASSIC_BUTTON_LEFT -> R.string.button_left; - case NativeInput.CLASSIC_BUTTON_RIGHT -> R.string.button_right; - case NativeInput.CLASSIC_BUTTON_STICKL_UP -> R.string.button_stickl_up; - case NativeInput.CLASSIC_BUTTON_STICKL_DOWN -> R.string.button_stickl_down; - case NativeInput.CLASSIC_BUTTON_STICKL_LEFT -> R.string.button_stickl_left; - case NativeInput.CLASSIC_BUTTON_STICKL_RIGHT -> R.string.button_stickl_right; - case NativeInput.CLASSIC_BUTTON_STICKR_UP -> R.string.button_stickr_up; - case NativeInput.CLASSIC_BUTTON_STICKR_DOWN -> R.string.button_stickr_down; - case NativeInput.CLASSIC_BUTTON_STICKR_LEFT -> R.string.button_stickr_left; - case NativeInput.CLASSIC_BUTTON_STICKR_RIGHT -> R.string.button_stickr_right; - default -> throw new IllegalArgumentException("Invalid buttonId " + buttonId + " for controllerType " + controllerType); - }; - } - if (controllerType == NativeInput.EMULATED_CONTROLLER_TYPE_WIIMOTE) { - return switch (buttonId) { - case NativeInput.WIIMOTE_BUTTON_A -> R.string.button_a; - case NativeInput.WIIMOTE_BUTTON_B -> R.string.button_b; - case NativeInput.WIIMOTE_BUTTON_1 -> R.string.button_1; - case NativeInput.WIIMOTE_BUTTON_2 -> R.string.button_2; - case NativeInput.WIIMOTE_BUTTON_NUNCHUCK_Z -> R.string.button_nunchuck_z; - case NativeInput.WIIMOTE_BUTTON_NUNCHUCK_C -> R.string.button_nunchuck_c; - case NativeInput.WIIMOTE_BUTTON_PLUS -> R.string.button_plus; - case NativeInput.WIIMOTE_BUTTON_MINUS -> R.string.button_minus; - case NativeInput.WIIMOTE_BUTTON_UP -> R.string.button_up; - case NativeInput.WIIMOTE_BUTTON_DOWN -> R.string.button_down; - case NativeInput.WIIMOTE_BUTTON_LEFT -> R.string.button_left; - case NativeInput.WIIMOTE_BUTTON_RIGHT -> R.string.button_right; - case NativeInput.WIIMOTE_BUTTON_NUNCHUCK_UP -> R.string.button_nunchuck_up; - case NativeInput.WIIMOTE_BUTTON_NUNCHUCK_DOWN -> R.string.button_nunchuck_down; - case NativeInput.WIIMOTE_BUTTON_NUNCHUCK_LEFT -> R.string.button_nunchuck_left; - case NativeInput.WIIMOTE_BUTTON_NUNCHUCK_RIGHT -> R.string.button_nunchuck_right; - case NativeInput.WIIMOTE_BUTTON_HOME -> R.string.button_home; - default -> throw new IllegalArgumentException("Invalid buttonId " + buttonId + " for controllerType " + controllerType); - }; - } - throw new IllegalArgumentException("Invalid controllerType " + controllerType); - } - - public static class ControllerInput { - public int buttonResourceIdName; - public int buttonId; - public String boundInput; - - public ControllerInput(int buttonResourceIdName, int buttonId, String boundInput) { - this.boundInput = boundInput; - this.buttonId = buttonId; - this.buttonResourceIdName = buttonResourceIdName; - } - } - - public static class ControllerInputGroup { - public int groupResourceIdName; - public List inputs; - - public ControllerInputGroup(int groupResourceIdName, List inputs) { - this.groupResourceIdName = groupResourceIdName; - this.inputs = inputs; - } - } - - private void addControllerInputsGroup(List controllerInputItems, int groupResourceIdName, int controllerType, List buttons, Map inputs) { - List controllerInputs = buttons.stream().map(buttonId -> new ControllerInput(getButtonResourceIdName(controllerType, buttonId), buttonId, inputs.getOrDefault(buttonId, ""))).collect(Collectors.toList()); - controllerInputItems.add(new ControllerInputGroup(groupResourceIdName, controllerInputs)); - } - - public List getControllerInputs(int controllerType, Map inputs) { - List controllerInputItems = new ArrayList<>(); - if (controllerType == NativeInput.EMULATED_CONTROLLER_TYPE_VPAD) { - addControllerInputsGroup(controllerInputItems, R.string.buttons, controllerType, List.of(NativeInput.VPAD_BUTTON_A, NativeInput.VPAD_BUTTON_B, NativeInput.VPAD_BUTTON_X, NativeInput.VPAD_BUTTON_Y, NativeInput.VPAD_BUTTON_L, NativeInput.VPAD_BUTTON_R, NativeInput.VPAD_BUTTON_ZL, NativeInput.VPAD_BUTTON_ZR, NativeInput.VPAD_BUTTON_PLUS, NativeInput.VPAD_BUTTON_MINUS), inputs); - addControllerInputsGroup(controllerInputItems, R.string.d_pad, controllerType, List.of(NativeInput.VPAD_BUTTON_UP, NativeInput.VPAD_BUTTON_DOWN, NativeInput.VPAD_BUTTON_LEFT, NativeInput.VPAD_BUTTON_RIGHT), inputs); - addControllerInputsGroup(controllerInputItems, R.string.left_axis, controllerType, List.of(NativeInput.VPAD_BUTTON_STICKL, NativeInput.VPAD_BUTTON_STICKL_UP, NativeInput.VPAD_BUTTON_STICKL_DOWN, NativeInput.VPAD_BUTTON_STICKL_LEFT, NativeInput.VPAD_BUTTON_STICKL_RIGHT), inputs); - addControllerInputsGroup(controllerInputItems, R.string.right_axis, controllerType, List.of(NativeInput.VPAD_BUTTON_STICKR, NativeInput.VPAD_BUTTON_STICKR_UP, NativeInput.VPAD_BUTTON_STICKR_DOWN, NativeInput.VPAD_BUTTON_STICKR_LEFT, NativeInput.VPAD_BUTTON_STICKR_RIGHT), inputs); - addControllerInputsGroup(controllerInputItems, R.string.extra, controllerType, List.of(NativeInput.VPAD_BUTTON_MIC, NativeInput.VPAD_BUTTON_SCREEN, NativeInput.VPAD_BUTTON_HOME), inputs); - } - if (controllerType == NativeInput.EMULATED_CONTROLLER_TYPE_PRO) { - addControllerInputsGroup(controllerInputItems, R.string.buttons, controllerType, List.of(NativeInput.PRO_BUTTON_A, NativeInput.PRO_BUTTON_B, NativeInput.PRO_BUTTON_X, NativeInput.PRO_BUTTON_Y, NativeInput.PRO_BUTTON_L, NativeInput.PRO_BUTTON_R, NativeInput.PRO_BUTTON_ZL, NativeInput.PRO_BUTTON_ZR, NativeInput.PRO_BUTTON_PLUS, NativeInput.PRO_BUTTON_MINUS, NativeInput.PRO_BUTTON_HOME), inputs); - addControllerInputsGroup(controllerInputItems, R.string.left_axis, controllerType, List.of(NativeInput.PRO_BUTTON_STICKL, NativeInput.PRO_BUTTON_STICKL_UP, NativeInput.PRO_BUTTON_STICKL_DOWN, NativeInput.PRO_BUTTON_STICKL_LEFT, NativeInput.PRO_BUTTON_STICKL_RIGHT), inputs); - addControllerInputsGroup(controllerInputItems, R.string.right_axis, controllerType, List.of(NativeInput.PRO_BUTTON_STICKR, NativeInput.PRO_BUTTON_STICKR_UP, NativeInput.PRO_BUTTON_STICKR_DOWN, NativeInput.PRO_BUTTON_STICKR_LEFT, NativeInput.PRO_BUTTON_STICKR_RIGHT), inputs); - addControllerInputsGroup(controllerInputItems, R.string.d_pad, controllerType, List.of(NativeInput.PRO_BUTTON_UP, NativeInput.PRO_BUTTON_DOWN, NativeInput.PRO_BUTTON_LEFT, NativeInput.PRO_BUTTON_RIGHT), inputs); - } - if (controllerType == NativeInput.EMULATED_CONTROLLER_TYPE_CLASSIC) { - addControllerInputsGroup(controllerInputItems, R.string.buttons, controllerType, List.of(NativeInput.CLASSIC_BUTTON_A, NativeInput.CLASSIC_BUTTON_B, NativeInput.CLASSIC_BUTTON_X, NativeInput.CLASSIC_BUTTON_Y, NativeInput.CLASSIC_BUTTON_L, NativeInput.CLASSIC_BUTTON_R, NativeInput.CLASSIC_BUTTON_ZL, NativeInput.CLASSIC_BUTTON_ZR, NativeInput.CLASSIC_BUTTON_PLUS, NativeInput.CLASSIC_BUTTON_MINUS, NativeInput.CLASSIC_BUTTON_HOME), inputs); - addControllerInputsGroup(controllerInputItems, R.string.left_axis, controllerType, List.of(NativeInput.CLASSIC_BUTTON_STICKL_UP, NativeInput.CLASSIC_BUTTON_STICKL_DOWN, NativeInput.CLASSIC_BUTTON_STICKL_LEFT, NativeInput.CLASSIC_BUTTON_STICKL_RIGHT), inputs); - addControllerInputsGroup(controllerInputItems, R.string.right_axis, controllerType, List.of(NativeInput.CLASSIC_BUTTON_STICKR_UP, NativeInput.CLASSIC_BUTTON_STICKR_DOWN, NativeInput.CLASSIC_BUTTON_STICKR_LEFT, NativeInput.CLASSIC_BUTTON_STICKR_RIGHT), inputs); - addControllerInputsGroup(controllerInputItems, R.string.d_pad, controllerType, List.of(NativeInput.CLASSIC_BUTTON_UP, NativeInput.CLASSIC_BUTTON_DOWN, NativeInput.CLASSIC_BUTTON_LEFT, NativeInput.CLASSIC_BUTTON_RIGHT), inputs); - } - if (controllerType == NativeInput.EMULATED_CONTROLLER_TYPE_WIIMOTE) { - addControllerInputsGroup(controllerInputItems, R.string.buttons, controllerType, List.of(NativeInput.WIIMOTE_BUTTON_A, NativeInput.WIIMOTE_BUTTON_B, NativeInput.WIIMOTE_BUTTON_1, NativeInput.WIIMOTE_BUTTON_2, NativeInput.WIIMOTE_BUTTON_NUNCHUCK_Z, NativeInput.WIIMOTE_BUTTON_NUNCHUCK_C, NativeInput.WIIMOTE_BUTTON_PLUS, NativeInput.WIIMOTE_BUTTON_MINUS, NativeInput.WIIMOTE_BUTTON_HOME), inputs); - addControllerInputsGroup(controllerInputItems, R.string.d_pad, controllerType, List.of(NativeInput.WIIMOTE_BUTTON_UP, NativeInput.WIIMOTE_BUTTON_DOWN, NativeInput.WIIMOTE_BUTTON_LEFT, NativeInput.WIIMOTE_BUTTON_RIGHT), inputs); - addControllerInputsGroup(controllerInputItems, R.string.nunchuck, controllerType, List.of(NativeInput.WIIMOTE_BUTTON_NUNCHUCK_UP, NativeInput.WIIMOTE_BUTTON_NUNCHUCK_DOWN, NativeInput.WIIMOTE_BUTTON_NUNCHUCK_LEFT, NativeInput.WIIMOTE_BUTTON_NUNCHUCK_RIGHT), inputs); - } - return controllerInputItems; - } - -} diff --git a/src/android/app/src/main/java/info/cemu/Cemu/settings/input/ControllerInputsFragment.java b/src/android/app/src/main/java/info/cemu/Cemu/settings/input/ControllerInputsFragment.java index 479e7d54..ea1dbe56 100644 --- a/src/android/app/src/main/java/info/cemu/Cemu/settings/input/ControllerInputsFragment.java +++ b/src/android/app/src/main/java/info/cemu/Cemu/settings/input/ControllerInputsFragment.java @@ -8,31 +8,34 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.StringRes; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; import com.google.android.material.dialog.MaterialAlertDialogBuilder; -import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.function.Function; import info.cemu.Cemu.R; import info.cemu.Cemu.databinding.LayoutGenericRecyclerViewBinding; import info.cemu.Cemu.guibasecomponents.GenericRecyclerViewAdapter; import info.cemu.Cemu.guibasecomponents.HeaderRecyclerViewItem; import info.cemu.Cemu.guibasecomponents.SingleSelectionRecyclerViewItem; +import info.cemu.Cemu.guibasecomponents.ToggleRecyclerViewItem; import info.cemu.Cemu.input.InputManager; import info.cemu.Cemu.nativeinterface.NativeInput; public class ControllerInputsFragment extends Fragment { public static final String CONTROLLER_INDEX = "ControllerIndex"; private int controllerIndex; - private int controllerType; + private int controllerType = NativeInput.EMULATED_CONTROLLER_TYPE_DISABLED; private final InputManager inputManager = new InputManager(); - private final ControllerInputsDataProvider controllerInputsDataProvider = new ControllerInputsDataProvider(); private final GenericRecyclerViewAdapter genericRecyclerViewAdapter = new GenericRecyclerViewAdapter(); private final EmulatedControllerTypeAdapter emulatedControllerTypeAdapter = new EmulatedControllerTypeAdapter(); + private Function buttonIdToStringResourceIdFunction; private void onTypeChanged(int controllerType) { if (this.controllerType == controllerType) { @@ -41,57 +44,253 @@ public class ControllerInputsFragment extends Fragment { this.controllerType = controllerType; NativeInput.setControllerType(controllerIndex, controllerType); genericRecyclerViewAdapter.clearRecyclerViewItems(); - setControllerInputs(new HashMap<>()); + setControllerInputs(); } - private void setControllerInputs(Map inputs) { + private void addHeader(@StringRes int resId) { + genericRecyclerViewAdapter.addRecyclerViewItem(new HeaderRecyclerViewItem(resId)); + } + + private void onInputPressed(InputRecyclerViewItem inputItem, int buttonId, @StringRes int buttonResourceIdName) { + var inputDialog = new MaterialAlertDialogBuilder(requireContext()).setTitle(R.string.inputBindingDialogTitle) + .setMessage(getString(R.string.inputBindingDialogMessage, getString(buttonResourceIdName))) + .setNeutralButton(getString(R.string.clear), (dialogInterface, i) -> { + NativeInput.clearControllerMapping(controllerIndex, buttonId); + inputItem.clearBoundInput(); + dialogInterface.dismiss(); + }) + .setNegativeButton(getString(R.string.cancel), (dialogInterface, i) -> dialogInterface.dismiss()) + .show(); + TextView messageTextView = inputDialog.requireViewById(android.R.id.message); + messageTextView.setFocusableInTouchMode(true); + messageTextView.requestFocus(); + messageTextView.setOnKeyListener((v, keyCode, event) -> { + if (inputManager.mapKeyEventToMappingId(controllerIndex, buttonId, event)) { + inputItem.setBoundInput(NativeInput.getControllerMapping(controllerIndex, buttonId)); + inputDialog.dismiss(); + } + return true; + }); + messageTextView.setOnGenericMotionListener((v, event) -> { + if (inputManager.mapMotionEventToMappingId(controllerIndex, buttonId, event)) { + inputItem.setBoundInput(NativeInput.getControllerMapping(controllerIndex, buttonId)); + inputDialog.dismiss(); + } + return true; + }); + } + + private void addInput(int buttonId, @StringRes int buttonResourceIdName, String boundInput) { + InputRecyclerViewItem inputRecyclerViewItem = new InputRecyclerViewItem( + buttonResourceIdName, + boundInput, + inputItem -> onInputPressed(inputItem, buttonId, buttonResourceIdName) + ); + genericRecyclerViewAdapter.addRecyclerViewItem(inputRecyclerViewItem); + } + + void addControllerInputsGroup(@StringRes int groupTextResourceId, List buttonIds, Map boundInputsMap) { + addHeader(groupTextResourceId); + for (var buttonId : buttonIds) { + addInput(buttonId, buttonIdToStringResourceIdFunction.apply(buttonId), boundInputsMap.getOrDefault(buttonId, "")); + } + } + + private void setControllerInputs() { emulatedControllerTypeAdapter.setSelectedValue(controllerType); emulatedControllerTypeAdapter.setControllerTypeCounts(NativeInput.getVPADControllersCount(), NativeInput.getWPADControllersCount()); String controllerTypeName = getString(ControllerTypeResourceNameMapper.controllerTypeToResourceNameId(controllerType)); + buttonIdToStringResourceIdFunction = getButtonIdToStringResIdFn(controllerType); SingleSelectionRecyclerViewItem emulatedControllerSelection = new SingleSelectionRecyclerViewItem<>(getString(R.string.emulated_controller_label), getString(R.string.emulated_controller_selection_description, controllerTypeName), emulatedControllerTypeAdapter, (controllerType, selectionRecyclerViewItem) -> onTypeChanged(controllerType)); genericRecyclerViewAdapter.addRecyclerViewItem(emulatedControllerSelection); - for (var controllerInputsGroups : controllerInputsDataProvider.getControllerInputs(controllerType, inputs)) { - genericRecyclerViewAdapter.addRecyclerViewItem(new HeaderRecyclerViewItem(controllerInputsGroups.groupResourceIdName)); - for (var controllerInput : controllerInputsGroups.inputs) { - int buttonId = controllerInput.buttonId; - int buttonResourceIdName = controllerInput.buttonResourceIdName; - InputRecyclerViewItem inputRecyclerViewItem = new InputRecyclerViewItem(controllerInput.buttonResourceIdName, controllerInput.boundInput, inputItem -> { - var inputDialog = new MaterialAlertDialogBuilder(requireContext()).setTitle(R.string.inputBindingDialogTitle) - .setMessage(getString(R.string.inputBindingDialogMessage, getString(buttonResourceIdName))) - .setNeutralButton(getString(R.string.clear), (dialogInterface, i) -> { - NativeInput.clearControllerMapping(controllerIndex, buttonId); - inputItem.clearBoundInput(); - dialogInterface.dismiss(); - }) - .setNegativeButton(getString(R.string.cancel), (dialogInterface, i) -> dialogInterface.dismiss()) - .show(); - TextView messageTextView = inputDialog.requireViewById(android.R.id.message); - messageTextView.setFocusableInTouchMode(true); - messageTextView.requestFocus(); - messageTextView.setOnKeyListener((v, keyCode, event) -> { - if (inputManager.mapKeyEventToMappingId(controllerIndex, buttonId, event)) { - inputItem.setBoundInput(NativeInput.getControllerMapping(controllerIndex, buttonId)); - inputDialog.dismiss(); - } - return true; - }); - messageTextView.setOnGenericMotionListener((v, event) -> { - if (inputManager.mapMotionEventToMappingId(controllerIndex, buttonId, event)) { - inputItem.setBoundInput(NativeInput.getControllerMapping(controllerIndex, buttonId)); - inputDialog.dismiss(); - } - return true; - }); - }); - genericRecyclerViewAdapter.addRecyclerViewItem(inputRecyclerViewItem); - } + switch (controllerType) { + case NativeInput.EMULATED_CONTROLLER_TYPE_VPAD -> configureVPADInputs(); + case NativeInput.EMULATED_CONTROLLER_TYPE_PRO -> configureProInputs(); + case NativeInput.EMULATED_CONTROLLER_TYPE_CLASSIC -> configureClassicInputs(); + case NativeInput.EMULATED_CONTROLLER_TYPE_WIIMOTE -> configureWiimoteInputs(); } } + void configureVPADInputs() { + Map boundInputsMap = NativeInput.getControllerMappings(controllerIndex); + addControllerInputsGroup( + R.string.buttons, + List.of(NativeInput.VPAD_BUTTON_A, + NativeInput.VPAD_BUTTON_B, + NativeInput.VPAD_BUTTON_X, + NativeInput.VPAD_BUTTON_Y, + NativeInput.VPAD_BUTTON_L, + NativeInput.VPAD_BUTTON_R, + NativeInput.VPAD_BUTTON_ZL, + NativeInput.VPAD_BUTTON_ZR, + NativeInput.VPAD_BUTTON_PLUS, + NativeInput.VPAD_BUTTON_MINUS), + boundInputsMap + ); + addControllerInputsGroup( + R.string.d_pad, + List.of(NativeInput.VPAD_BUTTON_UP, + NativeInput.VPAD_BUTTON_DOWN, + NativeInput.VPAD_BUTTON_LEFT, + NativeInput.VPAD_BUTTON_RIGHT), + boundInputsMap + ); + addControllerInputsGroup( + R.string.left_axis, + List.of(NativeInput.VPAD_BUTTON_STICKL, + NativeInput.VPAD_BUTTON_STICKL_UP, + NativeInput.VPAD_BUTTON_STICKL_DOWN, + NativeInput.VPAD_BUTTON_STICKL_LEFT, + NativeInput.VPAD_BUTTON_STICKL_RIGHT), + boundInputsMap + ); + addControllerInputsGroup( + R.string.right_axis, + List.of(NativeInput.VPAD_BUTTON_STICKR, + NativeInput.VPAD_BUTTON_STICKR_UP, + NativeInput.VPAD_BUTTON_STICKR_DOWN, + NativeInput.VPAD_BUTTON_STICKR_LEFT, + NativeInput.VPAD_BUTTON_STICKR_RIGHT), + boundInputsMap + ); + addControllerInputsGroup( + R.string.extra, + List.of(NativeInput.VPAD_BUTTON_MIC, + NativeInput.VPAD_BUTTON_HOME, + NativeInput.VPAD_BUTTON_SCREEN), + boundInputsMap + ); + ToggleRecyclerViewItem toggleShowScreen = new ToggleRecyclerViewItem( + getString(R.string.toggle_screen), + getString(R.string.toggle_screen_description), + NativeInput.getVPADScreenToggle(controllerIndex), + toggle -> NativeInput.setVPADScreenToggle(controllerIndex, toggle) + ); + genericRecyclerViewAdapter.addRecyclerViewItem(toggleShowScreen); + } + + void configureProInputs() { + Map boundInputsMap = NativeInput.getControllerMappings(controllerIndex); + addControllerInputsGroup( + R.string.buttons, + List.of(NativeInput.PRO_BUTTON_A, + NativeInput.PRO_BUTTON_B, + NativeInput.PRO_BUTTON_X, + NativeInput.PRO_BUTTON_Y, + NativeInput.PRO_BUTTON_L, + NativeInput.PRO_BUTTON_R, + NativeInput.PRO_BUTTON_ZL, + NativeInput.PRO_BUTTON_ZR, + NativeInput.PRO_BUTTON_PLUS, + NativeInput.PRO_BUTTON_MINUS, + NativeInput.PRO_BUTTON_HOME), + boundInputsMap + ); + addControllerInputsGroup( + R.string.left_axis, + List.of(NativeInput.PRO_BUTTON_STICKL, + NativeInput.PRO_BUTTON_STICKL_UP, + NativeInput.PRO_BUTTON_STICKL_DOWN, + NativeInput.PRO_BUTTON_STICKL_LEFT, + NativeInput.PRO_BUTTON_STICKL_RIGHT), + boundInputsMap + ); + addControllerInputsGroup( + R.string.right_axis, + List.of(NativeInput.PRO_BUTTON_STICKR, + NativeInput.PRO_BUTTON_STICKR_UP, + NativeInput.PRO_BUTTON_STICKR_DOWN, + NativeInput.PRO_BUTTON_STICKR_LEFT, + NativeInput.PRO_BUTTON_STICKR_RIGHT), + boundInputsMap + ); + addControllerInputsGroup( + R.string.d_pad, + List.of(NativeInput.PRO_BUTTON_UP, + NativeInput.PRO_BUTTON_DOWN, + NativeInput.PRO_BUTTON_LEFT, + NativeInput.PRO_BUTTON_RIGHT), + boundInputsMap + ); + } + + void configureClassicInputs() { + Map boundInputsMap = NativeInput.getControllerMappings(controllerIndex); + addControllerInputsGroup( + R.string.buttons, + List.of(NativeInput.CLASSIC_BUTTON_A, + NativeInput.CLASSIC_BUTTON_B, + NativeInput.CLASSIC_BUTTON_X, + NativeInput.CLASSIC_BUTTON_Y, + NativeInput.CLASSIC_BUTTON_L, + NativeInput.CLASSIC_BUTTON_R, + NativeInput.CLASSIC_BUTTON_ZL, + NativeInput.CLASSIC_BUTTON_ZR, + NativeInput.CLASSIC_BUTTON_PLUS, + NativeInput.CLASSIC_BUTTON_MINUS, + NativeInput.CLASSIC_BUTTON_HOME), + boundInputsMap + ); + addControllerInputsGroup( + R.string.left_axis, + List.of(NativeInput.CLASSIC_BUTTON_STICKL_UP, + NativeInput.CLASSIC_BUTTON_STICKL_DOWN, + NativeInput.CLASSIC_BUTTON_STICKL_LEFT, + NativeInput.CLASSIC_BUTTON_STICKL_RIGHT), + boundInputsMap + ); + addControllerInputsGroup( + R.string.right_axis, + List.of(NativeInput.CLASSIC_BUTTON_STICKR_UP, + NativeInput.CLASSIC_BUTTON_STICKR_DOWN, + NativeInput.CLASSIC_BUTTON_STICKR_LEFT, + NativeInput.CLASSIC_BUTTON_STICKR_RIGHT), + boundInputsMap + ); + addControllerInputsGroup( + R.string.d_pad, + List.of(NativeInput.CLASSIC_BUTTON_UP, + NativeInput.CLASSIC_BUTTON_DOWN, + NativeInput.CLASSIC_BUTTON_LEFT, + NativeInput.CLASSIC_BUTTON_RIGHT), + boundInputsMap + ); + } + + void configureWiimoteInputs() { + Map boundInputsMap = NativeInput.getControllerMappings(controllerIndex); + addControllerInputsGroup( + R.string.buttons, + List.of(NativeInput.WIIMOTE_BUTTON_A, + NativeInput.WIIMOTE_BUTTON_B, + NativeInput.WIIMOTE_BUTTON_1, + NativeInput.WIIMOTE_BUTTON_2, + NativeInput.WIIMOTE_BUTTON_NUNCHUCK_Z, + NativeInput.WIIMOTE_BUTTON_NUNCHUCK_C, + NativeInput.WIIMOTE_BUTTON_PLUS, + NativeInput.WIIMOTE_BUTTON_MINUS, + NativeInput.WIIMOTE_BUTTON_HOME), + boundInputsMap); + addControllerInputsGroup( + R.string.d_pad, + List.of(NativeInput.WIIMOTE_BUTTON_UP, + NativeInput.WIIMOTE_BUTTON_DOWN, + NativeInput.WIIMOTE_BUTTON_LEFT, + NativeInput.WIIMOTE_BUTTON_RIGHT), + boundInputsMap); + addControllerInputsGroup( + R.string.nunchuck, + List.of(NativeInput.WIIMOTE_BUTTON_NUNCHUCK_UP, + NativeInput.WIIMOTE_BUTTON_NUNCHUCK_DOWN, + NativeInput.WIIMOTE_BUTTON_NUNCHUCK_LEFT, + NativeInput.WIIMOTE_BUTTON_NUNCHUCK_RIGHT), + boundInputsMap); + } + @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { @@ -101,16 +300,140 @@ public class ControllerInputsFragment extends Fragment { if (actionBar != null) { actionBar.setTitle(getString(R.string.controller_numbered, controllerIndex + 1)); } - if (NativeInput.isControllerDisabled(controllerIndex)) { - controllerType = NativeInput.EMULATED_CONTROLLER_TYPE_DISABLED; - } else { + if (!NativeInput.isControllerDisabled(controllerIndex)) { controllerType = NativeInput.getControllerType(controllerIndex); } - - setControllerInputs(NativeInput.getControllerMappings(controllerIndex)); + setControllerInputs(); var binding = LayoutGenericRecyclerViewBinding.inflate(inflater, container, false); binding.recyclerView.setAdapter(genericRecyclerViewAdapter); return binding.getRoot(); } + + private Function getButtonIdToStringResIdFn(int controllerType) { + return switch (controllerType) { + case NativeInput.EMULATED_CONTROLLER_TYPE_VPAD -> this::getButtonVPADResourceIdName; + case NativeInput.EMULATED_CONTROLLER_TYPE_PRO -> this::getButtonProControllerResourceIdName; + case NativeInput.EMULATED_CONTROLLER_TYPE_CLASSIC -> this::getButtonClassicControllerResourceIdName; + case NativeInput.EMULATED_CONTROLLER_TYPE_WIIMOTE -> this::getButtonWiimoteResourceIdName; + case NativeInput.EMULATED_CONTROLLER_TYPE_DISABLED -> null; + default -> throw new IllegalArgumentException("Invalid controllerType " + controllerType); + }; + } + + private int getButtonVPADResourceIdName(int buttonId) { + return switch (buttonId) { + case NativeInput.VPAD_BUTTON_A -> R.string.button_a; + case NativeInput.VPAD_BUTTON_B -> R.string.button_b; + case NativeInput.VPAD_BUTTON_X -> R.string.button_x; + case NativeInput.VPAD_BUTTON_Y -> R.string.button_y; + case NativeInput.VPAD_BUTTON_L -> R.string.button_l; + case NativeInput.VPAD_BUTTON_R -> R.string.button_r; + case NativeInput.VPAD_BUTTON_ZL -> R.string.button_zl; + case NativeInput.VPAD_BUTTON_ZR -> R.string.button_zr; + case NativeInput.VPAD_BUTTON_PLUS -> R.string.button_plus; + case NativeInput.VPAD_BUTTON_MINUS -> R.string.button_minus; + case NativeInput.VPAD_BUTTON_UP -> R.string.button_up; + case NativeInput.VPAD_BUTTON_DOWN -> R.string.button_down; + case NativeInput.VPAD_BUTTON_LEFT -> R.string.button_left; + case NativeInput.VPAD_BUTTON_RIGHT -> R.string.button_right; + case NativeInput.VPAD_BUTTON_STICKL -> R.string.button_stickl; + case NativeInput.VPAD_BUTTON_STICKR -> R.string.button_stickr; + case NativeInput.VPAD_BUTTON_STICKL_UP -> R.string.button_stickl_up; + case NativeInput.VPAD_BUTTON_STICKL_DOWN -> R.string.button_stickl_down; + case NativeInput.VPAD_BUTTON_STICKL_LEFT -> R.string.button_stickl_left; + case NativeInput.VPAD_BUTTON_STICKL_RIGHT -> R.string.button_stickl_right; + case NativeInput.VPAD_BUTTON_STICKR_UP -> R.string.button_stickr_up; + case NativeInput.VPAD_BUTTON_STICKR_DOWN -> R.string.button_stickr_down; + case NativeInput.VPAD_BUTTON_STICKR_LEFT -> R.string.button_stickr_left; + case NativeInput.VPAD_BUTTON_STICKR_RIGHT -> R.string.button_stickr_right; + case NativeInput.VPAD_BUTTON_MIC -> R.string.button_mic; + case NativeInput.VPAD_BUTTON_SCREEN -> R.string.button_screen; + case NativeInput.VPAD_BUTTON_HOME -> R.string.button_home; + default -> throw new IllegalArgumentException("Invalid buttonId " + buttonId + " for VPAD controller type"); + }; + } + + private int getButtonProControllerResourceIdName(int buttonId) { + return switch (buttonId) { + case NativeInput.PRO_BUTTON_A -> R.string.button_a; + case NativeInput.PRO_BUTTON_B -> R.string.button_b; + case NativeInput.PRO_BUTTON_X -> R.string.button_x; + case NativeInput.PRO_BUTTON_Y -> R.string.button_y; + case NativeInput.PRO_BUTTON_L -> R.string.button_l; + case NativeInput.PRO_BUTTON_R -> R.string.button_r; + case NativeInput.PRO_BUTTON_ZL -> R.string.button_zl; + case NativeInput.PRO_BUTTON_ZR -> R.string.button_zr; + case NativeInput.PRO_BUTTON_PLUS -> R.string.button_plus; + case NativeInput.PRO_BUTTON_MINUS -> R.string.button_minus; + case NativeInput.PRO_BUTTON_HOME -> R.string.button_home; + case NativeInput.PRO_BUTTON_UP -> R.string.button_up; + case NativeInput.PRO_BUTTON_DOWN -> R.string.button_down; + case NativeInput.PRO_BUTTON_LEFT -> R.string.button_left; + case NativeInput.PRO_BUTTON_RIGHT -> R.string.button_right; + case NativeInput.PRO_BUTTON_STICKL -> R.string.button_stickl; + case NativeInput.PRO_BUTTON_STICKR -> R.string.button_stickr; + case NativeInput.PRO_BUTTON_STICKL_UP -> R.string.button_stickl_up; + case NativeInput.PRO_BUTTON_STICKL_DOWN -> R.string.button_stickl_down; + case NativeInput.PRO_BUTTON_STICKL_LEFT -> R.string.button_stickl_left; + case NativeInput.PRO_BUTTON_STICKL_RIGHT -> R.string.button_stickl_right; + case NativeInput.PRO_BUTTON_STICKR_UP -> R.string.button_stickr_up; + case NativeInput.PRO_BUTTON_STICKR_DOWN -> R.string.button_stickr_down; + case NativeInput.PRO_BUTTON_STICKR_LEFT -> R.string.button_stickr_left; + case NativeInput.PRO_BUTTON_STICKR_RIGHT -> R.string.button_stickr_right; + default -> throw new IllegalArgumentException("Invalid buttonId " + buttonId + " for Pro controller type"); + }; + } + + private int getButtonClassicControllerResourceIdName(int buttonId) { + return switch (buttonId) { + case NativeInput.CLASSIC_BUTTON_A -> R.string.button_a; + case NativeInput.CLASSIC_BUTTON_B -> R.string.button_b; + case NativeInput.CLASSIC_BUTTON_X -> R.string.button_x; + case NativeInput.CLASSIC_BUTTON_Y -> R.string.button_y; + case NativeInput.CLASSIC_BUTTON_L -> R.string.button_l; + case NativeInput.CLASSIC_BUTTON_R -> R.string.button_r; + case NativeInput.CLASSIC_BUTTON_ZL -> R.string.button_zl; + case NativeInput.CLASSIC_BUTTON_ZR -> R.string.button_zr; + case NativeInput.CLASSIC_BUTTON_PLUS -> R.string.button_plus; + case NativeInput.CLASSIC_BUTTON_MINUS -> R.string.button_minus; + case NativeInput.CLASSIC_BUTTON_HOME -> R.string.button_home; + case NativeInput.CLASSIC_BUTTON_UP -> R.string.button_up; + case NativeInput.CLASSIC_BUTTON_DOWN -> R.string.button_down; + case NativeInput.CLASSIC_BUTTON_LEFT -> R.string.button_left; + case NativeInput.CLASSIC_BUTTON_RIGHT -> R.string.button_right; + case NativeInput.CLASSIC_BUTTON_STICKL_UP -> R.string.button_stickl_up; + case NativeInput.CLASSIC_BUTTON_STICKL_DOWN -> R.string.button_stickl_down; + case NativeInput.CLASSIC_BUTTON_STICKL_LEFT -> R.string.button_stickl_left; + case NativeInput.CLASSIC_BUTTON_STICKL_RIGHT -> R.string.button_stickl_right; + case NativeInput.CLASSIC_BUTTON_STICKR_UP -> R.string.button_stickr_up; + case NativeInput.CLASSIC_BUTTON_STICKR_DOWN -> R.string.button_stickr_down; + case NativeInput.CLASSIC_BUTTON_STICKR_LEFT -> R.string.button_stickr_left; + case NativeInput.CLASSIC_BUTTON_STICKR_RIGHT -> R.string.button_stickr_right; + default -> throw new IllegalArgumentException("Invalid buttonId " + buttonId + " for Classic controller type"); + }; + } + + private int getButtonWiimoteResourceIdName(int buttonId) { + return switch (buttonId) { + case NativeInput.WIIMOTE_BUTTON_A -> R.string.button_a; + case NativeInput.WIIMOTE_BUTTON_B -> R.string.button_b; + case NativeInput.WIIMOTE_BUTTON_1 -> R.string.button_1; + case NativeInput.WIIMOTE_BUTTON_2 -> R.string.button_2; + case NativeInput.WIIMOTE_BUTTON_NUNCHUCK_Z -> R.string.button_nunchuck_z; + case NativeInput.WIIMOTE_BUTTON_NUNCHUCK_C -> R.string.button_nunchuck_c; + case NativeInput.WIIMOTE_BUTTON_PLUS -> R.string.button_plus; + case NativeInput.WIIMOTE_BUTTON_MINUS -> R.string.button_minus; + case NativeInput.WIIMOTE_BUTTON_UP -> R.string.button_up; + case NativeInput.WIIMOTE_BUTTON_DOWN -> R.string.button_down; + case NativeInput.WIIMOTE_BUTTON_LEFT -> R.string.button_left; + case NativeInput.WIIMOTE_BUTTON_RIGHT -> R.string.button_right; + case NativeInput.WIIMOTE_BUTTON_NUNCHUCK_UP -> R.string.button_nunchuck_up; + case NativeInput.WIIMOTE_BUTTON_NUNCHUCK_DOWN -> R.string.button_nunchuck_down; + case NativeInput.WIIMOTE_BUTTON_NUNCHUCK_LEFT -> R.string.button_nunchuck_left; + case NativeInput.WIIMOTE_BUTTON_NUNCHUCK_RIGHT -> R.string.button_nunchuck_right; + case NativeInput.WIIMOTE_BUTTON_HOME -> R.string.button_home; + default -> throw new IllegalArgumentException("Invalid buttonId " + buttonId + " for Wiimote controller type"); + }; + } } \ No newline at end of file diff --git a/src/android/app/src/main/res/layout/layout_controller_input.xml b/src/android/app/src/main/res/layout/layout_controller_input.xml index fc778e86..11c66a91 100644 --- a/src/android/app/src/main/res/layout/layout_controller_input.xml +++ b/src/android/app/src/main/res/layout/layout_controller_input.xml @@ -8,14 +8,14 @@ android:orientation="vertical" android:padding="8dp"> - - Device doesn\'t support creating shortcuts Enabled graphic packs count Graphic pack is enabled + Toggle screen + Makes the \"show screen\" button toggle between the TV and gamepad screens \ No newline at end of file