summaryrefslogtreecommitdiff
path: root/Source/Android/app/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Android/app/src/main/java')
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java8
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/MotionAlertDialog.java35
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/ControllerMappingHelper.java62
3 files changed, 96 insertions, 9 deletions
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 2adb2f209d..4688cbce05 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,6 +39,7 @@ import org.dolphinemu.dolphinemu.fragments.SaveLoadStateFragment;
import org.dolphinemu.dolphinemu.ui.main.MainPresenter;
import org.dolphinemu.dolphinemu.ui.platform.Platform;
import org.dolphinemu.dolphinemu.utils.Animations;
+import org.dolphinemu.dolphinemu.utils.ControllerMappingHelper;
import org.dolphinemu.dolphinemu.utils.Java_GCAdapter;
import org.dolphinemu.dolphinemu.utils.Java_WiimoteAdapter;
import org.dolphinemu.dolphinemu.utils.Log;
@@ -57,6 +58,7 @@ public final class EmulationActivity extends AppCompatActivity
private EmulationFragment mEmulationFragment;
private SharedPreferences mPreferences;
+ private ControllerMappingHelper mControllerMappingHelper;
// So that MainActivity knows which view to invalidate before the return animation.
private int mPosition;
@@ -164,6 +166,7 @@ public final class EmulationActivity extends AppCompatActivity
mScreenPath = gameToEmulate.getStringExtra("ScreenPath");
mPosition = gameToEmulate.getIntExtra("GridPosition", -1);
mDeviceHasTouchScreen = getPackageManager().hasSystemFeature("android.hardware.touchscreen");
+ mControllerMappingHelper = new ControllerMappingHelper();
int themeId;
if (mDeviceHasTouchScreen)
@@ -729,7 +732,10 @@ public final class EmulationActivity extends AppCompatActivity
for (InputDevice.MotionRange range : motions)
{
- NativeLibrary.onGamePadMoveEvent(input.getDescriptor(), range.getAxis(), event.getAxisValue(range.getAxis()));
+ int axis = range.getAxis();
+ float origValue = event.getAxisValue(axis);
+ float value = mControllerMappingHelper.scaleAxis(input, axis, origValue);
+ NativeLibrary.onGamePadMoveEvent(input.getDescriptor(), axis, value);
}
return true;
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 592aee6838..844d877ac6 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
@@ -9,6 +9,7 @@ import android.view.KeyEvent;
import android.view.MotionEvent;
import org.dolphinemu.dolphinemu.model.settings.view.InputBindingSetting;
+import org.dolphinemu.dolphinemu.utils.ControllerMappingHelper;
import org.dolphinemu.dolphinemu.utils.Log;
import java.util.List;
@@ -21,6 +22,7 @@ public final class MotionAlertDialog extends AlertDialog
{
// The selected input preference
private final InputBindingSetting setting;
+ private final ControllerMappingHelper mControllerMappingHelper;
private boolean mWaitingForEvent = true;
/**
@@ -34,6 +36,7 @@ public final class MotionAlertDialog extends AlertDialog
super(context);
this.setting = setting;
+ this.mControllerMappingHelper = new ControllerMappingHelper();
}
public boolean onKeyEvent(int keyCode, KeyEvent event)
@@ -42,8 +45,11 @@ public final class MotionAlertDialog extends AlertDialog
switch (event.getAction())
{
case KeyEvent.ACTION_DOWN:
- saveKeyInput(event);
-
+ if (!mControllerMappingHelper.shouldKeyBeIgnored(event.getDevice(), keyCode))
+ {
+ saveKeyInput(event);
+ }
+ // Even if we ignore the key, we still consume it. Thus return true regardless.
return true;
default:
@@ -69,13 +75,15 @@ public final class MotionAlertDialog extends AlertDialog
{
if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0)
return false;
-
- Log.debug("[MotionAlertDialog] Received motion event: " + event.getAction());
+ if (event.getAction() != MotionEvent.ACTION_MOVE)
+ return false;
InputDevice input = event.getDevice();
+
List<InputDevice.MotionRange> motionRanges = input.getMotionRanges();
int numMovedAxis = 0;
+ float axisMoveValue = 0.0f;
InputDevice.MotionRange lastMovedRange = null;
char lastMovedDir = '?';
if (mWaitingForEvent)
@@ -84,12 +92,23 @@ public final class MotionAlertDialog extends AlertDialog
for (InputDevice.MotionRange range : motionRanges)
{
int axis = range.getAxis();
- float value = event.getAxisValue(axis);
+ float origValue = event.getAxisValue(axis);
+ float value = mControllerMappingHelper.scaleAxis(input, axis, origValue);
if (Math.abs(value) > 0.5f)
{
- numMovedAxis++;
- lastMovedRange = range;
- lastMovedDir = value < 0.0f ? '-' : '+';
+ // It is common to have multiple axis 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 axis 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 ? '-' : '+';
+ }
}
}
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
new file mode 100644
index 0000000000..1cdc07604a
--- /dev/null
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/ControllerMappingHelper.java
@@ -0,0 +1,62 @@
+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 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
+ // Even though the triggers are L/R2, without mappings they generate L/R1 events.
+ return keyCode == KeyEvent.KEYCODE_BUTTON_L1 || keyCode == KeyEvent.KEYCODE_BUTTON_R1;
+ }
+ return false;
+ }
+
+ /** Scale an axis to be zero-centered with a proper range. */
+ public 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;
+ }
+ if (axis == MotionEvent.AXIS_GENERIC_1)
+ {
+ // This axis is stuck at ~.5. Ignore it.
+ return 0.0f;
+ }
+ }
+ return value;
+ }
+
+ private boolean isDualShock4(InputDevice inputDevice)
+ {
+ // Sony DualShock 4 controller
+ return inputDevice.getVendorId() == 0x54c && inputDevice.getProductId() == 0x9cc;
+ }
+
+ private boolean isXboxOneWireless(InputDevice inputDevice)
+ {
+ // Microsoft Xbox One controller
+ return inputDevice.getVendorId() == 0x45e && inputDevice.getProductId() == 0x2e0;
+ }
+}