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 844d877ac6..31334403a8 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,6 +12,7 @@ import org.dolphinemu.dolphinemu.model.settings.view.InputBindingSetting; import org.dolphinemu.dolphinemu.utils.ControllerMappingHelper; import org.dolphinemu.dolphinemu.utils.Log; +import java.util.ArrayList; import java.util.List; /** @@ -22,7 +23,8 @@ public final class MotionAlertDialog extends AlertDialog { // The selected input preference private final InputBindingSetting setting; - private final ControllerMappingHelper mControllerMappingHelper; + private final ArrayList mPreviousValues = new ArrayList<>(); + private int mPrevDeviceId = 0; private boolean mWaitingForEvent = true; /** @@ -36,7 +38,6 @@ public final class MotionAlertDialog extends AlertDialog super(context); this.setting = setting; - this.mControllerMappingHelper = new ControllerMappingHelper(); } public boolean onKeyEvent(int keyCode, KeyEvent event) @@ -45,7 +46,7 @@ public final class MotionAlertDialog extends AlertDialog switch (event.getAction()) { case KeyEvent.ACTION_DOWN: - if (!mControllerMappingHelper.shouldKeyBeIgnored(event.getDevice(), keyCode)) + if (!ControllerMappingHelper.shouldKeyBeIgnored(event.getDevice(), keyCode)) { saveKeyInput(event); } @@ -82,34 +83,63 @@ public final class MotionAlertDialog extends AlertDialog 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) { - // Get only the axis that seem to have moved (more than .5) - for (InputDevice.MotionRange range : motionRanges) + for (int i = 0; i < motionRanges.size(); i++) { + InputDevice.MotionRange range = motionRanges.get(i); int axis = range.getAxis(); float origValue = event.getAxisValue(axis); - float value = mControllerMappingHelper.scaleAxis(input, axis, origValue); - if (Math.abs(value) > 0.5f) + float value = ControllerMappingHelper.scaleAxis(input, axis, origValue); + if (firstEvent) { - // 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) + 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) { - axisMoveValue = value; numMovedAxis++; lastMovedRange = range; - lastMovedDir = value < 0.0f ? '-' : '+'; + lastMovedDir = previousValue < 0.0f ? '-' : '+'; } } + + mPreviousValues.set(i, value); } // If only one axis moved, that's the winner. 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 index 69edc7a448..a579b2d70f 100644 --- 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 @@ -8,7 +8,7 @@ import android.view.MotionEvent; public class ControllerMappingHelper { /** Some controllers report extra button presses that can be ignored. */ - public boolean shouldKeyBeIgnored(InputDevice inputDevice, int keyCode) + public static boolean shouldKeyBeIgnored(InputDevice inputDevice, int keyCode) { if (isDualShock4(inputDevice)) { // The two analog triggers generate analog motion events as well as a keycode. @@ -20,7 +20,7 @@ public class ControllerMappingHelper } /** Scale an axis to be zero-centered with a proper range. */ - public float scaleAxis(InputDevice inputDevice, int axis, float value) + public static float scaleAxis(InputDevice inputDevice, int axis, float value) { if (isDualShock4(inputDevice)) { @@ -39,38 +39,19 @@ public class ControllerMappingHelper { return (value + 1) / 2.0f; } - if (axis == MotionEvent.AXIS_GENERIC_1) - { - // This axis is stuck at ~.5. Ignore it. - return 0.0f; - } - } - else if (isMogaPro2Hid(inputDevice)) - { - // This controller has a broken axis that reports a constant value. Ignore it. - if (axis == MotionEvent.AXIS_GENERIC_1) - { - return 0.0f; - } } return value; } - private boolean isDualShock4(InputDevice inputDevice) + private static boolean isDualShock4(InputDevice inputDevice) { // Sony DualShock 4 controller return inputDevice.getVendorId() == 0x54c && inputDevice.getProductId() == 0x9cc; } - private boolean isXboxOneWireless(InputDevice inputDevice) + private static boolean isXboxOneWireless(InputDevice inputDevice) { // Microsoft Xbox One controller return inputDevice.getVendorId() == 0x45e && inputDevice.getProductId() == 0x2e0; } - - private boolean isMogaPro2Hid(InputDevice inputDevice) - { - // Moga Pro 2 HID - return inputDevice.getVendorId() == 0x20d6 && inputDevice.getProductId() == 0x6271; - } }