diff --git a/src/android/app/src/main/java/org/citra/citra_android/dialogs/MotionAlertDialog.java b/src/android/app/src/main/java/org/citra/citra_android/dialogs/MotionAlertDialog.java index 4fbf32b96..f355b7f83 100644 --- a/src/android/app/src/main/java/org/citra/citra_android/dialogs/MotionAlertDialog.java +++ b/src/android/app/src/main/java/org/citra/citra_android/dialogs/MotionAlertDialog.java @@ -3,6 +3,7 @@ package org.citra.citra_android.dialogs; import android.app.AlertDialog; import android.content.Context; import android.content.SharedPreferences; +import android.os.Vibrator; import android.preference.PreferenceManager; import android.view.InputDevice; import android.view.KeyEvent; @@ -12,16 +13,19 @@ import org.citra.citra_android.model.settings.view.InputBindingSetting; import org.citra.citra_android.utils.ControllerMappingHelper; import org.citra.citra_android.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 { +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; /** @@ -30,20 +34,21 @@ public final class MotionAlertDialog extends AlertDialog { * @param context The current {@link Context}. * @param setting The Preference to show this dialog for. */ - public MotionAlertDialog(Context context, InputBindingSetting setting) { + public MotionAlertDialog(Context context, InputBindingSetting setting) + { super(context); this.setting = setting; - this.mControllerMappingHelper = new ControllerMappingHelper(); } - public boolean onKeyEvent(int keyCode, KeyEvent event) { + public boolean onKeyEvent(int keyCode, KeyEvent event) + { Log.debug("[MotionAlertDialog] Received key event: " + event.getAction()); - switch (event.getAction()) { - case KeyEvent.ACTION_DOWN: - if (!mControllerMappingHelper.shouldKeyBeIgnored(event.getDevice(), keyCode)) { - saveKeyInput(event); - } + switch (event.getAction()) + { + case KeyEvent.ACTION_UP: + setting.onKeyInput(event); + dismiss(); // Even if we ignore the key, we still consume it. Thus return true regardless. return true; @@ -53,18 +58,27 @@ public final class MotionAlertDialog extends AlertDialog { } @Override - public boolean dispatchKeyEvent(KeyEvent event) { + public boolean onKeyLongPress(int keyCode, KeyEvent event) + { + 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(MotionEvent event) { + public boolean dispatchGenericMotionEvent(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) { + private boolean onMotionEvent(MotionEvent event) + { if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0) return false; if (event.getAction() != MotionEvent.ACTION_MOVE) @@ -74,85 +88,73 @@ 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) { + if (mWaitingForEvent) + { + 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) { - // 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; + float value = origValue;//ControllerMappingHelper.scaleAxis(input, axis, origValue); + 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 = value < 0.0f ? '-' : '+'; + lastMovedDir = previousValue < 0.0f ? '-' : '+'; } } + + mPreviousValues.set(i, value); } // If only one axis moved, that's the winner. - if (numMovedAxis == 1) { + if (numMovedAxis == 1) + { mWaitingForEvent = false; - saveMotionInput(input, lastMovedRange, lastMovedDir); + setting.onMotionInput(input, lastMovedRange, lastMovedDir); + dismiss(); } } - return true; } - - /** - * 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. - */ - private void saveKeyInput(KeyEvent keyEvent) { - InputDevice device = keyEvent.getDevice(); - String bindStr = "Device '" + device.getDescriptor() + "'-Button " + keyEvent.getKeyCode(); - String uiString = device.getName() + ": Button " + keyEvent.getKeyCode(); - - saveInput(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 '+' - */ - private void saveMotionInput(InputDevice device, InputDevice.MotionRange motionRange, - char axisDir) { - String bindStr = - "Device '" + device.getDescriptor() + "'-Axis " + motionRange.getAxis() + axisDir; - String uiString = device.getName() + ": Axis " + motionRange.getAxis() + axisDir; - - saveInput(bindStr, uiString); - } - - /** - * Save the input string to settings and SharedPreferences, then dismiss this Dialog. - */ - private void saveInput(String bind, String ui) { - setting.setValue(bind); - - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getContext()); - SharedPreferences.Editor editor = preferences.edit(); - - editor.putString(setting.getKey(), ui); - editor.apply(); - - dismiss(); - } -} +} \ No newline at end of file