summaryrefslogtreecommitdiff
path: root/Source/Android
diff options
context:
space:
mode:
authorJosJuice <josjuice@gmail.com>2022-01-23 21:47:57 +0100
committerJosJuice <josjuice@gmail.com>2023-03-03 22:28:24 +0100
commit2c529b9db12a60eb3640975f6ea4802237e118fa (patch)
tree4f88817c854ef49828cfab134bb5cdf8186c7306 /Source/Android
parentdd8976f18dd5fb0c44fb40f3a24803f6cc5009b2 (diff)
Android: Add new input mapping implementation
Diffstat (limited to 'Source/Android')
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/MotionAlertDialog.java169
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/MappingCommon.java24
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/Control.java27
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/ControlGroup.java29
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/ControlReference.java37
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/EmulatedController.java36
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/view/InputMappingControlSetting.java50
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/MotionAlertDialog.java95
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/viewholder/InputMappingControlSettingViewHolder.java (renamed from Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/InputBindingSettingViewHolder.java)28
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/Settings.java3
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/HeaderSetting.java5
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/InputBindingSetting.java108
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/RumbleBindingSetting.java69
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/SettingsItem.java3
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/MenuTag.java16
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsAdapter.java28
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragment.java16
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.java44
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/RumbleBindingViewHolder.java67
-rw-r--r--Source/Android/app/src/main/res/values/strings.xml18
-rw-r--r--Source/Android/jni/AndroidCommon/IDCache.cpp109
-rw-r--r--Source/Android/jni/AndroidCommon/IDCache.h16
-rw-r--r--Source/Android/jni/CMakeLists.txt9
-rw-r--r--Source/Android/jni/Input/Control.cpp51
-rw-r--r--Source/Android/jni/Input/Control.h13
-rw-r--r--Source/Android/jni/Input/ControlGroup.cpp51
-rw-r--r--Source/Android/jni/Input/ControlGroup.h13
-rw-r--r--Source/Android/jni/Input/ControlReference.cpp54
-rw-r--r--Source/Android/jni/Input/ControlReference.h11
-rw-r--r--Source/Android/jni/Input/EmulatedController.cpp81
-rw-r--r--Source/Android/jni/Input/MappingCommon.cpp56
31 files changed, 848 insertions, 488 deletions
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/MotionAlertDialog.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/MotionAlertDialog.java
deleted file mode 100644
index a111155181..0000000000
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/MotionAlertDialog.java
+++ /dev/null
@@ -1,169 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-package org.dolphinemu.dolphinemu.dialogs;
-
-import android.content.Context;
-import android.view.InputDevice;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.AlertDialog;
-
-import org.dolphinemu.dolphinemu.features.settings.model.view.InputBindingSetting;
-import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
-import org.dolphinemu.dolphinemu.utils.Log;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * {@link AlertDialog} derivative that listens for
- * motion events from controllers and joysticks.
- */
-public final class MotionAlertDialog extends AlertDialog
-{
- // The selected input preference
- private final InputBindingSetting setting;
- private final ArrayList<Float> mPreviousValues = new ArrayList<>();
- private int mPrevDeviceId = 0;
- private boolean mWaitingForEvent = true;
- private SettingsAdapter mAdapter;
-
- /**
- * Constructor
- *
- * @param context The current {@link Context}.
- * @param setting The Preference to show this dialog for.
- */
- public MotionAlertDialog(Context context, InputBindingSetting setting, SettingsAdapter adapter)
- {
- super(context);
-
- this.setting = setting;
- mAdapter = adapter;
- }
-
- public boolean onKeyEvent(int keyCode, KeyEvent event)
- {
- Log.debug("[MotionAlertDialog] Received key event: " + event.getAction());
- if (event.getAction() == KeyEvent.ACTION_UP)
- {
- if (true)
- {
- setting.onKeyInput(mAdapter.getSettings(), event);
- dismiss();
- }
- // Even if we ignore the key, we still consume it. Thus return true regardless.
- return true;
- }
- return false;
- }
-
- @Override
- public boolean onKeyLongPress(int keyCode, @NonNull KeyEvent event)
- {
- // Intended for devices with no touchscreen or mouse
- if (keyCode == KeyEvent.KEYCODE_BACK)
- {
- setting.clearValue(mAdapter.getSettings());
- dismiss();
- return true;
- }
- return super.onKeyLongPress(keyCode, event);
- }
-
- @Override
- public boolean dispatchKeyEvent(KeyEvent event)
- {
- // Handle this key if we care about it, otherwise pass it down the framework
- return onKeyEvent(event.getKeyCode(), event) || super.dispatchKeyEvent(event);
- }
-
- @Override
- public boolean dispatchGenericMotionEvent(@NonNull MotionEvent event)
- {
- // Handle this event if we care about it, otherwise pass it down the framework
- return onMotionEvent(event) || super.dispatchGenericMotionEvent(event);
- }
-
- private boolean onMotionEvent(MotionEvent event)
- {
- if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0)
- return false;
- if (event.getAction() != MotionEvent.ACTION_MOVE)
- return false;
-
- InputDevice input = event.getDevice();
-
- List<InputDevice.MotionRange> motionRanges = input.getMotionRanges();
-
- if (input.getId() != mPrevDeviceId)
- {
- mPreviousValues.clear();
- }
- mPrevDeviceId = input.getId();
- boolean firstEvent = mPreviousValues.isEmpty();
-
- int numMovedAxis = 0;
- float axisMoveValue = 0.0f;
- InputDevice.MotionRange lastMovedRange = null;
- char lastMovedDir = '?';
- if (mWaitingForEvent)
- {
- for (int i = 0; i < motionRanges.size(); i++)
- {
- InputDevice.MotionRange range = motionRanges.get(i);
- int axis = range.getAxis();
- float value = event.getAxisValue(axis);
- if (firstEvent)
- {
- mPreviousValues.add(value);
- }
- else
- {
- float previousValue = mPreviousValues.get(i);
-
- // Only handle the axes that are not neutral (more than 0.5)
- // but ignore any axis that has a constant value (e.g. always 1)
- if (Math.abs(value) > 0.5f && value != previousValue)
- {
- // It is common to have multiple axes with the same physical input. For example,
- // shoulder butters are provided as both AXIS_LTRIGGER and AXIS_BRAKE.
- // To handle this, we ignore an axis motion that's the exact same as a motion
- // we already saw. This way, we ignore axes with two names, but catch the case
- // where a joystick is moved in two directions.
- // ref: bottom of https://developer.android.com/training/game-controllers/controller-input.html
- if (value != axisMoveValue)
- {
- axisMoveValue = value;
- numMovedAxis++;
- lastMovedRange = range;
- lastMovedDir = value < 0.0f ? '-' : '+';
- }
- }
- // Special case for d-pads (axis value jumps between 0 and 1 without any values
- // in between). Without this, the user would need to press the d-pad twice
- // due to the first press being caught by the "if (firstEvent)" case further up.
- else if (Math.abs(value) < 0.25f && Math.abs(previousValue) > 0.75f)
- {
- numMovedAxis++;
- lastMovedRange = range;
- lastMovedDir = previousValue < 0.0f ? '-' : '+';
- }
- }
-
- mPreviousValues.set(i, value);
- }
-
- // If only one axis moved, that's the winner.
- if (numMovedAxis == 1)
- {
- mWaitingForEvent = false;
- setting.onMotionInput(mAdapter.getSettings(), input, lastMovedRange, lastMovedDir);
- dismiss();
- }
- }
- return true;
- }
-}
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/MappingCommon.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/MappingCommon.java
new file mode 100644
index 0000000000..cb136a908d
--- /dev/null
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/MappingCommon.java
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+package org.dolphinemu.dolphinemu.features.input.model;
+
+public final class MappingCommon
+{
+ private MappingCommon()
+ {
+ }
+
+ /**
+ * Waits until the user presses one or more inputs or until a timeout,
+ * then returns the pressed inputs.
+ *
+ * When this is being called, a separate thread must be calling ControllerInterface's
+ * dispatchKeyEvent and dispatchGenericMotionEvent, otherwise no inputs will be registered.
+ *
+ * @return The input(s) pressed by the user in the form of an InputCommon expression,
+ * or an empty string if there were no inputs.
+ */
+ public static native String detectInput();
+
+ public static native void save();
+}
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/Control.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/Control.java
new file mode 100644
index 0000000000..6033e17e37
--- /dev/null
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/Control.java
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+package org.dolphinemu.dolphinemu.features.input.model.controlleremu;
+
+import androidx.annotation.Keep;
+
+/**
+ * Represents a C++ ControllerEmu::Control.
+ *
+ * The lifetime of this class is managed by C++ code. Calling methods on it after it's destroyed
+ * in C++ is undefined behavior!
+ */
+public class Control
+{
+ @Keep
+ private final long mPointer;
+
+ @Keep
+ private Control(long pointer)
+ {
+ mPointer = pointer;
+ }
+
+ public native String getUiName();
+
+ public native ControlReference getControlReference();
+}
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/ControlGroup.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/ControlGroup.java
new file mode 100644
index 0000000000..ddfce9a737
--- /dev/null
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/ControlGroup.java
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+package org.dolphinemu.dolphinemu.features.input.model.controlleremu;
+
+import androidx.annotation.Keep;
+
+/**
+ * Represents a C++ ControllerEmu::ControlGroup.
+ *
+ * The lifetime of this class is managed by C++ code. Calling methods on it after it's destroyed
+ * in C++ is undefined behavior!
+ */
+public class ControlGroup
+{
+ @Keep
+ private final long mPointer;
+
+ @Keep
+ private ControlGroup(long pointer)
+ {
+ mPointer = pointer;
+ }
+
+ public native String getUiName();
+
+ public native int getControlCount();
+
+ public native Control getControl(int i);
+}
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/ControlReference.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/ControlReference.java
new file mode 100644
index 0000000000..fd01cc1705
--- /dev/null
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/ControlReference.java
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+package org.dolphinemu.dolphinemu.features.input.model.controlleremu;
+
+import androidx.annotation.Keep;
+import androidx.annotation.Nullable;
+
+/**
+ * Represents a C++ ControlReference.
+ *
+ * The lifetime of this class is managed by C++ code. Calling methods on it after it's destroyed
+ * in C++ is undefined behavior!
+ */
+public class ControlReference
+{
+ @Keep
+ private final long mPointer;
+
+ @Keep
+ private ControlReference(long pointer)
+ {
+ mPointer = pointer;
+ }
+
+ public native double getState();
+
+ public native String getExpression();
+
+ /**
+ * Sets the expression for this control reference.
+ *
+ * @param expr The new expression
+ * @return null on success, a human-readable error on failure
+ */
+ @Nullable
+ public native String setExpression(String expr);
+}
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/EmulatedController.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/EmulatedController.java
new file mode 100644
index 0000000000..b0fbd0fd92
--- /dev/null
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/EmulatedController.java
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+package org.dolphinemu.dolphinemu.features.input.model.controlleremu;
+
+import androidx.annotation.Keep;
+
+/**
+ * Represents a C++ ControllerEmu::EmulatedController.
+ *
+ * The lifetime of this class is managed by C++ code. Calling methods on it after it's destroyed
+ * in C++ is undefined behavior!
+ */
+public class EmulatedController
+{
+ @Keep
+ private final long mPointer;
+
+ @Keep
+ private EmulatedController(long pointer)
+ {
+ mPointer = pointer;
+ }
+
+ public native int getGroupCount();
+
+ public native ControlGroup getGroup(int index);
+
+ public native void updateSingleControlReference(ControlReference controlReference);
+
+ public static native EmulatedController getGcPad(int controllerIndex);
+
+ public static native EmulatedController getWiimote(int controllerIndex);
+
+ public static native EmulatedController getWiimoteAttachment(int controllerIndex,
+ int attachmentIndex);
+}
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/view/InputMappingControlSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/view/InputMappingControlSetting.java
new file mode 100644
index 0000000000..8888e2430b
--- /dev/null
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/view/InputMappingControlSetting.java
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+package org.dolphinemu.dolphinemu.features.input.model.view;
+
+import org.dolphinemu.dolphinemu.features.input.model.controlleremu.Control;
+import org.dolphinemu.dolphinemu.features.input.model.controlleremu.ControlReference;
+import org.dolphinemu.dolphinemu.features.input.model.controlleremu.EmulatedController;
+import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
+import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
+
+public final class InputMappingControlSetting extends SettingsItem
+{
+ private final ControlReference mControlReference;
+ private final EmulatedController mController;
+
+ public InputMappingControlSetting(Control control, EmulatedController controller)
+ {
+ super(control.getUiName(), "");
+ mControlReference = control.getControlReference();
+ mController = controller;
+ }
+
+ public String getValue()
+ {
+ return mControlReference.getExpression();
+ }
+
+ public void setValue(String expr)
+ {
+ mControlReference.setExpression(expr);
+ mController.updateSingleControlReference(mControlReference);
+ }
+
+ public void clearValue()
+ {
+ setValue("");
+ }
+
+ @Override
+ public int getType()
+ {
+ return TYPE_INPUT_MAPPING_CONTROL;
+ }
+
+ @Override
+ public AbstractSetting getSetting()
+ {
+ return null;
+ }
+}
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/MotionAlertDialog.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/MotionAlertDialog.java
new file mode 100644
index 0000000000..f36d9bc478
--- /dev/null
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/MotionAlertDialog.java
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+package org.dolphinemu.dolphinemu.features.input.ui;
+
+import android.app.Activity;
+import android.view.InputDevice;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+
+import org.dolphinemu.dolphinemu.features.input.model.ControllerInterface;
+import org.dolphinemu.dolphinemu.features.input.model.MappingCommon;
+import org.dolphinemu.dolphinemu.features.input.model.view.InputMappingControlSetting;
+
+/**
+ * {@link AlertDialog} derivative that listens for
+ * motion events from controllers and joysticks.
+ */
+public final class MotionAlertDialog extends AlertDialog
+{
+ private final Activity mActivity;
+ private final InputMappingControlSetting mSetting;
+ private boolean mRunning = false;
+
+ /**
+ * Constructor
+ *
+ * @param activity The current {@link Activity}.
+ * @param setting The setting to show this dialog for.
+ */
+ public MotionAlertDialog(Activity activity, InputMappingControlSetting setting)
+ {
+ super(activity);
+
+ mActivity = activity;
+ mSetting = setting;
+ }
+
+ @Override
+ protected void onStart()
+ {
+ super.onStart();
+
+ mRunning = true;
+ new Thread(() ->
+ {
+ String result = MappingCommon.detectInput();
+ mActivity.runOnUiThread(() ->
+ {
+ if (mRunning)
+ {
+ mSetting.setValue(result);
+ dismiss();
+ }
+ });
+ }).start();
+ }
+
+ @Override
+ protected void onStop()
+ {
+ super.onStop();
+ mRunning = false;
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event)
+ {
+ ControllerInterface.dispatchKeyEvent(event);
+
+ if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.isLongPress())
+ {
+ // Special case: Let the user cancel by long-pressing Back (intended for non-touch devices)
+ mSetting.clearValue();
+ dismiss();
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean dispatchGenericMotionEvent(@NonNull MotionEvent event)
+ {
+ if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0)
+ {
+ // Special case: Let the user cancel by touching an on-screen button
+ return super.dispatchGenericMotionEvent(event);
+ }
+
+ ControllerInterface.dispatchGenericMotionEvent(event);
+ return true;
+ }
+}
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/InputBindingSettingViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/viewholder/InputMappingControlSettingViewHolder.java
index b61fcc458b..72ddcb3fd3 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/InputBindingSettingViewHolder.java
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/viewholder/InputMappingControlSettingViewHolder.java
@@ -1,46 +1,38 @@
// SPDX-License-Identifier: GPL-2.0-or-later
-package org.dolphinemu.dolphinemu.features.settings.ui.viewholder;
+package org.dolphinemu.dolphinemu.features.input.ui.viewholder;
-import android.content.Context;
-import android.content.SharedPreferences;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.preference.PreferenceManager;
import org.dolphinemu.dolphinemu.databinding.ListItemSettingBinding;
-import org.dolphinemu.dolphinemu.features.settings.model.view.InputBindingSetting;
+import org.dolphinemu.dolphinemu.features.input.model.view.InputMappingControlSetting;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
+import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.SettingViewHolder;
-public final class InputBindingSettingViewHolder extends SettingViewHolder
+public final class InputMappingControlSettingViewHolder extends SettingViewHolder
{
- private InputBindingSetting mItem;
-
- private final Context mContext;
+ private InputMappingControlSetting mItem;
private final ListItemSettingBinding mBinding;
- public InputBindingSettingViewHolder(@NonNull ListItemSettingBinding binding,
- SettingsAdapter adapter, Context context)
+ public InputMappingControlSettingViewHolder(@NonNull ListItemSettingBinding binding,
+ SettingsAdapter adapter)
{
super(binding.getRoot(), adapter);
mBinding = binding;
- mContext = context;
}
@Override
public void bind(SettingsItem item)
{
- SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
-
- mItem = (InputBindingSetting) item;
+ mItem = (InputMappingControlSetting) item;
mBinding.textSettingName.setText(mItem.getName());
- mBinding.textSettingDescription
- .setText(sharedPreferences.getString(mItem.getKey() + mItem.getGameId(), ""));
+ mBinding.textSettingDescription.setText(mItem.getValue());
setStyle(mBinding.textSettingName, mItem);
}
@@ -54,7 +46,7 @@ public final class InputBindingSettingViewHolder extends SettingViewHolder
return;
}
- getAdapter().onInputBindingClick(mItem, getBindingAdapterPosition());
+ getAdapter().onInputMappingClick(mItem, getBindingAdapterPosition());
setStyle(mBinding.textSettingName, mItem);
}
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 7d3d5a5b19..9a94048838 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
@@ -8,6 +8,7 @@ import android.widget.Toast;
import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.R;
+import org.dolphinemu.dolphinemu.features.input.model.MappingCommon;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsActivityView;
import org.dolphinemu.dolphinemu.features.settings.utils.SettingsFile;
import org.dolphinemu.dolphinemu.services.GameFileCacheManager;
@@ -170,6 +171,8 @@ public class Settings implements Closeable
SettingsFile.saveFile(entry.getKey(), entry.getValue(), view);
}
+ MappingCommon.save();
+
NativeConfig.save(NativeConfig.LAYER_BASE);
if (!NativeLibrary.IsRunning())
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/HeaderSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/HeaderSetting.java
index 14c5f49021..b65f45837b 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/HeaderSetting.java
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/HeaderSetting.java
@@ -13,6 +13,11 @@ public class HeaderSetting extends SettingsItem
super(context, titleId, descriptionId);
}
+ public HeaderSetting(CharSequence title, CharSequence description)
+ {
+ super(title, description);
+ }
+
@Override
public int getType()
{
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
deleted file mode 100644
index 175986d3ba..0000000000
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/InputBindingSetting.java
+++ /dev/null
@@ -1,108 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-package org.dolphinemu.dolphinemu.features.settings.model.view;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.view.InputDevice;
-import android.view.KeyEvent;
-
-import androidx.preference.PreferenceManager;
-
-import org.dolphinemu.dolphinemu.DolphinApplication;
-import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
-import org.dolphinemu.dolphinemu.features.settings.model.Settings;
-
-public class InputBindingSetting extends SettingsItem
-{
- private String mFile;
- private String mSection;
- private String mKey;
-
- private String mGameId;
-
- public InputBindingSetting(Context context, String file, String section, String key, int titleId,
- String gameId)
- {
- super(context, titleId, 0);
- mFile = file;
- mSection = section;
- mKey = key;
- mGameId = gameId;
- }
-
- public String getKey()
- {
- return mKey;
- }
-
- public String getValue(Settings settings)
- {
- return settings.getSection(mFile, mSection).getString(mKey, "");
- }
-
- /**
- * Saves the provided key input setting both to the INI file (so native code can use it) and as
- * an Android preference (so it persists correctly and is human-readable.)
- *
- * @param keyEvent KeyEvent of this key press.
- */
- public void onKeyInput(Settings settings, KeyEvent keyEvent)
- {
- InputDevice device = keyEvent.getDevice();
- String bindStr = "Device '" + device.getDescriptor() + "'-Button " + keyEvent.getKeyCode();
- String uiString = device.getName() + ": Button " + keyEvent.getKeyCode();
- setValue(settings, bindStr, uiString);
- }
-
- /**
- * Saves the provided motion input setting both to the INI file (so native code can use it) and as
- * an Android preference (so it persists correctly and is human-readable.)
- *
- * @param device InputDevice from which the input event originated.
- * @param motionRange MotionRange of the movement
- * @param axisDir Either '-' or '+'
- */
- public void onMotionInput(Settings settings, InputDevice device,
- InputDevice.MotionRange motionRange, char axisDir)
- {
- String bindStr =
- "Device '" + device.getDescriptor() + "'-Axis " + motionRange.getAxis() + axisDir;
- String uiString = device.getName() + ": Axis " + motionRange.getAxis() + axisDir;
- setValue(settings, bindStr, uiString);
- }
-
- public void setValue(Settings settings, String bind, String ui)
- {
- SharedPreferences
- preferences =
- PreferenceManager.getDefaultSharedPreferences(DolphinApplication.getAppContext());
- SharedPreferences.Editor editor = preferences.edit();
- editor.putString(mKey + mGameId, ui);
- editor.apply();
-
- settings.getSection(mFile, mSection).setString(mKey, bind);
- }
-
- public void clearValue(Settings settings)
- {
- setValue(settings, "", "");
- }
-
- @Override
- public int getType()
- {
- return TYPE_INPUT_BINDING;
- }
-
- public String getGameId()
- {
- return mGameId;
- }
-
- @Override
- public AbstractSetting getSetting()
- {
- return null;
- }
-}
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/RumbleBindingSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/RumbleBindingSetting.java
deleted file mode 100644
index 6c3e11e17b..0000000000
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/RumbleBindingSetting.java
+++ /dev/null
@@ -1,69 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-package org.dolphinemu.dolphinemu.features.settings.model.view;
-
-import android.content.Context;
-import android.os.Vibrator;
-import android.view.InputDevice;
-import android.view.KeyEvent;
-
-import org.dolphinemu.dolphinemu.DolphinApplication;
-import org.dolphinemu.dolphinemu.R;
-import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
-import org.dolphinemu.dolphinemu.features.settings.model.Settings;
-import org.dolphinemu.dolphinemu.utils.Rumble;
-
-public class RumbleBindingSetting extends InputBindingSetting
-{
- public RumbleBindingSetting(Context context, String file, String section, String key, int titleId,
- String gameId)
- {
- super(context, file, section, key, titleId, gameId);
- }
-
- /**
- * Just need the device when saving rumble.
- */
- @Override
- public void onKeyInput(Settings settings, KeyEvent keyEvent)
- {
- saveRumble(settings, keyEvent.getDevice());
- }
-
- /**
- * Just need the device when saving rumble.
- */
- @Override
- public void onMotionInput(Settings settings, InputDevice device,
- InputDevice.MotionRange motionRange, char axisDir)
- {
- saveRumble(settings, device);
- }
-
- private void saveRumble(Settings settings, InputDevice device)
- {
- Vibrator vibrator = device.getVibrator();
- if (vibrator != null && vibrator.hasVibrator())
- {
- setValue(settings, device.getDescriptor(), device.getName());
- Rumble.doRumble(vibrator);
- }
- else
- {
- setValue(settings, "",
- DolphinApplication.getAppContext().getString(R.string.rumble_not_found));
- }
- }
-
- @Override
- public int getType()
- {
- return TYPE_RUMBLE_BINDING;
- }
-
- @Override
- public AbstractSetting getSetting()
- {
- return null;
- }
-}
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 7b41c8e3f8..9c7b89c12f 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
@@ -21,9 +21,8 @@ public abstract class SettingsItem
public static final int TYPE_SINGLE_CHOICE = 2;
public static final int TYPE_SLIDER = 3;
public static final int TYPE_SUBMENU = 4;
- public static final int TYPE_INPUT_BINDING = 5;
+ public static final int TYPE_INPUT_MAPPING_CONTROL = 5;
public static final int TYPE_STRING_SINGLE_CHOICE = 6;
- public static final int TYPE_RUMBLE_BINDING = 7;
public static final int TYPE_SINGLE_CHOICE_DYNAMIC_DESCRIPTIONS = 8;
public static final int TYPE_FILE_PICKER = 9;
public static final int TYPE_RUN_RUNNABLE = 10;
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/MenuTag.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/MenuTag.java
index 6fc30a381b..1d4fe28af9 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/MenuTag.java
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/MenuTag.java
@@ -31,14 +31,14 @@ public enum MenuTag
GCPAD_2("gcpad", 1),
GCPAD_3("gcpad", 2),
GCPAD_4("gcpad", 3),
- WIIMOTE_1("wiimote", 4),
- WIIMOTE_2("wiimote", 5),
- WIIMOTE_3("wiimote", 6),
- WIIMOTE_4("wiimote", 7),
- WIIMOTE_EXTENSION_1("wiimote_extension", 4),
- WIIMOTE_EXTENSION_2("wiimote_extension", 5),
- WIIMOTE_EXTENSION_3("wiimote_extension", 6),
- WIIMOTE_EXTENSION_4("wiimote_extension", 7);
+ WIIMOTE_1("wiimote", 0),
+ WIIMOTE_2("wiimote", 1),
+ WIIMOTE_3("wiimote", 2),
+ WIIMOTE_4("wiimote", 3),
+ WIIMOTE_EXTENSION_1("wiimote_extension", 0),
+ WIIMOTE_EXTENSION_2("wiimote_extension", 1),
+ WIIMOTE_EXTENSION_3("wiimote_extension", 2),
+ WIIMOTE_EXTENSION_4("wiimote_extension", 3);
private String tag;
private int subType = -1;
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 a7f028afe3..8fe3fe4602 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
@@ -37,15 +37,15 @@ import org.dolphinemu.dolphinemu.databinding.ListItemHeaderBinding;
import org.dolphinemu.dolphinemu.databinding.ListItemSettingBinding;
import org.dolphinemu.dolphinemu.databinding.ListItemSettingSwitchBinding;
import org.dolphinemu.dolphinemu.databinding.ListItemSubmenuBinding;
-import org.dolphinemu.dolphinemu.dialogs.MotionAlertDialog;
+import org.dolphinemu.dolphinemu.features.input.ui.MotionAlertDialog;
+import org.dolphinemu.dolphinemu.features.input.model.view.InputMappingControlSetting;
+import org.dolphinemu.dolphinemu.features.input.ui.viewholder.InputMappingControlSettingViewHolder;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.features.settings.model.view.DateTimeChoiceSetting;
import org.dolphinemu.dolphinemu.features.settings.model.view.SwitchSetting;
import org.dolphinemu.dolphinemu.features.settings.model.view.FilePicker;
import org.dolphinemu.dolphinemu.features.settings.model.view.FloatSliderSetting;
-import org.dolphinemu.dolphinemu.features.settings.model.view.InputBindingSetting;
import org.dolphinemu.dolphinemu.features.settings.model.view.IntSliderSetting;
-import org.dolphinemu.dolphinemu.features.settings.model.view.RumbleBindingSetting;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.model.view.SingleChoiceSetting;
import org.dolphinemu.dolphinemu.features.settings.model.view.SingleChoiceSettingDynamicDescriptions;
@@ -57,9 +57,7 @@ import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.DateTimeSetting
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.FilePickerViewHolder;
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.HeaderHyperLinkViewHolder;
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.HeaderViewHolder;
-import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.InputBindingSettingViewHolder;
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.InputStringSettingViewHolder;
-import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.RumbleBindingViewHolder;
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.RunRunnableViewHolder;
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.SettingViewHolder;
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.SingleChoiceViewHolder;
@@ -124,13 +122,9 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
case SettingsItem.TYPE_SUBMENU:
return new SubmenuViewHolder(ListItemSubmenuBinding.inflate(inflater), this);
- case SettingsItem.TYPE_INPUT_BINDING:
- return new InputBindingSettingViewHolder(ListItemSettingBinding.inflate(inflater), this,
- mContext);
-
- case SettingsItem.TYPE_RUMBLE_BINDING:
- return new RumbleBindingViewHolder(ListItemSettingBinding.inflate(inflater), this,
- mContext);
+ case SettingsItem.TYPE_INPUT_MAPPING_CONTROL:
+ return new InputMappingControlSettingViewHolder(ListItemSettingBinding.inflate(inflater),
+ this);
case SettingsItem.TYPE_FILE_PICKER:
return new FilePickerViewHolder(ListItemSettingBinding.inflate(inflater), this);
@@ -314,9 +308,9 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
mView.loadSubMenu(item.getMenuKey());
}
- public void onInputBindingClick(final InputBindingSetting item, final int position)
+ public void onInputMappingClick(final InputMappingControlSetting item, final int position)
{
- final MotionAlertDialog dialog = new MotionAlertDialog(mContext, item, this);
+ final MotionAlertDialog dialog = new MotionAlertDialog(mView.getActivity(), item);
Drawable background = ContextCompat.getDrawable(mContext, R.drawable.dialog_round);
@ColorInt int color = new ElevationOverlayProvider(dialog.getContext()).compositeOverlay(
@@ -326,13 +320,11 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
dialog.getWindow().setBackgroundDrawable(background);
dialog.setTitle(R.string.input_binding);
- dialog.setMessage(String.format(mContext.getString(
- item instanceof RumbleBindingSetting ?
- R.string.input_rumble_description : R.string.input_binding_description),
+ dialog.setMessage(String.format(mContext.getString(R.string.input_binding_description),
item.getName()));
dialog.setButton(AlertDialog.BUTTON_NEGATIVE, mContext.getString(R.string.cancel), this);
dialog.setButton(AlertDialog.BUTTON_NEUTRAL, mContext.getString(R.string.clear),
- (dialogInterface, i) -> item.clearValue(getSettings()));
+ (dialogInterface, i) -> item.clearValue());
dialog.setOnDismissListener(dialog1 ->
{
notifyItemChanged(position);
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragment.java
index 00699e3a0c..bb73093656 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragment.java
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragment.java
@@ -67,14 +67,14 @@ public final class SettingsFragment extends Fragment implements SettingsFragment
titles.put(MenuTag.GCPAD_2, R.string.controller_1);
titles.put(MenuTag.GCPAD_3, R.string.controller_2);
titles.put(MenuTag.GCPAD_4, R.string.controller_3);
- titles.put(MenuTag.WIIMOTE_1, R.string.wiimote_4);
- titles.put(MenuTag.WIIMOTE_2, R.string.wiimote_5);
- titles.put(MenuTag.WIIMOTE_3, R.string.wiimote_6);
- titles.put(MenuTag.WIIMOTE_4, R.string.wiimote_7);
- titles.put(MenuTag.WIIMOTE_EXTENSION_1, R.string.wiimote_extension_4);
- titles.put(MenuTag.WIIMOTE_EXTENSION_2, R.string.wiimote_extension_5);
- titles.put(MenuTag.WIIMOTE_EXTENSION_3, R.string.wiimote_extension_6);
- titles.put(MenuTag.WIIMOTE_EXTENSION_4, R.string.wiimote_extension_7);
+ titles.put(MenuTag.WIIMOTE_1, R.string.wiimote_0);
+ titles.put(MenuTag.WIIMOTE_2, R.string.wiimote_1);
+ titles.put(MenuTag.WIIMOTE_3, R.string.wiimote_2);
+ titles.put(MenuTag.WIIMOTE_4, R.string.wiimote_3);
+ titles.put(MenuTag.WIIMOTE_EXTENSION_1, R.string.wiimote_extension_0);
+ titles.put(MenuTag.WIIMOTE_EXTENSION_2, R.string.wiimote_extension_1);
+ titles.put(MenuTag.WIIMOTE_EXTENSION_3, R.string.wiimote_extension_2);
+ titles.put(MenuTag.WIIMOTE_EXTENSION_4, R.string.wiimote_extension_3);
}
private FragmentSettingsBinding mBinding;
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.java
index 9d1a783979..01f4b52b71 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.java
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.java
@@ -14,6 +14,9 @@ import androidx.appcompat.app.AppCompatActivity;
import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.activities.UserDataActivity;
+import org.dolphinemu.dolphinemu.features.input.model.controlleremu.ControlGroup;
+import org.dolphinemu.dolphinemu.features.input.model.controlleremu.EmulatedController;
+import org.dolphinemu.dolphinemu.features.input.model.view.InputMappingControlSetting;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractBooleanSetting;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractIntSetting;
import org.dolphinemu.dolphinemu.features.settings.model.AdHocBooleanSetting;
@@ -795,14 +798,14 @@ public final class SettingsFragmentPresenter
private void addWiimoteSettings(ArrayList<SettingsItem> sl)
{
- sl.add(new SingleChoiceSetting(mContext, IntSetting.WIIMOTE_1_SOURCE, R.string.wiimote_4, 0,
- R.array.wiimoteTypeEntries, R.array.wiimoteTypeValues, MenuTag.getWiimoteMenuTag(4)));
- sl.add(new SingleChoiceSetting(mContext, IntSetting.WIIMOTE_2_SOURCE, R.string.wiimote_5, 0,
- R.array.wiimoteTypeEntries, R.array.wiimoteTypeValues, MenuTag.getWiimoteMenuTag(5)));
- sl.add(new SingleChoiceSetting(mContext, IntSetting.WIIMOTE_3_SOURCE, R.string.wiimote_6, 0,
- R.array.wiimoteTypeEntries, R.array.wiimoteTypeValues, MenuTag.getWiimoteMenuTag(6)));
- sl.add(new SingleChoiceSetting(mContext, IntSetting.WIIMOTE_4_SOURCE, R.string.wiimote_7, 0,
- R.array.wiimoteTypeEntries, R.array.wiimoteTypeValues, MenuTag.getWiimoteMenuTag(7)));
+ sl.add(new SingleChoiceSetting(mContext, IntSetting.WIIMOTE_1_SOURCE, R.string.wiimote_0, 0,
+ R.array.wiimoteTypeEntries, R.array.wiimoteTypeValues, MenuTag.getWiimoteMenuTag(0)));
+ sl.add(new SingleChoiceSetting(mContext, IntSetting.WIIMOTE_2_SOURCE, R.string.wiimote_1, 0,
+ R.array.wiimoteTypeEntries, R.array.wiimoteTypeValues, MenuTag.getWiimoteMenuTag(1)));
+ sl.add(new SingleChoiceSetting(mContext, IntSetting.WIIMOTE_3_SOURCE, R.string.wiimote_2, 0,
+ R.array.wiimoteTypeEntries, R.array.wiimoteTypeValues, MenuTag.getWiimoteMenuTag(2)));
+ sl.add(new SingleChoiceSetting(mContext, IntSetting.WIIMOTE_4_SOURCE, R.string.wiimote_3, 0,
+ R.array.wiimoteTypeEntries, R.array.wiimoteTypeValues, MenuTag.getWiimoteMenuTag(3)));
}
private void addGraphicsSettings(ArrayList<SettingsItem> sl)
@@ -1073,7 +1076,7 @@ public final class SettingsFragmentPresenter
{
if (gcPadType == 6) // Emulated
{
- // TODO
+ addControllerSettings(sl, EmulatedController.getGcPad(gcPadNumber));
}
else if (gcPadType == 12) // Adapter
{
@@ -1086,13 +1089,30 @@ public final class SettingsFragmentPresenter
private void addWiimoteSubSettings(ArrayList<SettingsItem> sl, int wiimoteNumber)
{
- // TODO
+ addControllerSettings(sl, EmulatedController.getWiimote(wiimoteNumber));
}
private void addExtensionTypeSettings(ArrayList<SettingsItem> sl, int wiimoteNumber,
- int extentionType)
+ int extensionType)
{
- // TODO
+ addControllerSettings(sl,
+ EmulatedController.getWiimoteAttachment(wiimoteNumber, extensionType));
+ }
+
+ private void addControllerSettings(ArrayList<SettingsItem> sl, EmulatedController controller)
+ {
+ int groupCount = controller.getGroupCount();
+ for (int i = 0; i < groupCount; i++)
+ {
+ ControlGroup group = controller.getGroup(i);
+ sl.add(new HeaderSetting(group.getUiName(), ""));
+
+ int controlCount = group.getControlCount();
+ for (int j = 0; j < controlCount; j++)
+ {
+ sl.add(new InputMappingControlSetting(group.getControl(j), controller));
+ }
+ }
}
private static int getLogVerbosityEntries()
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/RumbleBindingViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/RumbleBindingViewHolder.java
deleted file mode 100644
index 3b7a6b0f75..0000000000
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/RumbleBindingViewHolder.java
+++ /dev/null
@@ -1,67 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-package org.dolphinemu.dolphinemu.features.settings.ui.viewholder;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.view.View;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.preference.PreferenceManager;
-
-import org.dolphinemu.dolphinemu.databinding.ListItemSettingBinding;
-import org.dolphinemu.dolphinemu.features.settings.model.view.RumbleBindingSetting;
-import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
-import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
-
-public class RumbleBindingViewHolder extends SettingViewHolder
-{
- private RumbleBindingSetting mItem;
-
- private final Context mContext;
-
- private final ListItemSettingBinding mBinding;
-
- public RumbleBindingViewHolder(@NonNull ListItemSettingBinding binding, SettingsAdapter adapter,
- Context context)
- {
- super(binding.getRoot(), adapter);
- mBinding = binding;
- mContext = context;
- }
-
- @Override
- public void bind(SettingsItem item)
- {
- SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
-
- mItem = (RumbleBindingSetting) item;
-
- mBinding.textSettingName.setText(item.getName());
- mBinding.textSettingDescription
- .setText(sharedPreferences.getString(mItem.getKey() + mItem.getGameId(), ""));
-
- setStyle(mBinding.textSettingName, mItem);
- }
-
- @Override
- public void onClick(View clicked)
- {
- if (!mItem.isEditable())
- {
- showNotRuntimeEditableError();
- return;
- }
-
- getAdapter().onInputBindingClick(mItem, getBindingAdapterPosition());
-
- setStyle(mBinding.textSettingName, mItem);
- }
-
- @Nullable @Override
- protected SettingsItem getItem()
- {
- return mItem;
- }
-}
diff --git a/Source/Android/app/src/main/res/values/strings.xml b/Source/Android/app/src/main/res/values/strings.xml
index cca14f13a8..a1c7a32f95 100644
--- a/Source/Android/app/src/main/res/values/strings.xml
+++ b/Source/Android/app/src/main/res/values/strings.xml
@@ -11,15 +11,15 @@
<string name="controller_2">GameCube Controller 3</string>
<string name="controller_3">GameCube Controller 4</string>
- <string name="wiimote_4">Wii Remote 1</string>
- <string name="wiimote_5">Wii Remote 2</string>
- <string name="wiimote_6">Wii Remote 3</string>
- <string name="wiimote_7">Wii Remote 4</string>
-
- <string name="wiimote_extension_4">Wii Remote Extension 1</string>
- <string name="wiimote_extension_5">Wii Remote Extension 2</string>
- <string name="wiimote_extension_6">Wii Remote Extension 3</string>
- <string name="wiimote_extension_7">Wii Remote Extension 4</string>
+ <string name="wiimote_0">Wii Remote 1</string>
+ <string name="wiimote_1">Wii Remote 2</string>
+ <string name="wiimote_2">Wii Remote 3</string>
+ <string name="wiimote_3">Wii Remote 4</string>
+
+ <string name="wiimote_extension_0">Wii Remote Extension 1</string>
+ <string name="wiimote_extension_1">Wii Remote Extension 2</string>
+ <string name="wiimote_extension_2">Wii Remote Extension 3</string>
+ <string name="wiimote_extension_3">Wii Remote Extension 4</string>
<string name="wiimote_extensions">Extension</string>
diff --git a/Source/Android/jni/AndroidCommon/IDCache.cpp b/Source/Android/jni/AndroidCommon/IDCache.cpp
index 8e43016c62..54d3f765c9 100644
--- a/Source/Android/jni/AndroidCommon/IDCache.cpp
+++ b/Source/Android/jni/AndroidCommon/IDCache.cpp
@@ -83,6 +83,22 @@ static jfieldID s_riivolution_patches_pointer;
static jclass s_wii_update_cb_class;
static jmethodID s_wii_update_cb_run;
+static jclass s_control_class;
+static jfieldID s_control_pointer;
+static jmethodID s_control_constructor;
+
+static jclass s_control_group_class;
+static jfieldID s_control_group_pointer;
+static jmethodID s_control_group_constructor;
+
+static jclass s_control_reference_class;
+static jfieldID s_control_reference_pointer;
+static jmethodID s_control_reference_constructor;
+
+static jclass s_emulated_controller_class;
+static jfieldID s_emulated_controller_pointer;
+static jmethodID s_emulated_controller_constructor;
+
namespace IDCache
{
JNIEnv* GetEnvForThread()
@@ -383,6 +399,66 @@ jmethodID GetWiiUpdateCallbackFunction()
return s_wii_update_cb_run;
}
+jclass GetControlClass()
+{
+ return s_control_class;
+}
+
+jfieldID GetControlPointer()
+{
+ return s_control_pointer;
+}
+
+jmethodID GetControlConstructor()
+{
+ return s_control_constructor;
+}
+
+jclass GetControlGroupClass()
+{
+ return s_control_group_class;
+}
+
+jfieldID GetControlGroupPointer()
+{
+ return s_control_group_pointer;
+}
+
+jmethodID GetControlGroupConstructor()
+{
+ return s_control_group_constructor;
+}
+
+jclass GetControlReferenceClass()
+{
+ return s_control_reference_class;
+}
+
+jfieldID GetControlReferencePointer()
+{
+ return s_control_reference_pointer;
+}
+
+jmethodID GetControlReferenceConstructor()
+{
+ return s_control_reference_constructor;
+}
+
+jclass GetEmulatedControllerClass()
+{
+ return s_emulated_controller_class;
+}
+
+jfieldID GetEmulatedControllerPointer()
+{
+ return s_emulated_controller_pointer;
+}
+
+jmethodID GetEmulatedControllerConstructor()
+{
+ return s_emulated_controller_constructor;
+}
+
} // namespace IDCache
extern "C" {
@@ -541,6 +617,35 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
s_wii_update_cb_run = env->GetMethodID(s_wii_update_cb_class, "run", "(IIJ)Z");
env->DeleteLocalRef(wii_update_cb_class);
+ const jclass control_class =
+ env->FindClass("org/dolphinemu/dolphinemu/features/input/model/controlleremu/Control");
+ s_control_class = reinterpret_cast<jclass>(env->NewGlobalRef(control_class));
+ s_control_pointer = env->GetFieldID(control_class, "mPointer", "J");
+ s_control_constructor = env->GetMethodID(control_class, "<init>", "(J)V");
+ env->DeleteLocalRef(control_class);
+
+ const jclass control_group_class =
+ env->FindClass("org/dolphinemu/dolphinemu/features/input/model/controlleremu/ControlGroup");
+ s_control_group_class = reinterpret_cast<jclass>(env->NewGlobalRef(control_group_class));
+ s_control_group_pointer = env->GetFieldID(control_group_class, "mPointer", "J");
+ s_control_group_constructor = env->GetMethodID(control_group_class, "<init>", "(J)V");
+ env->DeleteLocalRef(control_group_class);
+
+ const jclass control_reference_class = env->FindClass(
+ "org/dolphinemu/dolphinemu/features/input/model/controlleremu/ControlReference");
+ s_control_reference_class = reinterpret_cast<jclass>(env->NewGlobalRef(control_reference_class));
+ s_control_reference_pointer = env->GetFieldID(control_reference_class, "mPointer", "J");
+ s_control_reference_constructor = env->GetMethodID(control_reference_class, "<init>", "(J)V");
+ env->DeleteLocalRef(control_reference_class);
+
+ const jclass emulated_controller_class = env->FindClass(
+ "org/dolphinemu/dolphinemu/features/input/model/controlleremu/EmulatedController");
+ s_emulated_controller_class =
+ reinterpret_cast<jclass>(env->NewGlobalRef(emulated_controller_class));
+ s_emulated_controller_pointer = env->GetFieldID(emulated_controller_class, "mPointer", "J");
+ s_emulated_controller_constructor = env->GetMethodID(emulated_controller_class, "<init>", "(J)V");
+ env->DeleteLocalRef(emulated_controller_class);
+
return JNI_VERSION;
}
@@ -568,5 +673,9 @@ JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved)
env->DeleteGlobalRef(s_graphics_mod_class);
env->DeleteGlobalRef(s_riivolution_patches_class);
env->DeleteGlobalRef(s_wii_update_cb_class);
+ env->DeleteGlobalRef(s_control_class);
+ env->DeleteGlobalRef(s_control_group_class);
+ env->DeleteGlobalRef(s_control_reference_class);
+ env->DeleteGlobalRef(s_emulated_controller_class);
}
}
diff --git a/Source/Android/jni/AndroidCommon/IDCache.h b/Source/Android/jni/AndroidCommon/IDCache.h
index 79ab19acaa..bd727c12a9 100644
--- a/Source/Android/jni/AndroidCommon/IDCache.h
+++ b/Source/Android/jni/AndroidCommon/IDCache.h
@@ -82,4 +82,20 @@ jfieldID GetRiivolutionPatchesPointer();
jclass GetWiiUpdateCallbackClass();
jmethodID GetWiiUpdateCallbackFunction();
+jclass GetControlClass();
+jfieldID GetControlPointer();
+jmethodID GetControlConstructor();
+
+jclass GetControlGroupClass();
+jfieldID GetControlGroupPointer();
+jmethodID GetControlGroupConstructor();
+
+jclass GetControlReferenceClass();
+jfieldID GetControlReferencePointer();
+jmethodID GetControlReferenceConstructor();
+
+jclass GetEmulatedControllerClass();
+jfieldID GetEmulatedControllerPointer();
+jmethodID GetEmulatedControllerConstructor();
+
} // namespace IDCache
diff --git a/Source/Android/jni/CMakeLists.txt b/Source/Android/jni/CMakeLists.txt
index 1c419aefcf..575847290e 100644
--- a/Source/Android/jni/CMakeLists.txt
+++ b/Source/Android/jni/CMakeLists.txt
@@ -10,7 +10,15 @@ add_library(main SHARED
GameList/GameFile.cpp
GameList/GameFile.h
GameList/GameFileCache.cpp
+ Input/Control.cpp
+ Input/Control.h
+ Input/ControlGroup.cpp
+ Input/ControlGroup.h
+ Input/ControlReference.cpp
+ Input/ControlReference.h
+ Input/EmulatedController.cpp
Input/InputOverrider.cpp
+ Input/MappingCommon.cpp
IniFile.cpp
MainAndroid.cpp
RiivolutionPatches.cpp
@@ -23,6 +31,7 @@ PRIVATE
androidcommon
common
core
+ inputcommon
uicommon
)
diff --git a/Source/Android/jni/Input/Control.cpp b/Source/Android/jni/Input/Control.cpp
new file mode 100644
index 0000000000..3a0496b92e
--- /dev/null
+++ b/Source/Android/jni/Input/Control.cpp
@@ -0,0 +1,51 @@
+// Copyright 2022 Dolphin Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "jni/Input/Control.h"
+
+#include <string>
+
+#include <jni.h>
+
+#include "Common/MsgHandler.h"
+#include "InputCommon/ControlReference/ControlReference.h"
+#include "InputCommon/ControllerEmu/Control/Control.h"
+#include "jni/AndroidCommon/AndroidCommon.h"
+#include "jni/AndroidCommon/IDCache.h"
+#include "jni/Input/ControlReference.h"
+
+static ControllerEmu::Control* GetPointer(JNIEnv* env, jobject obj)
+{
+ return reinterpret_cast<ControllerEmu::Control*>(
+ env->GetLongField(obj, IDCache::GetControlPointer()));
+}
+
+jobject ControlToJava(JNIEnv* env, ControllerEmu::Control* control)
+{
+ if (!control)
+ return nullptr;
+
+ return env->NewObject(IDCache::GetControlClass(), IDCache::GetControlConstructor(),
+ reinterpret_cast<jlong>(control));
+}
+
+extern "C" {
+
+JNIEXPORT jstring JNICALL
+Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_Control_getUiName(JNIEnv* env,
+ jobject obj)
+{
+ ControllerEmu::Control* control = GetPointer(env, obj);
+ std::string ui_name = control->ui_name;
+ if (control->translate == ControllerEmu::Translatability::Translate)
+ ui_name = Common::GetStringT(ui_name.c_str());
+ return ToJString(env, ui_name);
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_Control_getControlReference(
+ JNIEnv* env, jobject obj)
+{
+ return ControlReferenceToJava(env, GetPointer(env, obj)->control_ref.get());
+}
+}
diff --git a/Source/Android/jni/Input/Control.h b/Source/Android/jni/Input/Control.h
new file mode 100644
index 0000000000..c27732dd38
--- /dev/null
+++ b/Source/Android/jni/Input/Control.h
@@ -0,0 +1,13 @@
+// Copyright 2022 Dolphin Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <jni.h>
+
+namespace ControllerEmu
+{
+class Control;
+}
+
+jobject ControlToJava(JNIEnv* env, ControllerEmu::Control* control);
diff --git a/Source/Android/jni/Input/ControlGroup.cpp b/Source/Android/jni/Input/ControlGroup.cpp
new file mode 100644
index 0000000000..0e56774e84
--- /dev/null
+++ b/Source/Android/jni/Input/ControlGroup.cpp
@@ -0,0 +1,51 @@
+// Copyright 2022 Dolphin Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "jni/Input/ControlGroup.h"
+
+#include <jni.h>
+
+#include "Common/MsgHandler.h"
+#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
+#include "jni/AndroidCommon/AndroidCommon.h"
+#include "jni/AndroidCommon/IDCache.h"
+#include "jni/Input/Control.h"
+
+static ControllerEmu::ControlGroup* GetPointer(JNIEnv* env, jobject obj)
+{
+ return reinterpret_cast<ControllerEmu::ControlGroup*>(
+ env->GetLongField(obj, IDCache::GetControlGroupPointer()));
+}
+
+jobject ControlGroupToJava(JNIEnv* env, ControllerEmu::ControlGroup* group)
+{
+ if (!group)
+ return nullptr;
+
+ return env->NewObject(IDCache::GetControlGroupClass(), IDCache::GetControlGroupConstructor(),
+ reinterpret_cast<jlong>(group));
+}
+
+extern "C" {
+
+JNIEXPORT jstring JNICALL
+Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_ControlGroup_getUiName(
+ JNIEnv* env, jobject obj)
+{
+ return ToJString(env, Common::GetStringT(GetPointer(env, obj)->ui_name.c_str()));
+}
+
+JNIEXPORT jint JNICALL
+Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_ControlGroup_getControlCount(
+ JNIEnv* env, jobject obj)
+{
+ return static_cast<jint>(GetPointer(env, obj)->controls.size());
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_ControlGroup_getControl(
+ JNIEnv* env, jobject obj, jint i)
+{
+ return ControlToJava(env, GetPointer(env, obj)->controls[i].get());
+}
+}
diff --git a/Source/Android/jni/Input/ControlGroup.h b/Source/Android/jni/Input/ControlGroup.h
new file mode 100644
index 0000000000..b7ec0e78d1
--- /dev/null
+++ b/Source/Android/jni/Input/ControlGroup.h
@@ -0,0 +1,13 @@
+// Copyright 2022 Dolphin Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <jni.h>
+
+namespace ControllerEmu
+{
+class ControlGroup;
+}
+
+jobject ControlGroupToJava(JNIEnv* env, ControllerEmu::ControlGroup* group);
diff --git a/Source/Android/jni/Input/ControlReference.cpp b/Source/Android/jni/Input/ControlReference.cpp
new file mode 100644
index 0000000000..8bf9351109
--- /dev/null
+++ b/Source/Android/jni/Input/ControlReference.cpp
@@ -0,0 +1,54 @@
+// Copyright 2022 Dolphin Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "jni/Input/ControlReference.h"
+
+#include <string>
+
+#include <jni.h>
+
+#include "InputCommon/ControlReference/ControlReference.h"
+#include "jni/AndroidCommon/AndroidCommon.h"
+#include "jni/AndroidCommon/IDCache.h"
+
+ControlReference* ControlReferenceFromJava(JNIEnv* env, jobject control_reference)
+{
+ return reinterpret_cast<ControlReference*>(
+ env->GetLongField(control_reference, IDCache::GetControlReferencePointer()));
+}
+
+jobject ControlReferenceToJava(JNIEnv* env, ControlReference* control_reference)
+{
+ if (!control_reference)
+ return nullptr;
+
+ return env->NewObject(IDCache::GetControlReferenceClass(),
+ IDCache::GetControlReferenceConstructor(),
+ reinterpret_cast<jlong>(control_reference));
+}
+
+extern "C" {
+
+JNIEXPORT jdouble JNICALL
+Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_ControlReference_getState(
+ JNIEnv* env, jobject obj)
+{
+ return ControlReferenceFromJava(env, obj)->GetState<double>();
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_ControlReference_getExpression(
+ JNIEnv* env, jobject obj)
+{
+ return ToJString(env, ControlReferenceFromJava(env, obj)->GetExpression());
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_ControlReference_setExpression(
+ JNIEnv* env, jobject obj, jstring expr)
+{
+ const std::optional<std::string> result =
+ ControlReferenceFromJava(env, obj)->SetExpression(GetJString(env, expr));
+ return result ? ToJString(env, *result) : nullptr;
+}
+}
diff --git a/Source/Android/jni/Input/ControlReference.h b/Source/Android/jni/Input/ControlReference.h
new file mode 100644
index 0000000000..c8bfb7041a
--- /dev/null
+++ b/Source/Android/jni/Input/ControlReference.h
@@ -0,0 +1,11 @@
+// Copyright 2022 Dolphin Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <jni.h>
+
+class ControlReference;
+
+jobject ControlReferenceToJava(JNIEnv* env, ControlReference* control_reference);
+ControlReference* ControlReferenceFromJava(JNIEnv* env, jobject control_reference);
diff --git a/Source/Android/jni/Input/EmulatedController.cpp b/Source/Android/jni/Input/EmulatedController.cpp
new file mode 100644
index 0000000000..af6ba3b48a
--- /dev/null
+++ b/Source/Android/jni/Input/EmulatedController.cpp
@@ -0,0 +1,81 @@
+// Copyright 2022 Dolphin Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <jni.h>
+
+#include "Core/HW/GCPad.h"
+#include "Core/HW/Wiimote.h"
+#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
+#include "InputCommon/ControllerEmu/ControlGroup/Attachments.h"
+#include "InputCommon/ControllerEmu/ControllerEmu.h"
+#include "InputCommon/ControllerInterface/ControllerInterface.h"
+#include "InputCommon/InputConfig.h"
+#include "jni/AndroidCommon/AndroidCommon.h"
+#include "jni/AndroidCommon/IDCache.h"
+#include "jni/Input/Control.h"
+#include "jni/Input/ControlGroup.h"
+#include "jni/Input/ControlReference.h"
+
+static ControllerEmu::EmulatedController* GetPointer(JNIEnv* env, jobject obj)
+{
+ return reinterpret_cast<ControllerEmu::EmulatedController*>(
+ env->GetLongField(obj, IDCache::GetEmulatedControllerPointer()));
+}
+
+static jobject EmulatedControllerToJava(JNIEnv* env, ControllerEmu::EmulatedController* controller)
+{
+ if (!controller)
+ return nullptr;
+
+ return env->NewObject(IDCache::GetEmulatedControllerClass(),
+ IDCache::GetEmulatedControllerConstructor(),
+ reinterpret_cast<jlong>(controller));
+}
+
+extern "C" {
+
+JNIEXPORT jint JNICALL
+Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_EmulatedController_getGroupCount(
+ JNIEnv* env, jobject obj)
+{
+ return static_cast<jint>(GetPointer(env, obj)->groups.size());
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_EmulatedController_getGroup(
+ JNIEnv* env, jobject obj, jint controller_index)
+{
+ return ControlGroupToJava(env, GetPointer(env, obj)->groups[controller_index].get());
+}
+
+JNIEXPORT void JNICALL
+Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_EmulatedController_updateSingleControlReference(
+ JNIEnv* env, jobject obj, jobject control_reference)
+{
+ return GetPointer(env, obj)->UpdateSingleControlReference(
+ g_controller_interface, ControlReferenceFromJava(env, control_reference));
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_EmulatedController_getGcPad(
+ JNIEnv* env, jclass, jint controller_index)
+{
+ return EmulatedControllerToJava(env, Pad::GetConfig()->GetController(controller_index));
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_EmulatedController_getWiimote(
+ JNIEnv* env, jclass, jint controller_index)
+{
+ return EmulatedControllerToJava(env, Wiimote::GetConfig()->GetController(controller_index));
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_EmulatedController_getWiimoteAttachment(
+ JNIEnv* env, jclass, jint controller_index, jint attachment_index)
+{
+ auto* attachments = static_cast<ControllerEmu::Attachments*>(
+ Wiimote::GetWiimoteGroup(controller_index, WiimoteEmu::WiimoteGroup::Attachments));
+ return EmulatedControllerToJava(env, attachments->GetAttachmentList()[attachment_index].get());
+}
+}
diff --git a/Source/Android/jni/Input/MappingCommon.cpp b/Source/Android/jni/Input/MappingCommon.cpp
new file mode 100644
index 0000000000..c02f1c2ae5
--- /dev/null
+++ b/Source/Android/jni/Input/MappingCommon.cpp
@@ -0,0 +1,56 @@
+// Copyright 2022 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include <chrono>
+#include <string>
+#include <vector>
+
+#include <jni.h>
+
+#include "Core/FreeLookManager.h"
+#include "Core/HW/GBAPad.h"
+#include "Core/HW/GCKeyboard.h"
+#include "Core/HW/GCPad.h"
+#include "Core/HW/Wiimote.h"
+#include "Core/HotkeyManager.h"
+#include "InputCommon/ControllerInterface/ControllerInterface.h"
+#include "InputCommon/ControllerInterface/MappingCommon.h"
+#include "jni/AndroidCommon/AndroidCommon.h"
+
+namespace
+{
+constexpr auto INPUT_DETECT_INITIAL_TIME = std::chrono::seconds(3);
+constexpr auto INPUT_DETECT_CONFIRMATION_TIME = std::chrono::milliseconds(0);
+constexpr auto INPUT_DETECT_MAXIMUM_TIME = std::chrono::seconds(5);
+} // namespace
+
+extern "C" {
+
+JNIEXPORT jstring JNICALL
+Java_org_dolphinemu_dolphinemu_features_input_model_MappingCommon_detectInput(JNIEnv* env, jclass)
+{
+ const std::vector<std::string> device_strings = g_controller_interface.GetAllDeviceStrings();
+ const ciface::Core::DeviceQualifier default_device{};
+
+ auto detections =
+ g_controller_interface.DetectInput(device_strings, INPUT_DETECT_INITIAL_TIME,
+ INPUT_DETECT_CONFIRMATION_TIME, INPUT_DETECT_MAXIMUM_TIME);
+
+ ciface::MappingCommon::RemoveSpuriousTriggerCombinations(&detections);
+
+ return ToJString(env, ciface::MappingCommon::BuildExpression(detections, default_device,
+ ciface::MappingCommon::Quote::On));
+}
+
+JNIEXPORT void JNICALL
+Java_org_dolphinemu_dolphinemu_features_input_model_MappingCommon_save(JNIEnv* env, jclass)
+{
+ Pad::GetConfig()->SaveConfig();
+ Pad::GetGBAConfig()->SaveConfig();
+ Keyboard::GetConfig()->SaveConfig();
+ Wiimote::GetConfig()->SaveConfig();
+ HotkeyManagerEmu::GetConfig()->SaveConfig();
+ FreeLook::GetInputConfig()->SaveConfig();
+}
+};