android: frontend: MotionAlertDialog: Merge latest Dolphin code.

This commit is contained in:
bunnei 2019-08-04 23:15:21 -04:00
parent 628675deb6
commit a64559a4c0

View File

@ -3,6 +3,7 @@ package org.citra.citra_android.dialogs;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Vibrator;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.view.InputDevice; import android.view.InputDevice;
import android.view.KeyEvent; 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.ControllerMappingHelper;
import org.citra.citra_android.utils.Log; import org.citra.citra_android.utils.Log;
import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* {@link AlertDialog} derivative that listens for * {@link AlertDialog} derivative that listens for
* motion events from controllers and joysticks. * motion events from controllers and joysticks.
*/ */
public final class MotionAlertDialog extends AlertDialog { public final class MotionAlertDialog extends AlertDialog
{
// The selected input preference // The selected input preference
private final InputBindingSetting setting; private final InputBindingSetting setting;
private final ControllerMappingHelper mControllerMappingHelper; private final ArrayList<Float> mPreviousValues = new ArrayList<>();
private int mPrevDeviceId = 0;
private boolean mWaitingForEvent = true; private boolean mWaitingForEvent = true;
/** /**
@ -30,20 +34,21 @@ public final class MotionAlertDialog extends AlertDialog {
* @param context The current {@link Context}. * @param context The current {@link Context}.
* @param setting The Preference to show this dialog for. * @param setting The Preference to show this dialog for.
*/ */
public MotionAlertDialog(Context context, InputBindingSetting setting) { public MotionAlertDialog(Context context, InputBindingSetting setting)
{
super(context); super(context);
this.setting = setting; 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()); Log.debug("[MotionAlertDialog] Received key event: " + event.getAction());
switch (event.getAction()) { switch (event.getAction())
case KeyEvent.ACTION_DOWN: {
if (!mControllerMappingHelper.shouldKeyBeIgnored(event.getDevice(), keyCode)) { case KeyEvent.ACTION_UP:
saveKeyInput(event); setting.onKeyInput(event);
} dismiss();
// Even if we ignore the key, we still consume it. Thus return true regardless. // Even if we ignore the key, we still consume it. Thus return true regardless.
return true; return true;
@ -53,18 +58,27 @@ public final class MotionAlertDialog extends AlertDialog {
} }
@Override @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 // Handle this key if we care about it, otherwise pass it down the framework
return onKeyEvent(event.getKeyCode(), event) || super.dispatchKeyEvent(event); return onKeyEvent(event.getKeyCode(), event) || super.dispatchKeyEvent(event);
} }
@Override @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 // Handle this event if we care about it, otherwise pass it down the framework
return onMotionEvent(event) || super.dispatchGenericMotionEvent(event); return onMotionEvent(event) || super.dispatchGenericMotionEvent(event);
} }
private boolean onMotionEvent(MotionEvent event) { private boolean onMotionEvent(MotionEvent event)
{
if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0) if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0)
return false; return false;
if (event.getAction() != MotionEvent.ACTION_MOVE) if (event.getAction() != MotionEvent.ACTION_MOVE)
@ -74,85 +88,73 @@ public final class MotionAlertDialog extends AlertDialog {
List<InputDevice.MotionRange> motionRanges = input.getMotionRanges(); List<InputDevice.MotionRange> motionRanges = input.getMotionRanges();
if (input.getId() != mPrevDeviceId)
{
mPreviousValues.clear();
}
mPrevDeviceId = input.getId();
boolean firstEvent = mPreviousValues.isEmpty();
int numMovedAxis = 0; int numMovedAxis = 0;
float axisMoveValue = 0.0f; float axisMoveValue = 0.0f;
InputDevice.MotionRange lastMovedRange = null; InputDevice.MotionRange lastMovedRange = null;
char lastMovedDir = '?'; char lastMovedDir = '?';
if (mWaitingForEvent) { 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(); int axis = range.getAxis();
float origValue = event.getAxisValue(axis); float origValue = event.getAxisValue(axis);
float value = mControllerMappingHelper.scaleAxis(input, axis, origValue); float value = origValue;//ControllerMappingHelper.scaleAxis(input, axis, origValue);
if (Math.abs(value) > 0.5f) { 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. mPreviousValues.add(value);
// 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 else
// where a joystick is moved in two directions. {
// ref: bottom of https://developer.android.com/training/game-controllers/controller-input.html float previousValue = mPreviousValues.get(i);
if (value != axisMoveValue) {
axisMoveValue = value; // 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++; numMovedAxis++;
lastMovedRange = range; lastMovedRange = range;
lastMovedDir = value < 0.0f ? '-' : '+'; lastMovedDir = previousValue < 0.0f ? '-' : '+';
} }
} }
mPreviousValues.set(i, value);
} }
// If only one axis moved, that's the winner. // If only one axis moved, that's the winner.
if (numMovedAxis == 1) { if (numMovedAxis == 1)
{
mWaitingForEvent = false; mWaitingForEvent = false;
saveMotionInput(input, lastMovedRange, lastMovedDir); setting.onMotionInput(input, lastMovedRange, lastMovedDir);
dismiss();
} }
} }
return true; 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();
}
}