Merge pull request #10371 from lynxnb/android-ir

Android: add two QoL settings to IR pointer
This commit is contained in:
JosJuice 2022-01-24 18:25:13 +01:00 committed by GitHub
commit b237c7479e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 160 additions and 27 deletions

View File

@ -100,9 +100,10 @@ public final class EmulationActivity extends AppCompatActivity
MENU_ACTION_SAVE_SLOT6, MENU_ACTION_LOAD_SLOT1, MENU_ACTION_LOAD_SLOT2, MENU_ACTION_SAVE_SLOT6, MENU_ACTION_LOAD_SLOT1, MENU_ACTION_LOAD_SLOT2,
MENU_ACTION_LOAD_SLOT3, MENU_ACTION_LOAD_SLOT4, MENU_ACTION_LOAD_SLOT5, 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_LOAD_SLOT6, MENU_ACTION_EXIT, MENU_ACTION_CHANGE_DISC,
MENU_ACTION_RESET_OVERLAY, MENU_SET_IR_SENSITIVITY, MENU_ACTION_CHOOSE_DOUBLETAP, MENU_ACTION_RESET_OVERLAY, MENU_SET_IR_RECENTER, MENU_SET_IR_MODE,
MENU_ACTION_MOTION_CONTROLS, MENU_ACTION_PAUSE_EMULATION, MENU_ACTION_UNPAUSE_EMULATION, MENU_SET_IR_SENSITIVITY, MENU_ACTION_CHOOSE_DOUBLETAP, MENU_ACTION_MOTION_CONTROLS,
MENU_ACTION_OVERLAY_CONTROLS, MENU_ACTION_SETTINGS}) MENU_ACTION_PAUSE_EMULATION, MENU_ACTION_UNPAUSE_EMULATION, MENU_ACTION_OVERLAY_CONTROLS,
MENU_ACTION_SETTINGS})
public @interface MenuAction public @interface MenuAction
{ {
} }
@ -134,13 +135,15 @@ public final class EmulationActivity extends AppCompatActivity
public static final int MENU_ACTION_JOYSTICK_REL_CENTER = 24; public static final int MENU_ACTION_JOYSTICK_REL_CENTER = 24;
public static final int MENU_ACTION_RUMBLE = 25; public static final int MENU_ACTION_RUMBLE = 25;
public static final int MENU_ACTION_RESET_OVERLAY = 26; public static final int MENU_ACTION_RESET_OVERLAY = 26;
public static final int MENU_SET_IR_SENSITIVITY = 27; public static final int MENU_SET_IR_RECENTER = 27;
public static final int MENU_ACTION_CHOOSE_DOUBLETAP = 28; public static final int MENU_SET_IR_MODE = 28;
public static final int MENU_ACTION_MOTION_CONTROLS = 29; public static final int MENU_SET_IR_SENSITIVITY = 29;
public static final int MENU_ACTION_PAUSE_EMULATION = 30; public static final int MENU_ACTION_CHOOSE_DOUBLETAP = 30;
public static final int MENU_ACTION_UNPAUSE_EMULATION = 31; public static final int MENU_ACTION_MOTION_CONTROLS = 31;
public static final int MENU_ACTION_OVERLAY_CONTROLS = 32; public static final int MENU_ACTION_PAUSE_EMULATION = 32;
public static final int MENU_ACTION_SETTINGS = 33; public static final int MENU_ACTION_UNPAUSE_EMULATION = 33;
public static final int MENU_ACTION_OVERLAY_CONTROLS = 34;
public static final int MENU_ACTION_SETTINGS = 35;
private static final SparseIntArray buttonsActionsMap = new SparseIntArray(); private static final SparseIntArray buttonsActionsMap = new SparseIntArray();
@ -159,6 +162,10 @@ public final class EmulationActivity extends AppCompatActivity
buttonsActionsMap.append(R.id.menu_emulation_rumble, EmulationActivity.MENU_ACTION_RUMBLE); buttonsActionsMap.append(R.id.menu_emulation_rumble, EmulationActivity.MENU_ACTION_RUMBLE);
buttonsActionsMap buttonsActionsMap
.append(R.id.menu_emulation_reset_overlay, EmulationActivity.MENU_ACTION_RESET_OVERLAY); .append(R.id.menu_emulation_reset_overlay, EmulationActivity.MENU_ACTION_RESET_OVERLAY);
buttonsActionsMap.append(R.id.menu_emulation_ir_recenter,
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, buttonsActionsMap.append(R.id.menu_emulation_set_ir_sensitivity,
EmulationActivity.MENU_SET_IR_SENSITIVITY); EmulationActivity.MENU_SET_IR_SENSITIVITY);
buttonsActionsMap.append(R.id.menu_emulation_choose_doubletap, buttonsActionsMap.append(R.id.menu_emulation_choose_doubletap,
@ -512,6 +519,11 @@ public final class EmulationActivity extends AppCompatActivity
.setChecked(BooleanSetting.MAIN_JOYSTICK_REL_CENTER.getBoolean(mSettings)); .setChecked(BooleanSetting.MAIN_JOYSTICK_REL_CENTER.getBoolean(mSettings));
menu.findItem(R.id.menu_emulation_rumble) menu.findItem(R.id.menu_emulation_rumble)
.setChecked(BooleanSetting.MAIN_PHONE_RUMBLE.getBoolean(mSettings)); .setChecked(BooleanSetting.MAIN_PHONE_RUMBLE.getBoolean(mSettings));
if (wii)
{
menu.findItem(R.id.menu_emulation_ir_recenter)
.setChecked(BooleanSetting.MAIN_IR_ALWAYS_RECENTER.getBoolean(mSettings));
}
popup.setOnMenuItemClickListener(this::onOptionsItemSelected); popup.setOnMenuItemClickListener(this::onOptionsItemSelected);
@ -550,6 +562,10 @@ public final class EmulationActivity extends AppCompatActivity
item.setChecked(!item.isChecked()); item.setChecked(!item.isChecked());
toggleRumble(item.isChecked()); toggleRumble(item.isChecked());
break; break;
case MENU_SET_IR_RECENTER:
item.setChecked(!item.isChecked());
toggleRecenter(item.isChecked());
break;
} }
} }
@ -676,6 +692,10 @@ public final class EmulationActivity extends AppCompatActivity
startActivityForResult(intent, REQUEST_CHANGE_DISC); startActivityForResult(intent, REQUEST_CHANGE_DISC);
break; break;
case MENU_SET_IR_MODE:
setIRMode();
break;
case MENU_SET_IR_SENSITIVITY: case MENU_SET_IR_SENSITIVITY:
setIRSensitivity(); setIRSensitivity();
break; break;
@ -724,6 +744,12 @@ public final class EmulationActivity extends AppCompatActivity
Rumble.setPhoneVibrator(state, this); Rumble.setPhoneVibrator(state, this);
} }
private void toggleRecenter(boolean state)
{
BooleanSetting.MAIN_IR_ALWAYS_RECENTER.setBoolean(mSettings, state);
mEmulationFragment.refreshOverlayPointer(mSettings);
}
private void editControlsPlacement() private void editControlsPlacement()
{ {
if (mEmulationFragment.isConfiguringControls()) if (mEmulationFragment.isConfiguringControls())
@ -971,6 +997,20 @@ public final class EmulationActivity extends AppCompatActivity
builder.show(); builder.show();
} }
private void setIRMode()
{
AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.DolphinDialogBase);
builder.setTitle(R.string.emulation_ir_mode);
builder.setSingleChoiceItems(R.array.irModeEntries,
IntSetting.MAIN_IR_MODE.getInt(mSettings),
(dialog, indexSelected) ->
IntSetting.MAIN_IR_MODE.setInt(mSettings, indexSelected));
builder.setPositiveButton(R.string.ok, (dialogInterface, i) ->
mEmulationFragment.refreshOverlayPointer(mSettings));
builder.show();
}
private void setIRSensitivity() private void setIRSensitivity()
{ {
// IR settings always get saved per-game since WiimoteNew.ini is wiped upon reinstall. // IR settings always get saved per-game since WiimoteNew.ini is wiped upon reinstall.

View File

@ -71,6 +71,8 @@ public enum BooleanSetting implements AbstractBooleanSetting
"PhoneRumble", true), "PhoneRumble", true),
MAIN_SHOW_INPUT_OVERLAY(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID, MAIN_SHOW_INPUT_OVERLAY(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID,
"ShowInputOverlay", true), "ShowInputOverlay", true),
MAIN_IR_ALWAYS_RECENTER(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID,
"IRAlwaysRecenter", false),
MAIN_BUTTON_TOGGLE_GC_0(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS, MAIN_BUTTON_TOGGLE_GC_0(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleGCButtonA", true), "ButtonToggleGCButtonA", true),

View File

@ -30,6 +30,8 @@ public enum IntSetting implements AbstractIntSetting
"EmulationOrientation", ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE), "EmulationOrientation", ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE),
MAIN_LAST_PLATFORM_TAB(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID, "LastPlatformTab", 0), 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_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),
MAIN_DOUBLE_TAP_BUTTON(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS, MAIN_DOUBLE_TAP_BUTTON(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"DoubleTapButton", "DoubleTapButton",

View File

@ -166,6 +166,12 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
mInputOverlay.refreshControls(); mInputOverlay.refreshControls();
} }
public void refreshOverlayPointer(Settings settings)
{
if (mInputOverlay != null)
mInputOverlay.refreshOverlayPointer(settings);
}
public void resetInputOverlay() public void resetInputOverlay()
{ {
if (mInputOverlay != null) if (mInputOverlay != null)

View File

@ -164,7 +164,9 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
doubleTapButton = InputOverlayPointer.DOUBLE_TAP_A; doubleTapButton = InputOverlayPointer.DOUBLE_TAP_A;
} }
overlayPointer = new InputOverlayPointer(mSurfacePosition, doubleTapButton); overlayPointer = new InputOverlayPointer(mSurfacePosition, doubleTapButton,
IntSetting.MAIN_IR_MODE.getIntGlobal(),
BooleanSetting.MAIN_IR_ALWAYS_RECENTER.getBooleanGlobal());
} }
@Override @Override
@ -769,6 +771,15 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
invalidate(); invalidate();
} }
public void refreshOverlayPointer(Settings settings)
{
if (overlayPointer != null)
{
overlayPointer.setMode(IntSetting.MAIN_IR_MODE.getInt(settings));
overlayPointer.setRecenter(BooleanSetting.MAIN_IR_ALWAYS_RECENTER.getBoolean(settings));
}
}
public void resetButtonPlacement() public void resetButtonPlacement()
{ {
boolean isLandscape = boolean isLandscape =

View File

@ -17,13 +17,24 @@ public class InputOverlayPointer
public static final int DOUBLE_TAP_2 = 2; public static final int DOUBLE_TAP_2 = 2;
public static final int DOUBLE_TAP_CLASSIC_A = 3; public static final int DOUBLE_TAP_CLASSIC_A = 3;
public static final int MODE_DISABLED = 0;
public static final int MODE_FOLLOW = 1;
public static final int MODE_DRAG = 2;
private final float[] axes = {0f, 0f}; private final float[] axes = {0f, 0f};
private final float[] oldaxes = {0f, 0f};
private float mGameCenterX; private float mGameCenterX;
private float mGameCenterY; private float mGameCenterY;
private float mGameWidthHalfInv; private float mGameWidthHalfInv;
private float mGameHeightHalfInv; private float mGameHeightHalfInv;
private float mTouchStartX;
private float mTouchStartY;
private int mMode;
private boolean mRecenter;
private boolean doubleTap = false; private boolean doubleTap = false;
private int doubleTapButton; private int doubleTapButton;
private int trackId = -1; private int trackId = -1;
@ -38,9 +49,11 @@ public class InputOverlayPointer
DOUBLE_TAP_OPTIONS.add(NativeLibrary.ButtonType.CLASSIC_BUTTON_A); DOUBLE_TAP_OPTIONS.add(NativeLibrary.ButtonType.CLASSIC_BUTTON_A);
} }
public InputOverlayPointer(Rect surfacePosition, int button) public InputOverlayPointer(Rect surfacePosition, int button, int mode, boolean recenter)
{ {
doubleTapButton = button; doubleTapButton = button;
mMode = mode;
mRecenter = recenter;
mGameCenterX = (surfacePosition.left + surfacePosition.right) / 2.0f; mGameCenterX = (surfacePosition.left + surfacePosition.right) / 2.0f;
mGameCenterY = (surfacePosition.top + surfacePosition.bottom) / 2.0f; mGameCenterY = (surfacePosition.top + surfacePosition.bottom) / 2.0f;
@ -76,38 +89,69 @@ public class InputOverlayPointer
case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN: case MotionEvent.ACTION_POINTER_DOWN:
trackId = event.getPointerId(pointerIndex); trackId = event.getPointerId(pointerIndex);
mTouchStartX = event.getX(pointerIndex);
mTouchStartY = event.getY(pointerIndex);
touchPress(); touchPress();
break; break;
case MotionEvent.ACTION_UP: case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP: case MotionEvent.ACTION_POINTER_UP:
if (trackId == event.getPointerId(pointerIndex)) if (trackId == event.getPointerId(pointerIndex))
trackId = -1; trackId = -1;
if (mMode == MODE_DRAG)
updateOldAxes();
if (mRecenter)
reset();
break; break;
} }
if (trackId == -1) if (trackId == -1)
return; return;
axes[0] = (event.getY(event.findPointerIndex(trackId)) - mGameCenterY) * mGameHeightHalfInv; if (mMode == MODE_FOLLOW)
axes[1] = (event.getX(event.findPointerIndex(trackId)) - mGameCenterX) * mGameWidthHalfInv; {
axes[0] = (event.getY(event.findPointerIndex(trackId)) - mGameCenterY) * mGameHeightHalfInv;
axes[1] = (event.getX(event.findPointerIndex(trackId)) - mGameCenterX) * mGameWidthHalfInv;
}
else if (mMode == MODE_DRAG)
{
axes[0] = oldaxes[0] +
(event.getY(event.findPointerIndex(trackId)) - mTouchStartY) * mGameHeightHalfInv;
axes[1] = oldaxes[1] +
(event.getX(event.findPointerIndex(trackId)) - mTouchStartX) * mGameWidthHalfInv;
}
} }
private void touchPress() private void touchPress()
{ {
if (doubleTap) if (mMode != MODE_DISABLED)
{ {
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, if (doubleTap)
doubleTapButton, NativeLibrary.ButtonState.PRESSED); {
new Handler().postDelayed(() -> NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice,
doubleTapButton, NativeLibrary.ButtonState.RELEASED), 50); doubleTapButton, NativeLibrary.ButtonState.PRESSED);
} new Handler()
else .postDelayed(() -> NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice,
{ doubleTapButton, NativeLibrary.ButtonState.RELEASED), 50);
doubleTap = true; }
new Handler().postDelayed(() -> doubleTap = false, 300); else
{
doubleTap = true;
new Handler().postDelayed(() -> doubleTap = false, 300);
}
} }
} }
private void updateOldAxes()
{
oldaxes[0] = axes[0];
oldaxes[1] = axes[1];
}
private void reset()
{
axes[0] = axes[1] = oldaxes[0] = oldaxes[1] = 0f;
}
public float[] getAxisValues() public float[] getAxisValues()
{ {
float[] iraxes = {0f, 0f, 0f, 0f}; float[] iraxes = {0f, 0f, 0f, 0f};
@ -117,4 +161,16 @@ public class InputOverlayPointer
iraxes[2] = axes[1]; iraxes[2] = axes[1];
return iraxes; return iraxes;
} }
public void setMode(int mode)
{
mMode = mode;
if (mode == MODE_DRAG)
updateOldAxes();
}
public void setRecenter(boolean recenter)
{
mRecenter = recenter;
}
} }

View File

@ -38,6 +38,13 @@
android:id="@+id/menu_emulation_ir_group" android:id="@+id/menu_emulation_ir_group"
android:title="@string/emulation_ir_group"> android:title="@string/emulation_ir_group">
<menu> <menu>
<item
android:id="@+id/menu_emulation_ir_recenter"
android:checkable="true"
android:title="@string/emulation_ir_recenter"/>
<item
android:id="@+id/menu_emulation_set_ir_mode"
android:title="@string/emulation_ir_mode"/>
<item <item
android:id="@+id/menu_emulation_set_ir_sensitivity" android:id="@+id/menu_emulation_set_ir_sensitivity"
android:title="@string/emulation_ir_sensitivity"/> android:title="@string/emulation_ir_sensitivity"/>

View File

@ -433,6 +433,12 @@
<item>Right Stick</item> <item>Right Stick</item>
</string-array> </string-array>
<string-array name="irModeEntries">
<item>Disabled</item>
<item>Follow</item>
<item>Drag</item>
</string-array>
<string-array name="doubleTap"> <string-array name="doubleTap">
<item>Button A</item> <item>Button A</item>
<item>Button B</item> <item>Button B</item>

View File

@ -545,6 +545,8 @@ It can efficiently compress both junk data and encrypted Wii data.
<string name="emulation_menu_help">Press Back to access the menu.\nLong press Back to exit emulation.</string> <string name="emulation_menu_help">Press Back to access the menu.\nLong press Back to exit emulation.</string>
<string name="emulation_touch_overlay_reset">Reset Overlay</string> <string name="emulation_touch_overlay_reset">Reset Overlay</string>
<string name="emulation_ir_group">Touch IR Pointer</string> <string name="emulation_ir_group">Touch IR Pointer</string>
<string name="emulation_ir_recenter">Always recenter</string>
<string name="emulation_ir_mode">IR Mode</string>
<string name="emulation_ir_sensitivity">IR Sensitivity</string> <string name="emulation_ir_sensitivity">IR Sensitivity</string>
<string name="emulation_choose_doubletap">Double tap button</string> <string name="emulation_choose_doubletap">Double tap button</string>
<string name="emulation_motion_controls">Motion Controls</string> <string name="emulation_motion_controls">Motion Controls</string>

View File

@ -38,9 +38,10 @@ bool IsSettingSaveable(const Config::Location& config_location)
// TODO: Kill the current Android controller mappings system // TODO: Kill the current Android controller mappings system
if (config_location.section == "Android") if (config_location.section == "Android")
{ {
static constexpr std::array<const char*, 8> android_setting_saveable = { static constexpr std::array<const char*, 10> android_setting_saveable = {
"ControlScale", "ControlOpacity", "EmulationOrientation", "JoystickRelCenter", "ControlScale", "ControlOpacity", "EmulationOrientation", "JoystickRelCenter",
"LastPlatformTab", "MotionControls", "PhoneRumble", "ShowInputOverlay"}; "LastPlatformTab", "MotionControls", "PhoneRumble", "ShowInputOverlay",
"IRMode", "IRAlwaysRecenter"};
return std::any_of( return std::any_of(
android_setting_saveable.cbegin(), android_setting_saveable.cend(), android_setting_saveable.cbegin(), android_setting_saveable.cend(),