From 0150f521f740fc3b1a00d49b432edd0ed32e31d1 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 14 Aug 2021 15:03:54 +0200 Subject: ControllerInterface/Android: Rip out ButtonManager ButtonManager is very different from how a normal input backend works, and is making it hard for us to improve controller support on Android. The following commits will add a new input backend in its place. --- .../org/dolphinemu/dolphinemu/NativeLibrary.java | 2 +- .../dolphinemu/activities/EmulationActivity.java | 49 ++-------------------- 2 files changed, 5 insertions(+), 46 deletions(-) (limited to 'Source/Android/app/src/main/java') diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java index d6fc236771..abd5e8cc2c 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java @@ -44,7 +44,7 @@ public final class NativeLibrary } /** - * Button type for use in onTouchEvent + * Button type, for legacy use only */ public static final class ButtonType { diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java index 808adbff26..fb839ed41a 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java @@ -894,21 +894,8 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP return super.dispatchKeyEvent(event); } - int action; - - switch (event.getAction()) - { - case KeyEvent.ACTION_DOWN: - action = NativeLibrary.ButtonState.PRESSED; - break; - case KeyEvent.ACTION_UP: - action = NativeLibrary.ButtonState.RELEASED; - break; - default: - return false; - } - InputDevice input = event.getDevice(); - return NativeLibrary.onGamePadEvent(input.getDescriptor(), event.getKeyCode(), action); + // TODO + return false; } private void toggleControls() @@ -1271,36 +1258,8 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP return false; } - if (((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0)) - { - return super.dispatchGenericMotionEvent(event); - } - - // Don't attempt to do anything if we are disconnecting a device. - if (event.getActionMasked() == MotionEvent.ACTION_CANCEL) - return true; - - InputDevice input = event.getDevice(); - List motions = input.getMotionRanges(); - - for (InputDevice.MotionRange range : motions) - { - int axis = range.getAxis(); - float origValue = event.getAxisValue(axis); - float value = ControllerMappingHelper.scaleAxis(input, axis, origValue); - // If the input is still in the "flat" area, that means it's really zero. - // This is used to compensate for imprecision in joysticks. - if (Math.abs(value) > range.getFlat()) - { - NativeLibrary.onGamePadMoveEvent(input.getDescriptor(), axis, value); - } - else - { - NativeLibrary.onGamePadMoveEvent(input.getDescriptor(), axis, 0.0f); - } - } - - return true; + // TODO + return false; } private void showSubMenu(SaveLoadStateFragment.SaveOrLoad saveOrLoad) -- cgit v1.2.3 From 9e7a2ee0fb307977bb0ae4245c8738ebd33df44b Mon Sep 17 00:00:00 2001 From: JosJuice Date: Fri, 16 Sep 2022 22:03:03 +0200 Subject: Android: Remove old motion input implementation --- .../org/dolphinemu/dolphinemu/NativeLibrary.java | 27 ----- .../dolphinemu/activities/EmulationActivity.java | 19 --- .../dolphinemu/utils/MotionListener.java | 128 --------------------- 3 files changed, 174 deletions(-) delete mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/MotionListener.java (limited to 'Source/Android/app/src/main/java') diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java index abd5e8cc2c..5f3c8f839f 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java @@ -234,30 +234,6 @@ public final class NativeLibrary // Disallows instantiation. } - /** - * Default touchscreen device - */ - public static final String TouchScreenDevice = "Touchscreen"; - - /** - * Handles button press events for a gamepad. - * - * @param Device The input descriptor of the gamepad. - * @param Button Key code identifying which button was pressed. - * @param Action Mask identifying which action is happening (button pressed down, or button released). - * @return If we handled the button press. - */ - public static native boolean onGamePadEvent(String Device, int Button, int Action); - - /** - * Handles gamepad movement events. - * - * @param Device The device ID of the gamepad. - * @param Axis The axis ID - * @param Value The value of the axis represented by the given ID. - */ - public static native void onGamePadMoveEvent(String Device, int Axis, float Value); - /** * Rumble sent from native. Currently only supports phone rumble. * @@ -277,9 +253,6 @@ public final class NativeLibrary Rumble.checkRumble(padID, state); } - public static native void SetMotionSensorsEnabled(boolean accelerometerEnabled, - boolean gyroscopeEnabled); - /** * Gets the Dolphin version string. * diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java index fb839ed41a..18372b1d20 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java @@ -64,7 +64,6 @@ import org.dolphinemu.dolphinemu.utils.AfterDirectoryInitializationRunner; import org.dolphinemu.dolphinemu.utils.ControllerMappingHelper; import org.dolphinemu.dolphinemu.utils.FileBrowserHelper; import org.dolphinemu.dolphinemu.utils.IniFile; -import org.dolphinemu.dolphinemu.utils.MotionListener; import org.dolphinemu.dolphinemu.utils.Rumble; import org.dolphinemu.dolphinemu.utils.ThemeHelper; @@ -89,7 +88,6 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP private EmulationFragment mEmulationFragment; private SharedPreferences mPreferences; - private MotionListener mMotionListener; private Settings mSettings; @@ -359,8 +357,6 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP updateOrientation(); - mMotionListener = new MotionListener(this); - // Set these options now so that the SurfaceView the game renders into is the right size. enableFullscreenImmersive(); @@ -452,16 +448,12 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP } updateOrientation(); - - if (NativeLibrary.IsGameMetadataValid()) - updateMotionListener(); } @Override protected void onPause() { super.onPause(); - mMotionListener.disable(); } @Override @@ -481,19 +473,10 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP } setTitle(NativeLibrary.GetCurrentTitleDescription()); - updateMotionListener(); mEmulationFragment.refreshInputOverlay(); } - private void updateMotionListener() - { - if (NativeLibrary.IsEmulatingWii() && IntSetting.MAIN_MOTION_CONTROLS.getInt(mSettings) != 2) - mMotionListener.enable(); - else - mMotionListener.disable(); - } - @Override protected void onDestroy() { @@ -1063,8 +1046,6 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP { IntSetting.MAIN_MOTION_CONTROLS.setInt(mSettings, indexSelected); - updateMotionListener(); - updateWiimoteNewImuIr(indexSelected); NativeLibrary.ReloadWiimoteConfig(); }) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/MotionListener.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/MotionListener.java deleted file mode 100644 index 0086f3beb5..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/MotionListener.java +++ /dev/null @@ -1,128 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -package org.dolphinemu.dolphinemu.utils; - -import android.app.Activity; -import android.content.Context; -import android.hardware.Sensor; -import android.hardware.SensorEvent; -import android.hardware.SensorEventListener; -import android.hardware.SensorManager; -import android.view.Surface; - -import org.dolphinemu.dolphinemu.NativeLibrary; -import org.dolphinemu.dolphinemu.NativeLibrary.ButtonType; - -public class MotionListener implements SensorEventListener -{ - private final Activity mActivity; - private final SensorManager mSensorManager; - private final Sensor mAccelSensor; - private final Sensor mGyroSensor; - - private boolean mEnabled = false; - - // The same sampling period as for Wii Remotes - private static final int SAMPLING_PERIOD_US = 1000000 / 200; - - public MotionListener(Activity activity) - { - mActivity = activity; - mSensorManager = (SensorManager) activity.getSystemService(Context.SENSOR_SERVICE); - mAccelSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); - mGyroSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE); - } - - @Override - public void onSensorChanged(SensorEvent sensorEvent) - { - float x, y; - float z = sensorEvent.values[2]; - int orientation = mActivity.getWindowManager().getDefaultDisplay().getRotation(); - switch (orientation) - { - default: - case Surface.ROTATION_0: - x = -sensorEvent.values[0]; - y = -sensorEvent.values[1]; - break; - case Surface.ROTATION_90: - x = sensorEvent.values[1]; - y = -sensorEvent.values[0]; - break; - case Surface.ROTATION_180: - x = sensorEvent.values[0]; - y = sensorEvent.values[1]; - break; - case Surface.ROTATION_270: - x = -sensorEvent.values[1]; - y = sensorEvent.values[0]; - break; - } - - if (sensorEvent.sensor == mAccelSensor) - { - NativeLibrary.onGamePadMoveEvent(NativeLibrary.TouchScreenDevice, - ButtonType.WIIMOTE_ACCEL_LEFT, x); - NativeLibrary.onGamePadMoveEvent(NativeLibrary.TouchScreenDevice, - ButtonType.WIIMOTE_ACCEL_RIGHT, x); - NativeLibrary.onGamePadMoveEvent(NativeLibrary.TouchScreenDevice, - ButtonType.WIIMOTE_ACCEL_FORWARD, y); - NativeLibrary.onGamePadMoveEvent(NativeLibrary.TouchScreenDevice, - ButtonType.WIIMOTE_ACCEL_BACKWARD, y); - NativeLibrary.onGamePadMoveEvent(NativeLibrary.TouchScreenDevice, - ButtonType.WIIMOTE_ACCEL_UP, z); - NativeLibrary.onGamePadMoveEvent(NativeLibrary.TouchScreenDevice, - ButtonType.WIIMOTE_ACCEL_DOWN, z); - } - - if (sensorEvent.sensor == mGyroSensor) - { - NativeLibrary.onGamePadMoveEvent(NativeLibrary.TouchScreenDevice, - ButtonType.WIIMOTE_GYRO_PITCH_UP, x); - NativeLibrary.onGamePadMoveEvent(NativeLibrary.TouchScreenDevice, - ButtonType.WIIMOTE_GYRO_PITCH_DOWN, x); - NativeLibrary.onGamePadMoveEvent(NativeLibrary.TouchScreenDevice, - ButtonType.WIIMOTE_GYRO_ROLL_LEFT, y); - NativeLibrary.onGamePadMoveEvent(NativeLibrary.TouchScreenDevice, - ButtonType.WIIMOTE_GYRO_ROLL_RIGHT, y); - NativeLibrary.onGamePadMoveEvent(NativeLibrary.TouchScreenDevice, - ButtonType.WIIMOTE_GYRO_YAW_LEFT, z); - NativeLibrary.onGamePadMoveEvent(NativeLibrary.TouchScreenDevice, - ButtonType.WIIMOTE_GYRO_YAW_RIGHT, z); - } - } - - @Override - public void onAccuracyChanged(Sensor sensor, int i) - { - // We don't care about this - } - - public void enable() - { - if (mEnabled) - return; - - if (mAccelSensor != null) - mSensorManager.registerListener(this, mAccelSensor, SAMPLING_PERIOD_US); - if (mGyroSensor != null) - mSensorManager.registerListener(this, mGyroSensor, SAMPLING_PERIOD_US); - - NativeLibrary.SetMotionSensorsEnabled(mAccelSensor != null, mGyroSensor != null); - - mEnabled = true; - } - - public void disable() - { - if (!mEnabled) - return; - - mSensorManager.unregisterListener(this); - - NativeLibrary.SetMotionSensorsEnabled(false, false); - - mEnabled = false; - } -} -- cgit v1.2.3 From 68ebb5c33e49aec1b7a49f1b1de94ef2291d319c Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 18 Sep 2022 14:33:02 +0200 Subject: Android: Remove old rumble implementation --- .../org/dolphinemu/dolphinemu/NativeLibrary.java | 20 ----- .../dolphinemu/activities/EmulationActivity.java | 17 ---- .../features/settings/model/BooleanSetting.java | 2 - .../org/dolphinemu/dolphinemu/utils/Rumble.java | 97 ---------------------- 4 files changed, 136 deletions(-) delete mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Rumble.java (limited to 'Source/Android/app/src/main/java') diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java index 5f3c8f839f..1db70b72d9 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java @@ -18,7 +18,6 @@ import org.dolphinemu.dolphinemu.activities.EmulationActivity; import org.dolphinemu.dolphinemu.dialogs.AlertMessage; import org.dolphinemu.dolphinemu.utils.CompressCallback; import org.dolphinemu.dolphinemu.utils.Log; -import org.dolphinemu.dolphinemu.utils.Rumble; import java.lang.ref.WeakReference; import java.util.LinkedHashMap; @@ -234,25 +233,6 @@ public final class NativeLibrary // Disallows instantiation. } - /** - * Rumble sent from native. Currently only supports phone rumble. - * - * @param padID Ignored for now. Future use would be to pass rumble to a connected controller - * @param state Ignored for now since phone rumble can't just be 'turned' on/off - */ - @Keep - public static void rumble(int padID, double state) - { - final EmulationActivity emulationActivity = sEmulationActivity.get(); - if (emulationActivity == null) - { - Log.warning("[NativeLibrary] EmulationActivity is null"); - return; - } - - Rumble.checkRumble(padID, state); - } - /** * Gets the Dolphin version string. * diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java index 18372b1d20..a90209b264 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java @@ -64,7 +64,6 @@ import org.dolphinemu.dolphinemu.utils.AfterDirectoryInitializationRunner; import org.dolphinemu.dolphinemu.utils.ControllerMappingHelper; import org.dolphinemu.dolphinemu.utils.FileBrowserHelper; import org.dolphinemu.dolphinemu.utils.IniFile; -import org.dolphinemu.dolphinemu.utils.Rumble; import org.dolphinemu.dolphinemu.utils.ThemeHelper; import java.io.File; @@ -157,7 +156,6 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP public static final int MENU_ACTION_EXIT = 22; public static final int MENU_ACTION_CHANGE_DISC = 23; public static final int MENU_ACTION_JOYSTICK_REL_CENTER = 24; - public static final int MENU_ACTION_RUMBLE = 25; public static final int MENU_ACTION_RESET_OVERLAY = 26; public static final int MENU_SET_IR_RECENTER = 27; public static final int MENU_SET_IR_MODE = 28; @@ -192,7 +190,6 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP EmulationActivity.MENU_ACTION_CHOOSE_CONTROLLER); buttonsActionsMap.append(R.id.menu_emulation_joystick_rel_center, EmulationActivity.MENU_ACTION_JOYSTICK_REL_CENTER); - buttonsActionsMap.append(R.id.menu_emulation_rumble, EmulationActivity.MENU_ACTION_RUMBLE); buttonsActionsMap .append(R.id.menu_emulation_reset_overlay, EmulationActivity.MENU_ACTION_RESET_OVERLAY); buttonsActionsMap.append(R.id.menu_emulation_ir_recenter, @@ -360,8 +357,6 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP // Set these options now so that the SurfaceView the game renders into is the right size. enableFullscreenImmersive(); - Rumble.initRumble(this); - ActivityEmulationBinding binding = ActivityEmulationBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); @@ -627,8 +622,6 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP // Populate the switch value for joystick center on touch menu.findItem(R.id.menu_emulation_joystick_rel_center) .setChecked(BooleanSetting.MAIN_JOYSTICK_REL_CENTER.getBoolean(mSettings)); - menu.findItem(R.id.menu_emulation_rumble) - .setChecked(BooleanSetting.MAIN_PHONE_RUMBLE.getBoolean(mSettings)); if (wii) { menu.findItem(R.id.menu_emulation_ir_recenter) @@ -668,10 +661,6 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP item.setChecked(!item.isChecked()); toggleJoystickRelCenter(item.isChecked()); break; - case MENU_ACTION_RUMBLE: - item.setChecked(!item.isChecked()); - toggleRumble(item.isChecked()); - break; case MENU_SET_IR_RECENTER: item.setChecked(!item.isChecked()); toggleRecenter(item.isChecked()); @@ -842,12 +831,6 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP BooleanSetting.MAIN_JOYSTICK_REL_CENTER.setBoolean(mSettings, state); } - private void toggleRumble(boolean state) - { - BooleanSetting.MAIN_PHONE_RUMBLE.setBoolean(mSettings, state); - Rumble.setPhoneVibrator(state, this); - } - private void toggleRecenter(boolean state) { BooleanSetting.MAIN_IR_ALWAYS_RECENTER.setBoolean(mSettings, state); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/BooleanSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/BooleanSetting.java index 1194e1f56a..cbaa7a4292 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/BooleanSetting.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/BooleanSetting.java @@ -100,8 +100,6 @@ public enum BooleanSetting implements AbstractBooleanSetting "UseBlackBackgrounds", false), MAIN_JOYSTICK_REL_CENTER(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID, "JoystickRelCenter", true), - MAIN_PHONE_RUMBLE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID, - "PhoneRumble", true), MAIN_SHOW_INPUT_OVERLAY(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID, "ShowInputOverlay", true), MAIN_IR_ALWAYS_RECENTER(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID, diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Rumble.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Rumble.java deleted file mode 100644 index 27d556898a..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Rumble.java +++ /dev/null @@ -1,97 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -package org.dolphinemu.dolphinemu.utils; - -import android.content.Context; -import android.os.Build; -import android.os.VibrationEffect; -import android.os.Vibrator; -import android.util.SparseArray; -import android.view.InputDevice; - -import org.dolphinemu.dolphinemu.activities.EmulationActivity; -import org.dolphinemu.dolphinemu.features.settings.model.AdHocStringSetting; -import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting; -import org.dolphinemu.dolphinemu.features.settings.model.Settings; -import org.dolphinemu.dolphinemu.features.settings.utils.SettingsFile; - -public class Rumble -{ - private static Vibrator phoneVibrator; - private static final SparseArray emuVibrators = new SparseArray<>(); - - public static void initRumble(EmulationActivity activity) - { - clear(); - - if (BooleanSetting.MAIN_PHONE_RUMBLE.getBooleanGlobal()) - { - setPhoneVibrator(true, activity); - } - - for (int i = 0; i < 8; i++) - { - String deviceName = AdHocStringSetting.getStringGlobal(Settings.FILE_DOLPHIN, - Settings.SECTION_BINDINGS, SettingsFile.KEY_EMU_RUMBLE + i, ""); - - if (!deviceName.isEmpty()) - { - for (int id : InputDevice.getDeviceIds()) - { - InputDevice device = InputDevice.getDevice(id); - if (deviceName.equals(device.getDescriptor())) - { - Vibrator vib = device.getVibrator(); - if (vib != null && vib.hasVibrator()) - emuVibrators.put(i, vib); - } - } - } - } - } - - public static void setPhoneVibrator(boolean set, EmulationActivity activity) - { - if (set) - { - Vibrator vib = (Vibrator) activity.getSystemService(Context.VIBRATOR_SERVICE); - if (vib != null && vib.hasVibrator()) - phoneVibrator = vib; - } - else - { - phoneVibrator = null; - } - } - - private static void clear() - { - phoneVibrator = null; - emuVibrators.clear(); - } - - public static void checkRumble(int padId, double state) - { - if (phoneVibrator != null) - doRumble(phoneVibrator); - - if (emuVibrators.get(padId) != null) - doRumble(emuVibrators.get(padId)); - } - - public static void doRumble(Vibrator vib) - { - // Check again that it exists and can vibrate - if (vib != null && vib.hasVibrator()) - { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) - { - vib.vibrate(VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE)); - } - else - { - vib.vibrate(100); - } - } - } -} -- cgit v1.2.3 From ca508e45033c022dbef558a11d170ab7f41c7bf9 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 1 Jan 2022 18:31:50 +0100 Subject: ControllerInterface/Android: Handle input events Android doesn't let us poll inputs whenever we want. Instead, we listen to input events (activities will have to forward them to the input backend), and store the received values in atomic variables in the Input classes. This is similar in concept to how ButtonManager worked, but without its homegrown second input mapping system. --- .../dolphinemu/activities/EmulationActivity.java | 23 +++++++++------- .../features/input/model/ControllerInterface.java | 31 ++++++++++++++++++++++ 2 files changed, 44 insertions(+), 10 deletions(-) create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java (limited to 'Source/Android/app/src/main/java') diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java index a90209b264..699e28a9e8 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java @@ -11,7 +11,6 @@ import android.os.Build; import android.os.Bundle; import android.util.Pair; import android.util.SparseIntArray; -import android.view.InputDevice; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; @@ -42,6 +41,7 @@ import org.dolphinemu.dolphinemu.databinding.ActivityEmulationBinding; import org.dolphinemu.dolphinemu.databinding.DialogInputAdjustBinding; import org.dolphinemu.dolphinemu.databinding.DialogIrSensitivityBinding; import org.dolphinemu.dolphinemu.databinding.DialogSkylandersManagerBinding; +import org.dolphinemu.dolphinemu.features.input.model.ControllerInterface; import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting; import org.dolphinemu.dolphinemu.features.settings.model.IntSetting; import org.dolphinemu.dolphinemu.features.settings.model.Settings; @@ -61,7 +61,6 @@ import org.dolphinemu.dolphinemu.overlay.InputOverlayPointer; import org.dolphinemu.dolphinemu.ui.main.MainPresenter; import org.dolphinemu.dolphinemu.ui.main.ThemeProvider; import org.dolphinemu.dolphinemu.utils.AfterDirectoryInitializationRunner; -import org.dolphinemu.dolphinemu.utils.ControllerMappingHelper; import org.dolphinemu.dolphinemu.utils.FileBrowserHelper; import org.dolphinemu.dolphinemu.utils.IniFile; import org.dolphinemu.dolphinemu.utils.ThemeHelper; @@ -855,13 +854,15 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP @Override public boolean dispatchKeyEvent(KeyEvent event) { - if (mMenuVisible || event.getKeyCode() == KeyEvent.KEYCODE_BACK) + if (!mMenuVisible) { - return super.dispatchKeyEvent(event); + if (ControllerInterface.dispatchKeyEvent(event)) + { + return true; + } } - // TODO - return false; + return super.dispatchKeyEvent(event); } private void toggleControls() @@ -1217,13 +1218,15 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP @Override public boolean dispatchGenericMotionEvent(MotionEvent event) { - if (mMenuVisible) + if (!mMenuVisible) { - return false; + if (ControllerInterface.dispatchGenericMotionEvent(event)) + { + return true; + } } - // TODO - return false; + return super.dispatchGenericMotionEvent(event); } private void showSubMenu(SaveLoadStateFragment.SaveOrLoad saveOrLoad) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java new file mode 100644 index 0000000000..80d21eeb57 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.features.input.model; + +import android.view.KeyEvent; +import android.view.MotionEvent; + +/** + * This class interfaces with the native ControllerInterface, + * which is where the emulator core gets inputs from. + */ +public final class ControllerInterface +{ + /** + * Activities which want to pass on inputs to native code + * should call this in their own dispatchKeyEvent method. + * + * @return true if the emulator core seems to be interested in this event. + * false if the event should be passed on to the default dispatchKeyEvent. + */ + public static native boolean dispatchKeyEvent(KeyEvent event); + + /** + * Activities which want to pass on inputs to native code + * should call this in their own dispatchGenericMotionEvent method. + * + * @return true if the emulator core seems to be interested in this event. + * false if the event should be passed on to the default dispatchGenericMotionEvent. + */ + public static native boolean dispatchGenericMotionEvent(MotionEvent event); +} -- cgit v1.2.3 From 104ea098921846e01eb58ebfa00822b14da46cda Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 6 Mar 2022 20:27:25 +0100 Subject: ControllerInterface/Android: Implement hotplug --- .../features/input/model/ControllerInterface.java | 72 ++++++++++++++++++++++ .../dolphinemu/dolphinemu/utils/LooperThread.java | 58 +++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/LooperThread.java (limited to 'Source/Android/app/src/main/java') diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java index 80d21eeb57..8a7bc8177f 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java @@ -2,15 +2,50 @@ package org.dolphinemu.dolphinemu.features.input.model; +import android.content.Context; +import android.hardware.input.InputManager; +import android.os.Handler; import android.view.KeyEvent; import android.view.MotionEvent; +import androidx.annotation.Keep; + +import org.dolphinemu.dolphinemu.DolphinApplication; +import org.dolphinemu.dolphinemu.utils.LooperThread; + /** * This class interfaces with the native ControllerInterface, * which is where the emulator core gets inputs from. */ public final class ControllerInterface { + private static final class InputDeviceListener implements InputManager.InputDeviceListener + { + @Override + public void onInputDeviceAdded(int deviceId) + { + // Simple implementation for now. We could do something fancier if we wanted to. + refreshDevices(); + } + + @Override + public void onInputDeviceRemoved(int deviceId) + { + // Simple implementation for now. We could do something fancier if we wanted to. + refreshDevices(); + } + + @Override + public void onInputDeviceChanged(int deviceId) + { + // Simple implementation for now. We could do something fancier if we wanted to. + refreshDevices(); + } + } + + private static InputDeviceListener mInputDeviceListener; + private static LooperThread mLooperThread; + /** * Activities which want to pass on inputs to native code * should call this in their own dispatchKeyEvent method. @@ -28,4 +63,41 @@ public final class ControllerInterface * false if the event should be passed on to the default dispatchGenericMotionEvent. */ public static native boolean dispatchGenericMotionEvent(MotionEvent event); + + /** + * Rescans for input devices. + */ + public static native void refreshDevices(); + + @Keep + private static void registerInputDeviceListener() + { + if (mLooperThread == null) + { + mLooperThread = new LooperThread("Hotplug thread"); + mLooperThread.start(); + } + + if (mInputDeviceListener == null) + { + InputManager im = (InputManager) + DolphinApplication.getAppContext().getSystemService(Context.INPUT_SERVICE); + + mInputDeviceListener = new InputDeviceListener(); + im.registerInputDeviceListener(mInputDeviceListener, new Handler(mLooperThread.getLooper())); + } + } + + @Keep + private static void unregisterInputDeviceListener() + { + if (mInputDeviceListener != null) + { + InputManager im = (InputManager) + DolphinApplication.getAppContext().getSystemService(Context.INPUT_SERVICE); + + im.unregisterInputDeviceListener(mInputDeviceListener); + mInputDeviceListener = null; + } + } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/LooperThread.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/LooperThread.java new file mode 100644 index 0000000000..8a67ec7e89 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/LooperThread.java @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.utils; + +import android.os.Looper; + +public class LooperThread extends Thread +{ + private Looper mLooper; + + public LooperThread() + { + super(); + } + + public LooperThread(String name) + { + super(name); + } + + @Override + public void run() + { + Looper.prepare(); + + synchronized (this) + { + mLooper = Looper.myLooper(); + notifyAll(); + } + + Looper.loop(); + } + + public Looper getLooper() + { + if (!isAlive()) + { + throw new IllegalStateException(); + } + + synchronized (this) + { + while (mLooper == null) + { + try + { + wait(); + } + catch (InterruptedException ignored) + { + } + } + } + + return mLooper; + } +} -- cgit v1.2.3 From 5e51b56d723cdd69bbe1eee39e53accfe609a812 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Fri, 16 Sep 2022 22:03:03 +0200 Subject: ControllerInterface/Android: Implement sensor input --- .../dolphinemu/activities/EmulationActivity.java | 5 + .../features/input/model/ControllerInterface.java | 20 ++ .../input/model/DolphinSensorEventListener.java | 361 +++++++++++++++++++++ .../features/input/model/SensorEventRequester.java | 16 + 4 files changed, 402 insertions(+) create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinSensorEventListener.java create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/SensorEventRequester.java (limited to 'Source/Android/app/src/main/java') diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java index 699e28a9e8..adf882d369 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java @@ -11,6 +11,7 @@ import android.os.Build; import android.os.Bundle; import android.util.Pair; import android.util.SparseIntArray; +import android.view.Display; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; @@ -42,6 +43,7 @@ import org.dolphinemu.dolphinemu.databinding.DialogInputAdjustBinding; import org.dolphinemu.dolphinemu.databinding.DialogIrSensitivityBinding; import org.dolphinemu.dolphinemu.databinding.DialogSkylandersManagerBinding; import org.dolphinemu.dolphinemu.features.input.model.ControllerInterface; +import org.dolphinemu.dolphinemu.features.input.model.SensorEventRequester; import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting; import org.dolphinemu.dolphinemu.features.settings.model.IntSetting; import org.dolphinemu.dolphinemu.features.settings.model.Settings; @@ -442,12 +444,15 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP } updateOrientation(); + + ControllerInterface.enableSensorEvents(() -> getWindowManager().getDefaultDisplay()); } @Override protected void onPause() { super.onPause(); + ControllerInterface.disableSensorEvents(); } @Override diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java index 8a7bc8177f..6038afe0f3 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java @@ -64,6 +64,26 @@ public final class ControllerInterface */ public static native boolean dispatchGenericMotionEvent(MotionEvent event); + /** + * {@link DolphinSensorEventListener} calls this for each axis of a received SensorEvent. + */ + public static native void dispatchSensorEvent(String axisName, float value); + + /** + * Enables delivering sensor events to native code. + * + * @param requester The activity or other component which is requesting sensor events to be + * delivered. + */ + public static native void enableSensorEvents(SensorEventRequester requester); + + /** + * Disables delivering sensor events to native code. + * + * Calling this when sensor events are no longer needed will save battery. + */ + public static native void disableSensorEvents(); + /** * Rescans for input devices. */ diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinSensorEventListener.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinSensorEventListener.java new file mode 100644 index 0000000000..f72a97d113 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinSensorEventListener.java @@ -0,0 +1,361 @@ +package org.dolphinemu.dolphinemu.features.input.model; + +import android.content.Context; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.os.Build; +import android.view.Surface; + +import androidx.annotation.Keep; + +import org.dolphinemu.dolphinemu.DolphinApplication; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; + +public class DolphinSensorEventListener implements SensorEventListener +{ + // Set of three axes. Creates a negative companion to each axis, and corrects for device rotation. + private static final int AXIS_SET_TYPE_DEVICE_COORDINATES = 0; + // Set of three axes. Creates a negative companion to each axis. + private static final int AXIS_SET_TYPE_OTHER_COORDINATES = 1; + + private static class AxisSetDetails + { + public final int firstAxisOfSet; + public final int axisSetType; + + public AxisSetDetails(int firstAxisOfSet, int axisSetType) + { + this.firstAxisOfSet = firstAxisOfSet; + this.axisSetType = axisSetType; + } + } + + private static class SensorDetails + { + public final int sensorType; + public final String[] axisNames; + public final AxisSetDetails[] axisSetDetails; + + public SensorDetails(int sensorType, String[] axisNames, AxisSetDetails[] axisSetDetails) + { + this.sensorType = sensorType; + this.axisNames = axisNames; + this.axisSetDetails = axisSetDetails; + } + } + + private final SensorManager mSensorManager; + + private final HashMap mSensorDetails = new HashMap<>(); + + private SensorEventRequester mRequester = null; + + // The fastest sampling rate Android lets us use without declaring the HIGH_SAMPLING_RATE_SENSORS + // permission is 200 Hz. This is also the sampling rate of a Wii Remote, so it fits us perfectly. + private static final int SAMPLING_PERIOD_US = 1000000 / 200; + + @Keep + public DolphinSensorEventListener() + { + mSensorManager = (SensorManager) + DolphinApplication.getAppContext().getSystemService(Context.SENSOR_SERVICE); + + addSensors(); + } + + private void addSensors() + { + tryAddSensor(Sensor.TYPE_ACCELEROMETER, new String[]{"Accel Right", "Accel Left", + "Accel Forward", "Accel Backward", "Accel Up", "Accel Down"}, + new AxisSetDetails[]{new AxisSetDetails(0, AXIS_SET_TYPE_DEVICE_COORDINATES)}); + + tryAddSensor(Sensor.TYPE_GYROSCOPE, new String[]{"Gyro Pitch Up", "Gyro Pitch Down", + "Gyro Roll Right", "Gyro Roll Left", "Gyro Yaw Left", "Gyro Yaw Right"}, + new AxisSetDetails[]{new AxisSetDetails(0, AXIS_SET_TYPE_DEVICE_COORDINATES)}); + + tryAddSensor(Sensor.TYPE_LIGHT, "Light"); + + tryAddSensor(Sensor.TYPE_PRESSURE, "Pressure"); + + tryAddSensor(Sensor.TYPE_TEMPERATURE, "Device Temperature"); + + tryAddSensor(Sensor.TYPE_PROXIMITY, "Proximity"); + + tryAddSensor(Sensor.TYPE_GRAVITY, new String[]{"Gravity Right", "Gravity Left", + "Gravity Forward", "Gravity Backward", "Gravity Up", "Gravity Down"}, + new AxisSetDetails[]{new AxisSetDetails(0, AXIS_SET_TYPE_DEVICE_COORDINATES)}); + + tryAddSensor(Sensor.TYPE_LINEAR_ACCELERATION, + new String[]{"Linear Acceleration Right", "Linear Acceleration Left", + "Linear Acceleration Forward", "Linear Acceleration Backward", + "Linear Acceleration Up", "Linear Acceleration Down"}, + new AxisSetDetails[]{new AxisSetDetails(0, AXIS_SET_TYPE_DEVICE_COORDINATES)}); + + // The values provided by this sensor can be interpreted as an Euler vector or a quaternion. + // The directions of X and Y are flipped to match the Wii Remote coordinate system. + tryAddSensor(Sensor.TYPE_ROTATION_VECTOR, + new String[]{"Rotation Vector X-", "Rotation Vector X+", "Rotation Vector Y-", + "Rotation Vector Y+", "Rotation Vector Z+", + "Rotation Vector Z-", "Rotation Vector R", "Rotation Vector Heading Accuracy"}, + new AxisSetDetails[]{new AxisSetDetails(0, AXIS_SET_TYPE_DEVICE_COORDINATES)}); + + tryAddSensor(Sensor.TYPE_RELATIVE_HUMIDITY, "Relative Humidity"); + + tryAddSensor(Sensor.TYPE_AMBIENT_TEMPERATURE, "Ambient Temperature"); + + // The values provided by this sensor can be interpreted as an Euler vector or a quaternion. + // The directions of X and Y are flipped to match the Wii Remote coordinate system. + tryAddSensor(Sensor.TYPE_GAME_ROTATION_VECTOR, + new String[]{"Game Rotation Vector X-", "Game Rotation Vector X+", + "Game Rotation Vector Y-", "Game Rotation Vector Y+", "Game Rotation Vector Z+", + "Game Rotation Vector Z-", "Game Rotation Vector R"}, + new AxisSetDetails[]{new AxisSetDetails(0, AXIS_SET_TYPE_DEVICE_COORDINATES)}); + + tryAddSensor(Sensor.TYPE_GYROSCOPE_UNCALIBRATED, + new String[]{"Gyro Uncalibrated Pitch Up", "Gyro Uncalibrated Pitch Down", + "Gyro Uncalibrated Roll Right", "Gyro Uncalibrated Roll Left", + "Gyro Uncalibrated Yaw Left", "Gyro Uncalibrated Yaw Right", + "Gyro Drift Pitch Up", "Gyro Drift Pitch Down", "Gyro Drift Roll Right", + "Gyro Drift Roll Left", "Gyro Drift Yaw Left", "Gyro Drift Yaw Right"}, + new AxisSetDetails[]{new AxisSetDetails(0, AXIS_SET_TYPE_DEVICE_COORDINATES), + new AxisSetDetails(3, AXIS_SET_TYPE_DEVICE_COORDINATES)}); + + tryAddSensor(Sensor.TYPE_HEART_RATE, "Heart Rate"); + + if (Build.VERSION.SDK_INT >= 24) + { + tryAddSensor(Sensor.TYPE_HEART_BEAT, "Heart Beat"); + } + + if (Build.VERSION.SDK_INT >= 26) + { + tryAddSensor(Sensor.TYPE_ACCELEROMETER_UNCALIBRATED, + new String[]{"Accel Uncalibrated Right", "Accel Uncalibrated Left", + "Accel Uncalibrated Forward", "Accel Uncalibrated Backward", + "Accel Uncalibrated Up", "Accel Uncalibrated Down", + "Accel Bias Right", "Accel Bias Left", "Accel Bias Forward", + "Accel Bias Backward", "Accel Bias Up", "Accel Bias Down"}, + new AxisSetDetails[]{new AxisSetDetails(0, AXIS_SET_TYPE_DEVICE_COORDINATES), + new AxisSetDetails(3, AXIS_SET_TYPE_DEVICE_COORDINATES)}); + } + + if (Build.VERSION.SDK_INT >= 30) + { + tryAddSensor(Sensor.TYPE_HINGE_ANGLE, "Hinge Angle"); + } + + if (Build.VERSION.SDK_INT >= 33) + { + // The values provided by this sensor can be interpreted as an Euler vector. + // The directions of X and Y are flipped to match the Wii Remote coordinate system. + tryAddSensor(Sensor.TYPE_HEAD_TRACKER, + new String[]{"Head Rotation Vector X-", "Head Rotation Vector X+", + "Head Rotation Vector Y-", "Head Rotation Vector Y+", + "Head Rotation Vector Z+", "Head Rotation Vector Z-", + "Head Pitch Up", "Head Pitch Down", "Head Roll Right", "Head Roll Left", + "Head Yaw Left", "Head Yaw Right"}, + new AxisSetDetails[]{new AxisSetDetails(0, AXIS_SET_TYPE_OTHER_COORDINATES), + new AxisSetDetails(3, AXIS_SET_TYPE_OTHER_COORDINATES)}); + + tryAddSensor(Sensor.TYPE_HEADING, new String[]{"Heading", "Heading Accuracy"}, + new AxisSetDetails[]{}); + } + } + + private void tryAddSensor(int sensorType, String axisName) + { + tryAddSensor(sensorType, new String[]{axisName}, new AxisSetDetails[]{}); + } + + private void tryAddSensor(int sensorType, String[] axisNames, AxisSetDetails[] axisSetDetails) + { + Sensor sensor = mSensorManager.getDefaultSensor(sensorType); + if (sensor != null) + { + mSensorDetails.put(sensor, new SensorDetails(sensorType, axisNames, axisSetDetails)); + } + } + + @Override + public void onSensorChanged(SensorEvent sensorEvent) + { + final SensorDetails sensorDetails = mSensorDetails.get(sensorEvent.sensor); + + final float[] values = sensorEvent.values; + final String[] axisNames = sensorDetails.axisNames; + final AxisSetDetails[] axisSetDetails = sensorDetails.axisSetDetails; + + int eventAxisIndex = 0; + int detailsAxisIndex = 0; + int detailsAxisSetIndex = 0; + while (eventAxisIndex < values.length && detailsAxisIndex < axisNames.length) + { + if (detailsAxisSetIndex < axisSetDetails.length && + axisSetDetails[detailsAxisSetIndex].firstAxisOfSet == eventAxisIndex) + { + int rotation = Surface.ROTATION_0; + if (axisSetDetails[detailsAxisSetIndex].axisSetType == AXIS_SET_TYPE_DEVICE_COORDINATES) + { + rotation = mRequester.getDisplay().getRotation(); + } + + float x, y; + switch (rotation) + { + default: + case Surface.ROTATION_0: + x = values[eventAxisIndex]; + y = values[eventAxisIndex + 1]; + break; + case Surface.ROTATION_90: + x = -values[eventAxisIndex + 1]; + y = values[eventAxisIndex]; + break; + case Surface.ROTATION_180: + x = -values[eventAxisIndex]; + y = -values[eventAxisIndex + 1]; + break; + case Surface.ROTATION_270: + x = values[eventAxisIndex + 1]; + y = -values[eventAxisIndex]; + break; + } + + float z = values[eventAxisIndex + 2]; + + ControllerInterface.dispatchSensorEvent(axisNames[detailsAxisIndex], x); + ControllerInterface.dispatchSensorEvent(axisNames[detailsAxisIndex + 1], x); + ControllerInterface.dispatchSensorEvent(axisNames[detailsAxisIndex + 2], y); + ControllerInterface.dispatchSensorEvent(axisNames[detailsAxisIndex + 3], y); + ControllerInterface.dispatchSensorEvent(axisNames[detailsAxisIndex + 4], z); + ControllerInterface.dispatchSensorEvent(axisNames[detailsAxisIndex + 5], z); + + eventAxisIndex += 3; + detailsAxisIndex += 6; + detailsAxisSetIndex++; + } + else + { + ControllerInterface.dispatchSensorEvent(axisNames[detailsAxisIndex], + values[eventAxisIndex]); + + eventAxisIndex++; + detailsAxisIndex++; + } + } + } + + @Override + public void onAccuracyChanged(Sensor sensor, int i) + { + // We don't care about this + } + + /** + * Enables delivering sensor events to native code. + * + * @param requester The activity or other component which is requesting sensor events to be + * delivered. + */ + @Keep + public void enableSensorEvents(SensorEventRequester requester) + { + if (mRequester != null) + { + throw new IllegalStateException("Attempted to enable sensor events when someone else" + + "had already enabled them"); + } + + mRequester = requester; + + for (Sensor sensor : mSensorDetails.keySet()) + { + mSensorManager.registerListener(this, sensor, SAMPLING_PERIOD_US); + } + } + + /** + * Disables delivering sensor events to native code. + * + * Calling this when sensor events are no longer needed will save battery. + */ + @Keep + public void disableSensorEvents() + { + mRequester = null; + + mSensorManager.unregisterListener(this); + } + + @Keep + public String[] getAxisNames() + { + ArrayList axisNames = new ArrayList<>(); + + for (SensorDetails sensorDetails : getSensorDetailsSorted()) + { + Collections.addAll(axisNames, sensorDetails.axisNames); + } + + return axisNames.toArray(new String[]{}); + } + + @Keep + public boolean[] getNegativeAxes() + { + ArrayList negativeAxes = new ArrayList<>(); + + for (SensorDetails sensorDetails : getSensorDetailsSorted()) + { + int eventAxisIndex = 0; + int detailsAxisIndex = 0; + int detailsAxisSetIndex = 0; + while (detailsAxisIndex < sensorDetails.axisNames.length) + { + if (detailsAxisSetIndex < sensorDetails.axisSetDetails.length && + sensorDetails.axisSetDetails[detailsAxisSetIndex].firstAxisOfSet == eventAxisIndex) + { + negativeAxes.add(false); + negativeAxes.add(true); + negativeAxes.add(false); + negativeAxes.add(true); + negativeAxes.add(false); + negativeAxes.add(true); + + eventAxisIndex += 3; + detailsAxisIndex += 6; + detailsAxisSetIndex++; + } + else + { + negativeAxes.add(false); + + eventAxisIndex++; + detailsAxisIndex++; + } + } + } + + boolean[] result = new boolean[negativeAxes.size()]; + for (int i = 0; i < result.length; i++) + { + result[i] = negativeAxes.get(i); + } + + return result; + } + + private List getSensorDetailsSorted() + { + ArrayList sensorDetails = new ArrayList<>(mSensorDetails.values()); + Collections.sort(sensorDetails, Comparator.comparingInt(s -> s.sensorType)); + return sensorDetails; + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/SensorEventRequester.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/SensorEventRequester.java new file mode 100644 index 0000000000..83b58015b2 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/SensorEventRequester.java @@ -0,0 +1,16 @@ +package org.dolphinemu.dolphinemu.features.input.model; + +import android.view.Display; + +import androidx.annotation.NonNull; + +public interface SensorEventRequester +{ + /** + * Returns the display the activity is shown on. + * + * This is used for getting the display orientation for rotating the axes of motion events. + */ + @NonNull + Display getDisplay(); +} -- cgit v1.2.3 From 36acb17700554f0789d8650b7fba77ac8a7796b6 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Fri, 16 Sep 2022 23:02:30 +0200 Subject: ControllerInterface/Android: Implement sensor input for InputDevices This functionality was added in Android 12 to let apps get motion data for gamepads. --- .../features/input/model/ControllerInterface.java | 3 +- .../input/model/DolphinSensorEventListener.java | 67 ++++++++++++++++++---- 2 files changed, 58 insertions(+), 12 deletions(-) (limited to 'Source/Android/app/src/main/java') diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java index 6038afe0f3..96480ab69c 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java @@ -67,7 +67,8 @@ public final class ControllerInterface /** * {@link DolphinSensorEventListener} calls this for each axis of a received SensorEvent. */ - public static native void dispatchSensorEvent(String axisName, float value); + public static native void dispatchSensorEvent(String deviceQualifier, String axisName, + float value); /** * Enables delivering sensor events to native code. diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinSensorEventListener.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinSensorEventListener.java index f72a97d113..21d533a430 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinSensorEventListener.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinSensorEventListener.java @@ -6,6 +6,7 @@ import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Build; +import android.view.InputDevice; import android.view.Surface; import androidx.annotation.Keep; @@ -55,6 +56,10 @@ public class DolphinSensorEventListener implements SensorEventListener private final HashMap mSensorDetails = new HashMap<>(); + private final boolean mRotateCoordinatesForScreenOrientation; + + private String mDeviceQualifier = ""; + private SensorEventRequester mRequester = null; // The fastest sampling rate Android lets us use without declaring the HIGH_SAMPLING_RATE_SENSORS @@ -66,10 +71,28 @@ public class DolphinSensorEventListener implements SensorEventListener { mSensorManager = (SensorManager) DolphinApplication.getAppContext().getSystemService(Context.SENSOR_SERVICE); + mRotateCoordinatesForScreenOrientation = true; addSensors(); } + @Keep + public DolphinSensorEventListener(InputDevice inputDevice) + { + mRotateCoordinatesForScreenOrientation = false; + + if (Build.VERSION.SDK_INT >= 31) + { + mSensorManager = inputDevice.getSensorManager(); + + addSensors(); + } + else + { + mSensorManager = null; + } + } + private void addSensors() { tryAddSensor(Sensor.TYPE_ACCELEROMETER, new String[]{"Accel Right", "Accel Left", @@ -201,7 +224,8 @@ public class DolphinSensorEventListener implements SensorEventListener axisSetDetails[detailsAxisSetIndex].firstAxisOfSet == eventAxisIndex) { int rotation = Surface.ROTATION_0; - if (axisSetDetails[detailsAxisSetIndex].axisSetType == AXIS_SET_TYPE_DEVICE_COORDINATES) + if (mRotateCoordinatesForScreenOrientation && + axisSetDetails[detailsAxisSetIndex].axisSetType == AXIS_SET_TYPE_DEVICE_COORDINATES) { rotation = mRequester.getDisplay().getRotation(); } @@ -230,12 +254,17 @@ public class DolphinSensorEventListener implements SensorEventListener float z = values[eventAxisIndex + 2]; - ControllerInterface.dispatchSensorEvent(axisNames[detailsAxisIndex], x); - ControllerInterface.dispatchSensorEvent(axisNames[detailsAxisIndex + 1], x); - ControllerInterface.dispatchSensorEvent(axisNames[detailsAxisIndex + 2], y); - ControllerInterface.dispatchSensorEvent(axisNames[detailsAxisIndex + 3], y); - ControllerInterface.dispatchSensorEvent(axisNames[detailsAxisIndex + 4], z); - ControllerInterface.dispatchSensorEvent(axisNames[detailsAxisIndex + 5], z); + ControllerInterface.dispatchSensorEvent(mDeviceQualifier, axisNames[detailsAxisIndex], x); + ControllerInterface.dispatchSensorEvent(mDeviceQualifier, axisNames[detailsAxisIndex + 1], + x); + ControllerInterface.dispatchSensorEvent(mDeviceQualifier, axisNames[detailsAxisIndex + 2], + y); + ControllerInterface.dispatchSensorEvent(mDeviceQualifier, axisNames[detailsAxisIndex + 3], + y); + ControllerInterface.dispatchSensorEvent(mDeviceQualifier, axisNames[detailsAxisIndex + 4], + z); + ControllerInterface.dispatchSensorEvent(mDeviceQualifier, axisNames[detailsAxisIndex + 5], + z); eventAxisIndex += 3; detailsAxisIndex += 6; @@ -243,7 +272,7 @@ public class DolphinSensorEventListener implements SensorEventListener } else { - ControllerInterface.dispatchSensorEvent(axisNames[detailsAxisIndex], + ControllerInterface.dispatchSensorEvent(mDeviceQualifier, axisNames[detailsAxisIndex], values[eventAxisIndex]); eventAxisIndex++; @@ -258,6 +287,16 @@ public class DolphinSensorEventListener implements SensorEventListener // We don't care about this } + /** + * The device qualifier set here will be passed on to native code, + * for the purpose of letting native code identify which device this object belongs to. + */ + @Keep + public void setDeviceQualifier(String deviceQualifier) + { + mDeviceQualifier = deviceQualifier; + } + /** * Enables delivering sensor events to native code. * @@ -275,9 +314,12 @@ public class DolphinSensorEventListener implements SensorEventListener mRequester = requester; - for (Sensor sensor : mSensorDetails.keySet()) + if (mSensorManager != null) { - mSensorManager.registerListener(this, sensor, SAMPLING_PERIOD_US); + for (Sensor sensor : mSensorDetails.keySet()) + { + mSensorManager.registerListener(this, sensor, SAMPLING_PERIOD_US); + } } } @@ -291,7 +333,10 @@ public class DolphinSensorEventListener implements SensorEventListener { mRequester = null; - mSensorManager.unregisterListener(this); + if (mSensorManager != null) + { + mSensorManager.unregisterListener(this); + } } @Keep -- cgit v1.2.3 From 065481d9899e6debc94bdbbb812512757f8eac62 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 17 Sep 2022 12:12:39 +0200 Subject: ControllerInterface/Android: Automatically suspend sensors This is a battery-saving measure. Whether a sensor should be suspended is determined in the same way as whether key events and motion events should be handled by the OS rather than consumed by Dolphin. --- .../dolphinemu/activities/EmulationActivity.java | 7 +- .../features/input/model/ControllerInterface.java | 22 ++--- .../input/model/DolphinSensorEventListener.java | 108 +++++++++++++-------- .../features/input/model/SensorEventRequester.java | 16 --- 4 files changed, 81 insertions(+), 72 deletions(-) delete mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/SensorEventRequester.java (limited to 'Source/Android/app/src/main/java') diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java index adf882d369..4a9816c259 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java @@ -11,7 +11,6 @@ import android.os.Build; import android.os.Bundle; import android.util.Pair; import android.util.SparseIntArray; -import android.view.Display; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; @@ -43,7 +42,7 @@ import org.dolphinemu.dolphinemu.databinding.DialogInputAdjustBinding; import org.dolphinemu.dolphinemu.databinding.DialogIrSensitivityBinding; import org.dolphinemu.dolphinemu.databinding.DialogSkylandersManagerBinding; import org.dolphinemu.dolphinemu.features.input.model.ControllerInterface; -import org.dolphinemu.dolphinemu.features.input.model.SensorEventRequester; +import org.dolphinemu.dolphinemu.features.input.model.DolphinSensorEventListener; import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting; import org.dolphinemu.dolphinemu.features.settings.model.IntSetting; import org.dolphinemu.dolphinemu.features.settings.model.Settings; @@ -445,14 +444,14 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP updateOrientation(); - ControllerInterface.enableSensorEvents(() -> getWindowManager().getDefaultDisplay()); + DolphinSensorEventListener.setDeviceRotation( + getWindowManager().getDefaultDisplay().getRotation()); } @Override protected void onPause() { super.onPause(); - ControllerInterface.disableSensorEvents(); } @Override diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java index 96480ab69c..2b6e1d62ee 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java @@ -66,24 +66,22 @@ public final class ControllerInterface /** * {@link DolphinSensorEventListener} calls this for each axis of a received SensorEvent. - */ - public static native void dispatchSensorEvent(String deviceQualifier, String axisName, - float value); - - /** - * Enables delivering sensor events to native code. * - * @param requester The activity or other component which is requesting sensor events to be - * delivered. + * @return true if the emulator core seems to be interested in this event. + * false if the sensor can be suspended to save battery. */ - public static native void enableSensorEvents(SensorEventRequester requester); + public static native boolean dispatchSensorEvent(String deviceQualifier, String axisName, + float value); /** - * Disables delivering sensor events to native code. + * Called when a sensor is suspended or unsuspended. * - * Calling this when sensor events are no longer needed will save battery. + * @param deviceQualifier A string used by native code for uniquely identifying devices. + * @param axisNames The name of all axes for the sensor. + * @param suspended Whether the sensor is now suspended. */ - public static native void disableSensorEvents(); + public static native void notifySensorSuspendedState(String deviceQualifier, String[] axisNames, + boolean suspended); /** * Rescans for input devices. diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinSensorEventListener.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinSensorEventListener.java index 21d533a430..cfc4f34dd7 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinSensorEventListener.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinSensorEventListener.java @@ -12,12 +12,15 @@ import android.view.Surface; import androidx.annotation.Keep; import org.dolphinemu.dolphinemu.DolphinApplication; +import org.dolphinemu.dolphinemu.utils.Log; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; +import java.util.Map; public class DolphinSensorEventListener implements SensorEventListener { @@ -43,6 +46,7 @@ public class DolphinSensorEventListener implements SensorEventListener public final int sensorType; public final String[] axisNames; public final AxisSetDetails[] axisSetDetails; + public boolean isSuspended = true; public SensorDetails(int sensorType, String[] axisNames, AxisSetDetails[] axisSetDetails) { @@ -52,6 +56,8 @@ public class DolphinSensorEventListener implements SensorEventListener } } + private static int sDeviceRotation = Surface.ROTATION_0; + private final SensorManager mSensorManager; private final HashMap mSensorDetails = new HashMap<>(); @@ -60,8 +66,6 @@ public class DolphinSensorEventListener implements SensorEventListener private String mDeviceQualifier = ""; - private SensorEventRequester mRequester = null; - // The fastest sampling rate Android lets us use without declaring the HIGH_SAMPLING_RATE_SENSORS // permission is 200 Hz. This is also the sampling rate of a Wii Remote, so it fits us perfectly. private static final int SAMPLING_PERIOD_US = 1000000 / 200; @@ -218,6 +222,7 @@ public class DolphinSensorEventListener implements SensorEventListener int eventAxisIndex = 0; int detailsAxisIndex = 0; int detailsAxisSetIndex = 0; + boolean keepSensorAlive = false; while (eventAxisIndex < values.length && detailsAxisIndex < axisNames.length) { if (detailsAxisSetIndex < axisSetDetails.length && @@ -227,7 +232,7 @@ public class DolphinSensorEventListener implements SensorEventListener if (mRotateCoordinatesForScreenOrientation && axisSetDetails[detailsAxisSetIndex].axisSetType == AXIS_SET_TYPE_DEVICE_COORDINATES) { - rotation = mRequester.getDisplay().getRotation(); + rotation = sDeviceRotation; } float x, y; @@ -254,17 +259,18 @@ public class DolphinSensorEventListener implements SensorEventListener float z = values[eventAxisIndex + 2]; - ControllerInterface.dispatchSensorEvent(mDeviceQualifier, axisNames[detailsAxisIndex], x); - ControllerInterface.dispatchSensorEvent(mDeviceQualifier, axisNames[detailsAxisIndex + 1], - x); - ControllerInterface.dispatchSensorEvent(mDeviceQualifier, axisNames[detailsAxisIndex + 2], - y); - ControllerInterface.dispatchSensorEvent(mDeviceQualifier, axisNames[detailsAxisIndex + 3], - y); - ControllerInterface.dispatchSensorEvent(mDeviceQualifier, axisNames[detailsAxisIndex + 4], - z); - ControllerInterface.dispatchSensorEvent(mDeviceQualifier, axisNames[detailsAxisIndex + 5], - z); + keepSensorAlive |= ControllerInterface.dispatchSensorEvent(mDeviceQualifier, + axisNames[detailsAxisIndex], x); + keepSensorAlive |= ControllerInterface.dispatchSensorEvent(mDeviceQualifier, + axisNames[detailsAxisIndex + 1], x); + keepSensorAlive |= ControllerInterface.dispatchSensorEvent(mDeviceQualifier, + axisNames[detailsAxisIndex + 2], y); + keepSensorAlive |= ControllerInterface.dispatchSensorEvent(mDeviceQualifier, + axisNames[detailsAxisIndex + 3], y); + keepSensorAlive |= ControllerInterface.dispatchSensorEvent(mDeviceQualifier, + axisNames[detailsAxisIndex + 4], z); + keepSensorAlive |= ControllerInterface.dispatchSensorEvent(mDeviceQualifier, + axisNames[detailsAxisIndex + 5], z); eventAxisIndex += 3; detailsAxisIndex += 6; @@ -272,13 +278,18 @@ public class DolphinSensorEventListener implements SensorEventListener } else { - ControllerInterface.dispatchSensorEvent(mDeviceQualifier, axisNames[detailsAxisIndex], - values[eventAxisIndex]); + keepSensorAlive |= ControllerInterface.dispatchSensorEvent(mDeviceQualifier, + axisNames[detailsAxisIndex], values[eventAxisIndex]); eventAxisIndex++; detailsAxisIndex++; } } + + if (!keepSensorAlive) + { + setSensorSuspended(sensorEvent.sensor, sensorDetails, true); + } } @Override @@ -298,44 +309,48 @@ public class DolphinSensorEventListener implements SensorEventListener } /** - * Enables delivering sensor events to native code. + * If a sensor has been suspended to save battery, this unsuspends it. + * If the sensor isn't currently suspended, nothing happens. * - * @param requester The activity or other component which is requesting sensor events to be - * delivered. + * @param axisName The name of any of the sensor's axes. */ @Keep - public void enableSensorEvents(SensorEventRequester requester) + public void requestUnsuspendSensor(String axisName) { - if (mRequester != null) + for (Map.Entry entry : mSensorDetails.entrySet()) { - throw new IllegalStateException("Attempted to enable sensor events when someone else" + - "had already enabled them"); + if (Arrays.asList(entry.getValue().axisNames).contains(axisName)) + { + setSensorSuspended(entry.getKey(), entry.getValue(), false); + } } + } - mRequester = requester; + private void setSensorSuspended(Sensor sensor, SensorDetails sensorDetails, boolean suspend) + { + boolean changeOccurred = false; - if (mSensorManager != null) + synchronized (sensorDetails) { - for (Sensor sensor : mSensorDetails.keySet()) + if (sensorDetails.isSuspended != suspend) { - mSensorManager.registerListener(this, sensor, SAMPLING_PERIOD_US); + ControllerInterface.notifySensorSuspendedState(mDeviceQualifier, sensorDetails.axisNames, + suspend); + + if (suspend) + mSensorManager.unregisterListener(this, sensor); + else + mSensorManager.registerListener(this, sensor, SAMPLING_PERIOD_US); + + sensorDetails.isSuspended = suspend; + + changeOccurred = true; } } - } - /** - * Disables delivering sensor events to native code. - * - * Calling this when sensor events are no longer needed will save battery. - */ - @Keep - public void disableSensorEvents() - { - mRequester = null; - - if (mSensorManager != null) + if (changeOccurred) { - mSensorManager.unregisterListener(this); + Log.info((suspend ? "Suspended sensor " : "Unsuspended sensor ") + sensor.getName()); } } @@ -403,4 +418,17 @@ public class DolphinSensorEventListener implements SensorEventListener Collections.sort(sensorDetails, Comparator.comparingInt(s -> s.sensorType)); return sensorDetails; } + + /** + * Should be called when an activity or other component that uses sensor events is resumed. + * + * Sensor events that contain device coordinates will have the coordinates rotated by the value + * passed to this function. + * + * @param deviceRotation The current rotation of the device (i.e. rotation of the default display) + */ + public static void setDeviceRotation(int deviceRotation) + { + sDeviceRotation = deviceRotation; + } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/SensorEventRequester.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/SensorEventRequester.java deleted file mode 100644 index 83b58015b2..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/SensorEventRequester.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.dolphinemu.dolphinemu.features.input.model; - -import android.view.Display; - -import androidx.annotation.NonNull; - -public interface SensorEventRequester -{ - /** - * Returns the display the activity is shown on. - * - * This is used for getting the display orientation for rotating the axes of motion events. - */ - @NonNull - Display getDisplay(); -} -- cgit v1.2.3 From 8e33458f4832daedf04a626d07c4541ad17ee675 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 18 Sep 2022 19:14:15 +0200 Subject: ControllerInterface/Android: Implement rumble --- .../features/input/model/ControllerInterface.java | 51 ++++++++++++++++++++++ .../input/model/DolphinVibratorManager.java | 20 +++++++++ .../input/model/DolphinVibratorManagerCompat.java | 35 +++++++++++++++ .../model/DolphinVibratorManagerPassthrough.java | 33 ++++++++++++++ 4 files changed, 139 insertions(+) create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinVibratorManager.java create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinVibratorManagerCompat.java create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinVibratorManagerPassthrough.java (limited to 'Source/Android/app/src/main/java') diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java index 2b6e1d62ee..0d6a078b4e 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java @@ -4,11 +4,18 @@ package org.dolphinemu.dolphinemu.features.input.model; import android.content.Context; import android.hardware.input.InputManager; +import android.os.Build; import android.os.Handler; +import android.os.VibrationEffect; +import android.os.Vibrator; +import android.os.VibratorManager; +import android.view.InputDevice; import android.view.KeyEvent; import android.view.MotionEvent; import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import org.dolphinemu.dolphinemu.DolphinApplication; import org.dolphinemu.dolphinemu.utils.LooperThread; @@ -119,4 +126,48 @@ public final class ControllerInterface mInputDeviceListener = null; } } + + @Keep @NonNull + private static DolphinVibratorManager getVibratorManager(InputDevice device) + { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) + { + return new DolphinVibratorManagerPassthrough(device.getVibratorManager()); + } + else + { + return new DolphinVibratorManagerCompat(device.getVibrator()); + } + } + + @Keep @NonNull + private static DolphinVibratorManager getSystemVibratorManager() + { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) + { + VibratorManager vibratorManager = (VibratorManager) + DolphinApplication.getAppContext().getSystemService(Context.VIBRATOR_MANAGER_SERVICE); + + if (vibratorManager != null) + return new DolphinVibratorManagerPassthrough(vibratorManager); + } + + Vibrator vibrator = (Vibrator) + DolphinApplication.getAppContext().getSystemService(Context.VIBRATOR_SERVICE); + + return new DolphinVibratorManagerCompat(vibrator); + } + + @Keep + private static void vibrate(@NonNull Vibrator vibrator) + { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) + { + vibrator.vibrate(VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE)); + } + else + { + vibrator.vibrate(100); + } + } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinVibratorManager.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinVibratorManager.java new file mode 100644 index 0000000000..abc04d969d --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinVibratorManager.java @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.features.input.model; + +import android.os.Vibrator; + +import androidx.annotation.Keep; +import androidx.annotation.NonNull; + +/** + * A wrapper around {@link android.os.VibratorManager}, for backwards compatibility. + */ +public interface DolphinVibratorManager +{ + @Keep @NonNull + Vibrator getVibrator(int vibratorId); + + @Keep @NonNull + int[] getVibratorIds(); +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinVibratorManagerCompat.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinVibratorManagerCompat.java new file mode 100644 index 0000000000..40c4fa95d1 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinVibratorManagerCompat.java @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.features.input.model; + +import android.os.Vibrator; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +public final class DolphinVibratorManagerCompat implements DolphinVibratorManager +{ + private final Vibrator mVibrator; + private final int[] mIds; + + public DolphinVibratorManagerCompat(@Nullable Vibrator vibrator) + { + mVibrator = vibrator; + mIds = vibrator != null && vibrator.hasVibrator() ? new int[]{0} : new int[]{}; + } + + @Override @NonNull + public Vibrator getVibrator(int vibratorId) + { + if (vibratorId > mIds.length) + throw new IndexOutOfBoundsException(); + + return mVibrator; + } + + @Override @NonNull + public int[] getVibratorIds() + { + return mIds; + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinVibratorManagerPassthrough.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinVibratorManagerPassthrough.java new file mode 100644 index 0000000000..2ca747f54f --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinVibratorManagerPassthrough.java @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.features.input.model; + +import android.os.Build; +import android.os.Vibrator; +import android.os.VibratorManager; + +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; + +@RequiresApi(api = Build.VERSION_CODES.S) +public final class DolphinVibratorManagerPassthrough implements DolphinVibratorManager +{ + private final VibratorManager mVibratorManager; + + public DolphinVibratorManagerPassthrough(@NonNull VibratorManager vibratorManager) + { + mVibratorManager = vibratorManager; + } + + @Override @NonNull + public Vibrator getVibrator(int vibratorId) + { + return mVibratorManager.getVibrator(vibratorId); + } + + @Override @NonNull + public int[] getVibratorIds() + { + return mVibratorManager.getVibratorIds(); + } +} -- cgit v1.2.3 From 93657cce5433552dbd0d836bac34e65143384a2c Mon Sep 17 00:00:00 2001 From: JosJuice Date: Thu, 30 Dec 2021 18:37:17 +0100 Subject: Android: Stop extracting pre-defined controller INIs --- .../dolphinemu/utils/DirectoryInitialization.java | 70 ++++------------------ 1 file changed, 10 insertions(+), 60 deletions(-) (limited to 'Source/Android/app/src/main/java') diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java index b1584df1be..c4bfdbd7bf 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java @@ -31,13 +31,16 @@ import java.io.InputStream; import java.io.OutputStream; /** - * A service that spawns its own thread in order to copy several binary and shader files - * from the Dolphin APK to the external file system. + * A class that spawns its own thread in order perform initialization. + * + * The initialization steps include: + * - Extracting the Sys directory from the APK so it can be accessed using regular file APIs + * - Letting the native code know where on external storage it should place the User directory + * - Running the native code's init steps (which include things like populating the User directory) */ public final class DirectoryInitialization { public static final String EXTRA_STATE = "directoryState"; - private static final int WiimoteNewVersion = 5; // Last changed in PR 8907 private static final MutableLiveData directoryState = new MutableLiveData<>(DirectoryInitializationState.NOT_YET_INITIALIZED); private static volatile boolean areDirectoriesAvailable = false; @@ -73,8 +76,7 @@ public final class DirectoryInitialization System.exit(1); } - initializeInternalStorage(context); - boolean wiimoteIniWritten = initializeExternalStorage(context); + extractSysDirectory(context); NativeLibrary.Initialize(); NativeLibrary.ReportStartToAnalytics(); @@ -82,7 +84,8 @@ public final class DirectoryInitialization checkThemeSettings(context); - if (wiimoteIniWritten) + // TODO: Does doing this still make sense? + if (false) { // This has to be done after calling NativeLibrary.Initialize(), // as it relies on the config system @@ -131,7 +134,7 @@ public final class DirectoryInitialization return true; } - private static void initializeInternalStorage(Context context) + private static void extractSysDirectory(Context context) { File sysDirectory = new File(context.getFilesDir(), "Sys"); @@ -153,45 +156,6 @@ public final class DirectoryInitialization SetSysDirectory(sysDirectory.getPath()); } - // Returns whether the WiimoteNew.ini file was written to - private static boolean initializeExternalStorage(Context context) - { - // Create User directory structure and copy some NAND files from the extracted Sys directory. - CreateUserDirectories(); - - // GCPadNew.ini and WiimoteNew.ini must contain specific values in order for controller - // input to work as intended (they aren't user configurable), so we overwrite them just - // in case the user has tried to modify them manually. - // - // ...Except WiimoteNew.ini contains the user configurable settings for Wii Remote - // extensions in addition to all of its lines that aren't user configurable, so since we - // don't want to lose the selected extensions, we don't overwrite that file if it exists. - // - // TODO: Redo the Android controller system so that we don't have to extract these INIs. - String configDirectory = NativeLibrary.GetUserDirectory() + File.separator + "Config"; - String profileDirectory = - NativeLibrary.GetUserDirectory() + File.separator + "Config/Profiles/Wiimote/"; - createWiimoteProfileDirectory(profileDirectory); - - copyAsset("GCPadNew.ini", new File(configDirectory, "GCPadNew.ini"), true, context); - - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - boolean overwriteWiimoteIni = prefs.getInt("WiimoteNewVersion", 0) != WiimoteNewVersion; - boolean wiimoteIniWritten = copyAsset("WiimoteNew.ini", - new File(configDirectory, "WiimoteNew.ini"), overwriteWiimoteIni, context); - if (overwriteWiimoteIni) - { - SharedPreferences.Editor sPrefsEditor = prefs.edit(); - sPrefsEditor.putInt("WiimoteNewVersion", WiimoteNewVersion); - sPrefsEditor.apply(); - } - - copyAsset("WiimoteProfile.ini", new File(profileDirectory, "WiimoteProfile.ini"), true, - context); - - return wiimoteIniWritten; - } - private static void deleteDirectoryRecursively(@NonNull final File file) { if (file.isDirectory()) @@ -322,18 +286,6 @@ public final class DirectoryInitialization } } - private static void createWiimoteProfileDirectory(String directory) - { - File wiiPath = new File(directory); - if (!wiiPath.isDirectory()) - { - if (!wiiPath.mkdirs()) - { - Log.error("[DirectoryInitialization] Failed to create folder " + wiiPath.getAbsolutePath()); - } - } - } - public static boolean preferOldFolderPicker(Context context) { // As of January 2021, ACTION_OPEN_DOCUMENT_TREE seems to be broken on the Nvidia Shield TV @@ -433,7 +385,5 @@ public final class DirectoryInitialization } } - private static native void CreateUserDirectories(); - private static native void SetSysDirectory(String path); } -- cgit v1.2.3 From 304d8989660c798156df58334c274ccfa75072b0 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Thu, 30 Dec 2021 18:40:00 +0100 Subject: Android: Remove copyAsset's overwrite parameter Because of the previous commit, this is no longer needed. --- .../dolphinemu/utils/DirectoryInitialization.java | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'Source/Android/app/src/main/java') diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java index c4bfdbd7bf..cf85e12740 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java @@ -145,7 +145,7 @@ public final class DirectoryInitialization // There is no extracted Sys directory, or there is a Sys directory from another // version of Dolphin that might contain outdated files. Let's (re-)extract Sys. deleteDirectoryRecursively(sysDirectory); - copyAssetFolder("Sys", sysDirectory, true, context); + copyAssetFolder("Sys", sysDirectory, context); SharedPreferences.Editor editor = preferences.edit(); editor.putString("sysDirectoryVersion", revision); @@ -209,21 +209,18 @@ public final class DirectoryInitialization return new File(context.getExternalCacheDir(), "gamelist.cache"); } - private static boolean copyAsset(String asset, File output, Boolean overwrite, Context context) + private static boolean copyAsset(String asset, File output, Context context) { Log.verbose("[DirectoryInitialization] Copying File " + asset + " to " + output); try { - if (!output.exists() || overwrite) + try (InputStream in = context.getAssets().open(asset)) { - try (InputStream in = context.getAssets().open(asset)) + try (OutputStream out = new FileOutputStream(output)) { - try (OutputStream out = new FileOutputStream(output)) - { - copyFile(in, out); - return true; - } + copyFile(in, out); + return true; } } } @@ -235,8 +232,7 @@ public final class DirectoryInitialization return false; } - private static void copyAssetFolder(String assetFolder, File outputFolder, Boolean overwrite, - Context context) + private static void copyAssetFolder(String assetFolder, File outputFolder, Context context) { Log.verbose("[DirectoryInitialization] Copying Folder " + assetFolder + " to " + outputFolder); @@ -263,9 +259,8 @@ public final class DirectoryInitialization createdFolder = true; } copyAssetFolder(assetFolder + File.separator + file, new File(outputFolder, file), - overwrite, context); - copyAsset(assetFolder + File.separator + file, new File(outputFolder, file), overwrite, context); + copyAsset(assetFolder + File.separator + file, new File(outputFolder, file), context); } } catch (IOException e) -- cgit v1.2.3 From dd8976f18dd5fb0c44fb40f3a24803f6cc5009b2 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 23 Jan 2022 21:47:57 +0100 Subject: Android: Remove old input mapping implementation This old code is of no use now that ButtonManager is gone. --- .../dolphinemu/dialogs/MotionAlertDialog.java | 6 +- .../settings/model/LegacyFloatSetting.java | 28 -- .../features/settings/model/Settings.java | 54 --- .../model/WiimoteProfileBooleanSetting.java | 70 --- .../model/WiimoteProfileStringSetting.java | 70 --- .../settings/ui/SettingsFragmentPresenter.java | 492 +-------------------- .../features/settings/utils/SettingsFile.java | 158 ------- .../dolphinemu/utils/ControllerMappingHelper.java | 65 --- 8 files changed, 5 insertions(+), 938 deletions(-) delete mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/LegacyFloatSetting.java delete mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/WiimoteProfileBooleanSetting.java delete mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/WiimoteProfileStringSetting.java delete mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/ControllerMappingHelper.java (limited to 'Source/Android/app/src/main/java') 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 index b0316f94cc..a111155181 100644 --- 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 @@ -12,7 +12,6 @@ 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.ControllerMappingHelper; import org.dolphinemu.dolphinemu.utils.Log; import java.util.ArrayList; @@ -50,7 +49,7 @@ public final class MotionAlertDialog extends AlertDialog Log.debug("[MotionAlertDialog] Received key event: " + event.getAction()); if (event.getAction() == KeyEvent.ACTION_UP) { - if (!ControllerMappingHelper.shouldKeyBeIgnored(event.getDevice(), keyCode)) + if (true) { setting.onKeyInput(mAdapter.getSettings(), event); dismiss(); @@ -116,8 +115,7 @@ public final class MotionAlertDialog extends AlertDialog { InputDevice.MotionRange range = motionRanges.get(i); int axis = range.getAxis(); - float origValue = event.getAxisValue(axis); - float value = ControllerMappingHelper.scaleAxis(input, axis, origValue); + float value = event.getAxisValue(axis); if (firstEvent) { mPreviousValues.add(value); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/LegacyFloatSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/LegacyFloatSetting.java deleted file mode 100644 index 0b92cba802..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/LegacyFloatSetting.java +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -package org.dolphinemu.dolphinemu.features.settings.model; - -import androidx.annotation.NonNull; - -public class LegacyFloatSetting extends AbstractLegacySetting implements AbstractFloatSetting -{ - private final float mDefaultValue; - - public LegacyFloatSetting(String file, String section, String key, float defaultValue) - { - super(file, section, key); - mDefaultValue = defaultValue; - } - - @Override - public float getFloat(@NonNull Settings settings) - { - return settings.getSection(mFile, mSection).getFloat(mKey, mDefaultValue); - } - - @Override - public void setFloat(@NonNull Settings settings, float newValue) - { - settings.getSection(mFile, mSection).setFloat(mKey, newValue); - } -} 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 ebdaf70691..7d3d5a5b19 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 @@ -24,7 +24,6 @@ public class Settings implements Closeable public static final String FILE_SYSCONF = "SYSCONF"; public static final String FILE_GFX = "GFX"; public static final String FILE_LOGGER = "Logger"; - public static final String FILE_GCPAD = "GCPadNew"; public static final String FILE_WIIMOTE = "WiimoteNew"; public static final String SECTION_INI_ANDROID = "Android"; @@ -46,8 +45,6 @@ public class Settings implements Closeable public static final String SECTION_STEREOSCOPY = "Stereoscopy"; - public static final String SECTION_WIIMOTE = "Wiimote"; - public static final String SECTION_BINDINGS = "Android"; public static final String SECTION_CONTROLS = "Controls"; public static final String SECTION_PROFILE = "Profile"; @@ -64,7 +61,6 @@ public class Settings implements Closeable FILE_WIIMOTE}; private Map mIniFiles = new HashMap<>(); - private final Map mWiimoteProfileFiles = new HashMap<>(); private boolean mLoadedRecursiveIsoPathsValue = false; @@ -99,50 +95,6 @@ public class Settings implements Closeable return mIsWii; } - public IniFile getWiimoteProfile(String profile, int padID) - { - IniFile wiimoteProfileIni = mWiimoteProfileFiles.computeIfAbsent(profile, profileComputed -> - { - IniFile newIni = new IniFile(); - newIni.load(SettingsFile.getWiiProfile(profileComputed), false); - return newIni; - }); - - if (!wiimoteProfileIni.exists(SECTION_PROFILE)) - { - String defaultWiiProfilePath = DirectoryInitialization.getUserDirectory() + - "/Config/Profiles/Wiimote/WiimoteProfile.ini"; - - wiimoteProfileIni.load(defaultWiiProfilePath, false); - - wiimoteProfileIni - .setString(SECTION_PROFILE, "Device", "Android/" + (padID + 4) + "/Touchscreen"); - } - - return wiimoteProfileIni; - } - - public void enableWiimoteProfile(Settings settings, String profile, String profileKey) - { - getWiimoteControlsSection(settings).setString(profileKey, profile); - } - - public boolean disableWiimoteProfile(Settings settings, String profileKey) - { - return getWiimoteControlsSection(settings).delete(profileKey); - } - - public boolean isWiimoteProfileEnabled(Settings settings, String profile, - String profileKey) - { - return profile.equals(getWiimoteControlsSection(settings).getString(profileKey, "")); - } - - private IniFile.Section getWiimoteControlsSection(Settings settings) - { - return settings.getSection(GAME_SETTINGS_PLACEHOLDER_FILE_NAME, SECTION_CONTROLS); - } - public int getWriteLayer() { return isGameSpecific() ? NativeConfig.LAYER_LOCAL_GAME : NativeConfig.LAYER_BASE_OR_CURRENT; @@ -224,7 +176,6 @@ public class Settings implements Closeable { // Notify the native code of the changes to legacy settings NativeLibrary.ReloadConfig(); - NativeLibrary.ReloadWiimoteConfig(); } // LogManager does use the new config system, but doesn't pick up on changes automatically @@ -251,11 +202,6 @@ public class Settings implements Closeable NativeConfig.save(NativeConfig.LAYER_LOCAL_GAME); } - - for (Map.Entry entry : mWiimoteProfileFiles.entrySet()) - { - entry.getValue().save(SettingsFile.getWiiProfile(entry.getKey())); - } } public void clearSettings() diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/WiimoteProfileBooleanSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/WiimoteProfileBooleanSetting.java deleted file mode 100644 index 1705e969c4..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/WiimoteProfileBooleanSetting.java +++ /dev/null @@ -1,70 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -package org.dolphinemu.dolphinemu.features.settings.model; - -import androidx.annotation.NonNull; - -import org.dolphinemu.dolphinemu.features.settings.utils.SettingsFile; - -// This stuff is pretty ugly. It's a kind of workaround for certain controller settings -// not actually being available as game-specific settings. -public class WiimoteProfileBooleanSetting implements AbstractBooleanSetting -{ - private final int mPadID; - - private final String mSection; - private final String mKey; - private final boolean mDefaultValue; - - private final String mProfileKey; - - private final String mProfile; - - public WiimoteProfileBooleanSetting(String gameID, int padID, String section, String key, - boolean defaultValue) - { - mPadID = padID; - mSection = section; - mKey = key; - mDefaultValue = defaultValue; - - mProfileKey = SettingsFile.KEY_WIIMOTE_PROFILE + (padID + 1); - - mProfile = gameID + "_Wii" + padID; - } - - @Override - public boolean isOverridden(@NonNull Settings settings) - { - return settings.isWiimoteProfileEnabled(settings, mProfile, mProfileKey); - } - - @Override - public boolean isRuntimeEditable() - { - return false; - } - - @Override - public boolean delete(@NonNull Settings settings) - { - return settings.disableWiimoteProfile(settings, mProfileKey); - } - - @Override - public boolean getBoolean(@NonNull Settings settings) - { - if (settings.isWiimoteProfileEnabled(settings, mProfile, mProfileKey)) - return settings.getWiimoteProfile(mProfile, mPadID).getBoolean(mSection, mKey, mDefaultValue); - else - return mDefaultValue; - } - - @Override - public void setBoolean(@NonNull Settings settings, boolean newValue) - { - settings.getWiimoteProfile(mProfile, mPadID).setBoolean(mSection, mKey, newValue); - - settings.enableWiimoteProfile(settings, mProfile, mProfileKey); - } -} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/WiimoteProfileStringSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/WiimoteProfileStringSetting.java deleted file mode 100644 index c62df5638d..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/WiimoteProfileStringSetting.java +++ /dev/null @@ -1,70 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -package org.dolphinemu.dolphinemu.features.settings.model; - -import androidx.annotation.NonNull; - -import org.dolphinemu.dolphinemu.features.settings.utils.SettingsFile; - -// This stuff is pretty ugly. It's a kind of workaround for certain controller settings -// not actually being available as game-specific settings. -public class WiimoteProfileStringSetting implements AbstractStringSetting -{ - private final int mPadID; - - private final String mSection; - private final String mKey; - private final String mDefaultValue; - - private final String mProfileKey; - - private final String mProfile; - - public WiimoteProfileStringSetting(String gameID, int padID, String section, String key, - String defaultValue) - { - mPadID = padID; - mSection = section; - mKey = key; - mDefaultValue = defaultValue; - - mProfileKey = SettingsFile.KEY_WIIMOTE_PROFILE + (padID + 1); - - mProfile = gameID + "_Wii" + padID; - } - - @Override - public boolean isOverridden(@NonNull Settings settings) - { - return settings.isWiimoteProfileEnabled(settings, mProfile, mProfileKey); - } - - @Override - public boolean isRuntimeEditable() - { - return false; - } - - @Override - public boolean delete(@NonNull Settings settings) - { - return settings.disableWiimoteProfile(settings, mProfileKey); - } - - @NonNull @Override - public String getString(@NonNull Settings settings) - { - if (settings.isWiimoteProfileEnabled(settings, mProfile, mProfileKey)) - return settings.getWiimoteProfile(mProfile, mPadID).getString(mSection, mKey, mDefaultValue); - else - return mDefaultValue; - } - - @Override - public void setString(@NonNull Settings settings, @NonNull String newValue) - { - settings.getWiimoteProfile(mProfile, mPadID).setString(mSection, mKey, newValue); - - settings.enableWiimoteProfile(settings, mProfile, mProfileKey); - } -} 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 3604d53087..9d1a783979 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 @@ -16,36 +16,30 @@ import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.activities.UserDataActivity; import org.dolphinemu.dolphinemu.features.settings.model.AbstractBooleanSetting; import org.dolphinemu.dolphinemu.features.settings.model.AbstractIntSetting; -import org.dolphinemu.dolphinemu.features.settings.model.AbstractStringSetting; import org.dolphinemu.dolphinemu.features.settings.model.AdHocBooleanSetting; import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting; import org.dolphinemu.dolphinemu.features.settings.model.FloatSetting; import org.dolphinemu.dolphinemu.features.settings.model.IntSetting; -import org.dolphinemu.dolphinemu.features.settings.model.LegacyStringSetting; import org.dolphinemu.dolphinemu.features.settings.model.PostProcessing; import org.dolphinemu.dolphinemu.features.settings.model.ScaledIntSetting; import org.dolphinemu.dolphinemu.features.settings.model.Settings; import org.dolphinemu.dolphinemu.features.settings.model.StringSetting; -import org.dolphinemu.dolphinemu.features.settings.model.WiimoteProfileStringSetting; 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.HeaderSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.HyperLinkHeaderSetting; -import org.dolphinemu.dolphinemu.features.settings.model.view.InputBindingSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.InputStringSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.IntSliderSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.InvertedSwitchSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.LogSwitchSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.PercentSliderSetting; -import org.dolphinemu.dolphinemu.features.settings.model.view.RumbleBindingSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.RunRunnable; 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; import org.dolphinemu.dolphinemu.features.settings.model.view.StringSingleChoiceSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.SubmenuSetting; -import org.dolphinemu.dolphinemu.features.settings.utils.SettingsFile; import org.dolphinemu.dolphinemu.ui.main.MainPresenter; import org.dolphinemu.dolphinemu.utils.BooleanSupplier; import org.dolphinemu.dolphinemu.utils.EGLHelper; @@ -1079,62 +1073,7 @@ public final class SettingsFragmentPresenter { if (gcPadType == 6) // Emulated { - sl.add(new HeaderSetting(mContext, R.string.generic_buttons, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_GCBIND_A + gcPadNumber, R.string.button_a, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_GCBIND_B + gcPadNumber, R.string.button_b, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_GCBIND_X + gcPadNumber, R.string.button_x, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_GCBIND_Y + gcPadNumber, R.string.button_y, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_GCBIND_Z + gcPadNumber, R.string.button_z, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_GCBIND_START + gcPadNumber, R.string.button_start, mGameID)); - - sl.add(new HeaderSetting(mContext, R.string.controller_control, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_GCBIND_CONTROL_UP + gcPadNumber, R.string.generic_up, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_GCBIND_CONTROL_DOWN + gcPadNumber, R.string.generic_down, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_GCBIND_CONTROL_LEFT + gcPadNumber, R.string.generic_left, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_GCBIND_CONTROL_RIGHT + gcPadNumber, R.string.generic_right, - mGameID)); - - sl.add(new HeaderSetting(mContext, R.string.controller_c, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_GCBIND_C_UP + gcPadNumber, R.string.generic_up, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_GCBIND_C_DOWN + gcPadNumber, R.string.generic_down, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_GCBIND_C_LEFT + gcPadNumber, R.string.generic_left, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_GCBIND_C_RIGHT + gcPadNumber, R.string.generic_right, mGameID)); - - sl.add(new HeaderSetting(mContext, R.string.controller_trig, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_GCBIND_TRIGGER_L + gcPadNumber, R.string.trigger_left, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_GCBIND_TRIGGER_R + gcPadNumber, R.string.trigger_right, mGameID)); - - sl.add(new HeaderSetting(mContext, R.string.controller_dpad, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_GCBIND_DPAD_UP + gcPadNumber, R.string.generic_up, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_GCBIND_DPAD_DOWN + gcPadNumber, R.string.generic_down, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_GCBIND_DPAD_LEFT + gcPadNumber, R.string.generic_left, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_GCBIND_DPAD_RIGHT + gcPadNumber, R.string.generic_right, mGameID)); - - - sl.add(new HeaderSetting(mContext, R.string.emulation_control_rumble, 0)); - sl.add(new RumbleBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_EMU_RUMBLE + gcPadNumber, R.string.emulation_control_rumble, - mGameID)); + // TODO } else if (gcPadType == 12) // Adapter { @@ -1147,438 +1086,13 @@ public final class SettingsFragmentPresenter private void addWiimoteSubSettings(ArrayList sl, int wiimoteNumber) { - // Bindings use controller numbers 4-7 (0-3 are GameCube), but the extension setting uses 1-4. - // But game specific extension settings are saved in their own profile. These profiles - // do not have any way to specify the controller that is loaded outside of knowing the filename - // of the profile that was loaded. - AbstractStringSetting extension; - final String defaultExtension = "None"; - if (mGameID.isEmpty()) - { - extension = new LegacyStringSetting(Settings.FILE_WIIMOTE, - Settings.SECTION_WIIMOTE + (wiimoteNumber - 3), SettingsFile.KEY_WIIMOTE_EXTENSION, - defaultExtension); - } - else - { - extension = new WiimoteProfileStringSetting(mGameID, wiimoteNumber - 4, - Settings.SECTION_PROFILE, SettingsFile.KEY_WIIMOTE_EXTENSION, defaultExtension); - } - - sl.add(new StringSingleChoiceSetting(mContext, extension, R.string.wiimote_extensions, 0, - R.array.wiimoteExtensionsEntries, R.array.wiimoteExtensionsValues, - MenuTag.getWiimoteExtensionMenuTag(wiimoteNumber))); - - sl.add(new HeaderSetting(mContext, R.string.generic_buttons, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_A + wiimoteNumber, R.string.button_a, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_B + wiimoteNumber, R.string.button_b, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_1 + wiimoteNumber, R.string.button_one, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_2 + wiimoteNumber, R.string.button_two, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_MINUS + wiimoteNumber, R.string.button_minus, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_PLUS + wiimoteNumber, R.string.button_plus, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_HOME + wiimoteNumber, R.string.button_home, mGameID)); - - sl.add(new HeaderSetting(mContext, R.string.wiimote_ir, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_IR_UP + wiimoteNumber, R.string.generic_up, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_IR_DOWN + wiimoteNumber, R.string.generic_down, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_IR_LEFT + wiimoteNumber, R.string.generic_left, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_IR_RIGHT + wiimoteNumber, R.string.generic_right, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_IR_FORWARD + wiimoteNumber, R.string.generic_forward, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_IR_BACKWARD + wiimoteNumber, R.string.generic_backward, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_IR_HIDE + wiimoteNumber, R.string.ir_hide, mGameID)); - - sl.add(new HeaderSetting(mContext, R.string.wiimote_swing, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_SWING_UP + wiimoteNumber, R.string.generic_up, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_SWING_DOWN + wiimoteNumber, R.string.generic_down, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_SWING_LEFT + wiimoteNumber, R.string.generic_left, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_SWING_RIGHT + wiimoteNumber, R.string.generic_right, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_SWING_FORWARD + wiimoteNumber, R.string.generic_forward, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_SWING_BACKWARD + wiimoteNumber, R.string.generic_backward, - mGameID)); - - sl.add(new HeaderSetting(mContext, R.string.wiimote_tilt, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_TILT_FORWARD + wiimoteNumber, R.string.generic_forward, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_TILT_BACKWARD + wiimoteNumber, R.string.generic_backward, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_TILT_LEFT + wiimoteNumber, R.string.generic_left, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_TILT_RIGHT + wiimoteNumber, R.string.generic_right, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_TILT_MODIFIER + wiimoteNumber, R.string.tilt_modifier, - mGameID)); - - sl.add(new HeaderSetting(mContext, R.string.wiimote_shake, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_SHAKE_X + wiimoteNumber, R.string.shake_x, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_SHAKE_Y + wiimoteNumber, R.string.shake_y, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_SHAKE_Z + wiimoteNumber, R.string.shake_z, mGameID)); - - sl.add(new HeaderSetting(mContext, R.string.controller_dpad, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_DPAD_UP + wiimoteNumber, R.string.generic_up, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_DPAD_DOWN + wiimoteNumber, R.string.generic_down, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_DPAD_LEFT + wiimoteNumber, R.string.generic_left, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_DPAD_RIGHT + wiimoteNumber, R.string.generic_right, mGameID)); - - - sl.add(new HeaderSetting(mContext, R.string.emulation_control_rumble, 0)); - sl.add(new RumbleBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_EMU_RUMBLE + wiimoteNumber, R.string.emulation_control_rumble, - mGameID)); + // TODO } private void addExtensionTypeSettings(ArrayList sl, int wiimoteNumber, int extentionType) { - switch (extentionType) - { - case 1: // Nunchuk - sl.add(new HeaderSetting(mContext, R.string.generic_buttons, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_NUNCHUK_C + wiimoteNumber, R.string.nunchuk_button_c, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_NUNCHUK_Z + wiimoteNumber, R.string.button_z, mGameID)); - - sl.add(new HeaderSetting(mContext, R.string.generic_stick, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_NUNCHUK_UP + wiimoteNumber, R.string.generic_up, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_NUNCHUK_DOWN + wiimoteNumber, R.string.generic_down, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_NUNCHUK_LEFT + wiimoteNumber, R.string.generic_left, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_NUNCHUK_RIGHT + wiimoteNumber, R.string.generic_right, - mGameID)); - - sl.add(new HeaderSetting(mContext, R.string.wiimote_swing, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_NUNCHUK_SWING_UP + wiimoteNumber, R.string.generic_up, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_NUNCHUK_SWING_DOWN + wiimoteNumber, R.string.generic_down, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_NUNCHUK_SWING_LEFT + wiimoteNumber, R.string.generic_left, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_NUNCHUK_SWING_RIGHT + wiimoteNumber, - R.string.generic_right, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_NUNCHUK_SWING_FORWARD + wiimoteNumber, - R.string.generic_forward, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_NUNCHUK_SWING_BACKWARD + wiimoteNumber, - R.string.generic_backward, mGameID)); - - sl.add(new HeaderSetting(mContext, R.string.wiimote_tilt, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_NUNCHUK_TILT_FORWARD + wiimoteNumber, - R.string.generic_forward, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_NUNCHUK_TILT_BACKWARD + wiimoteNumber, - R.string.generic_backward, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_NUNCHUK_TILT_LEFT + wiimoteNumber, R.string.generic_left, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_NUNCHUK_TILT_RIGHT + wiimoteNumber, R.string.generic_right, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_NUNCHUK_TILT_MODIFIER + wiimoteNumber, - R.string.tilt_modifier, mGameID)); - - sl.add(new HeaderSetting(mContext, R.string.wiimote_shake, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_NUNCHUK_SHAKE_X + wiimoteNumber, R.string.shake_x, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_NUNCHUK_SHAKE_Y + wiimoteNumber, R.string.shake_y, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_NUNCHUK_SHAKE_Z + wiimoteNumber, R.string.shake_z, - mGameID)); - break; - case 2: // Classic - sl.add(new HeaderSetting(mContext, R.string.generic_buttons, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_CLASSIC_A + wiimoteNumber, R.string.button_a, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_CLASSIC_B + wiimoteNumber, R.string.button_b, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_CLASSIC_X + wiimoteNumber, R.string.button_x, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_CLASSIC_Y + wiimoteNumber, R.string.button_y, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_CLASSIC_ZL + wiimoteNumber, R.string.classic_button_zl, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_CLASSIC_ZR + wiimoteNumber, R.string.classic_button_zr, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_CLASSIC_MINUS + wiimoteNumber, R.string.button_minus, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_CLASSIC_PLUS + wiimoteNumber, R.string.button_plus, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_CLASSIC_HOME + wiimoteNumber, R.string.button_home, - mGameID)); - - sl.add(new HeaderSetting(mContext, R.string.classic_leftstick, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_CLASSIC_LEFT_UP + wiimoteNumber, R.string.generic_up, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_CLASSIC_LEFT_DOWN + wiimoteNumber, R.string.generic_down, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_CLASSIC_LEFT_LEFT + wiimoteNumber, R.string.generic_left, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_CLASSIC_LEFT_RIGHT + wiimoteNumber, R.string.generic_right, - mGameID)); - - sl.add(new HeaderSetting(mContext, R.string.classic_rightstick, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_CLASSIC_RIGHT_UP + wiimoteNumber, R.string.generic_up, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_CLASSIC_RIGHT_DOWN + wiimoteNumber, R.string.generic_down, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_CLASSIC_RIGHT_LEFT + wiimoteNumber, R.string.generic_left, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_CLASSIC_RIGHT_RIGHT + wiimoteNumber, - R.string.generic_right, mGameID)); - - sl.add(new HeaderSetting(mContext, R.string.controller_trig, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_CLASSIC_TRIGGER_L + wiimoteNumber, R.string.trigger_left, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_CLASSIC_TRIGGER_R + wiimoteNumber, R.string.trigger_right, - mGameID)); - - sl.add(new HeaderSetting(mContext, R.string.controller_dpad, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_CLASSIC_DPAD_UP + wiimoteNumber, R.string.generic_up, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_CLASSIC_DPAD_DOWN + wiimoteNumber, R.string.generic_down, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_CLASSIC_DPAD_LEFT + wiimoteNumber, R.string.generic_left, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_CLASSIC_DPAD_RIGHT + wiimoteNumber, R.string.generic_right, - mGameID)); - break; - case 3: // Guitar - sl.add(new HeaderSetting(mContext, R.string.guitar_frets, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_GUITAR_FRET_GREEN + wiimoteNumber, R.string.generic_green, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_GUITAR_FRET_RED + wiimoteNumber, R.string.generic_red, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_GUITAR_FRET_YELLOW + wiimoteNumber, - R.string.generic_yellow, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_GUITAR_FRET_BLUE + wiimoteNumber, R.string.generic_blue, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_GUITAR_FRET_ORANGE + wiimoteNumber, - R.string.generic_orange, mGameID)); - - sl.add(new HeaderSetting(mContext, R.string.guitar_strum, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_GUITAR_STRUM_UP + wiimoteNumber, R.string.generic_up, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_GUITAR_STRUM_DOWN + wiimoteNumber, R.string.generic_down, - mGameID)); - - sl.add(new HeaderSetting(mContext, R.string.generic_buttons, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_GUITAR_MINUS + wiimoteNumber, R.string.button_minus, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_GUITAR_PLUS + wiimoteNumber, R.string.button_plus, - mGameID)); - - sl.add(new HeaderSetting(mContext, R.string.generic_stick, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_GUITAR_STICK_UP + wiimoteNumber, R.string.generic_up, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_GUITAR_STICK_DOWN + wiimoteNumber, R.string.generic_down, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_GUITAR_STICK_LEFT + wiimoteNumber, R.string.generic_left, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_GUITAR_STICK_RIGHT + wiimoteNumber, R.string.generic_right, - mGameID)); - - sl.add(new HeaderSetting(mContext, R.string.guitar_whammy, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_GUITAR_WHAMMY_BAR + wiimoteNumber, R.string.generic_right, - mGameID)); - break; - case 4: // Drums - sl.add(new HeaderSetting(mContext, R.string.drums_pads, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_DRUMS_PAD_RED + wiimoteNumber, R.string.generic_red, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_DRUMS_PAD_YELLOW + wiimoteNumber, R.string.generic_yellow, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_DRUMS_PAD_BLUE + wiimoteNumber, R.string.generic_blue, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_DRUMS_PAD_GREEN + wiimoteNumber, R.string.generic_green, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_DRUMS_PAD_ORANGE + wiimoteNumber, R.string.generic_orange, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_DRUMS_PAD_BASS + wiimoteNumber, R.string.drums_pad_bass, - mGameID)); - - sl.add(new HeaderSetting(mContext, R.string.generic_stick, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_DRUMS_STICK_UP + wiimoteNumber, R.string.generic_up, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_DRUMS_STICK_DOWN + wiimoteNumber, R.string.generic_down, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_DRUMS_STICK_LEFT + wiimoteNumber, R.string.generic_left, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_DRUMS_STICK_RIGHT + wiimoteNumber, R.string.generic_right, - mGameID)); - - sl.add(new HeaderSetting(mContext, R.string.generic_buttons, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_DRUMS_MINUS + wiimoteNumber, R.string.button_minus, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_DRUMS_PLUS + wiimoteNumber, R.string.button_plus, - mGameID)); - break; - case 5: // Turntable - sl.add(new HeaderSetting(mContext, R.string.generic_buttons, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_TURNTABLE_GREEN_LEFT + wiimoteNumber, - R.string.turntable_button_green_left, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_TURNTABLE_RED_LEFT + wiimoteNumber, - R.string.turntable_button_red_left, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_TURNTABLE_BLUE_LEFT + wiimoteNumber, - R.string.turntable_button_blue_left, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_TURNTABLE_GREEN_RIGHT + wiimoteNumber, - R.string.turntable_button_green_right, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_TURNTABLE_RED_RIGHT + wiimoteNumber, - R.string.turntable_button_red_right, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_TURNTABLE_BLUE_RIGHT + wiimoteNumber, - R.string.turntable_button_blue_right, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_TURNTABLE_MINUS + wiimoteNumber, - R.string.button_minus, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_TURNTABLE_PLUS + wiimoteNumber, - R.string.button_plus, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_TURNTABLE_EUPHORIA + wiimoteNumber, - R.string.turntable_button_euphoria, mGameID)); - - sl.add(new HeaderSetting(mContext, R.string.turntable_table_left, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_TURNTABLE_LEFT_LEFT + wiimoteNumber, R.string.generic_left, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_TURNTABLE_LEFT_RIGHT + wiimoteNumber, - R.string.generic_right, mGameID)); - - sl.add(new HeaderSetting(mContext, R.string.turntable_table_right, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_TURNTABLE_RIGHT_LEFT + wiimoteNumber, - R.string.generic_left, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_TURNTABLE_RIGHT_RIGHT + wiimoteNumber, - R.string.generic_right, mGameID)); - - sl.add(new HeaderSetting(mContext, R.string.generic_stick, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_TURNTABLE_STICK_UP + wiimoteNumber, R.string.generic_up, - mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_TURNTABLE_STICK_DOWN + wiimoteNumber, - R.string.generic_down, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_TURNTABLE_STICK_LEFT + wiimoteNumber, - R.string.generic_left, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_TURNTABLE_STICK_RIGHT + wiimoteNumber, - R.string.generic_right, mGameID)); - - sl.add(new HeaderSetting(mContext, R.string.turntable_effect, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_TURNTABLE_EFFECT_DIAL + wiimoteNumber, - R.string.turntable_effect_dial, mGameID)); - - sl.add(new HeaderSetting(mContext, R.string.turntable_crossfade, 0)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_TURNTABLE_CROSSFADE_LEFT + wiimoteNumber, - R.string.generic_left, mGameID)); - sl.add(new InputBindingSetting(mContext, Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS, - SettingsFile.KEY_WIIBIND_TURNTABLE_CROSSFADE_RIGHT + wiimoteNumber, - R.string.generic_right, mGameID)); - break; - } + // TODO } private static int getLogVerbosityEntries() diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/utils/SettingsFile.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/utils/SettingsFile.java index 87f58b4d02..9362b4e980 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/utils/SettingsFile.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/utils/SettingsFile.java @@ -22,158 +22,9 @@ public final class SettingsFile public static final String KEY_GCPAD_PLAYER_1 = "SIDevice0"; - public static final String KEY_GCBIND_A = "InputA_"; - public static final String KEY_GCBIND_B = "InputB_"; - public static final String KEY_GCBIND_X = "InputX_"; - public static final String KEY_GCBIND_Y = "InputY_"; - public static final String KEY_GCBIND_Z = "InputZ_"; - public static final String KEY_GCBIND_START = "InputStart_"; - public static final String KEY_GCBIND_CONTROL_UP = "MainUp_"; - public static final String KEY_GCBIND_CONTROL_DOWN = "MainDown_"; - public static final String KEY_GCBIND_CONTROL_LEFT = "MainLeft_"; - public static final String KEY_GCBIND_CONTROL_RIGHT = "MainRight_"; - public static final String KEY_GCBIND_C_UP = "CStickUp_"; - public static final String KEY_GCBIND_C_DOWN = "CStickDown_"; - public static final String KEY_GCBIND_C_LEFT = "CStickLeft_"; - public static final String KEY_GCBIND_C_RIGHT = "CStickRight_"; - public static final String KEY_GCBIND_TRIGGER_L = "InputL_"; - public static final String KEY_GCBIND_TRIGGER_R = "InputR_"; - public static final String KEY_GCBIND_DPAD_UP = "DPadUp_"; - public static final String KEY_GCBIND_DPAD_DOWN = "DPadDown_"; - public static final String KEY_GCBIND_DPAD_LEFT = "DPadLeft_"; - public static final String KEY_GCBIND_DPAD_RIGHT = "DPadRight_"; - - public static final String KEY_EMU_RUMBLE = "EmuRumble"; - - public static final String KEY_WIIMOTE_EXTENSION = "Extension"; - - // Controller keys for game specific settings - public static final String KEY_WIIMOTE_PROFILE = "WiimoteProfile"; - - public static final String KEY_WIIBIND_A = "WiimoteA_"; - public static final String KEY_WIIBIND_B = "WiimoteB_"; - public static final String KEY_WIIBIND_1 = "Wiimote1_"; - public static final String KEY_WIIBIND_2 = "Wiimote2_"; - public static final String KEY_WIIBIND_MINUS = "WiimoteMinus_"; - public static final String KEY_WIIBIND_PLUS = "WiimotePlus_"; - public static final String KEY_WIIBIND_HOME = "WiimoteHome_"; - public static final String KEY_WIIBIND_IR_UP = "IRUp_"; - public static final String KEY_WIIBIND_IR_DOWN = "IRDown_"; - public static final String KEY_WIIBIND_IR_LEFT = "IRLeft_"; - public static final String KEY_WIIBIND_IR_RIGHT = "IRRight_"; - public static final String KEY_WIIBIND_IR_FORWARD = "IRForward_"; - public static final String KEY_WIIBIND_IR_BACKWARD = "IRBackward_"; - public static final String KEY_WIIBIND_IR_HIDE = "IRHide_"; public static final String KEY_WIIBIND_IR_PITCH = "IRTotalPitch"; public static final String KEY_WIIBIND_IR_YAW = "IRTotalYaw"; public static final String KEY_WIIBIND_IR_VERTICAL_OFFSET = "IRVerticalOffset"; - public static final String KEY_WIIBIND_SWING_UP = "SwingUp_"; - public static final String KEY_WIIBIND_SWING_DOWN = "SwingDown_"; - public static final String KEY_WIIBIND_SWING_LEFT = "SwingLeft_"; - public static final String KEY_WIIBIND_SWING_RIGHT = "SwingRight_"; - public static final String KEY_WIIBIND_SWING_FORWARD = "SwingForward_"; - public static final String KEY_WIIBIND_SWING_BACKWARD = "SwingBackward_"; - public static final String KEY_WIIBIND_TILT_FORWARD = "TiltForward_"; - public static final String KEY_WIIBIND_TILT_BACKWARD = "TiltBackward_"; - public static final String KEY_WIIBIND_TILT_LEFT = "TiltLeft_"; - public static final String KEY_WIIBIND_TILT_RIGHT = "TiltRight_"; - public static final String KEY_WIIBIND_TILT_MODIFIER = "TiltModifier_"; - public static final String KEY_WIIBIND_SHAKE_X = "ShakeX_"; - public static final String KEY_WIIBIND_SHAKE_Y = "ShakeY_"; - public static final String KEY_WIIBIND_SHAKE_Z = "ShakeZ_"; - public static final String KEY_WIIBIND_DPAD_UP = "WiimoteUp_"; - public static final String KEY_WIIBIND_DPAD_DOWN = "WiimoteDown_"; - public static final String KEY_WIIBIND_DPAD_LEFT = "WiimoteLeft_"; - public static final String KEY_WIIBIND_DPAD_RIGHT = "WiimoteRight_"; - public static final String KEY_WIIBIND_NUNCHUK_C = "NunchukC_"; - public static final String KEY_WIIBIND_NUNCHUK_Z = "NunchukZ_"; - public static final String KEY_WIIBIND_NUNCHUK_UP = "NunchukUp_"; - public static final String KEY_WIIBIND_NUNCHUK_DOWN = "NunchukDown_"; - public static final String KEY_WIIBIND_NUNCHUK_LEFT = "NunchukLeft_"; - public static final String KEY_WIIBIND_NUNCHUK_RIGHT = "NunchukRight_"; - public static final String KEY_WIIBIND_NUNCHUK_SWING_UP = "NunchukSwingUp_"; - public static final String KEY_WIIBIND_NUNCHUK_SWING_DOWN = "NunchukSwingDown_"; - public static final String KEY_WIIBIND_NUNCHUK_SWING_LEFT = "NunchukSwingLeft_"; - public static final String KEY_WIIBIND_NUNCHUK_SWING_RIGHT = "NunchukSwingRight_"; - public static final String KEY_WIIBIND_NUNCHUK_SWING_FORWARD = "NunchukSwingForward_"; - public static final String KEY_WIIBIND_NUNCHUK_SWING_BACKWARD = "NunchukSwingBackward_"; - public static final String KEY_WIIBIND_NUNCHUK_TILT_FORWARD = "NunchukTiltForward_"; - public static final String KEY_WIIBIND_NUNCHUK_TILT_BACKWARD = "NunchukTiltBackward_"; - public static final String KEY_WIIBIND_NUNCHUK_TILT_LEFT = "NunchukTiltLeft_"; - public static final String KEY_WIIBIND_NUNCHUK_TILT_RIGHT = "NunchukTiltRight_"; - public static final String KEY_WIIBIND_NUNCHUK_TILT_MODIFIER = "NunchukTiltModifier_"; - public static final String KEY_WIIBIND_NUNCHUK_SHAKE_X = "NunchukShakeX_"; - public static final String KEY_WIIBIND_NUNCHUK_SHAKE_Y = "NunchukShakeY_"; - public static final String KEY_WIIBIND_NUNCHUK_SHAKE_Z = "NunchukShakeZ_"; - public static final String KEY_WIIBIND_CLASSIC_A = "ClassicA_"; - public static final String KEY_WIIBIND_CLASSIC_B = "ClassicB_"; - public static final String KEY_WIIBIND_CLASSIC_X = "ClassicX_"; - public static final String KEY_WIIBIND_CLASSIC_Y = "ClassicY_"; - public static final String KEY_WIIBIND_CLASSIC_ZL = "ClassicZL_"; - public static final String KEY_WIIBIND_CLASSIC_ZR = "ClassicZR_"; - public static final String KEY_WIIBIND_CLASSIC_MINUS = "ClassicMinus_"; - public static final String KEY_WIIBIND_CLASSIC_PLUS = "ClassicPlus_"; - public static final String KEY_WIIBIND_CLASSIC_HOME = "ClassicHome_"; - public static final String KEY_WIIBIND_CLASSIC_LEFT_UP = "ClassicLeftStickUp_"; - public static final String KEY_WIIBIND_CLASSIC_LEFT_DOWN = "ClassicLeftStickDown_"; - public static final String KEY_WIIBIND_CLASSIC_LEFT_LEFT = "ClassicLeftStickLeft_"; - public static final String KEY_WIIBIND_CLASSIC_LEFT_RIGHT = "ClassicLeftStickRight_"; - public static final String KEY_WIIBIND_CLASSIC_RIGHT_UP = "ClassicRightStickUp_"; - public static final String KEY_WIIBIND_CLASSIC_RIGHT_DOWN = "ClassicRightStickDown_"; - public static final String KEY_WIIBIND_CLASSIC_RIGHT_LEFT = "ClassicRightStickLeft_"; - public static final String KEY_WIIBIND_CLASSIC_RIGHT_RIGHT = "ClassicRightStickRight_"; - public static final String KEY_WIIBIND_CLASSIC_TRIGGER_L = "ClassicTriggerL_"; - public static final String KEY_WIIBIND_CLASSIC_TRIGGER_R = "ClassicTriggerR_"; - public static final String KEY_WIIBIND_CLASSIC_DPAD_UP = "ClassicUp_"; - public static final String KEY_WIIBIND_CLASSIC_DPAD_DOWN = "ClassicDown_"; - public static final String KEY_WIIBIND_CLASSIC_DPAD_LEFT = "ClassicLeft_"; - public static final String KEY_WIIBIND_CLASSIC_DPAD_RIGHT = "ClassicRight_"; - public static final String KEY_WIIBIND_GUITAR_FRET_GREEN = "GuitarGreen_"; - public static final String KEY_WIIBIND_GUITAR_FRET_RED = "GuitarRed_"; - public static final String KEY_WIIBIND_GUITAR_FRET_YELLOW = "GuitarYellow_"; - public static final String KEY_WIIBIND_GUITAR_FRET_BLUE = "GuitarBlue_"; - public static final String KEY_WIIBIND_GUITAR_FRET_ORANGE = "GuitarOrange_"; - public static final String KEY_WIIBIND_GUITAR_STRUM_UP = "GuitarStrumUp_"; - public static final String KEY_WIIBIND_GUITAR_STRUM_DOWN = "GuitarStrumDown_"; - public static final String KEY_WIIBIND_GUITAR_MINUS = "GuitarMinus_"; - public static final String KEY_WIIBIND_GUITAR_PLUS = "GuitarPlus_"; - public static final String KEY_WIIBIND_GUITAR_STICK_UP = "GuitarUp_"; - public static final String KEY_WIIBIND_GUITAR_STICK_DOWN = "GuitarDown_"; - public static final String KEY_WIIBIND_GUITAR_STICK_LEFT = "GuitarLeft_"; - public static final String KEY_WIIBIND_GUITAR_STICK_RIGHT = "GuitarRight_"; - public static final String KEY_WIIBIND_GUITAR_WHAMMY_BAR = "GuitarWhammy_"; - public static final String KEY_WIIBIND_DRUMS_PAD_RED = "DrumsRed_"; - public static final String KEY_WIIBIND_DRUMS_PAD_YELLOW = "DrumsYellow_"; - public static final String KEY_WIIBIND_DRUMS_PAD_BLUE = "DrumsBlue_"; - public static final String KEY_WIIBIND_DRUMS_PAD_GREEN = "DrumsGreen_"; - public static final String KEY_WIIBIND_DRUMS_PAD_ORANGE = "DrumsOrange_"; - public static final String KEY_WIIBIND_DRUMS_PAD_BASS = "DrumsBass_"; - public static final String KEY_WIIBIND_DRUMS_MINUS = "DrumsMinus_"; - public static final String KEY_WIIBIND_DRUMS_PLUS = "DrumsPlus_"; - public static final String KEY_WIIBIND_DRUMS_STICK_UP = "DrumsUp_"; - public static final String KEY_WIIBIND_DRUMS_STICK_DOWN = "DrumsDown_"; - public static final String KEY_WIIBIND_DRUMS_STICK_LEFT = "DrumsLeft_"; - public static final String KEY_WIIBIND_DRUMS_STICK_RIGHT = "DrumsRight_"; - public static final String KEY_WIIBIND_TURNTABLE_GREEN_LEFT = "TurntableGreenLeft_"; - public static final String KEY_WIIBIND_TURNTABLE_RED_LEFT = "TurntableRedLeft_"; - public static final String KEY_WIIBIND_TURNTABLE_BLUE_LEFT = "TurntableBlueLeft_"; - public static final String KEY_WIIBIND_TURNTABLE_GREEN_RIGHT = "TurntableGreenRight_"; - public static final String KEY_WIIBIND_TURNTABLE_RED_RIGHT = "TurntableRedRight_"; - public static final String KEY_WIIBIND_TURNTABLE_BLUE_RIGHT = "TurntableBlueRight_"; - public static final String KEY_WIIBIND_TURNTABLE_MINUS = "TurntableMinus_"; - public static final String KEY_WIIBIND_TURNTABLE_PLUS = "TurntablePlus_"; - public static final String KEY_WIIBIND_TURNTABLE_EUPHORIA = "TurntableEuphoria_"; - public static final String KEY_WIIBIND_TURNTABLE_LEFT_LEFT = "TurntableLeftLeft_"; - public static final String KEY_WIIBIND_TURNTABLE_LEFT_RIGHT = "TurntableLeftRight_"; - public static final String KEY_WIIBIND_TURNTABLE_RIGHT_LEFT = "TurntableRightLeft_"; - public static final String KEY_WIIBIND_TURNTABLE_RIGHT_RIGHT = "TurntableRightRight_"; - public static final String KEY_WIIBIND_TURNTABLE_STICK_UP = "TurntableUp_"; - public static final String KEY_WIIBIND_TURNTABLE_STICK_DOWN = "TurntableDown_"; - public static final String KEY_WIIBIND_TURNTABLE_STICK_LEFT = "TurntableLeft_"; - public static final String KEY_WIIBIND_TURNTABLE_STICK_RIGHT = "TurntableRight_"; - public static final String KEY_WIIBIND_TURNTABLE_EFFECT_DIAL = "TurntableEffDial_"; - public static final String KEY_WIIBIND_TURNTABLE_CROSSFADE_LEFT = "TurntableCrossLeft_"; - public static final String KEY_WIIBIND_TURNTABLE_CROSSFADE_RIGHT = "TurntableCrossRight_"; private static BiMap sectionsMap = new BiMap<>(); @@ -283,13 +134,4 @@ public final class SettingsFile return new File( DirectoryInitialization.getUserDirectory() + "/GameSettings/" + gameId + ".ini"); } - - public static File getWiiProfile(String profile) - { - String wiiConfigPath = - DirectoryInitialization.getUserDirectory() + "/Config/Profiles/Wiimote/" + - profile + ".ini"; - - return new File(wiiConfigPath); - } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/ControllerMappingHelper.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/ControllerMappingHelper.java deleted file mode 100644 index 9e31a46a96..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/ControllerMappingHelper.java +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -package org.dolphinemu.dolphinemu.utils; - -import android.view.InputDevice; -import android.view.KeyEvent; -import android.view.MotionEvent; - -/** - * Some controllers have incorrect mappings. This class has special-case fixes for them. - */ -public class ControllerMappingHelper -{ - /** - * Some controllers report extra button presses that can be ignored. - */ - public static boolean shouldKeyBeIgnored(InputDevice inputDevice, int keyCode) - { - if (isDualShock4(inputDevice)) - { - // The two analog triggers generate analog motion events as well as a keycode. - // We always prefer to use the analog values, so throw away the button press - return keyCode == KeyEvent.KEYCODE_BUTTON_L2 || keyCode == KeyEvent.KEYCODE_BUTTON_R2; - } - return false; - } - - /** - * Scale an axis to be zero-centered with a proper range. - */ - public static float scaleAxis(InputDevice inputDevice, int axis, float value) - { - if (isDualShock4(inputDevice)) - { - // Android doesn't have correct mappings for this controller's triggers. It reports them - // as RX & RY, centered at -1.0, and with a range of [-1.0, 1.0] - // Scale them to properly zero-centered with a range of [0.0, 1.0]. - if (axis == MotionEvent.AXIS_RX || axis == MotionEvent.AXIS_RY) - { - return (value + 1) / 2.0f; - } - } - else if (isXboxOneWireless(inputDevice)) - { - // Same as the DualShock 4, the mappings are missing. - if (axis == MotionEvent.AXIS_Z || axis == MotionEvent.AXIS_RZ) - { - return (value + 1) / 2.0f; - } - } - return value; - } - - private static boolean isDualShock4(InputDevice inputDevice) - { - // Sony DualShock 4 controller - return inputDevice.getVendorId() == 0x54c && inputDevice.getProductId() == 0x9cc; - } - - private static boolean isXboxOneWireless(InputDevice inputDevice) - { - // Microsoft Xbox One controller - return inputDevice.getVendorId() == 0x45e && inputDevice.getProductId() == 0x2e0; - } -} -- cgit v1.2.3 From 2c529b9db12a60eb3640975f6ea4802237e118fa Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 23 Jan 2022 21:47:57 +0100 Subject: Android: Add new input mapping implementation --- .../dolphinemu/dialogs/MotionAlertDialog.java | 169 --------------------- .../features/input/model/MappingCommon.java | 24 +++ .../input/model/controlleremu/Control.java | 27 ++++ .../input/model/controlleremu/ControlGroup.java | 29 ++++ .../model/controlleremu/ControlReference.java | 37 +++++ .../model/controlleremu/EmulatedController.java | 36 +++++ .../model/view/InputMappingControlSetting.java | 50 ++++++ .../features/input/ui/MotionAlertDialog.java | 95 ++++++++++++ .../InputMappingControlSettingViewHolder.java | 59 +++++++ .../features/settings/model/Settings.java | 3 + .../settings/model/view/HeaderSetting.java | 5 + .../settings/model/view/InputBindingSetting.java | 108 ------------- .../settings/model/view/RumbleBindingSetting.java | 69 --------- .../features/settings/model/view/SettingsItem.java | 3 +- .../dolphinemu/features/settings/ui/MenuTag.java | 16 +- .../features/settings/ui/SettingsAdapter.java | 28 ++-- .../features/settings/ui/SettingsFragment.java | 16 +- .../settings/ui/SettingsFragmentPresenter.java | 44 ++++-- .../viewholder/InputBindingSettingViewHolder.java | 67 -------- .../ui/viewholder/RumbleBindingViewHolder.java | 67 -------- 20 files changed, 424 insertions(+), 528 deletions(-) delete mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/MotionAlertDialog.java create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/MappingCommon.java create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/Control.java create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/ControlGroup.java create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/ControlReference.java create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/EmulatedController.java create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/view/InputMappingControlSetting.java create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/MotionAlertDialog.java create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/viewholder/InputMappingControlSettingViewHolder.java delete mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/InputBindingSetting.java delete mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/RumbleBindingSetting.java delete mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/InputBindingSettingViewHolder.java delete mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/RumbleBindingViewHolder.java (limited to 'Source/Android/app/src/main/java') 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 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 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/input/ui/viewholder/InputMappingControlSettingViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/viewholder/InputMappingControlSettingViewHolder.java new file mode 100644 index 0000000000..72ddcb3fd3 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/viewholder/InputMappingControlSettingViewHolder.java @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.features.input.ui.viewholder; + +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.dolphinemu.dolphinemu.databinding.ListItemSettingBinding; +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 InputMappingControlSettingViewHolder extends SettingViewHolder +{ + private InputMappingControlSetting mItem; + + private final ListItemSettingBinding mBinding; + + public InputMappingControlSettingViewHolder(@NonNull ListItemSettingBinding binding, + SettingsAdapter adapter) + { + super(binding.getRoot(), adapter); + mBinding = binding; + } + + @Override + public void bind(SettingsItem item) + { + mItem = (InputMappingControlSetting) item; + + mBinding.textSettingName.setText(mItem.getName()); + mBinding.textSettingDescription.setText(mItem.getValue()); + + setStyle(mBinding.textSettingName, mItem); + } + + @Override + public void onClick(View clicked) + { + if (!mItem.isEditable()) + { + showNotRuntimeEditableError(); + return; + } + + getAdapter().onInputMappingClick(mItem, getBindingAdapterPosition()); + + setStyle(mBinding.textSettingName, mItem); + } + + @Nullable @Override + protected SettingsItem getItem() + { + return 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 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 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 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 sl, int wiimoteNumber) { - // TODO + addControllerSettings(sl, EmulatedController.getWiimote(wiimoteNumber)); } private void addExtensionTypeSettings(ArrayList sl, int wiimoteNumber, - int extentionType) + int extensionType) { - // TODO + addControllerSettings(sl, + EmulatedController.getWiimoteAttachment(wiimoteNumber, extensionType)); + } + + private void addControllerSettings(ArrayList 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/InputBindingSettingViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/InputBindingSettingViewHolder.java deleted file mode 100644 index b61fcc458b..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/InputBindingSettingViewHolder.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.InputBindingSetting; -import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem; -import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter; - -public final class InputBindingSettingViewHolder extends SettingViewHolder -{ - private InputBindingSetting mItem; - - private final Context mContext; - - private final ListItemSettingBinding mBinding; - - public InputBindingSettingViewHolder(@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 = (InputBindingSetting) item; - - mBinding.textSettingName.setText(mItem.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/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; - } -} -- cgit v1.2.3 From 1c26a85e35f94169ddc83e8174d6824aec82d322 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Mon, 18 Apr 2022 16:11:14 +0200 Subject: Android: Add NumericSetting support --- .../input/model/InputMappingBooleanSetting.java | 48 ++++++++++++ .../input/model/InputMappingDoubleSetting.java | 49 ++++++++++++ .../input/model/controlleremu/ControlGroup.java | 4 + .../input/model/controlleremu/NumericSetting.java | 89 ++++++++++++++++++++++ .../settings/model/view/FloatSliderSetting.java | 7 ++ .../settings/model/view/SliderSetting.java | 8 ++ .../settings/ui/SettingsFragmentPresenter.java | 26 +++++++ 7 files changed, 231 insertions(+) create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/InputMappingBooleanSetting.java create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/InputMappingDoubleSetting.java create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/NumericSetting.java (limited to 'Source/Android/app/src/main/java') diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/InputMappingBooleanSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/InputMappingBooleanSetting.java new file mode 100644 index 0000000000..7241d6e125 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/InputMappingBooleanSetting.java @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.features.input.model; + +import org.dolphinemu.dolphinemu.features.input.model.controlleremu.NumericSetting; +import org.dolphinemu.dolphinemu.features.settings.model.AbstractBooleanSetting; +import org.dolphinemu.dolphinemu.features.settings.model.Settings; + +public class InputMappingBooleanSetting implements AbstractBooleanSetting +{ + private final NumericSetting mNumericSetting; + + public InputMappingBooleanSetting(NumericSetting numericSetting) + { + mNumericSetting = numericSetting; + } + + @Override + public boolean getBoolean(Settings settings) + { + return mNumericSetting.getBooleanValue(); + } + + @Override + public void setBoolean(Settings settings, boolean newValue) + { + mNumericSetting.setBooleanValue(newValue); + } + + @Override + public boolean isOverridden(Settings settings) + { + return false; + } + + @Override + public boolean isRuntimeEditable() + { + return true; + } + + @Override + public boolean delete(Settings settings) + { + mNumericSetting.setBooleanValue(mNumericSetting.getBooleanDefaultValue()); + return true; + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/InputMappingDoubleSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/InputMappingDoubleSetting.java new file mode 100644 index 0000000000..e84b61a045 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/InputMappingDoubleSetting.java @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.features.input.model; + +import org.dolphinemu.dolphinemu.features.input.model.controlleremu.NumericSetting; +import org.dolphinemu.dolphinemu.features.settings.model.AbstractFloatSetting; +import org.dolphinemu.dolphinemu.features.settings.model.Settings; + +// Yes, floats are not the same thing as doubles... They're close enough, though +public class InputMappingDoubleSetting implements AbstractFloatSetting +{ + private final NumericSetting mNumericSetting; + + public InputMappingDoubleSetting(NumericSetting numericSetting) + { + mNumericSetting = numericSetting; + } + + @Override + public float getFloat(Settings settings) + { + return (float) mNumericSetting.getDoubleValue(); + } + + @Override + public void setFloat(Settings settings, float newValue) + { + mNumericSetting.setDoubleValue(newValue); + } + + @Override + public boolean isOverridden(Settings settings) + { + return false; + } + + @Override + public boolean isRuntimeEditable() + { + return true; + } + + @Override + public boolean delete(Settings settings) + { + mNumericSetting.setDoubleValue(mNumericSetting.getDoubleDefaultValue()); + return true; + } +} 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 index ddfce9a737..19423d5f14 100644 --- 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 @@ -26,4 +26,8 @@ public class ControlGroup public native int getControlCount(); public native Control getControl(int i); + + public native int getNumericSettingCount(); + + public native NumericSetting getNumericSetting(int i); } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/NumericSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/NumericSetting.java new file mode 100644 index 0000000000..9baa2c41d7 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/NumericSetting.java @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.features.input.model.controlleremu; + +import androidx.annotation.Keep; + +/** + * Represents a C++ ControllerEmu::NumericSetting. + * + * 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 NumericSetting +{ + public static final int TYPE_INT = 0; + public static final int TYPE_DOUBLE = 1; + public static final int TYPE_BOOLEAN = 2; + + @Keep + private final long mPointer; + + @Keep + private NumericSetting(long pointer) + { + mPointer = pointer; + } + + /** + * @return The name used in the UI. + */ + public native String getUiName(); + + /** + * @return A string applied to the number in the UI (unit of measure). + */ + public native String getUiSuffix(); + + /** + * @return Detailed description of the setting. + */ + public native String getUiDescription(); + + /** + * @return TYPE_INT, TYPE_DOUBLE or TYPE_BOOLEAN + */ + public native int getType(); + + public native ControlReference getControlReference(); + + /** + * If the type is TYPE_DOUBLE, gets the current value. Otherwise, undefined behavior! + */ + public native double getDoubleValue(); + + /** + * If the type is TYPE_DOUBLE, sets the current value. Otherwise, undefined behavior! + */ + public native void setDoubleValue(double value); + + /** + * If the type is TYPE_DOUBLE, gets the default value. Otherwise, undefined behavior! + */ + public native double getDoubleDefaultValue(); + + /** + * If the type is TYPE_DOUBLE, returns the minimum valid value. Otherwise, undefined behavior! + */ + public native double getDoubleMin(); + + /** + * If the type is TYPE_DOUBLE, returns the maximum valid value. Otherwise, undefined behavior! + */ + public native double getDoubleMax(); + + /** + * If the type is TYPE_BOOLEAN, gets the current value. Otherwise, undefined behavior! + */ + public native boolean getBooleanValue(); + + /** + * If the type is TYPE_BOOLEAN, sets the current value. Otherwise, undefined behavior! + */ + public native void setBooleanValue(boolean value); + + /** + * If the type is TYPE_BOOLEAN, gets the default value. Otherwise, undefined behavior! + */ + public native boolean getBooleanDefaultValue(); +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/FloatSliderSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/FloatSliderSetting.java index 167c5a471b..5b91517f75 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/FloatSliderSetting.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/FloatSliderSetting.java @@ -19,6 +19,13 @@ public class FloatSliderSetting extends SliderSetting mSetting = setting; } + public FloatSliderSetting(AbstractFloatSetting setting, CharSequence name, + CharSequence description, int min, int max, String units) + { + super(name, description, min, max, units); + mSetting = setting; + } + public int getSelectedValue(Settings settings) { return Math.round(mSetting.getFloat(settings)); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/SliderSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/SliderSetting.java index 48961839c0..e63fde3bad 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/SliderSetting.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/SliderSetting.java @@ -23,6 +23,14 @@ public abstract class SliderSetting extends SettingsItem mStepSize = stepSize; } + public SliderSetting(CharSequence name, CharSequence description, int min, int max, String units) + { + super(name, description); + mMin = min; + mMax = max; + mUnits = units; + } + public abstract int getSelectedValue(Settings settings); public int getMin() 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 01f4b52b71..775c9b3f8a 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,8 +14,11 @@ 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.InputMappingBooleanSetting; +import org.dolphinemu.dolphinemu.features.input.model.InputMappingDoubleSetting; 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.controlleremu.NumericSetting; 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; @@ -30,6 +33,7 @@ import org.dolphinemu.dolphinemu.features.settings.model.StringSetting; 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.HeaderSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.HyperLinkHeaderSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.InputStringSetting; @@ -1112,6 +1116,28 @@ public final class SettingsFragmentPresenter { sl.add(new InputMappingControlSetting(group.getControl(j), controller)); } + + int numericSettingCount = group.getNumericSettingCount(); + for (int j = 0; j < numericSettingCount; j++) + { + addNumericSetting(sl, group.getNumericSetting(j)); + } + } + } + + private void addNumericSetting(ArrayList sl, NumericSetting setting) + { + switch (setting.getType()) + { + case NumericSetting.TYPE_DOUBLE: + sl.add(new FloatSliderSetting(new InputMappingDoubleSetting(setting), setting.getUiName(), + "", (int) Math.ceil(setting.getDoubleMin()), + (int) Math.floor(setting.getDoubleMax()), setting.getUiSuffix())); + break; + case NumericSetting.TYPE_BOOLEAN: + sl.add(new SwitchSetting(new InputMappingBooleanSetting(setting), setting.getUiName(), + setting.getUiDescription())); + break; } } -- cgit v1.2.3 From 0dd8bbbbbb91f701f284561f244fa4e6f29b5f61 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Mon, 18 Apr 2022 17:17:48 +0200 Subject: Android: Add extension selection --- .../input/model/InputMappingIntSetting.java | 48 ++++++++++++++++++++++ .../input/model/controlleremu/ControlGroup.java | 23 +++++++++++ .../input/model/controlleremu/NumericSetting.java | 15 +++++++ .../settings/ui/SettingsFragmentPresenter.java | 10 +++++ 4 files changed, 96 insertions(+) create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/InputMappingIntSetting.java (limited to 'Source/Android/app/src/main/java') diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/InputMappingIntSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/InputMappingIntSetting.java new file mode 100644 index 0000000000..989f2b7cde --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/InputMappingIntSetting.java @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.features.input.model; + +import org.dolphinemu.dolphinemu.features.input.model.controlleremu.NumericSetting; +import org.dolphinemu.dolphinemu.features.settings.model.AbstractIntSetting; +import org.dolphinemu.dolphinemu.features.settings.model.Settings; + +public class InputMappingIntSetting implements AbstractIntSetting +{ + private final NumericSetting mNumericSetting; + + public InputMappingIntSetting(NumericSetting numericSetting) + { + mNumericSetting = numericSetting; + } + + @Override + public int getInt(Settings settings) + { + return mNumericSetting.getIntValue(); + } + + @Override + public void setInt(Settings settings, int newValue) + { + mNumericSetting.setIntValue(newValue); + } + + @Override + public boolean isOverridden(Settings settings) + { + return false; + } + + @Override + public boolean isRuntimeEditable() + { + return true; + } + + @Override + public boolean delete(Settings settings) + { + mNumericSetting.setIntValue(mNumericSetting.getIntDefaultValue()); + return true; + } +} 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 index 19423d5f14..0a7681af6d 100644 --- 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 @@ -12,6 +12,21 @@ import androidx.annotation.Keep; */ public class ControlGroup { + public static final int TYPE_OTHER = 0; + public static final int TYPE_STICK = 1; + public static final int TYPE_MIXED_TRIGGERS = 2; + public static final int TYPE_BUTTONS = 3; + public static final int TYPE_FORCE = 4; + public static final int TYPE_ATTACHMENTS = 5; + public static final int TYPE_TILT = 6; + public static final int TYPE_CURSOR = 7; + public static final int TYPE_TRIGGERS = 8; + public static final int TYPE_SLIDER = 9; + public static final int TYPE_SHAKE = 10; + public static final int TYPE_IMU_ACCELEROMETER = 11; + public static final int TYPE_IMU_GYROSCOPE = 12; + public static final int TYPE_IMU_CURSOR = 13; + @Keep private final long mPointer; @@ -23,6 +38,8 @@ public class ControlGroup public native String getUiName(); + public native int getGroupType(); + public native int getControlCount(); public native Control getControl(int i); @@ -30,4 +47,10 @@ public class ControlGroup public native int getNumericSettingCount(); public native NumericSetting getNumericSetting(int i); + + /** + * If getGroupType returns TYPE_ATTACHMENTS, this returns the attachment selection setting. + * Otherwise, undefined behavior! + */ + public native NumericSetting getAttachmentSetting(); } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/NumericSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/NumericSetting.java index 9baa2c41d7..bcb9dce181 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/NumericSetting.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/NumericSetting.java @@ -47,6 +47,21 @@ public class NumericSetting public native ControlReference getControlReference(); + /** + * If the type is TYPE_INT, gets the current value. Otherwise, undefined behavior! + */ + public native int getIntValue(); + + /** + * If the type is TYPE_INT, sets the current value. Otherwise, undefined behavior! + */ + public native void setIntValue(int value); + + /** + * If the type is TYPE_INT, gets the default value. Otherwise, undefined behavior! + */ + public native int getIntDefaultValue(); + /** * If the type is TYPE_DOUBLE, gets the current value. Otherwise, undefined behavior! */ 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 775c9b3f8a..fded8e56de 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 @@ -16,6 +16,7 @@ import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.activities.UserDataActivity; import org.dolphinemu.dolphinemu.features.input.model.InputMappingBooleanSetting; import org.dolphinemu.dolphinemu.features.input.model.InputMappingDoubleSetting; +import org.dolphinemu.dolphinemu.features.input.model.InputMappingIntSetting; 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.controlleremu.NumericSetting; @@ -1117,6 +1118,15 @@ public final class SettingsFragmentPresenter sl.add(new InputMappingControlSetting(group.getControl(j), controller)); } + if (group.getGroupType() == ControlGroup.TYPE_ATTACHMENTS) + { + NumericSetting attachmentSetting = group.getAttachmentSetting(); + sl.add(new SingleChoiceSetting(mContext, new InputMappingIntSetting(attachmentSetting), + R.string.wiimote_extensions, 0, R.array.wiimoteExtensionsEntries, + R.array.wiimoteExtensionsValues, + MenuTag.getWiimoteExtensionMenuTag(mControllerNumber))); + } + int numericSettingCount = group.getNumericSettingCount(); for (int j = 0; j < numericSettingCount; j++) { -- cgit v1.2.3 From e7530a1cb91d9b49257fbfb75cb000757b212489 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Mon, 18 Apr 2022 17:57:29 +0200 Subject: Android: Split Wii Remote settings into submenus Too much stuff on one screen otherwise. This split matches DolphinQt. --- .../dolphinemu/features/settings/ui/MenuTag.java | 29 ++++++++- .../features/settings/ui/SettingsFragment.java | 12 ++++ .../settings/ui/SettingsFragmentPresenter.java | 74 ++++++++++++++++++++-- 3 files changed, 109 insertions(+), 6 deletions(-) (limited to 'Source/Android/app/src/main/java') 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 1d4fe28af9..f97a013074 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 @@ -38,7 +38,19 @@ public enum MenuTag WIIMOTE_EXTENSION_1("wiimote_extension", 0), WIIMOTE_EXTENSION_2("wiimote_extension", 1), WIIMOTE_EXTENSION_3("wiimote_extension", 2), - WIIMOTE_EXTENSION_4("wiimote_extension", 3); + WIIMOTE_EXTENSION_4("wiimote_extension", 3), + WIIMOTE_GENERAL_1("wiimote_general", 0), + WIIMOTE_GENERAL_2("wiimote_general", 1), + WIIMOTE_GENERAL_3("wiimote_general", 2), + WIIMOTE_GENERAL_4("wiimote_general", 3), + WIIMOTE_MOTION_SIMULATION_1("wiimote_motion_simulation", 0), + WIIMOTE_MOTION_SIMULATION_2("wiimote_motion_simulation", 1), + WIIMOTE_MOTION_SIMULATION_3("wiimote_motion_simulation", 2), + WIIMOTE_MOTION_SIMULATION_4("wiimote_motion_simulation", 3), + WIIMOTE_MOTION_INPUT_1("wiimote_motion_input", 0), + WIIMOTE_MOTION_INPUT_2("wiimote_motion_input", 1), + WIIMOTE_MOTION_INPUT_3("wiimote_motion_input", 2), + WIIMOTE_MOTION_INPUT_4("wiimote_motion_input", 3); private String tag; private int subType = -1; @@ -112,6 +124,21 @@ public enum MenuTag return getMenuTag("wiimote_extension", subtype); } + public static MenuTag getWiimoteGeneralMenuTag(int subtype) + { + return getMenuTag("wiimote_general", subtype); + } + + public static MenuTag getWiimoteMotionSimulationMenuTag(int subtype) + { + return getMenuTag("wiimote_motion_simulation", subtype); + } + + public static MenuTag getWiimoteMotionInputMenuTag(int subtype) + { + return getMenuTag("wiimote_motion_input", subtype); + } + private static MenuTag getMenuTag(String tag, int subtype) { for (MenuTag menuTag : MenuTag.values()) 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 bb73093656..11ed282cf4 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 @@ -75,6 +75,18 @@ public final class SettingsFragment extends Fragment implements SettingsFragment 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); + titles.put(MenuTag.WIIMOTE_GENERAL_1, R.string.wiimote_general); + titles.put(MenuTag.WIIMOTE_GENERAL_2, R.string.wiimote_general); + titles.put(MenuTag.WIIMOTE_GENERAL_3, R.string.wiimote_general); + titles.put(MenuTag.WIIMOTE_GENERAL_4, R.string.wiimote_general); + titles.put(MenuTag.WIIMOTE_MOTION_SIMULATION_1, R.string.wiimote_motion_simulation); + titles.put(MenuTag.WIIMOTE_MOTION_SIMULATION_2, R.string.wiimote_motion_simulation); + titles.put(MenuTag.WIIMOTE_MOTION_SIMULATION_3, R.string.wiimote_motion_simulation); + titles.put(MenuTag.WIIMOTE_MOTION_SIMULATION_4, R.string.wiimote_motion_simulation); + titles.put(MenuTag.WIIMOTE_MOTION_INPUT_1, R.string.wiimote_motion_input); + titles.put(MenuTag.WIIMOTE_MOTION_INPUT_2, R.string.wiimote_motion_input); + titles.put(MenuTag.WIIMOTE_MOTION_INPUT_3, R.string.wiimote_motion_input); + titles.put(MenuTag.WIIMOTE_MOTION_INPUT_4, R.string.wiimote_motion_input); } 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 fded8e56de..3f60937810 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 @@ -10,6 +10,7 @@ import android.text.TextUtils; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; +import androidx.collection.ArraySet; import org.dolphinemu.dolphinemu.NativeLibrary; import org.dolphinemu.dolphinemu.R; @@ -56,8 +57,11 @@ import org.dolphinemu.dolphinemu.utils.ThreadUtil; import org.dolphinemu.dolphinemu.utils.WiiUtils; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Set; public final class SettingsFragmentPresenter { @@ -248,6 +252,27 @@ public final class SettingsFragmentPresenter addExtensionTypeSettings(sl, mControllerNumber, mControllerType); break; + case WIIMOTE_GENERAL_1: + case WIIMOTE_GENERAL_2: + case WIIMOTE_GENERAL_3: + case WIIMOTE_GENERAL_4: + addWiimoteGeneralSubSettings(sl, mControllerNumber); + break; + + case WIIMOTE_MOTION_SIMULATION_1: + case WIIMOTE_MOTION_SIMULATION_2: + case WIIMOTE_MOTION_SIMULATION_3: + case WIIMOTE_MOTION_SIMULATION_4: + addWiimoteMotionSimulationSubSettings(sl, mControllerNumber); + break; + + case WIIMOTE_MOTION_INPUT_1: + case WIIMOTE_MOTION_INPUT_2: + case WIIMOTE_MOTION_INPUT_3: + case WIIMOTE_MOTION_INPUT_4: + addWiimoteMotionInputSubSettings(sl, mControllerNumber); + break; + default: throw new UnsupportedOperationException("Unimplemented menu"); } @@ -1081,7 +1106,7 @@ public final class SettingsFragmentPresenter { if (gcPadType == 6) // Emulated { - addControllerSettings(sl, EmulatedController.getGcPad(gcPadNumber)); + addControllerSettings(sl, EmulatedController.getGcPad(gcPadNumber), null); } else if (gcPadType == 12) // Adapter { @@ -1094,22 +1119,61 @@ public final class SettingsFragmentPresenter private void addWiimoteSubSettings(ArrayList sl, int wiimoteNumber) { - addControllerSettings(sl, EmulatedController.getWiimote(wiimoteNumber)); + sl.add(new HeaderSetting(mContext, R.string.wiimote, 0)); + sl.add(new SubmenuSetting(mContext, R.string.wiimote_general, + MenuTag.getWiimoteGeneralMenuTag(wiimoteNumber))); + sl.add(new SubmenuSetting(mContext, R.string.wiimote_motion_simulation, + MenuTag.getWiimoteMotionSimulationMenuTag(wiimoteNumber))); + sl.add(new SubmenuSetting(mContext, R.string.wiimote_motion_input, + MenuTag.getWiimoteMotionInputMenuTag(wiimoteNumber))); + + addControllerSettings(sl, EmulatedController.getWiimote(wiimoteNumber), + Collections.singleton(ControlGroup.TYPE_ATTACHMENTS)); } private void addExtensionTypeSettings(ArrayList sl, int wiimoteNumber, int extensionType) { addControllerSettings(sl, - EmulatedController.getWiimoteAttachment(wiimoteNumber, extensionType)); + EmulatedController.getWiimoteAttachment(wiimoteNumber, extensionType), null); + } + + private void addWiimoteGeneralSubSettings(ArrayList sl, int wiimoteNumber) + { + addControllerSettings(sl, EmulatedController.getWiimote(wiimoteNumber), + new ArraySet<>(Arrays.asList(ControlGroup.TYPE_BUTTONS, ControlGroup.TYPE_OTHER))); + } + + private void addWiimoteMotionSimulationSubSettings(ArrayList sl, int wiimoteNumber) + { + addControllerSettings(sl, EmulatedController.getWiimote(wiimoteNumber), + new ArraySet<>(Arrays.asList(ControlGroup.TYPE_FORCE, ControlGroup.TYPE_TILT, + ControlGroup.TYPE_CURSOR, ControlGroup.TYPE_SHAKE))); } - private void addControllerSettings(ArrayList sl, EmulatedController controller) + private void addWiimoteMotionInputSubSettings(ArrayList sl, int wiimoteNumber) + { + addControllerSettings(sl, EmulatedController.getWiimote(wiimoteNumber), + new ArraySet<>(Arrays.asList(ControlGroup.TYPE_IMU_ACCELEROMETER, + ControlGroup.TYPE_IMU_GYROSCOPE, ControlGroup.TYPE_IMU_CURSOR))); + } + + /** + * @param sl The list to place controller settings into. + * @param controller The controller to add settings for. + * @param groupTypeFilter If this is non-null, only groups whose types match this are considered. + */ + private void addControllerSettings(ArrayList sl, EmulatedController controller, + Set groupTypeFilter) { int groupCount = controller.getGroupCount(); for (int i = 0; i < groupCount; i++) { ControlGroup group = controller.getGroup(i); + int groupType = group.getGroupType(); + if (groupTypeFilter != null && !groupTypeFilter.contains(groupType)) + continue; + sl.add(new HeaderSetting(group.getUiName(), "")); int controlCount = group.getControlCount(); @@ -1118,7 +1182,7 @@ public final class SettingsFragmentPresenter sl.add(new InputMappingControlSetting(group.getControl(j), controller)); } - if (group.getGroupType() == ControlGroup.TYPE_ATTACHMENTS) + if (groupType == ControlGroup.TYPE_ATTACHMENTS) { NumericSetting attachmentSetting = group.getAttachmentSetting(); sl.add(new SingleChoiceSetting(mContext, new InputMappingIntSetting(attachmentSetting), -- cgit v1.2.3 From a78dca5fb08d7c0f18d3d43d5b3b485549a5a8ce Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 17 Sep 2022 14:16:45 +0200 Subject: Android: Move Sideways Wii Remote setting one submenu up A slight departure from DolphinQt, but I think it makes sense, because it will make the important Sideways Wii Remote setting easier to find. --- .../dolphinemu/features/settings/ui/SettingsFragmentPresenter.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'Source/Android/app/src/main/java') 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 3f60937810..f731a3426f 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 @@ -1127,8 +1127,10 @@ public final class SettingsFragmentPresenter sl.add(new SubmenuSetting(mContext, R.string.wiimote_motion_input, MenuTag.getWiimoteMotionInputMenuTag(wiimoteNumber))); + // TYPE_OTHER is included here instead of in addWiimoteGeneralSubSettings so that touchscreen + // users won't have to dig into a submenu to find the Sideways Wii Remote setting addControllerSettings(sl, EmulatedController.getWiimote(wiimoteNumber), - Collections.singleton(ControlGroup.TYPE_ATTACHMENTS)); + new ArraySet<>(Arrays.asList(ControlGroup.TYPE_ATTACHMENTS, ControlGroup.TYPE_OTHER))); } private void addExtensionTypeSettings(ArrayList sl, int wiimoteNumber, @@ -1141,7 +1143,7 @@ public final class SettingsFragmentPresenter private void addWiimoteGeneralSubSettings(ArrayList sl, int wiimoteNumber) { addControllerSettings(sl, EmulatedController.getWiimote(wiimoteNumber), - new ArraySet<>(Arrays.asList(ControlGroup.TYPE_BUTTONS, ControlGroup.TYPE_OTHER))); + Collections.singleton(ControlGroup.TYPE_BUTTONS)); } private void addWiimoteMotionSimulationSubSettings(ArrayList sl, int wiimoteNumber) -- cgit v1.2.3 From 2113bf5e3afface4acd072f677c620c60bd6edde Mon Sep 17 00:00:00 2001 From: JosJuice Date: Mon, 18 Apr 2022 18:54:58 +0200 Subject: Android: Implement enabling/disabling control groups All this code for just a single checkbox... Ah well, it has to be done --- .../input/model/ControlGroupEnabledSetting.java | 50 ++++++++++++++++++++++ .../input/model/controlleremu/ControlGroup.java | 10 +++++ .../settings/ui/SettingsFragmentPresenter.java | 7 +++ 3 files changed, 67 insertions(+) create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControlGroupEnabledSetting.java (limited to 'Source/Android/app/src/main/java') diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControlGroupEnabledSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControlGroupEnabledSetting.java new file mode 100644 index 0000000000..95aa080429 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControlGroupEnabledSetting.java @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.features.input.model; + +import org.dolphinemu.dolphinemu.features.input.model.controlleremu.ControlGroup; +import org.dolphinemu.dolphinemu.features.settings.model.AbstractBooleanSetting; +import org.dolphinemu.dolphinemu.features.settings.model.Settings; + +public class ControlGroupEnabledSetting implements AbstractBooleanSetting +{ + private final ControlGroup mControlGroup; + + public ControlGroupEnabledSetting(ControlGroup controlGroup) + { + mControlGroup = controlGroup; + } + + @Override + public boolean getBoolean(Settings settings) + { + return mControlGroup.getEnabled(); + } + + @Override + public void setBoolean(Settings settings, boolean newValue) + { + mControlGroup.setEnabled(newValue); + } + + @Override + public boolean isOverridden(Settings settings) + { + return false; + } + + @Override + public boolean isRuntimeEditable() + { + return true; + } + + @Override + public boolean delete(Settings settings) + { + boolean newValue = mControlGroup.getDefaultEnabledValue() != ControlGroup.DEFAULT_ENABLED_NO; + mControlGroup.setEnabled(newValue); + + return true; + } +} 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 index 0a7681af6d..1bafd4a1f2 100644 --- 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 @@ -27,6 +27,10 @@ public class ControlGroup public static final int TYPE_IMU_GYROSCOPE = 12; public static final int TYPE_IMU_CURSOR = 13; + public static final int DEFAULT_ENABLED_ALWAYS = 0; + public static final int DEFAULT_ENABLED_YES = 1; + public static final int DEFAULT_ENABLED_NO = 2; + @Keep private final long mPointer; @@ -40,6 +44,12 @@ public class ControlGroup public native int getGroupType(); + public native int getDefaultEnabledValue(); + + public native boolean getEnabled(); + + public native void setEnabled(boolean value); + public native int getControlCount(); public native Control getControl(int i); 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 f731a3426f..8ace1df30b 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 @@ -19,6 +19,7 @@ import org.dolphinemu.dolphinemu.features.input.model.InputMappingBooleanSetting import org.dolphinemu.dolphinemu.features.input.model.InputMappingDoubleSetting; import org.dolphinemu.dolphinemu.features.input.model.InputMappingIntSetting; import org.dolphinemu.dolphinemu.features.input.model.controlleremu.ControlGroup; +import org.dolphinemu.dolphinemu.features.input.model.ControlGroupEnabledSetting; import org.dolphinemu.dolphinemu.features.input.model.controlleremu.EmulatedController; import org.dolphinemu.dolphinemu.features.input.model.controlleremu.NumericSetting; import org.dolphinemu.dolphinemu.features.input.model.view.InputMappingControlSetting; @@ -1178,6 +1179,12 @@ public final class SettingsFragmentPresenter sl.add(new HeaderSetting(group.getUiName(), "")); + if (group.getDefaultEnabledValue() != ControlGroup.DEFAULT_ENABLED_ALWAYS) + { + sl.add(new SwitchSetting(mContext, new ControlGroupEnabledSetting(group), R.string.enabled, + 0)); + } + int controlCount = group.getControlCount(); for (int j = 0; j < controlCount; j++) { -- cgit v1.2.3 From 2b1dd52750c8c85796be4a6785fb769481ec191c Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 14 Aug 2022 11:32:22 +0200 Subject: Android: Add input device selection --- .../features/input/model/ControllerInterface.java | 2 + .../features/input/model/MappingCommon.java | 9 ++- .../model/controlleremu/EmulatedController.java | 4 ++ .../input/model/view/InputDeviceSetting.java | 64 ++++++++++++++++++++++ .../model/view/InputMappingControlSetting.java | 5 ++ .../features/input/ui/MotionAlertDialog.java | 2 +- .../features/settings/model/view/SettingsItem.java | 5 ++ .../model/view/StringSingleChoiceSetting.java | 26 ++++++++- .../features/settings/ui/SettingsAdapter.java | 2 + .../settings/ui/SettingsFragmentPresenter.java | 40 +++++++++++--- .../settings/ui/viewholder/SettingViewHolder.java | 2 +- .../ui/viewholder/SingleChoiceViewHolder.java | 6 +- 12 files changed, 149 insertions(+), 18 deletions(-) create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/view/InputDeviceSetting.java (limited to 'Source/Android/app/src/main/java') diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java index 0d6a078b4e..b2535465e8 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java @@ -95,6 +95,8 @@ public final class ControllerInterface */ public static native void refreshDevices(); + public static native String[] getAllDeviceStrings(); + @Keep private static void registerInputDeviceListener() { 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 index cb136a908d..b0dc489fec 100644 --- 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 @@ -2,6 +2,10 @@ package org.dolphinemu.dolphinemu.features.input.model; +import androidx.annotation.NonNull; + +import org.dolphinemu.dolphinemu.features.input.model.controlleremu.EmulatedController; + public final class MappingCommon { private MappingCommon() @@ -15,10 +19,13 @@ public final class MappingCommon * When this is being called, a separate thread must be calling ControllerInterface's * dispatchKeyEvent and dispatchGenericMotionEvent, otherwise no inputs will be registered. * + * @param controller The device to detect inputs from. + * @param allDevices Whether to also detect inputs from devices other than the specified one. * @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 String detectInput(@NonNull EmulatedController controller, + boolean allDevices); public static native void save(); } 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 index b0fbd0fd92..5a5793f530 100644 --- 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 @@ -21,6 +21,10 @@ public class EmulatedController mPointer = pointer; } + public native String getDefaultDevice(); + + public native void setDefaultDevice(String device); + public native int getGroupCount(); public native ControlGroup getGroup(int index); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/view/InputDeviceSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/view/InputDeviceSetting.java new file mode 100644 index 0000000000..2462e867d3 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/view/InputDeviceSetting.java @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.features.input.model.view; + +import android.content.Context; + +import org.dolphinemu.dolphinemu.features.input.model.ControllerInterface; +import org.dolphinemu.dolphinemu.features.input.model.controlleremu.EmulatedController; +import org.dolphinemu.dolphinemu.features.settings.model.Settings; +import org.dolphinemu.dolphinemu.features.settings.model.view.StringSingleChoiceSetting; + +public class InputDeviceSetting extends StringSingleChoiceSetting +{ + private final EmulatedController mController; + + public InputDeviceSetting(Context context, int titleId, int descriptionId, + EmulatedController controller) + { + super(context, null, titleId, descriptionId, null, null, null); + + mController = controller; + + refreshChoicesAndValues(); + } + + @Override + public String getSelectedChoice(Settings settings) + { + return mController.getDefaultDevice(); + } + + @Override + public String getSelectedValue(Settings settings) + { + return mController.getDefaultDevice(); + } + + @Override + public void setSelectedValue(Settings settings, String newValue) + { + mController.setDefaultDevice(newValue); + } + + @Override + public void refreshChoicesAndValues() + { + String[] devices = ControllerInterface.getAllDeviceStrings(); + + mChoices = devices; + mValues = devices; + } + + @Override + public boolean canClear() + { + return true; + } + + @Override + public void clear(Settings settings) + { + setSelectedValue(settings, ""); + } +} 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 index 8888e2430b..a858b35099 100644 --- 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 @@ -47,4 +47,9 @@ public final class InputMappingControlSetting extends SettingsItem { return null; } + + public EmulatedController getController() + { + return mController; + } } 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 index f36d9bc478..0a4afc7acf 100644 --- 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 @@ -46,7 +46,7 @@ public final class MotionAlertDialog extends AlertDialog mRunning = true; new Thread(() -> { - String result = MappingCommon.detectInput(); + String result = MappingCommon.detectInput(mSetting.getController(), false); mActivity.runOnUiThread(() -> { if (mRunning) 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 9c7b89c12f..6f06677be3 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 @@ -95,6 +95,11 @@ public abstract class SettingsItem return getSetting() != null; } + public boolean canClear() + { + return hasSetting(); + } + public void clear(Settings settings) { getSetting().delete(settings); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/StringSingleChoiceSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/StringSingleChoiceSetting.java index df7ee6f4e9..70463f216b 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/StringSingleChoiceSetting.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/StringSingleChoiceSetting.java @@ -14,8 +14,8 @@ public class StringSingleChoiceSetting extends SettingsItem { private AbstractStringSetting mSetting; - private String[] mChoices; - private String[] mValues; + protected String[] mChoices; + protected String[] mValues; private MenuTag mMenuTag; public StringSingleChoiceSetting(Context context, AbstractStringSetting setting, int titleId, @@ -60,6 +60,19 @@ public class StringSingleChoiceSetting extends SettingsItem return mValues; } + public String getChoiceAt(int index) + { + if (mChoices == null) + return null; + + if (index >= 0 && index < mChoices.length) + { + return mChoices[index]; + } + + return ""; + } + public String getValueAt(int index) { if (mValues == null) @@ -73,6 +86,11 @@ public class StringSingleChoiceSetting extends SettingsItem return ""; } + public String getSelectedChoice(Settings settings) + { + return getChoiceAt(getSelectedValueIndex(settings)); + } + public String getSelectedValue(Settings settings) { return mSetting.getString(settings); @@ -102,6 +120,10 @@ public class StringSingleChoiceSetting extends SettingsItem mSetting.setString(settings, selection); } + public void refreshChoicesAndValues() + { + } + @Override public int getType() { 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 8fe3fe4602..cd2d047ecb 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 @@ -253,6 +253,8 @@ public final class SettingsAdapter extends RecyclerView.Adapter sl, int wiimoteNumber) { + EmulatedController wiimote = EmulatedController.getWiimote(wiimoteNumber); + + addControllerMetaSettings(sl, wiimote); + sl.add(new HeaderSetting(mContext, R.string.wiimote, 0)); sl.add(new SubmenuSetting(mContext, R.string.wiimote_general, MenuTag.getWiimoteGeneralMenuTag(wiimoteNumber))); @@ -1130,44 +1138,58 @@ public final class SettingsFragmentPresenter // TYPE_OTHER is included here instead of in addWiimoteGeneralSubSettings so that touchscreen // users won't have to dig into a submenu to find the Sideways Wii Remote setting - addControllerSettings(sl, EmulatedController.getWiimote(wiimoteNumber), + addControllerMappingSettings(sl, wiimote, new ArraySet<>(Arrays.asList(ControlGroup.TYPE_ATTACHMENTS, ControlGroup.TYPE_OTHER))); } private void addExtensionTypeSettings(ArrayList sl, int wiimoteNumber, int extensionType) { - addControllerSettings(sl, + addControllerMappingSettings(sl, EmulatedController.getWiimoteAttachment(wiimoteNumber, extensionType), null); } private void addWiimoteGeneralSubSettings(ArrayList sl, int wiimoteNumber) { - addControllerSettings(sl, EmulatedController.getWiimote(wiimoteNumber), + addControllerMappingSettings(sl, EmulatedController.getWiimote(wiimoteNumber), Collections.singleton(ControlGroup.TYPE_BUTTONS)); } private void addWiimoteMotionSimulationSubSettings(ArrayList sl, int wiimoteNumber) { - addControllerSettings(sl, EmulatedController.getWiimote(wiimoteNumber), + addControllerMappingSettings(sl, EmulatedController.getWiimote(wiimoteNumber), new ArraySet<>(Arrays.asList(ControlGroup.TYPE_FORCE, ControlGroup.TYPE_TILT, ControlGroup.TYPE_CURSOR, ControlGroup.TYPE_SHAKE))); } private void addWiimoteMotionInputSubSettings(ArrayList sl, int wiimoteNumber) { - addControllerSettings(sl, EmulatedController.getWiimote(wiimoteNumber), + addControllerMappingSettings(sl, EmulatedController.getWiimote(wiimoteNumber), new ArraySet<>(Arrays.asList(ControlGroup.TYPE_IMU_ACCELEROMETER, ControlGroup.TYPE_IMU_GYROSCOPE, ControlGroup.TYPE_IMU_CURSOR))); } /** - * @param sl The list to place controller settings into. + * Adds settings and actions that apply to a controller as a whole. + * For instance, the device setting and the Clear action. + * + * @param sl The list to place controller settings into. * @param controller The controller to add settings for. + */ + private void addControllerMetaSettings(ArrayList sl, EmulatedController controller) + { + sl.add(new InputDeviceSetting(mContext, R.string.input_device, 0, controller)); + } + + /** + * Adds mapping settings and other control-specific settings. + * + * @param sl The list to place controller settings into. + * @param controller The controller to add settings for. * @param groupTypeFilter If this is non-null, only groups whose types match this are considered. */ - private void addControllerSettings(ArrayList sl, EmulatedController controller, - Set groupTypeFilter) + private void addControllerMappingSettings(ArrayList sl, + EmulatedController controller, Set groupTypeFilter) { int groupCount = controller.getGroupCount(); for (int i = 0; i < groupCount; i++) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/SettingViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/SettingViewHolder.java index d34e4a1536..18fd466461 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/SettingViewHolder.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/SettingViewHolder.java @@ -83,7 +83,7 @@ public abstract class SettingViewHolder extends RecyclerView.ViewHolder { SettingsItem item = getItem(); - if (item == null || !item.hasSetting()) + if (item == null || !item.canClear()) return false; if (!item.isEditable()) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/SingleChoiceViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/SingleChoiceViewHolder.java index db56ebea40..beb15867c5 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/SingleChoiceViewHolder.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/SingleChoiceViewHolder.java @@ -64,10 +64,8 @@ public final class SingleChoiceViewHolder extends SettingViewHolder else if (item instanceof StringSingleChoiceSetting) { StringSingleChoiceSetting setting = (StringSingleChoiceSetting) item; - String[] choices = setting.getChoices(); - int valueIndex = setting.getSelectedValueIndex(settings); - if (valueIndex != -1) - mBinding.textSettingDescription.setText(choices[valueIndex]); + String choice = setting.getSelectedChoice(settings); + mBinding.textSettingDescription.setText(choice); } else if (item instanceof SingleChoiceSettingDynamicDescriptions) { -- cgit v1.2.3 From a1cc19f443fb9c39d1341f3aa1c80b1ecfe0ec4d Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 30 Oct 2022 17:20:10 +0100 Subject: Android: Add "Create mappings for other devices" --- .../features/input/ui/MotionAlertDialog.java | 12 +++++--- .../features/settings/ui/SettingsActivity.java | 25 ++++++++++++++-- .../features/settings/ui/SettingsActivityView.java | 12 ++++++++ .../features/settings/ui/SettingsAdapter.java | 3 +- .../features/settings/ui/SettingsFragment.java | 12 ++++++++ .../settings/ui/SettingsFragmentPresenter.java | 34 ++++++++++++++++++++++ .../features/settings/ui/SettingsFragmentView.java | 12 ++++++++ 7 files changed, 103 insertions(+), 7 deletions(-) (limited to 'Source/Android/app/src/main/java') 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 index 0a4afc7acf..9872bdd01e 100644 --- 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 @@ -22,20 +22,24 @@ public final class MotionAlertDialog extends AlertDialog { private final Activity mActivity; private final InputMappingControlSetting mSetting; + private final boolean mAllDevices; private boolean mRunning = false; /** * Constructor * - * @param activity The current {@link Activity}. - * @param setting The setting to show this dialog for. + * @param activity The current {@link Activity}. + * @param setting The setting to show this dialog for. + * @param allDevices Whether to detect inputs from devices other than the configured one. */ - public MotionAlertDialog(Activity activity, InputMappingControlSetting setting) + public MotionAlertDialog(Activity activity, InputMappingControlSetting setting, + boolean allDevices) { super(activity); mActivity = activity; mSetting = setting; + mAllDevices = allDevices; } @Override @@ -46,7 +50,7 @@ public final class MotionAlertDialog extends AlertDialog mRunning = true; new Thread(() -> { - String result = MappingCommon.detectInput(mSetting.getController(), false); + String result = MappingCommon.detectInput(mSetting.getController(), mAllDevices); mActivity.runOnUiThread(() -> { if (mRunning) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivity.java index 2af17e2d2f..f10a915bcc 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivity.java @@ -41,15 +41,17 @@ public final class SettingsActivity extends AppCompatActivity implements Setting private static final String ARG_GAME_ID = "game_id"; private static final String ARG_REVISION = "revision"; private static final String ARG_IS_WII = "is_wii"; + private static final String KEY_MAPPING_ALL_DEVICES = "all_devices"; private static final String FRAGMENT_TAG = "settings"; - private SettingsActivityPresenter mPresenter; + private SettingsActivityPresenter mPresenter; private AlertDialog dialog; - private CollapsingToolbarLayout mToolbarLayout; private ActivitySettingsBinding mBinding; + private boolean mMappingAllDevices = false; + public static void launch(Context context, MenuTag menuTag, String gameId, int revision, boolean isWii) { @@ -82,6 +84,10 @@ public final class SettingsActivity extends AppCompatActivity implements Setting { MainPresenter.skipRescanningLibrary(); } + else + { + mMappingAllDevices = savedInstanceState.getBoolean(KEY_MAPPING_ALL_DEVICES); + } mBinding = ActivitySettingsBinding.inflate(getLayoutInflater()); setContentView(mBinding.getRoot()); @@ -125,7 +131,10 @@ public final class SettingsActivity extends AppCompatActivity implements Setting { // Critical: If super method is not called, rotations will be busted. super.onSaveInstanceState(outState); + mPresenter.saveState(outState); + + outState.putBoolean(KEY_MAPPING_ALL_DEVICES, mMappingAllDevices); } @Override @@ -333,6 +342,18 @@ public final class SettingsActivity extends AppCompatActivity implements Setting mToolbarLayout.setTitle(title); } + @Override + public void setMappingAllDevices(boolean allDevices) + { + mMappingAllDevices = allDevices; + } + + @Override + public boolean isMappingAllDevices() + { + return mMappingAllDevices; + } + private void setInsets() { ViewCompat.setOnApplyWindowInsetsListener(mBinding.appbarSettings, (v, windowInsets) -> diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivityView.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivityView.java index c835aa4399..d71d729af8 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivityView.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivityView.java @@ -97,4 +97,16 @@ public interface SettingsActivityView * Accesses the material toolbar layout and changes the title */ void setToolbarTitle(String title); + + /** + * Sets whether the input mapping dialog should detect inputs from all devices, + * not just the device configured for the controller. + */ + void setMappingAllDevices(boolean allDevices); + + /** + * Returns whether the input mapping dialog should detect inputs from all devices, + * not just the device configured for the controller. + */ + boolean isMappingAllDevices(); } 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 cd2d047ecb..10ca9ddef2 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 @@ -312,7 +312,8 @@ public final class SettingsAdapter extends RecyclerView.Adapter 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 c0540cefed..e2199d2922 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 @@ -1179,6 +1179,40 @@ public final class SettingsFragmentPresenter private void addControllerMetaSettings(ArrayList sl, EmulatedController controller) { sl.add(new InputDeviceSetting(mContext, R.string.input_device, 0, controller)); + + sl.add(new SwitchSetting(mContext, new AbstractBooleanSetting() + { + @Override + public boolean isOverridden(Settings settings) + { + return false; + } + + @Override + public boolean isRuntimeEditable() + { + return true; + } + + @Override + public boolean delete(Settings settings) + { + mView.setMappingAllDevices(false); + return true; + } + + @Override + public boolean getBoolean(Settings settings) + { + return mView.isMappingAllDevices(); + } + + @Override + public void setBoolean(Settings settings, boolean newValue) + { + mView.setMappingAllDevices(newValue); + } + }, R.string.input_device_all_devices, R.string.input_device_all_devices_description)); } /** diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentView.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentView.java index 295ff95abd..280657158f 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentView.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentView.java @@ -89,4 +89,16 @@ public interface SettingsFragmentView * @param value The current value of the setting. */ boolean hasMenuTagActionForValue(@NonNull MenuTag menuTag, int value); + + /** + * Sets whether the input mapping dialog should detect inputs from all devices, + * not just the device configured for the controller. + */ + void setMappingAllDevices(boolean allDevices); + + /** + * Returns whether the input mapping dialog should detect inputs from all devices, + * not just the device configured for the controller. + */ + boolean isMappingAllDevices(); } -- cgit v1.2.3 From ea3200d4ba9378c4dbec647c75b994a0c7aefced Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 30 Oct 2022 19:06:04 +0100 Subject: Android: Prevent showing mapping dialog with no device selected --- .../dolphinemu/features/settings/ui/SettingsAdapter.java | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'Source/Android/app/src/main/java') 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 10ca9ddef2..2cf2883fda 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 @@ -312,6 +312,15 @@ public final class SettingsAdapter extends RecyclerView.Adapter Date: Sun, 14 Aug 2022 13:05:30 +0200 Subject: Android: Add Default and Clear actions for controllers --- .../input/model/controlleremu/EmulatedController.java | 4 ++++ .../settings/ui/SettingsFragmentPresenter.java | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+) (limited to 'Source/Android/app/src/main/java') 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 index 5a5793f530..5f6275ffcd 100644 --- 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 @@ -31,6 +31,10 @@ public class EmulatedController public native void updateSingleControlReference(ControlReference controlReference); + public native void loadDefaultSettings(); + + public native void clearSettings(); + public static native EmulatedController getGcPad(int controllerIndex); public static native EmulatedController getWiimote(int controllerIndex); 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 e2199d2922..8d9a34c252 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 @@ -1213,6 +1213,13 @@ public final class SettingsFragmentPresenter mView.setMappingAllDevices(newValue); } }, R.string.input_device_all_devices, R.string.input_device_all_devices_description)); + + sl.add(new RunRunnable(mContext, R.string.input_reset_to_default, + R.string.input_reset_to_default_description, R.string.input_reset_warning, 0, true, + () -> loadDefaultControllerSettings(controller))); + + sl.add(new RunRunnable(mContext, R.string.input_clear, R.string.input_clear_description, + R.string.input_reset_warning, 0, true, () -> clearControllerSettings(controller))); } /** @@ -1280,6 +1287,18 @@ public final class SettingsFragmentPresenter } } + private void loadDefaultControllerSettings(EmulatedController controller) + { + controller.loadDefaultSettings(); + mView.getAdapter().notifyAllSettingsChanged(); + } + + private void clearControllerSettings(EmulatedController controller) + { + controller.clearSettings(); + mView.getAdapter().notifyAllSettingsChanged(); + } + private static int getLogVerbosityEntries() { // Value obtained from LogLevel in Common/Logging/Log.h -- cgit v1.2.3 From 7ef229d9082f72795e71db58ed13824bdd3d3e2c Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 14 Aug 2022 21:11:00 +0200 Subject: Android: Show warning when using old pre-defined controller INIs Co-authored-by: Charles Lombardo --- .../features/settings/ui/SettingsActivity.java | 15 ++++++++++++++- .../features/settings/ui/SettingsActivityView.java | 9 +++++++++ .../features/settings/ui/SettingsFragment.java | 16 ++++++++++++++-- .../settings/ui/SettingsFragmentPresenter.java | 18 ++++++++++++++++++ .../features/settings/ui/SettingsFragmentView.java | 8 ++++++++ 5 files changed, 63 insertions(+), 3 deletions(-) (limited to 'Source/Android/app/src/main/java') diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivity.java index f10a915bcc..d4ec285681 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivity.java @@ -9,6 +9,7 @@ import android.os.Bundle; import android.provider.Settings; import android.view.Menu; import android.view.MenuInflater; +import android.view.View; import android.widget.Toast; import androidx.annotation.NonNull; @@ -339,7 +340,7 @@ public final class SettingsActivity extends AppCompatActivity implements Setting public void setToolbarTitle(String title) { - mToolbarLayout.setTitle(title); + mBinding.toolbarSettingsLayout.setTitle(title); } @Override @@ -354,6 +355,14 @@ public final class SettingsActivity extends AppCompatActivity implements Setting return mMappingAllDevices; } + @Override + public int setOldControllerSettingsWarningVisibility(boolean visible) + { + // We use INVISIBLE instead of GONE to avoid getting a stale height for the return value + mBinding.oldControllerSettingsWarning.setVisibility(visible ? View.VISIBLE : View.INVISIBLE); + return visible ? mBinding.oldControllerSettingsWarning.getHeight() : 0; + } + private void setInsets() { ViewCompat.setOnApplyWindowInsetsListener(mBinding.appbarSettings, (v, windowInsets) -> @@ -364,6 +373,10 @@ public final class SettingsActivity extends AppCompatActivity implements Setting mBinding.frameContentSettings.setPadding(insets.left, 0, insets.right, 0); + int textPadding = getResources().getDimensionPixelSize(R.dimen.spacing_large); + mBinding.oldControllerSettingsWarning.setPadding(textPadding + insets.left, textPadding, + textPadding + insets.right, textPadding + insets.bottom); + InsetsHelper.applyNavbarWorkaround(insets.bottom, mBinding.workaroundView); ThemeHelper.setNavigationBarColor(this, MaterialColors.getColor(mBinding.appbarSettings, R.attr.colorSurface)); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivityView.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivityView.java index d71d729af8..203b14ca4b 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivityView.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivityView.java @@ -109,4 +109,13 @@ public interface SettingsActivityView * not just the device configured for the controller. */ boolean isMappingAllDevices(); + + /** + * Shows or hides a warning telling the user that they're using incompatible controller settings. + * The warning is hidden by default. + * + * @param visible Whether the warning should be visible. + * @return The height of the warning view, or 0 if the view is now invisible. + */ + int setOldControllerSettingsWarningVisibility(boolean visible); } 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 7a3f7b6db8..fcc27c4e5d 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 @@ -38,6 +38,8 @@ public final class SettingsFragment extends Fragment implements SettingsFragment private SettingsAdapter mAdapter; + private int mOldControllerSettingsWarningHeight = 0; + private static final Map titles = new HashMap<>(); static @@ -260,13 +262,23 @@ public final class SettingsFragment extends Fragment implements SettingsFragment return mActivity.isMappingAllDevices(); } + @Override + public void setOldControllerSettingsWarningVisibility(boolean visible) + { + mOldControllerSettingsWarningHeight = + mActivity.setOldControllerSettingsWarningVisibility(visible); + + // Trigger the insets listener we've registered + mBinding.listSettings.requestApplyInsets(); + } + private void setInsets() { ViewCompat.setOnApplyWindowInsetsListener(mBinding.listSettings, (v, windowInsets) -> { Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()); - v.setPadding(0, 0, 0, - insets.bottom + getResources().getDimensionPixelSize(R.dimen.spacing_list)); + int listSpacing = getResources().getDimensionPixelSize(R.dimen.spacing_list); + v.setPadding(0, 0, 0, insets.bottom + listSpacing + mOldControllerSettingsWarningHeight); return windowInsets; }); } 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 8d9a34c252..6cce1361ec 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 @@ -80,6 +80,7 @@ public final class SettingsFragmentPresenter private Settings mSettings; private ArrayList mSettingsList; + private boolean mHasOldControllerSettings = false; private int mSerialPort1Type; private int mControllerNumber; @@ -144,6 +145,7 @@ public final class SettingsFragmentPresenter else { mView.showSettingsList(mSettingsList); + mView.setOldControllerSettingsWarningVisibility(mHasOldControllerSettings); } } @@ -1220,6 +1222,8 @@ public final class SettingsFragmentPresenter sl.add(new RunRunnable(mContext, R.string.input_clear, R.string.input_clear_description, R.string.input_reset_warning, 0, true, () -> clearControllerSettings(controller))); + + updateOldControllerSettingsWarningVisibility(controller); } /** @@ -1232,6 +1236,8 @@ public final class SettingsFragmentPresenter private void addControllerMappingSettings(ArrayList sl, EmulatedController controller, Set groupTypeFilter) { + updateOldControllerSettingsWarningVisibility(controller); + int groupCount = controller.getGroupCount(); for (int i = 0; i < groupCount; i++) { @@ -1287,16 +1293,28 @@ public final class SettingsFragmentPresenter } } + private void updateOldControllerSettingsWarningVisibility(EmulatedController controller) + { + String defaultDevice = controller.getDefaultDevice(); + + mHasOldControllerSettings = defaultDevice.startsWith("Android/") && + defaultDevice.endsWith("/Touchscreen"); + + mView.setOldControllerSettingsWarningVisibility(mHasOldControllerSettings); + } + private void loadDefaultControllerSettings(EmulatedController controller) { controller.loadDefaultSettings(); mView.getAdapter().notifyAllSettingsChanged(); + updateOldControllerSettingsWarningVisibility(controller); } private void clearControllerSettings(EmulatedController controller) { controller.clearSettings(); mView.getAdapter().notifyAllSettingsChanged(); + updateOldControllerSettingsWarningVisibility(controller); } private static int getLogVerbosityEntries() diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentView.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentView.java index 280657158f..53a3010962 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentView.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentView.java @@ -101,4 +101,12 @@ public interface SettingsFragmentView * not just the device configured for the controller. */ boolean isMappingAllDevices(); + + /** + * Shows or hides a warning telling the user that they're using incompatible controller settings. + * The warning is hidden by default. + * + * @param visible Whether the warning should be visible. + */ + void setOldControllerSettingsWarningVisibility(boolean visible); } -- cgit v1.2.3 From 1eeded23df829973065d51c2595bf743910bc07e Mon Sep 17 00:00:00 2001 From: JosJuice Date: Mon, 26 Dec 2022 19:26:58 +0100 Subject: Android: Add input profile management Co-authored-by: Charles Lombardo --- .../model/controlleremu/EmulatedController.java | 4 + .../features/input/ui/ProfileAdapter.java | 65 +++++++++ .../dolphinemu/features/input/ui/ProfileDialog.kt | 76 +++++++++++ .../features/input/ui/ProfileDialogPresenter.java | 150 +++++++++++++++++++++ .../features/input/ui/ProfileViewHolder.java | 76 +++++++++++ .../dolphinemu/features/settings/ui/MenuTag.java | 15 ++- .../features/settings/ui/SettingsActivity.java | 14 ++ .../features/settings/ui/SettingsActivityView.java | 16 +++ .../features/settings/ui/SettingsFragment.java | 14 ++ .../settings/ui/SettingsFragmentPresenter.java | 15 ++- .../features/settings/ui/SettingsFragmentView.java | 11 ++ .../dolphinemu/utils/DirectoryInitialization.java | 14 +- 12 files changed, 464 insertions(+), 6 deletions(-) create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileAdapter.java create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileDialog.kt create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileDialogPresenter.java create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileViewHolder.java (limited to 'Source/Android/app/src/main/java') 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 index 5f6275ffcd..47d4dc5c96 100644 --- 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 @@ -35,6 +35,10 @@ public class EmulatedController public native void clearSettings(); + public native void loadProfile(String path); + + public native void saveProfile(String path); + public static native EmulatedController getGcPad(int controllerIndex); public static native EmulatedController getWiimote(int controllerIndex); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileAdapter.java new file mode 100644 index 0000000000..9908d6f5fd --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileAdapter.java @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.features.input.ui; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import org.dolphinemu.dolphinemu.databinding.ListItemProfileBinding; + +public final class ProfileAdapter extends RecyclerView.Adapter +{ + private final Context mContext; + private final ProfileDialogPresenter mPresenter; + + private final String[] mStockProfileNames; + private final String[] mUserProfileNames; + + public ProfileAdapter(Context context, ProfileDialogPresenter presenter) + { + mContext = context; + mPresenter = presenter; + + mStockProfileNames = presenter.getProfileNames(true); + mUserProfileNames = presenter.getProfileNames(false); + } + + @NonNull @Override + public ProfileViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) + { + LayoutInflater inflater = LayoutInflater.from(parent.getContext()); + + ListItemProfileBinding binding = ListItemProfileBinding.inflate(inflater, parent, false); + return new ProfileViewHolder(mPresenter, binding); + } + + @Override + public void onBindViewHolder(@NonNull ProfileViewHolder holder, int position) + { + if (position < mStockProfileNames.length) + { + holder.bind(mStockProfileNames[position], true); + return; + } + + position -= mStockProfileNames.length; + + if (position < mUserProfileNames.length) + { + holder.bind(mUserProfileNames[position], false); + return; + } + + holder.bindAsEmpty(mContext); + } + + @Override + public int getItemCount() + { + return mStockProfileNames.length + mUserProfileNames.length + 1; + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileDialog.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileDialog.kt new file mode 100644 index 0000000000..2779ee7473 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileDialog.kt @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.features.input.ui + +import android.os.Build +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.LinearLayoutManager +import com.google.android.material.bottomsheet.BottomSheetBehavior +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import com.google.android.material.divider.MaterialDividerItemDecoration +import org.dolphinemu.dolphinemu.R +import org.dolphinemu.dolphinemu.databinding.DialogInputProfilesBinding +import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag + +class ProfileDialog : BottomSheetDialogFragment() { + private var presenter: ProfileDialogPresenter? = null + + private var _binding: DialogInputProfilesBinding? = null + private val binding get() = _binding!! + + override fun onCreate(savedInstanceState: Bundle?) { + val menuTag: MenuTag = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + requireArguments().getSerializable(KEY_MENU_TAG, MenuTag::class.java) as MenuTag + } else { + requireArguments().getSerializable(KEY_MENU_TAG) as MenuTag + } + + presenter = ProfileDialogPresenter(this, menuTag) + + super.onCreate(savedInstanceState) + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = DialogInputProfilesBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + binding.profileList.adapter = ProfileAdapter(context, presenter) + binding.profileList.layoutManager = LinearLayoutManager(context) + val divider = MaterialDividerItemDecoration(requireActivity(), LinearLayoutManager.VERTICAL) + divider.isLastItemDecorated = false + binding.profileList.addItemDecoration(divider) + + // You can't expand a bottom sheet with a controller/remote/other non-touch devices + val behavior: BottomSheetBehavior = BottomSheetBehavior.from(view.parent as View) + if (!resources.getBoolean(R.bool.hasTouch)) { + behavior.state = BottomSheetBehavior.STATE_EXPANDED + } + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + + companion object { + private const val KEY_MENU_TAG = "menu_tag" + + @JvmStatic + fun create(menuTag: MenuTag): ProfileDialog { + val dialog = ProfileDialog() + val args = Bundle() + args.putSerializable(KEY_MENU_TAG, menuTag) + dialog.arguments = args + return dialog + } + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileDialogPresenter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileDialogPresenter.java new file mode 100644 index 0000000000..ae35aec46d --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileDialogPresenter.java @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.features.input.ui; + +import android.content.Context; +import android.view.LayoutInflater; + +import androidx.annotation.NonNull; +import androidx.fragment.app.DialogFragment; + +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.google.android.material.textfield.TextInputEditText; + +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.databinding.DialogInputStringBinding; +import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag; +import org.dolphinemu.dolphinemu.features.settings.ui.SettingsActivityView; +import org.dolphinemu.dolphinemu.utils.DirectoryInitialization; + +import java.io.File; +import java.text.Collator; +import java.util.Arrays; + +public final class ProfileDialogPresenter +{ + private static final String EXTENSION = ".ini"; + + private final Context mContext; + private final DialogFragment mDialog; + private final MenuTag mMenuTag; + + public ProfileDialogPresenter(DialogFragment dialog, MenuTag menuTag) + { + mContext = dialog.getContext(); + mDialog = dialog; + mMenuTag = menuTag; + } + + public String[] getProfileNames(boolean stock) + { + File[] profiles = new File(getProfileDirectoryPath(stock)).listFiles( + file -> !file.isDirectory() && file.getName().endsWith(EXTENSION)); + + if (profiles == null) + return new String[0]; + + return Arrays.stream(profiles) + .map(file -> file.getName().substring(0, file.getName().length() - EXTENSION.length())) + .sorted(Collator.getInstance()) + .toArray(String[]::new); + } + + public void loadProfile(@NonNull String profileName, boolean stock) + { + new MaterialAlertDialogBuilder(mContext) + .setMessage(mContext.getString(R.string.input_profile_confirm_load, profileName)) + .setPositiveButton(R.string.yes, (dialogInterface, i) -> + { + mMenuTag.getCorrespondingEmulatedController() + .loadProfile(getProfilePath(profileName, stock)); + ((SettingsActivityView) mDialog.requireActivity()).onControllerSettingsChanged(); + mDialog.dismiss(); + }) + .setNegativeButton(R.string.no, null) + .show(); + } + + public void saveProfile(@NonNull String profileName) + { + // If the user is saving over an existing profile, we should show an overwrite warning. + // If the user is creating a new profile, we normally shouldn't show a warning, + // but if they've entered the name of an existing profile, we should shown an overwrite warning. + + String profilePath = getProfilePath(profileName, false); + if (!new File(profilePath).exists()) + { + mMenuTag.getCorrespondingEmulatedController().saveProfile(profilePath); + mDialog.dismiss(); + } + else + { + new MaterialAlertDialogBuilder(mContext) + .setMessage(mContext.getString(R.string.input_profile_confirm_save, profileName)) + .setPositiveButton(R.string.yes, (dialogInterface, i) -> + { + mMenuTag.getCorrespondingEmulatedController().saveProfile(profilePath); + mDialog.dismiss(); + }) + .setNegativeButton(R.string.no, null) + .show(); + } + } + + public void saveProfileAndPromptForName() + { + LayoutInflater inflater = LayoutInflater.from(mContext); + + DialogInputStringBinding binding = DialogInputStringBinding.inflate(inflater); + TextInputEditText input = binding.input; + + new MaterialAlertDialogBuilder(mContext) + .setView(binding.getRoot()) + .setPositiveButton(R.string.ok, (dialogInterface, i) -> + saveProfile(input.getText().toString())) + .setNegativeButton(R.string.cancel, null) + .show(); + } + + public void deleteProfile(@NonNull String profileName) + { + new MaterialAlertDialogBuilder(mContext) + .setMessage(mContext.getString(R.string.input_profile_confirm_delete, profileName)) + .setPositiveButton(R.string.yes, (dialogInterface, i) -> + { + new File(getProfilePath(profileName, false)).delete(); + mDialog.dismiss(); + }) + .setNegativeButton(R.string.no, null) + .show(); + } + + private String getProfileDirectoryName() + { + if (mMenuTag.isGCPadMenu()) + return "GCPad"; + else if (mMenuTag.isWiimoteMenu()) + return "Wiimote"; + else + throw new UnsupportedOperationException(); + } + + private String getProfileDirectoryPath(boolean stock) + { + if (stock) + { + return DirectoryInitialization.getSysDirectory() + "/Profiles/" + getProfileDirectoryName() + + '/'; + } + else + { + return DirectoryInitialization.getUserDirectory() + "/Config/Profiles/" + + getProfileDirectoryName() + '/'; + } + } + + private String getProfilePath(String profileName, boolean stock) + { + return getProfileDirectoryPath(stock) + profileName + EXTENSION; + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileViewHolder.java new file mode 100644 index 0000000000..d4d40c0c65 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileViewHolder.java @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.features.input.ui; + +import android.content.Context; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.databinding.ListItemProfileBinding; + +public class ProfileViewHolder extends RecyclerView.ViewHolder +{ + private final ProfileDialogPresenter mPresenter; + private final ListItemProfileBinding mBinding; + + private String mProfileName; + private boolean mStock; + + public ProfileViewHolder(@NonNull ProfileDialogPresenter presenter, + @NonNull ListItemProfileBinding binding) + { + super(binding.getRoot()); + + mPresenter = presenter; + mBinding = binding; + + binding.buttonLoad.setOnClickListener(view -> loadProfile()); + binding.buttonSave.setOnClickListener(view -> saveProfile()); + binding.buttonDelete.setOnClickListener(view -> deleteProfile()); + } + + public void bind(String profileName, boolean stock) + { + mProfileName = profileName; + mStock = stock; + + mBinding.textName.setText(profileName); + + mBinding.buttonLoad.setVisibility(View.VISIBLE); + mBinding.buttonSave.setVisibility(stock ? View.GONE : View.VISIBLE); + mBinding.buttonDelete.setVisibility(stock ? View.GONE : View.VISIBLE); + } + + public void bindAsEmpty(Context context) + { + mProfileName = null; + mStock = false; + + mBinding.textName.setText(context.getText(R.string.input_profile_new)); + + mBinding.buttonLoad.setVisibility(View.GONE); + mBinding.buttonSave.setVisibility(View.VISIBLE); + mBinding.buttonDelete.setVisibility(View.GONE); + } + + private void loadProfile() + { + mPresenter.loadProfile(mProfileName, mStock); + } + + private void saveProfile() + { + if (mProfileName == null) + mPresenter.saveProfileAndPromptForName(); + else + mPresenter.saveProfile(mProfileName); + } + + private void deleteProfile() + { + mPresenter.deleteProfile(mProfileName); + } +} 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 f97a013074..a0a67dd838 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 @@ -4,6 +4,8 @@ package org.dolphinemu.dolphinemu.features.settings.ui; import androidx.annotation.NonNull; +import org.dolphinemu.dolphinemu.features.input.model.controlleremu.EmulatedController; + public enum MenuTag { SETTINGS("settings"), @@ -88,6 +90,16 @@ public enum MenuTag return subType; } + public EmulatedController getCorrespondingEmulatedController() + { + if (isGCPadMenu()) + return EmulatedController.getGcPad(getSubType()); + else if (isWiimoteMenu()) + return EmulatedController.getWiimote(getSubType()); + else + throw new UnsupportedOperationException(); + } + public boolean isSerialPort1Menu() { return this == CONFIG_SERIALPORT1; @@ -143,7 +155,8 @@ public enum MenuTag { for (MenuTag menuTag : MenuTag.values()) { - if (menuTag.tag.equals(tag) && menuTag.subType == subtype) return menuTag; + if (menuTag.tag.equals(tag) && menuTag.subType == subtype) + return menuTag; } throw new IllegalArgumentException("You are asking for a menu that is not available or " + diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivity.java index d4ec285681..bce24c1c46 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivity.java @@ -19,6 +19,7 @@ import androidx.core.graphics.Insets; import androidx.core.view.ViewCompat; import androidx.core.view.WindowCompat; import androidx.core.view.WindowInsetsCompat; +import androidx.fragment.app.DialogFragment; import androidx.fragment.app.FragmentTransaction; import androidx.lifecycle.ViewModelProvider; @@ -44,6 +45,7 @@ public final class SettingsActivity extends AppCompatActivity implements Setting private static final String ARG_IS_WII = "is_wii"; private static final String KEY_MAPPING_ALL_DEVICES = "all_devices"; private static final String FRAGMENT_TAG = "settings"; + private static final String FRAGMENT_DIALOG_TAG = "settings_dialog"; private SettingsActivityPresenter mPresenter; private AlertDialog dialog; @@ -191,6 +193,12 @@ public final class SettingsActivity extends AppCompatActivity implements Setting transaction.commit(); } + @Override + public void showDialogFragment(DialogFragment fragment) + { + fragment.show(getSupportFragmentManager(), FRAGMENT_DIALOG_TAG); + } + private boolean areSystemAnimationsEnabled() { float duration = Settings.Global.getFloat( @@ -314,6 +322,12 @@ public final class SettingsActivity extends AppCompatActivity implements Setting mPresenter.onSettingChanged(); } + @Override + public void onControllerSettingsChanged() + { + getFragment().onControllerSettingsChanged(); + } + @Override public void onMenuTagAction(@NonNull MenuTag menuTag, int value) { diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivityView.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivityView.java index 203b14ca4b..464d0ea165 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivityView.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivityView.java @@ -5,6 +5,7 @@ package org.dolphinemu.dolphinemu.features.settings.ui; import android.os.Bundle; import androidx.annotation.NonNull; +import androidx.fragment.app.DialogFragment; import org.dolphinemu.dolphinemu.features.settings.model.Settings; @@ -21,6 +22,13 @@ public interface SettingsActivityView */ void showSettingsFragment(MenuTag menuTag, Bundle extras, boolean addToStack, String gameId); + /** + * Shows a DialogFragment. + * + * Only one can be shown at a time. + */ + void showDialogFragment(DialogFragment fragment); + /** * Called by a contained Fragment to get access to the Setting HashMap * loaded from disk, so that each Fragment doesn't need to perform its own @@ -60,6 +68,14 @@ public interface SettingsActivityView */ void onSettingChanged(); + /** + * Refetches the values of all controller settings. + * + * To be used when loading an input profile or performing some other action that changes all + * controller settings at once. + */ + void onControllerSettingsChanged(); + /** * Called by a containing Fragment to tell the containing Activity that the user wants to open the * MenuTag associated with a setting. 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 fcc27c4e5d..5f3202e63e 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 @@ -13,6 +13,7 @@ import androidx.annotation.Nullable; import androidx.core.graphics.Insets; import androidx.core.view.ViewCompat; import androidx.core.view.WindowInsetsCompat; +import androidx.fragment.app.DialogFragment; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -221,6 +222,12 @@ public final class SettingsFragment extends Fragment implements SettingsFragment mActivity.showSettingsFragment(menuKey, null, true, getArguments().getString(ARGUMENT_GAME_ID)); } + @Override + public void showDialogFragment(DialogFragment fragment) + { + mActivity.showDialogFragment(fragment); + } + @Override public void showToastMessage(String message) { @@ -239,6 +246,13 @@ public final class SettingsFragment extends Fragment implements SettingsFragment mActivity.onSettingChanged(); } + @Override + public void onControllerSettingsChanged() + { + mAdapter.notifyAllSettingsChanged(); + mPresenter.updateOldControllerSettingsWarningVisibility(); + } + @Override public void onMenuTagAction(@NonNull MenuTag menuTag, int value) { 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 6cce1361ec..3d33237439 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 @@ -24,6 +24,7 @@ import org.dolphinemu.dolphinemu.features.input.model.controlleremu.EmulatedCont import org.dolphinemu.dolphinemu.features.input.model.controlleremu.NumericSetting; import org.dolphinemu.dolphinemu.features.input.model.view.InputDeviceSetting; import org.dolphinemu.dolphinemu.features.input.model.view.InputMappingControlSetting; +import org.dolphinemu.dolphinemu.features.input.ui.ProfileDialog; import org.dolphinemu.dolphinemu.features.settings.model.AbstractBooleanSetting; import org.dolphinemu.dolphinemu.features.settings.model.AbstractIntSetting; import org.dolphinemu.dolphinemu.features.settings.model.AdHocBooleanSetting; @@ -1223,6 +1224,9 @@ public final class SettingsFragmentPresenter sl.add(new RunRunnable(mContext, R.string.input_clear, R.string.input_clear_description, R.string.input_reset_warning, 0, true, () -> clearControllerSettings(controller))); + sl.add(new RunRunnable(mContext, R.string.input_profiles, 0, 0, 0, true, + () -> mView.showDialogFragment(ProfileDialog.create(mMenuTag)))); + updateOldControllerSettingsWarningVisibility(controller); } @@ -1293,6 +1297,11 @@ public final class SettingsFragmentPresenter } } + public void updateOldControllerSettingsWarningVisibility() + { + updateOldControllerSettingsWarningVisibility(mMenuTag.getCorrespondingEmulatedController()); + } + private void updateOldControllerSettingsWarningVisibility(EmulatedController controller) { String defaultDevice = controller.getDefaultDevice(); @@ -1306,15 +1315,13 @@ public final class SettingsFragmentPresenter private void loadDefaultControllerSettings(EmulatedController controller) { controller.loadDefaultSettings(); - mView.getAdapter().notifyAllSettingsChanged(); - updateOldControllerSettingsWarningVisibility(controller); + mView.onControllerSettingsChanged(); } private void clearControllerSettings(EmulatedController controller) { controller.clearSettings(); - mView.getAdapter().notifyAllSettingsChanged(); - updateOldControllerSettingsWarningVisibility(controller); + mView.onControllerSettingsChanged(); } private static int getLogVerbosityEntries() diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentView.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentView.java index 53a3010962..809f26f7cc 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentView.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentView.java @@ -3,6 +3,7 @@ package org.dolphinemu.dolphinemu.features.settings.ui; import androidx.annotation.NonNull; +import androidx.fragment.app.DialogFragment; import androidx.fragment.app.FragmentActivity; import org.dolphinemu.dolphinemu.features.settings.model.Settings; @@ -55,6 +56,8 @@ public interface SettingsFragmentView */ void loadSubMenu(MenuTag menuKey); + void showDialogFragment(DialogFragment fragment); + /** * Tell the Fragment to tell the containing activity to display a toast message. * @@ -72,6 +75,14 @@ public interface SettingsFragmentView */ void onSettingChanged(); + /** + * Refetches the values of all controller settings. + * + * To be used when loading an input profile or performing some other action that changes all + * controller settings at once. + */ + void onControllerSettingsChanged(); + /** * Have the fragment tell the containing Activity that the user wants to open the MenuTag * associated with a setting. diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java index cf85e12740..45f2960bd9 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java @@ -45,6 +45,7 @@ public final class DirectoryInitialization new MutableLiveData<>(DirectoryInitializationState.NOT_YET_INITIALIZED); private static volatile boolean areDirectoriesAvailable = false; private static String userPath; + private static String sysPath; private static boolean isUsingLegacyUserDirectory = false; public enum DirectoryInitializationState @@ -153,7 +154,8 @@ public final class DirectoryInitialization } // Let the native code know where the Sys directory is. - SetSysDirectory(sysDirectory.getPath()); + sysPath = sysDirectory.getPath(); + SetSysDirectory(sysPath); } private static void deleteDirectoryRecursively(@NonNull final File file) @@ -204,6 +206,16 @@ public final class DirectoryInitialization return userPath; } + public static String getSysDirectory() + { + if (!areDirectoriesAvailable) + { + throw new IllegalStateException( + "DirectoryInitialization must run before accessing the Sys directory!"); + } + return sysPath; + } + public static File getGameListCache(Context context) { return new File(context.getExternalCacheDir(), "gamelist.cache"); -- cgit v1.2.3 From 42943672bbbed6c18aa2bc85c41102a0616547f7 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Mon, 26 Dec 2022 20:25:09 +0100 Subject: Android: Add selecting input profile per game --- .../features/input/ui/ProfileDialogPresenter.java | 7 +++ .../model/view/StringSingleChoiceSetting.java | 17 +++++- .../features/settings/ui/SettingsAdapter.java | 23 ++++++-- .../settings/ui/SettingsFragmentPresenter.java | 65 ++++++++++++++++------ 4 files changed, 89 insertions(+), 23 deletions(-) (limited to 'Source/Android/app/src/main/java') diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileDialogPresenter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileDialogPresenter.java index ae35aec46d..667cc9017c 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileDialogPresenter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileDialogPresenter.java @@ -29,6 +29,13 @@ public final class ProfileDialogPresenter private final DialogFragment mDialog; private final MenuTag mMenuTag; + public ProfileDialogPresenter(MenuTag menuTag) + { + mContext = null; + mDialog = null; + mMenuTag = menuTag; + } + public ProfileDialogPresenter(DialogFragment dialog, MenuTag menuTag) { mContext = dialog.getContext(); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/StringSingleChoiceSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/StringSingleChoiceSetting.java index 70463f216b..1a9e237728 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/StringSingleChoiceSetting.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/StringSingleChoiceSetting.java @@ -12,11 +12,12 @@ import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag; public class StringSingleChoiceSetting extends SettingsItem { - private AbstractStringSetting mSetting; + private final AbstractStringSetting mSetting; protected String[] mChoices; protected String[] mValues; - private MenuTag mMenuTag; + private final MenuTag mMenuTag; + private int mNoChoicesAvailableString = 0; public StringSingleChoiceSetting(Context context, AbstractStringSetting setting, int titleId, int descriptionId, String[] choices, String[] values, MenuTag menuTag) @@ -34,6 +35,13 @@ public class StringSingleChoiceSetting extends SettingsItem this(context, setting, titleId, descriptionId, choices, values, null); } + public StringSingleChoiceSetting(Context context, AbstractStringSetting setting, int titleId, + int descriptionId, String[] choices, String[] values, int noChoicesAvailableString) + { + this(context, setting, titleId, descriptionId, choices, values, null); + mNoChoicesAvailableString = noChoicesAvailableString; + } + public StringSingleChoiceSetting(Context context, AbstractStringSetting setting, int titleId, int descriptionId, int choicesId, int valuesId, MenuTag menuTag) { @@ -115,6 +123,11 @@ public class StringSingleChoiceSetting extends SettingsItem return mMenuTag; } + public int getNoChoicesAvailableString() + { + return mNoChoicesAvailableString; + } + public void setSelectedValue(Settings settings, String selection) { mSetting.setString(settings, selection); 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 2cf2883fda..0a965b953e 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 @@ -255,11 +255,24 @@ public final class SettingsAdapter extends RecyclerView.Adapter(Arrays.asList(ControlGroup.TYPE_ATTACHMENTS, ControlGroup.TYPE_OTHER))); + if (!TextUtils.isEmpty(mGameID)) + { + addControllerPerGameSettings(sl, "Wiimote", wiimoteNumber); + } + else + { + addControllerMetaSettings(sl, wiimote); + + sl.add(new HeaderSetting(mContext, R.string.wiimote, 0)); + sl.add(new SubmenuSetting(mContext, R.string.wiimote_general, + MenuTag.getWiimoteGeneralMenuTag(wiimoteNumber))); + sl.add(new SubmenuSetting(mContext, R.string.wiimote_motion_simulation, + MenuTag.getWiimoteMotionSimulationMenuTag(wiimoteNumber))); + sl.add(new SubmenuSetting(mContext, R.string.wiimote_motion_input, + MenuTag.getWiimoteMotionInputMenuTag(wiimoteNumber))); + + // TYPE_OTHER is included here instead of in addWiimoteGeneralSubSettings so that touchscreen + // users won't have to dig into a submenu to find the Sideways Wii Remote setting + addControllerMappingSettings(sl, wiimote, new ArraySet<>( + Arrays.asList(ControlGroup.TYPE_ATTACHMENTS, ControlGroup.TYPE_OTHER))); + } } private void addExtensionTypeSettings(ArrayList sl, int wiimoteNumber, @@ -1172,6 +1188,23 @@ public final class SettingsFragmentPresenter ControlGroup.TYPE_IMU_GYROSCOPE, ControlGroup.TYPE_IMU_CURSOR))); } + /** + * Adds controller settings that can be set on a per-game basis. + * + * @param sl The list to place controller settings into. + * @param profileString The prefix used for the profile setting in game INI files. + * @param controllerNumber The index of the controller, 0-3. + */ + private void addControllerPerGameSettings(ArrayList sl, String profileString, + int controllerNumber) + { + String[] profiles = new ProfileDialogPresenter(mMenuTag).getProfileNames(false); + String profileKey = profileString + "Profile" + controllerNumber; + sl.add(new StringSingleChoiceSetting(mContext, + new LegacyStringSetting("", "Controls", profileKey, ""), + R.string.input_profile, 0, profiles, profiles, R.string.input_profiles_empty)); + } + /** * Adds settings and actions that apply to a controller as a whole. * For instance, the device setting and the Clear action. -- cgit v1.2.3 From c2779aef060137d9062cfd29babb3c43fc5fa2b5 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 27 Dec 2022 16:29:01 +0100 Subject: Android: Add the advanced input mapping dialog It's missing a lot of features from the PC version for now, like buttons for inserting functions and the ability to see what the expression evaluates to. I mostly just wanted to get something in place so you can set up rumble. Co-authored-by: Charles Lombardo --- .../features/input/model/ControllerInterface.java | 3 + .../features/input/model/CoreDevice.java | 48 +++++++ .../features/input/model/MappingCommon.java | 3 + .../model/controlleremu/ControlReference.java | 2 + .../model/view/InputMappingControlSetting.java | 10 ++ .../input/ui/AdvancedMappingControlAdapter.java | 55 ++++++++ .../input/ui/AdvancedMappingControlViewHolder.java | 34 +++++ .../features/input/ui/AdvancedMappingDialog.java | 151 +++++++++++++++++++++ .../InputMappingControlSettingViewHolder.java | 26 +++- .../features/settings/ui/SettingsAdapter.java | 43 +++++- 10 files changed, 370 insertions(+), 5 deletions(-) create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/CoreDevice.java create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/AdvancedMappingControlAdapter.java create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/AdvancedMappingControlViewHolder.java create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/AdvancedMappingDialog.java (limited to 'Source/Android/app/src/main/java') diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java index b2535465e8..732ed97a7c 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.java @@ -97,6 +97,9 @@ public final class ControllerInterface public static native String[] getAllDeviceStrings(); + @Nullable + public static native CoreDevice getDevice(String deviceString); + @Keep private static void registerInputDeviceListener() { diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/CoreDevice.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/CoreDevice.java new file mode 100644 index 0000000000..b69e9a0236 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/CoreDevice.java @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.features.input.model; + +import androidx.annotation.Keep; + +/** + * Represents a C++ ciface::Core::Device. + */ +public final class CoreDevice +{ + /** + * Represents a C++ ciface::Core::Device::Control. + * + * This class is non-static to ensure that the CoreDevice parent does not get garbage collected + * while a Control is still accessible. (CoreDevice's finalizer may delete the native controls.) + */ + @SuppressWarnings("InnerClassMayBeStatic") + public final class Control + { + @Keep + private final long mPointer; + + @Keep + private Control(long pointer) + { + mPointer = pointer; + } + + public native String getName(); + } + + @Keep + private final long mPointer; + + @Keep + private CoreDevice(long pointer) + { + mPointer = pointer; + } + + @Override + protected native void finalize(); + + public native Control[] getInputs(); + + public native Control[] getOutputs(); +} 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 index b0dc489fec..5e4c0076ea 100644 --- 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 @@ -27,5 +27,8 @@ public final class MappingCommon public static native String detectInput(@NonNull EmulatedController controller, boolean allDevices); + public static native String getExpressionForControl(String control, String device, + String defaultDevice); + public static native void save(); } 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 index fd01cc1705..66fd9fa02d 100644 --- 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 @@ -34,4 +34,6 @@ public class ControlReference */ @Nullable public native String setExpression(String expr); + + public native boolean isInput(); } 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 index a858b35099..1e8bb1e6d3 100644 --- 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 @@ -52,4 +52,14 @@ public final class InputMappingControlSetting extends SettingsItem { return mController; } + + public ControlReference getControlReference() + { + return mControlReference; + } + + public boolean isInput() + { + return mControlReference.isInput(); + } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/AdvancedMappingControlAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/AdvancedMappingControlAdapter.java new file mode 100644 index 0000000000..0ad589fe40 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/AdvancedMappingControlAdapter.java @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.features.input.ui; + +import android.view.LayoutInflater; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import org.dolphinemu.dolphinemu.databinding.ListItemAdvancedMappingControlBinding; + +import java.util.function.Consumer; + +public final class AdvancedMappingControlAdapter + extends RecyclerView.Adapter +{ + private final Consumer mOnClickCallback; + + private String[] mControls = new String[0]; + + public AdvancedMappingControlAdapter(Consumer onClickCallback) + { + mOnClickCallback = onClickCallback; + } + + @NonNull @Override + public AdvancedMappingControlViewHolder onCreateViewHolder(@NonNull ViewGroup parent, + int viewType) + { + LayoutInflater inflater = LayoutInflater.from(parent.getContext()); + + ListItemAdvancedMappingControlBinding binding = + ListItemAdvancedMappingControlBinding.inflate(inflater); + return new AdvancedMappingControlViewHolder(binding, mOnClickCallback); + } + + @Override + public void onBindViewHolder(@NonNull AdvancedMappingControlViewHolder holder, int position) + { + holder.bind(mControls[position]); + } + + @Override + public int getItemCount() + { + return mControls.length; + } + + public void setControls(String[] controls) + { + mControls = controls; + notifyDataSetChanged(); + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/AdvancedMappingControlViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/AdvancedMappingControlViewHolder.java new file mode 100644 index 0000000000..2ce925235b --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/AdvancedMappingControlViewHolder.java @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.features.input.ui; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import org.dolphinemu.dolphinemu.databinding.ListItemAdvancedMappingControlBinding; + +import java.util.function.Consumer; + +public class AdvancedMappingControlViewHolder extends RecyclerView.ViewHolder +{ + private final ListItemAdvancedMappingControlBinding mBinding; + + private String mName; + + public AdvancedMappingControlViewHolder(@NonNull ListItemAdvancedMappingControlBinding binding, + Consumer onClickCallback) + { + super(binding.getRoot()); + + mBinding = binding; + + binding.getRoot().setOnClickListener(view -> onClickCallback.accept(mName)); + } + + public void bind(String name) + { + mName = name; + + mBinding.textName.setText(name); + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/AdvancedMappingDialog.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/AdvancedMappingDialog.java new file mode 100644 index 0000000000..de8e8265a6 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/AdvancedMappingDialog.java @@ -0,0 +1,151 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.features.input.ui; + +import android.content.Context; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; + +import androidx.appcompat.app.AlertDialog; +import androidx.recyclerview.widget.LinearLayoutManager; + +import com.google.android.material.divider.MaterialDividerItemDecoration; + +import org.dolphinemu.dolphinemu.databinding.DialogAdvancedMappingBinding; +import org.dolphinemu.dolphinemu.features.input.model.ControllerInterface; +import org.dolphinemu.dolphinemu.features.input.model.CoreDevice; +import org.dolphinemu.dolphinemu.features.input.model.MappingCommon; +import org.dolphinemu.dolphinemu.features.input.model.controlleremu.ControlReference; +import org.dolphinemu.dolphinemu.features.input.model.controlleremu.EmulatedController; + +import java.util.Arrays; +import java.util.Optional; + +public final class AdvancedMappingDialog extends AlertDialog + implements AdapterView.OnItemClickListener +{ + private final DialogAdvancedMappingBinding mBinding; + private final ControlReference mControlReference; + private final EmulatedController mController; + private final String[] mDevices; + private final AdvancedMappingControlAdapter mControlAdapter; + + private String mSelectedDevice; + + public AdvancedMappingDialog(Context context, DialogAdvancedMappingBinding binding, + ControlReference controlReference, EmulatedController controller) + { + super(context); + + mBinding = binding; + mControlReference = controlReference; + mController = controller; + + mDevices = ControllerInterface.getAllDeviceStrings(); + + // TODO: Remove workaround for text filtering issue in material components when fixed + // https://github.com/material-components/material-components-android/issues/1464 + mBinding.dropdownDevice.setSaveEnabled(false); + + binding.dropdownDevice.setOnItemClickListener(this); + + ArrayAdapter deviceAdapter = new ArrayAdapter<>( + context, android.R.layout.simple_spinner_dropdown_item, mDevices); + binding.dropdownDevice.setAdapter(deviceAdapter); + + mControlAdapter = new AdvancedMappingControlAdapter(this::onControlClicked); + mBinding.listControl.setAdapter(mControlAdapter); + mBinding.listControl.setLayoutManager(new LinearLayoutManager(context)); + + MaterialDividerItemDecoration divider = + new MaterialDividerItemDecoration(context, LinearLayoutManager.VERTICAL); + divider.setLastItemDecorated(false); + mBinding.listControl.addItemDecoration(divider); + + binding.editExpression.setText(controlReference.getExpression()); + + selectDefaultDevice(); + } + + public String getExpression() + { + return mBinding.editExpression.getText().toString(); + } + + @Override + public void onItemClick(AdapterView adapterView, View view, int position, long id) + { + setSelectedDevice(mDevices[position]); + } + + private void setSelectedDevice(String deviceString) + { + mSelectedDevice = deviceString; + + CoreDevice device = ControllerInterface.getDevice(deviceString); + if (device == null) + setControls(new CoreDevice.Control[0]); + else if (mControlReference.isInput()) + setControls(device.getInputs()); + else + setControls(device.getOutputs()); + } + + private void setControls(CoreDevice.Control[] controls) + { + mControlAdapter.setControls( + Arrays.stream(controls) + .map(CoreDevice.Control::getName) + .toArray(String[]::new)); + } + + private void onControlClicked(String control) + { + String expression = MappingCommon.getExpressionForControl(control, mSelectedDevice, + mController.getDefaultDevice()); + + int start = Math.max(mBinding.editExpression.getSelectionStart(), 0); + int end = Math.max(mBinding.editExpression.getSelectionEnd(), 0); + mBinding.editExpression.getText().replace( + Math.min(start, end), Math.max(start, end), expression, 0, expression.length()); + } + + private void selectDefaultDevice() + { + String defaultDevice = mController.getDefaultDevice(); + boolean isInput = mControlReference.isInput(); + + if (Arrays.asList(mDevices).contains(defaultDevice) && + (isInput || deviceHasOutputs(defaultDevice))) + { + // The default device is available, and it's an appropriate choice. Pick it + setSelectedDevice(defaultDevice); + mBinding.dropdownDevice.setText(defaultDevice, false); + return; + } + else if (!isInput) + { + // Find the first device that has an output. (Most built-in devices don't have any) + Optional deviceWithOutputs = Arrays.stream(mDevices) + .filter(AdvancedMappingDialog::deviceHasOutputs) + .findFirst(); + + if (deviceWithOutputs.isPresent()) + { + setSelectedDevice(deviceWithOutputs.get()); + mBinding.dropdownDevice.setText(deviceWithOutputs.get(), false); + return; + } + } + + // Nothing found + setSelectedDevice(""); + } + + private static boolean deviceHasOutputs(String deviceString) + { + CoreDevice device = ControllerInterface.getDevice(deviceString); + return device != null && device.getOutputs().length > 0; + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/viewholder/InputMappingControlSettingViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/viewholder/InputMappingControlSettingViewHolder.java index 72ddcb3fd3..fd4b92cf95 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/viewholder/InputMappingControlSettingViewHolder.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/viewholder/InputMappingControlSettingViewHolder.java @@ -7,7 +7,7 @@ import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import org.dolphinemu.dolphinemu.databinding.ListItemSettingBinding; +import org.dolphinemu.dolphinemu.databinding.ListItemMappingBinding; 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; @@ -17,9 +17,9 @@ public final class InputMappingControlSettingViewHolder extends SettingViewHolde { private InputMappingControlSetting mItem; - private final ListItemSettingBinding mBinding; + private final ListItemMappingBinding mBinding; - public InputMappingControlSettingViewHolder(@NonNull ListItemSettingBinding binding, + public InputMappingControlSettingViewHolder(@NonNull ListItemMappingBinding binding, SettingsAdapter adapter) { super(binding.getRoot(), adapter); @@ -33,6 +33,7 @@ public final class InputMappingControlSettingViewHolder extends SettingViewHolde mBinding.textSettingName.setText(mItem.getName()); mBinding.textSettingDescription.setText(mItem.getValue()); + mBinding.buttonAdvancedSettings.setOnClickListener(this::onLongClick); setStyle(mBinding.textSettingName, mItem); } @@ -46,11 +47,28 @@ public final class InputMappingControlSettingViewHolder extends SettingViewHolde return; } - getAdapter().onInputMappingClick(mItem, getBindingAdapterPosition()); + if (mItem.isInput()) + getAdapter().onInputMappingClick(mItem, getBindingAdapterPosition()); + else + getAdapter().onAdvancedInputMappingClick(mItem, getBindingAdapterPosition()); setStyle(mBinding.textSettingName, mItem); } + @Override + public boolean onLongClick(View clicked) + { + if (!mItem.isEditable()) + { + showNotRuntimeEditableError(); + return true; + } + + getAdapter().onAdvancedInputMappingClick(mItem, getBindingAdapterPosition()); + + return true; + } + @Nullable @Override protected SettingsItem getItem() { 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 0a965b953e..ca405b15fd 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 @@ -31,12 +31,15 @@ import com.google.android.material.timepicker.MaterialTimePicker; import com.google.android.material.timepicker.TimeFormat; import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.databinding.DialogAdvancedMappingBinding; import org.dolphinemu.dolphinemu.databinding.DialogInputStringBinding; import org.dolphinemu.dolphinemu.databinding.DialogSliderBinding; import org.dolphinemu.dolphinemu.databinding.ListItemHeaderBinding; +import org.dolphinemu.dolphinemu.databinding.ListItemMappingBinding; import org.dolphinemu.dolphinemu.databinding.ListItemSettingBinding; import org.dolphinemu.dolphinemu.databinding.ListItemSettingSwitchBinding; import org.dolphinemu.dolphinemu.databinding.ListItemSubmenuBinding; +import org.dolphinemu.dolphinemu.features.input.ui.AdvancedMappingDialog; 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; @@ -123,7 +126,7 @@ public final class SettingsAdapter extends RecyclerView.Adapter + { + item.setValue(dialog.getExpression()); + notifyItemChanged(position); + mView.onSettingChanged(); + }); + 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(); + notifyItemChanged(position); + mView.onSettingChanged(); + }); + dialog.setCanceledOnTouchOutside(false); + dialog.show(); + } + public void onFilePickerDirectoryClick(SettingsItem item, int position) { mClickedItem = item; -- cgit v1.2.3 From 32cb41007bedf94573ebae92495bbbb179d3113c Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 23 Apr 2022 23:49:18 +0200 Subject: Android: Allow changing controller settings during emulation --- .../dolphinemu/features/input/model/view/InputDeviceSetting.java | 6 ++++++ .../features/input/model/view/InputMappingControlSetting.java | 6 ++++++ .../features/settings/ui/SettingsFragmentPresenter.java | 9 +++------ .../org/dolphinemu/dolphinemu/fragments/EmulationFragment.java | 4 ++++ .../java/org/dolphinemu/dolphinemu/overlay/InputOverlay.java | 4 ---- 5 files changed, 19 insertions(+), 10 deletions(-) (limited to 'Source/Android/app/src/main/java') diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/view/InputDeviceSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/view/InputDeviceSetting.java index 2462e867d3..e27d0f57ae 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/view/InputDeviceSetting.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/view/InputDeviceSetting.java @@ -50,6 +50,12 @@ public class InputDeviceSetting extends StringSingleChoiceSetting mValues = devices; } + @Override + public boolean isEditable() + { + return true; + } + @Override public boolean canClear() { 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 index 1e8bb1e6d3..86379bf5a6 100644 --- 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 @@ -48,6 +48,12 @@ public final class InputMappingControlSetting extends SettingsItem return null; } + @Override + public boolean isEditable() + { + return true; + } + public EmulatedController getController() { return mController; 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 20d4111b98..cd39f8c10f 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 @@ -293,13 +293,10 @@ public final class SettingsFragmentPresenter sl.add(new SubmenuSetting(mContext, R.string.config, MenuTag.CONFIG)); sl.add(new SubmenuSetting(mContext, R.string.graphics_settings, MenuTag.GRAPHICS)); - if (!NativeLibrary.IsRunning()) + sl.add(new SubmenuSetting(mContext, R.string.gcpad_settings, MenuTag.GCPAD_TYPE)); + if (mSettings.isWii()) { - sl.add(new SubmenuSetting(mContext, R.string.gcpad_settings, MenuTag.GCPAD_TYPE)); - if (mSettings.isWii()) - { - sl.add(new SubmenuSetting(mContext, R.string.wiimote_settings, MenuTag.WIIMOTE)); - } + sl.add(new SubmenuSetting(mContext, R.string.wiimote_settings, MenuTag.WIIMOTE)); } sl.add(new HeaderSetting(mContext, R.string.setting_clear_info, 0)); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java index 142aca0641..c356969136 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java @@ -133,6 +133,10 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C public void onResume() { super.onResume(); + + if (mInputOverlay != null && NativeLibrary.IsGameMetadataValid()) + mInputOverlay.refreshControls(); + run(activity.isActivityRecreated()); } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlay.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlay.java index 7d949befed..0a961ac16f 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlay.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlay.java @@ -131,10 +131,6 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener if (!mPreferences.getBoolean("OverlayInitV3", false)) defaultOverlay(); - // Load the controls if we can. If not, EmulationActivity has to do it later. - if (NativeLibrary.IsGameMetadataValid()) - refreshControls(); - // Set the on touch listener. setOnTouchListener(this); -- cgit v1.2.3 From ee2c7dc24b7eee565dc298e5657d9766f712f5e3 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 26 Jun 2022 14:44:50 +0200 Subject: Android: Remove the in-emulation motion control options You can set this in the normal controller settings now. --- .../dolphinemu/activities/EmulationActivity.java | 39 ++-------------------- .../features/settings/model/IntSetting.java | 1 - 2 files changed, 3 insertions(+), 37 deletions(-) (limited to 'Source/Android/app/src/main/java') diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java index 4a9816c259..c0e77b8380 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java @@ -124,9 +124,9 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP MENU_ACTION_LOAD_SLOT3, MENU_ACTION_LOAD_SLOT4, MENU_ACTION_LOAD_SLOT5, MENU_ACTION_LOAD_SLOT6, MENU_ACTION_EXIT, MENU_ACTION_CHANGE_DISC, MENU_ACTION_RESET_OVERLAY, MENU_SET_IR_RECENTER, MENU_SET_IR_MODE, - MENU_SET_IR_SENSITIVITY, MENU_ACTION_CHOOSE_DOUBLETAP, MENU_ACTION_MOTION_CONTROLS, - MENU_ACTION_PAUSE_EMULATION, MENU_ACTION_UNPAUSE_EMULATION, MENU_ACTION_OVERLAY_CONTROLS, - MENU_ACTION_SETTINGS, MENU_ACTION_SKYLANDERS}) + MENU_SET_IR_SENSITIVITY, MENU_ACTION_CHOOSE_DOUBLETAP, + MENU_ACTION_PAUSE_EMULATION, MENU_ACTION_UNPAUSE_EMULATION, + MENU_ACTION_OVERLAY_CONTROLS, MENU_ACTION_SETTINGS, MENU_ACTION_SKYLANDERS}) public @interface MenuAction { } @@ -161,7 +161,6 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP public static final int MENU_SET_IR_MODE = 28; public static final int MENU_SET_IR_SENSITIVITY = 29; public static final int MENU_ACTION_CHOOSE_DOUBLETAP = 30; - public static final int MENU_ACTION_MOTION_CONTROLS = 31; public static final int MENU_ACTION_PAUSE_EMULATION = 32; public static final int MENU_ACTION_UNPAUSE_EMULATION = 33; public static final int MENU_ACTION_OVERLAY_CONTROLS = 34; @@ -200,8 +199,6 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP EmulationActivity.MENU_SET_IR_SENSITIVITY); buttonsActionsMap.append(R.id.menu_emulation_choose_doubletap, EmulationActivity.MENU_ACTION_CHOOSE_DOUBLETAP); - buttonsActionsMap.append(R.id.menu_emulation_motion_controls, - EmulationActivity.MENU_ACTION_MOTION_CONTROLS); } public static void launch(FragmentActivity activity, String filePath, boolean riivolution) @@ -300,7 +297,6 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP public static void updateWiimoteNewIniPreferences(Context context) { updateWiimoteNewController(InputOverlay.getConfiguredControllerType(context), context); - updateWiimoteNewImuIr(IntSetting.MAIN_MOTION_CONTROLS.getIntGlobal()); } private static void updateWiimoteNewController(int value, Context context) @@ -313,14 +309,6 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP wiimoteNewIni.save(wiimoteNewFile); } - private static void updateWiimoteNewImuIr(int value) - { - File wiimoteNewFile = SettingsFile.getSettingsFile(Settings.FILE_WIIMOTE); - IniFile wiimoteNewIni = new IniFile(wiimoteNewFile); - wiimoteNewIni.setBoolean("Wiimote1", "IMUIR/Enabled", value != 1); - wiimoteNewIni.save(wiimoteNewFile); - } - @Override protected void onCreate(Bundle savedInstanceState) { @@ -806,10 +794,6 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP chooseDoubleTapButton(); break; - case MENU_ACTION_MOTION_CONTROLS: - showMotionControlsOptions(); - break; - case MENU_ACTION_SETTINGS: SettingsActivity.launch(this, MenuTag.SETTINGS); break; @@ -1024,23 +1008,6 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP .show(); } - private void showMotionControlsOptions() - { - new MaterialAlertDialogBuilder(this) - .setTitle(R.string.emulation_motion_controls) - .setSingleChoiceItems(R.array.motionControlsEntries, - IntSetting.MAIN_MOTION_CONTROLS.getInt(mSettings), - (dialog, indexSelected) -> - { - IntSetting.MAIN_MOTION_CONTROLS.setInt(mSettings, indexSelected); - - updateWiimoteNewImuIr(indexSelected); - NativeLibrary.ReloadWiimoteConfig(); - }) - .setPositiveButton(R.string.ok, (dialogInterface, i) -> dialogInterface.dismiss()) - .show(); - } - private void setIRMode() { new MaterialAlertDialogBuilder(this) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/IntSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/IntSetting.java index a51eb71749..10503f7da0 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/IntSetting.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/IntSetting.java @@ -41,7 +41,6 @@ public enum IntSetting implements AbstractIntSetting MAIN_INTERFACE_THEME_MODE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID, "InterfaceThemeMode", -1), MAIN_LAST_PLATFORM_TAB(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID, "LastPlatformTab", 0), - MAIN_MOTION_CONTROLS(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID, "MotionControls", 1), MAIN_IR_MODE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID, "IRMode", InputOverlayPointer.MODE_FOLLOW), -- cgit v1.2.3 From 4c326f2030fda4c23cb4374fef1dee3da0c4822d Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 26 Jun 2022 15:19:46 +0200 Subject: Android: Remove the in-emulation IR sensitivity options This too can be set in the normal controller settings now. --- .../dolphinemu/activities/EmulationActivity.java | 96 +--------------------- .../features/settings/model/Settings.java | 1 - .../features/settings/utils/SettingsFile.java | 4 - 3 files changed, 3 insertions(+), 98 deletions(-) (limited to 'Source/Android/app/src/main/java') diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java index c0e77b8380..439d697247 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java @@ -39,7 +39,6 @@ import org.dolphinemu.dolphinemu.NativeLibrary; import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.databinding.ActivityEmulationBinding; import org.dolphinemu.dolphinemu.databinding.DialogInputAdjustBinding; -import org.dolphinemu.dolphinemu.databinding.DialogIrSensitivityBinding; import org.dolphinemu.dolphinemu.databinding.DialogSkylandersManagerBinding; import org.dolphinemu.dolphinemu.features.input.model.ControllerInterface; import org.dolphinemu.dolphinemu.features.input.model.DolphinSensorEventListener; @@ -124,9 +123,9 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP MENU_ACTION_LOAD_SLOT3, MENU_ACTION_LOAD_SLOT4, MENU_ACTION_LOAD_SLOT5, MENU_ACTION_LOAD_SLOT6, MENU_ACTION_EXIT, MENU_ACTION_CHANGE_DISC, MENU_ACTION_RESET_OVERLAY, MENU_SET_IR_RECENTER, MENU_SET_IR_MODE, - MENU_SET_IR_SENSITIVITY, MENU_ACTION_CHOOSE_DOUBLETAP, - MENU_ACTION_PAUSE_EMULATION, MENU_ACTION_UNPAUSE_EMULATION, - MENU_ACTION_OVERLAY_CONTROLS, MENU_ACTION_SETTINGS, MENU_ACTION_SKYLANDERS}) + MENU_ACTION_CHOOSE_DOUBLETAP, MENU_ACTION_PAUSE_EMULATION, + MENU_ACTION_UNPAUSE_EMULATION, MENU_ACTION_OVERLAY_CONTROLS, MENU_ACTION_SETTINGS, + MENU_ACTION_SKYLANDERS}) public @interface MenuAction { } @@ -159,7 +158,6 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP public static final int MENU_ACTION_RESET_OVERLAY = 26; public static final int MENU_SET_IR_RECENTER = 27; public static final int MENU_SET_IR_MODE = 28; - public static final int MENU_SET_IR_SENSITIVITY = 29; public static final int MENU_ACTION_CHOOSE_DOUBLETAP = 30; public static final int MENU_ACTION_PAUSE_EMULATION = 32; public static final int MENU_ACTION_UNPAUSE_EMULATION = 33; @@ -195,8 +193,6 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP EmulationActivity.MENU_SET_IR_RECENTER); buttonsActionsMap.append(R.id.menu_emulation_set_ir_mode, EmulationActivity.MENU_SET_IR_MODE); - buttonsActionsMap.append(R.id.menu_emulation_set_ir_sensitivity, - EmulationActivity.MENU_SET_IR_SENSITIVITY); buttonsActionsMap.append(R.id.menu_emulation_choose_doubletap, EmulationActivity.MENU_ACTION_CHOOSE_DOUBLETAP); } @@ -786,10 +782,6 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP setIRMode(); break; - case MENU_SET_IR_SENSITIVITY: - setIRSensitivity(); - break; - case MENU_ACTION_CHOOSE_DOUBLETAP: chooseDoubleTapButton(); break; @@ -1021,88 +1013,6 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP .show(); } - private void setIRSensitivity() - { - // IR settings always get saved per-game since WiimoteNew.ini is wiped upon reinstall. - File file = SettingsFile.getCustomGameSettingsFile(NativeLibrary.GetCurrentGameID()); - IniFile ini = new IniFile(file); - - int ir_pitch = ini.getInt(Settings.SECTION_CONTROLS, SettingsFile.KEY_WIIBIND_IR_PITCH, 20); - - DialogIrSensitivityBinding dialogBinding = - DialogIrSensitivityBinding.inflate(getLayoutInflater()); - - TextView text_slider_value_pitch = dialogBinding.textIrPitch; - TextView units = dialogBinding.textIrPitchUnits; - Slider slider_pitch = dialogBinding.sliderPitch; - - text_slider_value_pitch.setText(String.valueOf(ir_pitch)); - units.setText(getString(R.string.pitch)); - slider_pitch.setValueTo(100); - slider_pitch.setValue(ir_pitch); - slider_pitch.setStepSize(1); - slider_pitch.addOnChangeListener( - (slider, progress, fromUser) -> text_slider_value_pitch.setText( - String.valueOf((int) progress))); - - int ir_yaw = ini.getInt(Settings.SECTION_CONTROLS, SettingsFile.KEY_WIIBIND_IR_YAW, 25); - - TextView text_slider_value_yaw = dialogBinding.textIrYaw; - TextView units_yaw = dialogBinding.textIrYawUnits; - Slider seekbar_yaw = dialogBinding.sliderYaw; - - text_slider_value_yaw.setText(String.valueOf(ir_yaw)); - units_yaw.setText(getString(R.string.yaw)); - seekbar_yaw.setValueTo(100); - seekbar_yaw.setValue(ir_yaw); - seekbar_yaw.setStepSize(1); - seekbar_yaw.addOnChangeListener((slider, progress, fromUser) -> text_slider_value_yaw.setText( - String.valueOf((int) progress))); - - int ir_vertical_offset = - ini.getInt(Settings.SECTION_CONTROLS, SettingsFile.KEY_WIIBIND_IR_VERTICAL_OFFSET, 10); - - TextView text_slider_value_vertical_offset = dialogBinding.textIrVerticalOffset; - TextView units_vertical_offset = dialogBinding.textIrVerticalOffsetUnits; - Slider seekbar_vertical_offset = dialogBinding.sliderVerticalOffset; - - text_slider_value_vertical_offset.setText(String.valueOf(ir_vertical_offset)); - units_vertical_offset.setText(getString(R.string.vertical_offset)); - seekbar_vertical_offset.setValueTo(100); - seekbar_vertical_offset.setValue(ir_vertical_offset); - seekbar_vertical_offset.setStepSize(1); - seekbar_vertical_offset.addOnChangeListener( - (slider, progress, fromUser) -> text_slider_value_vertical_offset.setText( - String.valueOf((int) progress))); - - new MaterialAlertDialogBuilder(this) - .setTitle(getString(R.string.emulation_ir_sensitivity)) - .setView(dialogBinding.getRoot()) - .setPositiveButton(R.string.ok, (dialogInterface, i) -> - { - ini.setString(Settings.SECTION_CONTROLS, SettingsFile.KEY_WIIBIND_IR_PITCH, - text_slider_value_pitch.getText().toString()); - ini.setString(Settings.SECTION_CONTROLS, SettingsFile.KEY_WIIBIND_IR_YAW, - text_slider_value_yaw.getText().toString()); - ini.setString(Settings.SECTION_CONTROLS, SettingsFile.KEY_WIIBIND_IR_VERTICAL_OFFSET, - text_slider_value_vertical_offset.getText().toString()); - ini.save(file); - - NativeLibrary.ReloadWiimoteConfig(); - }) - .setNegativeButton(R.string.cancel, null) - .setNeutralButton(R.string.default_values, (dialogInterface, i) -> - { - ini.deleteKey(Settings.SECTION_CONTROLS, SettingsFile.KEY_WIIBIND_IR_PITCH); - ini.deleteKey(Settings.SECTION_CONTROLS, SettingsFile.KEY_WIIBIND_IR_YAW); - ini.deleteKey(Settings.SECTION_CONTROLS, SettingsFile.KEY_WIIBIND_IR_VERTICAL_OFFSET); - ini.save(file); - - NativeLibrary.ReloadWiimoteConfig(); - }) - .show(); - } - private void showSkylanderPortalSettings() { mSkylandersBinding = 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 9a94048838..fb5e16965b 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 @@ -47,7 +47,6 @@ public class Settings implements Closeable public static final String SECTION_STEREOSCOPY = "Stereoscopy"; public static final String SECTION_BINDINGS = "Android"; - public static final String SECTION_CONTROLS = "Controls"; public static final String SECTION_PROFILE = "Profile"; public static final String SECTION_ANALYTICS = "Analytics"; diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/utils/SettingsFile.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/utils/SettingsFile.java index 9362b4e980..2cabb8edc7 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/utils/SettingsFile.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/utils/SettingsFile.java @@ -22,10 +22,6 @@ public final class SettingsFile public static final String KEY_GCPAD_PLAYER_1 = "SIDevice0"; - public static final String KEY_WIIBIND_IR_PITCH = "IRTotalPitch"; - public static final String KEY_WIIBIND_IR_YAW = "IRTotalYaw"; - public static final String KEY_WIIBIND_IR_VERTICAL_OFFSET = "IRVerticalOffset"; - private static BiMap sectionsMap = new BiMap<>(); static -- cgit v1.2.3 From 1b55d7c59429ae96b014b61c5393a4dacc578cfa Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 26 Jun 2022 20:27:18 +0200 Subject: Android: Change how the overlay controller setting works Up until now, there have been two settings on Android that stored the selected Wii Remote extension: the normal one that's also used on PC, and a SharedPreferences one that's used by the overlay controls to determine what controls to show. It is possible for these two to end up out of sync, and my input changes have made that more likely to happen. To fix this, let's rework how the overlay controller setting works. We don't want it to encode the currently selected Wii Remote extension. However, we can't simply get rid of the setting, because for some Wii games we need the ability to switch between a GameCube controller and a Wii Remote. What this commit does is give the user the option to select any of the 4 GameCube controllers and any of the 4 Wii Remotes. (Before, controllers 2-4 weren't available in the overlay.) Could be useful for things like the Psycho Mantis fight in Metal Gear Solid. I'm also switching from SharedPreferences to Dolphin.ini while I'm at it. --- .../org/dolphinemu/dolphinemu/NativeLibrary.java | 2 - .../dolphinemu/activities/EmulationActivity.java | 96 ++++++---- .../model/controlleremu/EmulatedController.java | 4 + .../features/settings/model/IntSetting.java | 16 ++ .../features/settings/utils/SettingsFile.java | 2 - .../dolphinemu/fragments/EmulationFragment.java | 18 +- .../dolphinemu/overlay/InputOverlay.java | 202 +++++++++++---------- .../dolphinemu/utils/DirectoryInitialization.java | 8 - 8 files changed, 191 insertions(+), 157 deletions(-) (limited to 'Source/Android/app/src/main/java') diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java index 1db70b72d9..68fdfee277 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java @@ -404,8 +404,6 @@ public final class NativeLibrary */ public static native void RefreshWiimotes(); - public static native void ReloadWiimoteConfig(); - public static native LinkedHashMap GetLogTypeNames(); public static native void ReloadLoggerConfig(); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java index 439d697247..9780f8de7b 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java @@ -2,7 +2,6 @@ package org.dolphinemu.dolphinemu.activities; -import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; @@ -48,7 +47,6 @@ import org.dolphinemu.dolphinemu.features.settings.model.Settings; import org.dolphinemu.dolphinemu.features.settings.model.StringSetting; import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag; import org.dolphinemu.dolphinemu.features.settings.ui.SettingsActivity; -import org.dolphinemu.dolphinemu.features.settings.utils.SettingsFile; import org.dolphinemu.dolphinemu.features.skylanders.SkylanderConfig; import org.dolphinemu.dolphinemu.features.skylanders.model.Skylander; import org.dolphinemu.dolphinemu.features.skylanders.ui.SkylanderSlot; @@ -62,10 +60,8 @@ import org.dolphinemu.dolphinemu.ui.main.MainPresenter; import org.dolphinemu.dolphinemu.ui.main.ThemeProvider; import org.dolphinemu.dolphinemu.utils.AfterDirectoryInitializationRunner; import org.dolphinemu.dolphinemu.utils.FileBrowserHelper; -import org.dolphinemu.dolphinemu.utils.IniFile; import org.dolphinemu.dolphinemu.utils.ThemeHelper; -import java.io.File; import java.lang.annotation.Retention; import java.util.ArrayList; import java.util.List; @@ -290,21 +286,6 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP sIgnoreLaunchRequests = false; } - public static void updateWiimoteNewIniPreferences(Context context) - { - updateWiimoteNewController(InputOverlay.getConfiguredControllerType(context), context); - } - - private static void updateWiimoteNewController(int value, Context context) - { - File wiimoteNewFile = SettingsFile.getSettingsFile(Settings.FILE_WIIMOTE); - IniFile wiimoteNewIni = new IniFile(wiimoteNewFile); - wiimoteNewIni.setString("Wiimote1", "Extension", - context.getResources().getStringArray(R.array.controllersValues)[value]); - wiimoteNewIni.setBoolean("Wiimote1", "Options/Sideways Wiimote", value == 2); - wiimoteNewIni.save(wiimoteNewFile); - } - @Override protected void onCreate(Bundle savedInstanceState) { @@ -456,7 +437,7 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP setTitle(NativeLibrary.GetCurrentTitleDescription()); - mEmulationFragment.refreshInputOverlay(); + mEmulationFragment.refreshInputOverlay(mSettings); } @Override @@ -680,7 +661,7 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP adjustScale(); break; - // (Wii games only) Change the controller for the input overlay. + // Change the controller for the input overlay. case MENU_ACTION_CHOOSE_CONTROLLER: chooseController(); break; @@ -850,9 +831,9 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this) .setTitle(R.string.emulation_toggle_controls); - int currentController = InputOverlay.getConfiguredControllerType(this); + int currentController = InputOverlay.getConfiguredControllerType(mSettings); - if (!NativeLibrary.IsEmulatingWii() || currentController == InputOverlay.OVERLAY_GAMECUBE) + if (currentController == InputOverlay.OVERLAY_GAMECUBE) { boolean[] gcEnabledButtons = new boolean[11]; String gcSettingBase = "MAIN_BUTTON_TOGGLE_GC_"; @@ -906,7 +887,7 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP builder.setNeutralButton(R.string.emulation_toggle_all, (dialogInterface, i) -> mEmulationFragment.toggleInputOverlayVisibility(mSettings)) .setPositiveButton(R.string.ok, (dialogInterface, i) -> - mEmulationFragment.refreshInputOverlay()) + mEmulationFragment.refreshInputOverlay(mSettings)) .show(); } @@ -914,7 +895,7 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP { int currentValue = IntSetting.MAIN_DOUBLE_TAP_BUTTON.getInt(mSettings); - int buttonList = InputOverlay.getConfiguredControllerType(this) == + int buttonList = InputOverlay.getConfiguredControllerType(mSettings) == InputOverlay.OVERLAY_WIIMOTE_CLASSIC ? R.array.doubleTapWithClassic : R.array.doubleTap; int checkedItem = -1; @@ -933,7 +914,7 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP (DialogInterface dialog, int which) -> IntSetting.MAIN_DOUBLE_TAP_BUTTON.setInt( mSettings, InputOverlayPointer.DOUBLE_TAP_OPTIONS.get(which))) .setPositiveButton(R.string.ok, - (dialogInterface, i) -> mEmulationFragment.initInputPointer()) + (dialogInterface, i) -> mEmulationFragment.initInputPointer(mSettings)) .show(); } @@ -967,35 +948,72 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP { IntSetting.MAIN_CONTROL_SCALE.setInt(mSettings, (int) scaleSlider.getValue()); IntSetting.MAIN_CONTROL_OPACITY.setInt(mSettings, (int) sliderOpacity.getValue()); - mEmulationFragment.refreshInputOverlay(); + mEmulationFragment.refreshInputOverlay(mSettings); }) .setNeutralButton(R.string.default_values, (dialog, which) -> { IntSetting.MAIN_CONTROL_SCALE.delete(mSettings); IntSetting.MAIN_CONTROL_OPACITY.delete(mSettings); - mEmulationFragment.refreshInputOverlay(); + mEmulationFragment.refreshInputOverlay(mSettings); }) .show(); } + private void addControllerIfNotNone(List entries, List values, + IntSetting controller, int entry, int value) + { + if (controller.getInt(mSettings) != 0) + { + entries.add(getString(entry)); + values.add(value); + } + } + private void chooseController() { + ArrayList entries = new ArrayList<>(); + ArrayList values = new ArrayList<>(); + + entries.add(getString(R.string.none)); + values.add(-1); + + addControllerIfNotNone(entries, values, IntSetting.MAIN_SI_DEVICE_0, R.string.controller_0, 0); + addControllerIfNotNone(entries, values, IntSetting.MAIN_SI_DEVICE_1, R.string.controller_1, 1); + addControllerIfNotNone(entries, values, IntSetting.MAIN_SI_DEVICE_2, R.string.controller_2, 2); + addControllerIfNotNone(entries, values, IntSetting.MAIN_SI_DEVICE_3, R.string.controller_3, 3); + + if (NativeLibrary.IsEmulatingWii()) + { + addControllerIfNotNone(entries, values, IntSetting.WIIMOTE_1_SOURCE, R.string.wiimote_0, 4); + addControllerIfNotNone(entries, values, IntSetting.WIIMOTE_2_SOURCE, R.string.wiimote_1, 5); + addControllerIfNotNone(entries, values, IntSetting.WIIMOTE_3_SOURCE, R.string.wiimote_2, 6); + addControllerIfNotNone(entries, values, IntSetting.WIIMOTE_4_SOURCE, R.string.wiimote_3, 7); + } + + IntSetting controllerSetting = NativeLibrary.IsEmulatingWii() ? + IntSetting.MAIN_OVERLAY_WII_CONTROLLER : IntSetting.MAIN_OVERLAY_GC_CONTROLLER; + int currentValue = controllerSetting.getInt(mSettings); + + int checkedItem = -1; + for (int i = 0; i < values.size(); i++) + { + if (values.get(i) == currentValue) + { + checkedItem = i; + break; + } + } + final SharedPreferences.Editor editor = mPreferences.edit(); new MaterialAlertDialogBuilder(this) .setTitle(R.string.emulation_choose_controller) - .setSingleChoiceItems(R.array.controllersEntries, - InputOverlay.getConfiguredControllerType(this), + .setSingleChoiceItems(entries.toArray(new CharSequence[]{}), checkedItem, (dialog, indexSelected) -> - { - editor.putInt("wiiController", indexSelected); - - updateWiimoteNewController(indexSelected, this); - NativeLibrary.ReloadWiimoteConfig(); - }) + controllerSetting.setInt(mSettings, values.get(indexSelected))) .setPositiveButton(R.string.ok, (dialogInterface, i) -> { editor.apply(); - mEmulationFragment.refreshInputOverlay(); + mEmulationFragment.refreshInputOverlay(mSettings); }) .show(); } @@ -1045,7 +1063,7 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP new MaterialAlertDialogBuilder(this) .setTitle(getString(R.string.emulation_touch_overlay_reset)) .setPositiveButton(R.string.yes, - (dialogInterface, i) -> mEmulationFragment.resetInputOverlay()) + (dialogInterface, i) -> mEmulationFragment.resetInputOverlay(mSettings)) .setNegativeButton(R.string.cancel, null) .show(); } @@ -1140,7 +1158,7 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP public void initInputPointer() { - mEmulationFragment.initInputPointer(); + mEmulationFragment.initInputPointer(mSettings); } @Override 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 index 47d4dc5c96..39645ffbba 100644 --- 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 @@ -45,4 +45,8 @@ public class EmulatedController public static native EmulatedController getWiimoteAttachment(int controllerIndex, int attachmentIndex); + + public static native int getSelectedWiimoteAttachment(int controllerIndex); + + public static native NumericSetting getSidewaysWiimoteSetting(int controllerIndex); } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/IntSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/IntSetting.java index 10503f7da0..77cf7b339a 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/IntSetting.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/IntSetting.java @@ -33,6 +33,10 @@ public enum IntSetting implements AbstractIntSetting MAIN_AUDIO_VOLUME(Settings.FILE_DOLPHIN, Settings.SECTION_INI_DSP, "Volume", 100), + MAIN_OVERLAY_GC_CONTROLLER(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID, + "OverlayGCController", 0), // Defaults to GameCube controller 1 + MAIN_OVERLAY_WII_CONTROLLER(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID, + "OverlayWiiController", 4), // Defaults to Wii Remote 1 MAIN_CONTROL_SCALE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID, "ControlScale", 50), MAIN_CONTROL_OPACITY(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID, "ControlOpacity", 65), MAIN_EMULATION_ORIENTATION(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID, @@ -188,4 +192,16 @@ public enum IntSetting implements AbstractIntSetting { NativeConfig.setInt(layer, mFile, mSection, mKey, newValue); } + + public static IntSetting getSettingForSIDevice(int channel) + { + return new IntSetting[]{MAIN_SI_DEVICE_0, MAIN_SI_DEVICE_1, MAIN_SI_DEVICE_2, MAIN_SI_DEVICE_3} + [channel]; + } + + public static IntSetting getSettingForWiimoteSource(int index) + { + return new IntSetting[]{WIIMOTE_1_SOURCE, WIIMOTE_2_SOURCE, WIIMOTE_3_SOURCE, WIIMOTE_4_SOURCE, + WIIMOTE_BB_SOURCE}[index]; + } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/utils/SettingsFile.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/utils/SettingsFile.java index 2cabb8edc7..acad8c2d19 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/utils/SettingsFile.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/utils/SettingsFile.java @@ -20,8 +20,6 @@ public final class SettingsFile public static final String KEY_ISO_PATH_BASE = "ISOPath"; public static final String KEY_ISO_PATHS = "ISOPaths"; - public static final String KEY_GCPAD_PLAYER_1 = "SIDevice0"; - private static BiMap sectionsMap = new BiMap<>(); static diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java index c356969136..27e425d8b6 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java @@ -115,7 +115,7 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C { int overlayX = mInputOverlay.getLeft(); int overlayY = mInputOverlay.getTop(); - mInputOverlay.setSurfacePosition(new Rect( + mInputOverlay.setSurfacePosition(activity.getSettings(), new Rect( surfaceView.getLeft() - overlayX, surfaceView.getTop() - overlayY, surfaceView.getRight() - overlayX, surfaceView.getBottom() - overlayY)); }); @@ -135,7 +135,7 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C super.onResume(); if (mInputOverlay != null && NativeLibrary.IsGameMetadataValid()) - mInputOverlay.refreshControls(); + mInputOverlay.refreshControls(activity.getSettings()); run(activity.isActivityRecreated()); } @@ -174,19 +174,19 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C .setBoolean(settings, !BooleanSetting.MAIN_SHOW_INPUT_OVERLAY.getBoolean(settings)); if (mInputOverlay != null) - mInputOverlay.refreshControls(); + mInputOverlay.refreshControls(settings); } - public void initInputPointer() + public void initInputPointer(Settings settings) { if (mInputOverlay != null) - mInputOverlay.initTouchPointer(); + mInputOverlay.initTouchPointer(settings); } - public void refreshInputOverlay() + public void refreshInputOverlay(Settings settings) { if (mInputOverlay != null) - mInputOverlay.refreshControls(); + mInputOverlay.refreshControls(settings); } public void refreshOverlayPointer(Settings settings) @@ -195,10 +195,10 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C mInputOverlay.refreshOverlayPointer(settings); } - public void resetInputOverlay() + public void resetInputOverlay(Settings settings) { if (mInputOverlay != null) - mInputOverlay.resetButtonPlacement(); + mInputOverlay.resetButtonPlacement(settings); } @Override diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlay.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlay.java index 0a961ac16f..1fed472b56 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlay.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlay.java @@ -29,13 +29,14 @@ import androidx.preference.PreferenceManager; import org.dolphinemu.dolphinemu.NativeLibrary; import org.dolphinemu.dolphinemu.NativeLibrary.ButtonType; import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.features.input.model.InputMappingBooleanSetting; import org.dolphinemu.dolphinemu.features.input.model.InputOverrider; import org.dolphinemu.dolphinemu.features.input.model.InputOverrider.ControlId; +import org.dolphinemu.dolphinemu.features.input.model.controlleremu.EmulatedController; +import org.dolphinemu.dolphinemu.features.input.model.controlleremu.NumericSetting; import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting; import org.dolphinemu.dolphinemu.features.settings.model.IntSetting; import org.dolphinemu.dolphinemu.features.settings.model.Settings; -import org.dolphinemu.dolphinemu.features.settings.utils.SettingsFile; -import org.dolphinemu.dolphinemu.utils.IniFile; import java.util.ArrayList; import java.util.HashSet; @@ -69,6 +70,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener private boolean mGameCubeRegistered = false; private boolean mWiiRegistered = false; private boolean mIsInEditMode = false; + private int mControllerType = -1; private InputOverlayDrawableButton mButtonBeingConfigured; private InputOverlayDrawableDpad mDpadBeingConfigured; private InputOverlayDrawableJoystick mJoystickBeingConfigured; @@ -141,13 +143,13 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener requestFocus(); } - public void setSurfacePosition(Rect rect) + public void setSurfacePosition(Settings settings, Rect rect) { mSurfacePosition = rect; - initTouchPointer(); + initTouchPointer(settings); } - public void initTouchPointer() + public void initTouchPointer(Settings settings) { // Check if we have all the data we need yet boolean aspectRatioAvailable = NativeLibrary.IsRunningAndStarted(); @@ -160,7 +162,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener int doubleTapButton = IntSetting.MAIN_DOUBLE_TAP_BUTTON.getIntGlobal(); - if (getConfiguredControllerType() != InputOverlay.OVERLAY_WIIMOTE_CLASSIC && + if (getConfiguredControllerType(settings) != InputOverlay.OVERLAY_WIIMOTE_CLASSIC && doubleTapButton == ButtonType.CLASSIC_BUTTON_A) { doubleTapButton = ButtonType.WIIMOTE_BUTTON_A; @@ -355,7 +357,6 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener int fingerPositionX = (int) event.getX(pointerIndex); int fingerPositionY = (int) event.getY(pointerIndex); - int controller = getConfiguredControllerType(); String orientation = getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT ? "-Portrait" : ""; @@ -394,7 +395,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener // Persist button position by saving new place. saveControlPosition(mButtonBeingConfigured.getLegacyId(), mButtonBeingConfigured.getBounds().left, - mButtonBeingConfigured.getBounds().top, controller, orientation); + mButtonBeingConfigured.getBounds().top, orientation); mButtonBeingConfigured = null; } break; @@ -432,7 +433,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener // Persist button position by saving new place. saveControlPosition(mDpadBeingConfigured.getLegacyId(), mDpadBeingConfigured.getBounds().left, mDpadBeingConfigured.getBounds().top, - controller, orientation); + orientation); mDpadBeingConfigured = null; } break; @@ -465,7 +466,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener { saveControlPosition(mJoystickBeingConfigured.getLegacyId(), mJoystickBeingConfigured.getBounds().left, - mJoystickBeingConfigured.getBounds().top, controller, orientation); + mJoystickBeingConfigured.getBounds().top, orientation); mJoystickBeingConfigured = null; } break; @@ -781,7 +782,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener } } - public void refreshControls() + public void refreshControls(Settings settings) { unregisterControllers(); @@ -794,67 +795,52 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT ? "-Portrait" : ""; + mControllerType = getConfiguredControllerType(settings); + if (BooleanSetting.MAIN_SHOW_INPUT_OVERLAY.getBooleanGlobal()) { // Add all the enabled overlay items back to the HashSet. - if (!NativeLibrary.IsEmulatingWii()) + switch (mControllerType) { - IniFile dolphinIni = new IniFile(SettingsFile.getSettingsFile(Settings.FILE_DOLPHIN)); + case OVERLAY_GAMECUBE: + IntSetting controllerSetting = NativeLibrary.IsEmulatingWii() ? + IntSetting.MAIN_OVERLAY_WII_CONTROLLER : IntSetting.MAIN_OVERLAY_GC_CONTROLLER; + int controllerIndex = controllerSetting.getInt(settings); - switch (dolphinIni.getInt(Settings.SECTION_INI_CORE, SettingsFile.KEY_GCPAD_PLAYER_1, - EMULATED_GAMECUBE_CONTROLLER)) - { - case DISABLED_GAMECUBE_CONTROLLER: - if (mIsFirstRun) - { - Toast.makeText(getContext(), R.string.disabled_gc_overlay_notice, Toast.LENGTH_SHORT) - .show(); - } - break; + if (IntSetting.getSettingForSIDevice(controllerIndex).getInt(settings) == + DISABLED_GAMECUBE_CONTROLLER && mIsFirstRun) + { + Toast.makeText(getContext(), R.string.disabled_gc_overlay_notice, Toast.LENGTH_SHORT) + .show(); + } - case EMULATED_GAMECUBE_CONTROLLER: - InputOverrider.registerGameCube(0); - mGameCubeRegistered = true; - addGameCubeOverlayControls(orientation); - break; + InputOverrider.registerGameCube(0); + mGameCubeRegistered = true; + addGameCubeOverlayControls(orientation); + break; - case GAMECUBE_ADAPTER: - break; - } - } - else - { - switch (getConfiguredControllerType()) - { - case OVERLAY_GAMECUBE: - InputOverrider.registerGameCube(0); - mGameCubeRegistered = true; - addGameCubeOverlayControls(orientation); - break; - - case OVERLAY_WIIMOTE: - case OVERLAY_WIIMOTE_SIDEWAYS: - InputOverrider.registerWii(0); - mWiiRegistered = true; - addWiimoteOverlayControls(orientation); - break; - - case OVERLAY_WIIMOTE_NUNCHUK: - InputOverrider.registerWii(0); - mWiiRegistered = true; - addWiimoteOverlayControls(orientation); - addNunchukOverlayControls(orientation); - break; - - case OVERLAY_WIIMOTE_CLASSIC: - InputOverrider.registerWii(0); - mWiiRegistered = true; - addClassicOverlayControls(orientation); - break; - - case OVERLAY_NONE: - break; - } + case OVERLAY_WIIMOTE: + case OVERLAY_WIIMOTE_SIDEWAYS: + InputOverrider.registerWii(0); + mWiiRegistered = true; + addWiimoteOverlayControls(orientation); + break; + + case OVERLAY_WIIMOTE_NUNCHUK: + InputOverrider.registerWii(0); + mWiiRegistered = true; + addWiimoteOverlayControls(orientation); + addNunchukOverlayControls(orientation); + break; + + case OVERLAY_WIIMOTE_CLASSIC: + InputOverrider.registerWii(0); + mWiiRegistered = true; + addClassicOverlayControls(orientation); + break; + + case OVERLAY_NONE: + break; } } @@ -871,20 +857,20 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener } } - public void resetButtonPlacement() + public void resetButtonPlacement(Settings settings) { boolean isLandscape = getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; - // Values for these come from R.array.controllersEntries - if (!NativeLibrary.IsEmulatingWii() || getConfiguredControllerType() == OVERLAY_GAMECUBE) + final int controller = getConfiguredControllerType(settings); + if (controller == OVERLAY_GAMECUBE) { if (isLandscape) gcDefaultOverlay(); else gcPortraitDefaultOverlay(); } - else if (getConfiguredControllerType() == OVERLAY_WIIMOTE_CLASSIC) + else if (controller == OVERLAY_WIIMOTE_CLASSIC) { if (isLandscape) wiiClassicDefaultOverlay(); @@ -904,27 +890,52 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener wiiOnlyPortraitDefaultOverlay(); } } - refreshControls(); + refreshControls(settings); } - public static int getConfiguredControllerType(Context context) + public static int getConfiguredControllerType(Settings settings) { - return PreferenceManager.getDefaultSharedPreferences(context) - .getInt("wiiController", OVERLAY_WIIMOTE_NUNCHUK); - } + IntSetting controllerSetting = NativeLibrary.IsEmulatingWii() ? + IntSetting.MAIN_OVERLAY_WII_CONTROLLER : IntSetting.MAIN_OVERLAY_GC_CONTROLLER; + int controllerIndex = controllerSetting.getInt(settings); - private int getConfiguredControllerType() - { - return mPreferences.getInt("wiiController", OVERLAY_WIIMOTE_NUNCHUK); + if (controllerIndex >= 0 && controllerIndex < 4) + { + // GameCube controller + if (IntSetting.getSettingForSIDevice(controllerIndex).getInt(settings) == 6) + return OVERLAY_GAMECUBE; + } + else if (controllerIndex >= 4 && controllerIndex < 8) + { + // Wii Remote + int wiimoteIndex = controllerIndex - 4; + if (IntSetting.getSettingForWiimoteSource(wiimoteIndex).getInt(settings) == 1) + { + int attachmentIndex = EmulatedController.getSelectedWiimoteAttachment(wiimoteIndex); + switch (attachmentIndex) + { + case 1: + return OVERLAY_WIIMOTE_NUNCHUK; + case 2: + return OVERLAY_WIIMOTE_CLASSIC; + } + + NumericSetting sidewaysSetting = EmulatedController.getSidewaysWiimoteSetting(wiimoteIndex); + boolean sideways = new InputMappingBooleanSetting(sidewaysSetting).getBoolean(settings); + + return sideways ? OVERLAY_WIIMOTE_SIDEWAYS : OVERLAY_WIIMOTE; + } + } + + return OVERLAY_NONE; } - private void saveControlPosition(int sharedPrefsId, int x, int y, int controller, - String orientation) + private void saveControlPosition(int sharedPrefsId, int x, int y, String orientation) { final SharedPreferences sPrefs = PreferenceManager.getDefaultSharedPreferences(getContext()); SharedPreferences.Editor sPrefsEditor = sPrefs.edit(); - sPrefsEditor.putFloat(getXKey(sharedPrefsId, controller, orientation), x); - sPrefsEditor.putFloat(getYKey(sharedPrefsId, controller, orientation), y); + sPrefsEditor.putFloat(getXKey(sharedPrefsId, mControllerType, orientation), x); + sPrefsEditor.putFloat(getYKey(sharedPrefsId, mControllerType, orientation), y); sPrefsEditor.apply(); } @@ -985,7 +996,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener * @param control Control identifier for the button the InputOverlayDrawableButton represents. * @return An {@link InputOverlayDrawableButton} with the correct drawing bounds set. */ - private static InputOverlayDrawableButton initializeOverlayButton(Context context, + private InputOverlayDrawableButton initializeOverlayButton(Context context, int defaultResId, int pressedResId, int legacyId, int control, String orientation) { // Resources handle for fetching the initial Drawable resource. @@ -993,7 +1004,6 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener // SharedPreference to retrieve the X and Y coordinates for the InputOverlayDrawableButton. final SharedPreferences sPrefs = PreferenceManager.getDefaultSharedPreferences(context); - int controller = getConfiguredControllerType(context); // Decide scale based on button ID and user preference float scale; @@ -1019,7 +1029,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener break; case ButtonType.WIIMOTE_BUTTON_1: case ButtonType.WIIMOTE_BUTTON_2: - if (controller == 2) + if (mControllerType == OVERLAY_WIIMOTE_SIDEWAYS) scale = 0.14f; else scale = 0.0875f; @@ -1057,8 +1067,8 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener // The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay. // These were set in the input overlay configuration menu. - int drawableX = (int) sPrefs.getFloat(getXKey(legacyId, controller, orientation), 0f); - int drawableY = (int) sPrefs.getFloat(getYKey(legacyId, controller, orientation), 0f); + int drawableX = (int) sPrefs.getFloat(getXKey(legacyId, mControllerType, orientation), 0f); + int drawableY = (int) sPrefs.getFloat(getYKey(legacyId, mControllerType, orientation), 0f); int width = overlayDrawable.getWidth(); int height = overlayDrawable.getHeight(); @@ -1088,7 +1098,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener * @param rightControl Control identifier for the right button. * @return the initialized {@link InputOverlayDrawableDpad} */ - private static InputOverlayDrawableDpad initializeOverlayDpad(Context context, + private InputOverlayDrawableDpad initializeOverlayDpad(Context context, int defaultResId, int pressedOneDirectionResId, int pressedTwoDirectionsResId, @@ -1104,7 +1114,6 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener // SharedPreference to retrieve the X and Y coordinates for the InputOverlayDrawableDpad. final SharedPreferences sPrefs = PreferenceManager.getDefaultSharedPreferences(context); - int controller = getConfiguredControllerType(context); // Decide scale based on button ID and user preference float scale; @@ -1118,7 +1127,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener scale = 0.275f; break; default: - if (controller == 2 || controller == 1) + if (mControllerType == OVERLAY_WIIMOTE_SIDEWAYS || mControllerType == OVERLAY_WIIMOTE) scale = 0.275f; else scale = 0.2125f; @@ -1144,8 +1153,8 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener // The X and Y coordinates of the InputOverlayDrawableDpad on the InputOverlay. // These were set in the input overlay configuration menu. - int drawableX = (int) sPrefs.getFloat(getXKey(legacyId, controller, orientation), 0f); - int drawableY = (int) sPrefs.getFloat(getYKey(legacyId, controller, orientation), 0f); + int drawableX = (int) sPrefs.getFloat(getXKey(legacyId, mControllerType, orientation), 0f); + int drawableY = (int) sPrefs.getFloat(getYKey(legacyId, mControllerType, orientation), 0f); int width = overlayDrawable.getWidth(); int height = overlayDrawable.getHeight(); @@ -1173,16 +1182,15 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener * @param yControl Control identifier for the Y axis. * @return the initialized {@link InputOverlayDrawableJoystick}. */ - private static InputOverlayDrawableJoystick initializeOverlayJoystick(Context context, - int resOuter, int defaultResInner, int pressedResInner, int legacyId, int xControl, - int yControl, String orientation) + private InputOverlayDrawableJoystick initializeOverlayJoystick(Context context, int resOuter, + int defaultResInner, int pressedResInner, int legacyId, int xControl, int yControl, + String orientation) { // Resources handle for fetching the initial Drawable resource. final Resources res = context.getResources(); // SharedPreference to retrieve the X and Y coordinates for the InputOverlayDrawableJoystick. final SharedPreferences sPrefs = PreferenceManager.getDefaultSharedPreferences(context); - int controller = getConfiguredControllerType(context); // Decide scale based on user preference float scale = 0.275f; @@ -1197,8 +1205,8 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener // The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay. // These were set in the input overlay configuration menu. - int drawableX = (int) sPrefs.getFloat(getXKey(legacyId, controller, orientation), 0f); - int drawableY = (int) sPrefs.getFloat(getYKey(legacyId, controller, orientation), 0f); + int drawableX = (int) sPrefs.getFloat(getXKey(legacyId, mControllerType, orientation), 0f); + int drawableY = (int) sPrefs.getFloat(getYKey(legacyId, mControllerType, orientation), 0f); // Decide inner scale based on joystick ID float innerScale; diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java index 45f2960bd9..bb2f45de43 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java @@ -85,14 +85,6 @@ public final class DirectoryInitialization checkThemeSettings(context); - // TODO: Does doing this still make sense? - if (false) - { - // This has to be done after calling NativeLibrary.Initialize(), - // as it relies on the config system - EmulationActivity.updateWiimoteNewIniPreferences(context); - } - directoryState.postValue(DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED); } -- cgit v1.2.3 From 6b5f82c12f0230c1595fd6c4cdff8239013b6886 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 28 Jun 2022 23:24:24 +0200 Subject: Android: Change how the overlay controller setting works, part 2 The previous commit wasn't enough for getting inputs to work for controllers 2-4. --- .../dolphinemu/overlay/InputOverlay.java | 85 +++++++++++++--------- .../overlay/InputOverlayDrawableJoystick.java | 10 ++- .../dolphinemu/overlay/InputOverlayPointer.java | 10 ++- 3 files changed, 67 insertions(+), 38 deletions(-) (limited to 'Source/Android/app/src/main/java') diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlay.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlay.java index 1fed472b56..f0a212248f 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlay.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlay.java @@ -39,6 +39,7 @@ import org.dolphinemu.dolphinemu.features.settings.model.IntSetting; import org.dolphinemu.dolphinemu.features.settings.model.Settings; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.Set; @@ -67,10 +68,11 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener private Rect mSurfacePosition = null; private boolean mIsFirstRun = true; - private boolean mGameCubeRegistered = false; - private boolean mWiiRegistered = false; + private boolean[] mGcPadRegistered = new boolean[4]; + private boolean[] mWiimoteRegistered = new boolean[4]; private boolean mIsInEditMode = false; private int mControllerType = -1; + private int mControllerIndex = 0; private InputOverlayDrawableButton mButtonBeingConfigured; private InputOverlayDrawableDpad mDpadBeingConfigured; private InputOverlayDrawableJoystick mJoystickBeingConfigured; @@ -184,7 +186,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener overlayPointer = new InputOverlayPointer(mSurfacePosition, doubleTapControl, IntSetting.MAIN_IR_MODE.getIntGlobal(), - BooleanSetting.MAIN_IR_ALWAYS_RECENTER.getBooleanGlobal()); + BooleanSetting.MAIN_IR_ALWAYS_RECENTER.getBooleanGlobal(), mControllerIndex); } @Override @@ -237,11 +239,11 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener button.setPressedState(true); button.setTrackId(event.getPointerId(pointerIndex)); pressed = true; - InputOverrider.setControlState(0, button.getControl(), 1.0); + InputOverrider.setControlState(mControllerIndex, button.getControl(), 1.0); int analogControl = getAnalogControlForTrigger(button.getControl()); if (analogControl >= 0) - InputOverrider.setControlState(0, analogControl, 1.0); + InputOverrider.setControlState(mControllerIndex, analogControl, 1.0); } break; case MotionEvent.ACTION_UP: @@ -250,11 +252,11 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener if (button.getTrackId() == event.getPointerId(pointerIndex)) { button.setPressedState(false); - InputOverrider.setControlState(0, button.getControl(), 0.0); + InputOverrider.setControlState(mControllerIndex, button.getControl(), 0.0); int analogControl = getAnalogControlForTrigger(button.getControl()); if (analogControl >= 0) - InputOverrider.setControlState(0, analogControl, 0.0); + InputOverrider.setControlState(mControllerIndex, analogControl, 0.0); button.setTrackId(-1); } @@ -296,7 +298,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener { if (!dpadPressed[i]) { - InputOverrider.setControlState(0, dpad.getControl(i), 0.0); + InputOverrider.setControlState(mControllerIndex, dpad.getControl(i), 0.0); } } // Press buttons @@ -304,7 +306,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener { if (dpadPressed[i]) { - InputOverrider.setControlState(0, dpad.getControl(i), 1.0); + InputOverrider.setControlState(mControllerIndex, dpad.getControl(i), 1.0); } } setDpadState(dpad, dpadPressed[0], dpadPressed[1], dpadPressed[2], dpadPressed[3]); @@ -318,7 +320,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener for (int i = 0; i < 4; i++) { dpad.setState(InputOverlayDrawableDpad.STATE_DEFAULT); - InputOverrider.setControlState(0, dpad.getControl(i), 0.0); + InputOverrider.setControlState(mControllerIndex, dpad.getControl(i), 0.0); } dpad.setTrackId(-1); } @@ -334,16 +336,18 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener pressed = true; } - InputOverrider.setControlState(0, joystick.getXControl(), joystick.getX()); - InputOverrider.setControlState(0, joystick.getYControl(), -joystick.getY()); + InputOverrider.setControlState(mControllerIndex, joystick.getXControl(), joystick.getX()); + InputOverrider.setControlState(mControllerIndex, joystick.getYControl(), -joystick.getY()); } // No button/joystick pressed, safe to move pointer if (!pressed && overlayPointer != null) { overlayPointer.onTouch(event); - InputOverrider.setControlState(0, ControlId.WIIMOTE_IR_X, overlayPointer.getX()); - InputOverrider.setControlState(0, ControlId.WIIMOTE_IR_Y, -overlayPointer.getY()); + InputOverrider.setControlState(mControllerIndex, ControlId.WIIMOTE_IR_X, + overlayPointer.getX()); + InputOverrider.setControlState(mControllerIndex, ControlId.WIIMOTE_IR_Y, + -overlayPointer.getY()); } invalidate(); @@ -483,14 +487,20 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener private void unregisterControllers() { - if (mGameCubeRegistered) - InputOverrider.unregisterGameCube(0); + for (int i = 0; i < mGcPadRegistered.length; i++) + { + if (mGcPadRegistered[i]) + InputOverrider.unregisterGameCube(i); + } - if (mWiiRegistered) - InputOverrider.unregisterWii(0); + for (int i = 0; i < mWiimoteRegistered.length; i++) + { + if (mWiimoteRegistered[i]) + InputOverrider.unregisterWii(i); + } - mGameCubeRegistered = false; - mWiiRegistered = false; + Arrays.fill(mGcPadRegistered, false); + Arrays.fill(mWiimoteRegistered, false); } private int getAnalogControlForTrigger(int control) @@ -797,16 +807,16 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener mControllerType = getConfiguredControllerType(settings); + IntSetting controllerSetting = NativeLibrary.IsEmulatingWii() ? + IntSetting.MAIN_OVERLAY_WII_CONTROLLER : IntSetting.MAIN_OVERLAY_GC_CONTROLLER; + int controllerIndex = controllerSetting.getInt(settings); + if (BooleanSetting.MAIN_SHOW_INPUT_OVERLAY.getBooleanGlobal()) { // Add all the enabled overlay items back to the HashSet. switch (mControllerType) { case OVERLAY_GAMECUBE: - IntSetting controllerSetting = NativeLibrary.IsEmulatingWii() ? - IntSetting.MAIN_OVERLAY_WII_CONTROLLER : IntSetting.MAIN_OVERLAY_GC_CONTROLLER; - int controllerIndex = controllerSetting.getInt(settings); - if (IntSetting.getSettingForSIDevice(controllerIndex).getInt(settings) == DISABLED_GAMECUBE_CONTROLLER && mIsFirstRun) { @@ -814,28 +824,36 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener .show(); } - InputOverrider.registerGameCube(0); - mGameCubeRegistered = true; + mControllerIndex = controllerIndex; + InputOverrider.registerGameCube(mControllerIndex); + mGcPadRegistered[mControllerIndex] = true; + addGameCubeOverlayControls(orientation); break; case OVERLAY_WIIMOTE: case OVERLAY_WIIMOTE_SIDEWAYS: - InputOverrider.registerWii(0); - mWiiRegistered = true; + mControllerIndex = controllerIndex - 4; + InputOverrider.registerWii(mControllerIndex); + mWiimoteRegistered[mControllerIndex] = true; + addWiimoteOverlayControls(orientation); break; case OVERLAY_WIIMOTE_NUNCHUK: - InputOverrider.registerWii(0); - mWiiRegistered = true; + mControllerIndex = controllerIndex - 4; + InputOverrider.registerWii(mControllerIndex); + mWiimoteRegistered[mControllerIndex] = true; + addWiimoteOverlayControls(orientation); addNunchukOverlayControls(orientation); break; case OVERLAY_WIIMOTE_CLASSIC: - InputOverrider.registerWii(0); - mWiiRegistered = true; + mControllerIndex = controllerIndex - 4; + InputOverrider.registerWii(mControllerIndex); + mWiimoteRegistered[mControllerIndex] = true; + addClassicOverlayControls(orientation); break; @@ -1229,7 +1247,8 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener // Send the drawableId to the joystick so it can be referenced when saving control position. final InputOverlayDrawableJoystick overlayDrawable = new InputOverlayDrawableJoystick(res, bitmapOuter, bitmapInnerDefault, - bitmapInnerPressed, outerRect, innerRect, legacyId, xControl, yControl); + bitmapInnerPressed, outerRect, innerRect, legacyId, xControl, yControl, + mControllerIndex); // Need to set the image's position overlayDrawable.setPosition(drawableX, drawableY); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableJoystick.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableJoystick.java index d580df7349..ee8c852610 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableJoystick.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableJoystick.java @@ -31,6 +31,7 @@ public final class InputOverlayDrawableJoystick private int mPreviousTouchX, mPreviousTouchY; private final int mWidth; private final int mHeight; + private final int mControllerIndex; private Rect mVirtBounds; private Rect mOrigBounds; private int mOpacity; @@ -55,7 +56,7 @@ public final class InputOverlayDrawableJoystick */ public InputOverlayDrawableJoystick(Resources res, Bitmap bitmapOuter, Bitmap bitmapInnerDefault, Bitmap bitmapInnerPressed, Rect rectOuter, Rect rectInner, int legacyId, int xControl, - int yControl) + int yControl, int controllerIndex) { mJoystickLegacyId = legacyId; mJoystickXControl = xControl; @@ -68,6 +69,10 @@ public final class InputOverlayDrawableJoystick mWidth = bitmapOuter.getWidth(); mHeight = bitmapOuter.getHeight(); + if (controllerIndex < 0 || controllerIndex >= 4) + throw new IllegalArgumentException("controllerIndex must be 0-3"); + mControllerIndex = controllerIndex; + setBounds(rectOuter); mDefaultStateInnerBitmap.setBounds(rectInner); mPressedStateInnerBitmap.setBounds(rectInner); @@ -221,7 +226,8 @@ public final class InputOverlayDrawableJoystick double angle = Math.atan2(y, x) + Math.PI + Math.PI; double radius = Math.hypot(y, x); - double maxRadius = InputOverrider.getGateRadiusAtAngle(0, mJoystickXControl, angle); + double maxRadius = InputOverrider.getGateRadiusAtAngle(mControllerIndex, mJoystickXControl, + angle); if (radius > maxRadius) { y = maxRadius * Math.sin(angle); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayPointer.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayPointer.java index 18de4f4b47..1d96f5c617 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayPointer.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayPointer.java @@ -32,6 +32,7 @@ public class InputOverlayPointer private int mMode; private boolean mRecenter; + private int mControllerIndex; private boolean doubleTap = false; private int mDoubleTapControl; @@ -47,11 +48,13 @@ public class InputOverlayPointer DOUBLE_TAP_OPTIONS.add(NativeLibrary.ButtonType.CLASSIC_BUTTON_A); } - public InputOverlayPointer(Rect surfacePosition, int doubleTapControl, int mode, boolean recenter) + public InputOverlayPointer(Rect surfacePosition, int doubleTapControl, int mode, boolean recenter, + int controllerIndex) { mDoubleTapControl = doubleTapControl; mMode = mode; mRecenter = recenter; + mControllerIndex = controllerIndex; mGameCenterX = (surfacePosition.left + surfacePosition.right) / 2.0f; mGameCenterY = (surfacePosition.top + surfacePosition.bottom) / 2.0f; @@ -128,8 +131,9 @@ public class InputOverlayPointer { if (doubleTap) { - InputOverrider.setControlState(0, mDoubleTapControl, 1.0); - new Handler().postDelayed(() -> InputOverrider.setControlState(0, mDoubleTapControl, 0.0), + InputOverrider.setControlState(mControllerIndex, mDoubleTapControl, 1.0); + new Handler().postDelayed(() -> InputOverrider.setControlState(mControllerIndex, + mDoubleTapControl, 0.0), 50); } else -- cgit v1.2.3 From 1788a797e76779c568de88605d567b1407cb992d Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 17 Sep 2022 16:10:45 +0200 Subject: Android: Add "more settings" button to overlay control setting dialog Some people might wonder where the ability to select an extension and the Sideways Wii Remote went. This button will take them to the general settings, which is where those settings now live. At some point in the future, we should probably move everything to the general settings. But this pull request is already big enough as it is! --- .../java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Source/Android/app/src/main/java') diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java index 9780f8de7b..9aebeb1ded 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java @@ -1015,6 +1015,8 @@ public final class EmulationActivity extends AppCompatActivity implements ThemeP editor.apply(); mEmulationFragment.refreshInputOverlay(mSettings); }) + .setNeutralButton(R.string.emulation_more_controller_settings, + (dialogInterface, i) -> SettingsActivity.launch(this, MenuTag.SETTINGS)) .show(); } -- cgit v1.2.3 From 75fb1a7edfb12f490b08ab0b76a8e2f1536d2d9b Mon Sep 17 00:00:00 2001 From: JosJuice Date: Mon, 6 Mar 2023 19:03:53 +0100 Subject: Android: Disable input device sensor input due to crash --- .../features/input/model/DolphinSensorEventListener.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'Source/Android/app/src/main/java') diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinSensorEventListener.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinSensorEventListener.java index cfc4f34dd7..78d0e4785d 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinSensorEventListener.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/DolphinSensorEventListener.java @@ -89,7 +89,13 @@ public class DolphinSensorEventListener implements SensorEventListener { mSensorManager = inputDevice.getSensorManager(); - addSensors(); + // TODO: There is a bug where after suspending sensors, onSensorChanged can get called for + // a sensor that we never registered as a listener for. The way our code is currently written, + // this causes a NullPointerException, but if we checked for null we would instead have the + // problem of being spammed with onSensorChanged calls even though the sensor shouldn't be + // enabled. For now, let's comment out the ability to use InputDevice sensors. + + //addSensors(); } else { -- cgit v1.2.3