Merge pull request #9624 from JosJuice/input-override
Add new "input override" system for TAS input and Android touch controls
This commit is contained in:
commit
052c7395fb
|
@ -280,9 +280,6 @@ public final class NativeLibrary
|
|||
public static native void SetMotionSensorsEnabled(boolean accelerometerEnabled,
|
||||
boolean gyroscopeEnabled);
|
||||
|
||||
// Angle is in radians and should be non-negative
|
||||
public static native double GetInputRadiusAtAngle(int emu_pad_id, int stick, double angle);
|
||||
|
||||
/**
|
||||
* Gets the Dolphin version string.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.dolphinemu.dolphinemu.features.input.model;
|
||||
|
||||
public final class InputOverrider
|
||||
{
|
||||
public static final class ControlId
|
||||
{
|
||||
public static final int GCPAD_A_BUTTON = 0;
|
||||
public static final int GCPAD_B_BUTTON = 1;
|
||||
public static final int GCPAD_X_BUTTON = 2;
|
||||
public static final int GCPAD_Y_BUTTON = 3;
|
||||
public static final int GCPAD_Z_BUTTON = 4;
|
||||
public static final int GCPAD_START_BUTTON = 5;
|
||||
public static final int GCPAD_DPAD_UP = 6;
|
||||
public static final int GCPAD_DPAD_DOWN = 7;
|
||||
public static final int GCPAD_DPAD_LEFT = 8;
|
||||
public static final int GCPAD_DPAD_RIGHT = 9;
|
||||
public static final int GCPAD_L_DIGITAL = 10;
|
||||
public static final int GCPAD_R_DIGITAL = 11;
|
||||
public static final int GCPAD_L_ANALOG = 12;
|
||||
public static final int GCPAD_R_ANALOG = 13;
|
||||
public static final int GCPAD_MAIN_STICK_X = 14;
|
||||
public static final int GCPAD_MAIN_STICK_Y = 15;
|
||||
public static final int GCPAD_C_STICK_X = 16;
|
||||
public static final int GCPAD_C_STICK_Y = 17;
|
||||
|
||||
public static final int WIIMOTE_A_BUTTON = 18;
|
||||
public static final int WIIMOTE_B_BUTTON = 19;
|
||||
public static final int WIIMOTE_ONE_BUTTON = 20;
|
||||
public static final int WIIMOTE_TWO_BUTTON = 21;
|
||||
public static final int WIIMOTE_PLUS_BUTTON = 22;
|
||||
public static final int WIIMOTE_MINUS_BUTTON = 23;
|
||||
public static final int WIIMOTE_HOME_BUTTON = 24;
|
||||
public static final int WIIMOTE_DPAD_UP = 25;
|
||||
public static final int WIIMOTE_DPAD_DOWN = 26;
|
||||
public static final int WIIMOTE_DPAD_LEFT = 27;
|
||||
public static final int WIIMOTE_DPAD_RIGHT = 28;
|
||||
public static final int WIIMOTE_IR_X = 29;
|
||||
public static final int WIIMOTE_IR_Y = 30;
|
||||
|
||||
public static final int NUNCHUK_C_BUTTON = 31;
|
||||
public static final int NUNCHUK_Z_BUTTON = 32;
|
||||
public static final int NUNCHUK_STICK_X = 33;
|
||||
public static final int NUNCHUK_STICK_Y = 34;
|
||||
|
||||
public static final int CLASSIC_A_BUTTON = 35;
|
||||
public static final int CLASSIC_B_BUTTON = 36;
|
||||
public static final int CLASSIC_X_BUTTON = 37;
|
||||
public static final int CLASSIC_Y_BUTTON = 38;
|
||||
public static final int CLASSIC_ZL_BUTTON = 39;
|
||||
public static final int CLASSIC_ZR_BUTTON = 40;
|
||||
public static final int CLASSIC_PLUS_BUTTON = 41;
|
||||
public static final int CLASSIC_MINUS_BUTTON = 42;
|
||||
public static final int CLASSIC_HOME_BUTTON = 43;
|
||||
public static final int CLASSIC_DPAD_UP = 44;
|
||||
public static final int CLASSIC_DPAD_DOWN = 45;
|
||||
public static final int CLASSIC_DPAD_LEFT = 46;
|
||||
public static final int CLASSIC_DPAD_RIGHT = 47;
|
||||
public static final int CLASSIC_L_DIGITAL = 48;
|
||||
public static final int CLASSIC_R_DIGITAL = 49;
|
||||
public static final int CLASSIC_L_ANALOG = 50;
|
||||
public static final int CLASSIC_R_ANALOG = 51;
|
||||
public static final int CLASSIC_LEFT_STICK_X = 52;
|
||||
public static final int CLASSIC_LEFT_STICK_Y = 53;
|
||||
public static final int CLASSIC_RIGHT_STICK_X = 54;
|
||||
public static final int CLASSIC_RIGHT_STICK_Y = 55;
|
||||
}
|
||||
|
||||
public static native void registerGameCube(int controllerIndex);
|
||||
|
||||
public static native void registerWii(int controllerIndex);
|
||||
|
||||
public static native void unregisterGameCube(int controllerIndex);
|
||||
|
||||
public static native void unregisterWii(int controllerIndex);
|
||||
|
||||
public static native void setControlState(int controllerIndex, int control, double state);
|
||||
|
||||
public static native void clearControlState(int controllerIndex, int control);
|
||||
|
||||
// Angle is in radians and should be non-negative
|
||||
public static native double getGateRadiusAtAngle(int emuPadId, int stick, double angle);
|
||||
}
|
|
@ -40,8 +40,7 @@ public enum IntSetting implements AbstractIntSetting
|
|||
InputOverlayPointer.MODE_FOLLOW),
|
||||
|
||||
MAIN_DOUBLE_TAP_BUTTON(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
|
||||
"DoubleTapButton",
|
||||
InputOverlayPointer.DOUBLE_TAP_OPTIONS.get(InputOverlayPointer.DOUBLE_TAP_A)),
|
||||
"DoubleTapButton", NativeLibrary.ButtonType.WIIMOTE_BUTTON_A),
|
||||
|
||||
SYSCONF_LANGUAGE(Settings.FILE_SYSCONF, "IPL", "LNG", 0x01),
|
||||
SYSCONF_SOUND_MODE(Settings.FILE_SYSCONF, "IPL", "SND", 0x01),
|
||||
|
|
|
@ -138,6 +138,15 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
|
|||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy()
|
||||
{
|
||||
if (mInputOverlay != null)
|
||||
mInputOverlay.onDestroy();
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach()
|
||||
{
|
||||
|
|
|
@ -26,9 +26,10 @@ import android.view.View.OnTouchListener;
|
|||
import android.widget.Toast;
|
||||
|
||||
import org.dolphinemu.dolphinemu.NativeLibrary;
|
||||
import org.dolphinemu.dolphinemu.NativeLibrary.ButtonState;
|
||||
import org.dolphinemu.dolphinemu.NativeLibrary.ButtonType;
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
import org.dolphinemu.dolphinemu.features.input.model.InputOverrider;
|
||||
import org.dolphinemu.dolphinemu.features.input.model.InputOverrider.ControlId;
|
||||
import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting;
|
||||
import org.dolphinemu.dolphinemu.features.settings.model.IntSetting;
|
||||
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
|
||||
|
@ -64,6 +65,8 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
private Rect mSurfacePosition = null;
|
||||
|
||||
private boolean mIsFirstRun = true;
|
||||
private boolean mGameCubeRegistered = false;
|
||||
private boolean mWiiRegistered = false;
|
||||
private boolean mIsInEditMode = false;
|
||||
private InputOverlayDrawableButton mButtonBeingConfigured;
|
||||
private InputOverlayDrawableDpad mDpadBeingConfigured;
|
||||
|
@ -158,12 +161,26 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
int doubleTapButton = IntSetting.MAIN_DOUBLE_TAP_BUTTON.getIntGlobal();
|
||||
|
||||
if (getConfiguredControllerType() != InputOverlay.OVERLAY_WIIMOTE_CLASSIC &&
|
||||
doubleTapButton == InputOverlayPointer.DOUBLE_TAP_CLASSIC_A)
|
||||
doubleTapButton == ButtonType.CLASSIC_BUTTON_A)
|
||||
{
|
||||
doubleTapButton = InputOverlayPointer.DOUBLE_TAP_A;
|
||||
doubleTapButton = ButtonType.WIIMOTE_BUTTON_A;
|
||||
}
|
||||
|
||||
overlayPointer = new InputOverlayPointer(mSurfacePosition, doubleTapButton,
|
||||
int doubleTapControl = ControlId.WIIMOTE_A_BUTTON;
|
||||
switch (doubleTapButton)
|
||||
{
|
||||
case ButtonType.WIIMOTE_BUTTON_A:
|
||||
doubleTapControl = ControlId.WIIMOTE_A_BUTTON;
|
||||
break;
|
||||
case ButtonType.WIIMOTE_BUTTON_B:
|
||||
doubleTapControl = ControlId.WIIMOTE_B_BUTTON;
|
||||
break;
|
||||
case ButtonType.WIIMOTE_BUTTON_2:
|
||||
doubleTapControl = ControlId.WIIMOTE_TWO_BUTTON;
|
||||
break;
|
||||
}
|
||||
|
||||
overlayPointer = new InputOverlayPointer(mSurfacePosition, doubleTapControl,
|
||||
IntSetting.MAIN_IR_MODE.getIntGlobal(),
|
||||
BooleanSetting.MAIN_IR_ALWAYS_RECENTER.getBooleanGlobal());
|
||||
}
|
||||
|
@ -218,8 +235,11 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
button.setPressedState(true);
|
||||
button.setTrackId(event.getPointerId(pointerIndex));
|
||||
pressed = true;
|
||||
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, button.getId(),
|
||||
ButtonState.PRESSED);
|
||||
InputOverrider.setControlState(0, button.getControl(), 1.0);
|
||||
|
||||
int analogControl = getAnalogControlForTrigger(button.getControl());
|
||||
if (analogControl >= 0)
|
||||
InputOverrider.setControlState(0, analogControl, 1.0);
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
|
@ -228,8 +248,12 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
if (button.getTrackId() == event.getPointerId(pointerIndex))
|
||||
{
|
||||
button.setPressedState(false);
|
||||
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, button.getId(),
|
||||
ButtonState.RELEASED);
|
||||
InputOverrider.setControlState(0, button.getControl(), 0.0);
|
||||
|
||||
int analogControl = getAnalogControlForTrigger(button.getControl());
|
||||
if (analogControl >= 0)
|
||||
InputOverrider.setControlState(0, analogControl, 0.0);
|
||||
|
||||
button.setTrackId(-1);
|
||||
}
|
||||
break;
|
||||
|
@ -270,8 +294,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
{
|
||||
if (!dpadPressed[i])
|
||||
{
|
||||
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(i),
|
||||
ButtonState.RELEASED);
|
||||
InputOverrider.setControlState(0, dpad.getControl(i), 0.0);
|
||||
}
|
||||
}
|
||||
// Press buttons
|
||||
|
@ -279,8 +302,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
{
|
||||
if (dpadPressed[i])
|
||||
{
|
||||
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(i),
|
||||
ButtonState.PRESSED);
|
||||
InputOverrider.setControlState(0, dpad.getControl(i), 1.0);
|
||||
}
|
||||
}
|
||||
setDpadState(dpad, dpadPressed[0], dpadPressed[1], dpadPressed[2], dpadPressed[3]);
|
||||
|
@ -294,8 +316,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
dpad.setState(InputOverlayDrawableDpad.STATE_DEFAULT);
|
||||
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(i),
|
||||
ButtonState.RELEASED);
|
||||
InputOverrider.setControlState(0, dpad.getControl(i), 0.0);
|
||||
}
|
||||
dpad.setTrackId(-1);
|
||||
}
|
||||
|
@ -310,27 +331,17 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
if (joystick.getTrackId() != -1)
|
||||
pressed = true;
|
||||
}
|
||||
int[] axisIDs = joystick.getAxisIDs();
|
||||
float[] axises = joystick.getAxisValues();
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
NativeLibrary.onGamePadMoveEvent(NativeLibrary.TouchScreenDevice, axisIDs[i], axises[i]);
|
||||
}
|
||||
InputOverrider.setControlState(0, joystick.getXControl(), joystick.getX());
|
||||
InputOverrider.setControlState(0, joystick.getYControl(), -joystick.getY());
|
||||
}
|
||||
|
||||
// No button/joystick pressed, safe to move pointer
|
||||
if (!pressed && overlayPointer != null)
|
||||
{
|
||||
overlayPointer.onTouch(event);
|
||||
float[] axes = overlayPointer.getAxisValues();
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
NativeLibrary
|
||||
.onGamePadMoveEvent(NativeLibrary.TouchScreenDevice, ButtonType.WIIMOTE_IR_UP + i,
|
||||
axes[i]);
|
||||
}
|
||||
InputOverrider.setControlState(0, ControlId.WIIMOTE_IR_X, overlayPointer.getX());
|
||||
InputOverrider.setControlState(0, ControlId.WIIMOTE_IR_Y, -overlayPointer.getY());
|
||||
}
|
||||
|
||||
invalidate();
|
||||
|
@ -381,7 +392,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
if (mButtonBeingConfigured == button)
|
||||
{
|
||||
// Persist button position by saving new place.
|
||||
saveControlPosition(mButtonBeingConfigured.getId(),
|
||||
saveControlPosition(mButtonBeingConfigured.getLegacyId(),
|
||||
mButtonBeingConfigured.getBounds().left,
|
||||
mButtonBeingConfigured.getBounds().top, controller, orientation);
|
||||
mButtonBeingConfigured = null;
|
||||
|
@ -419,7 +430,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
if (mDpadBeingConfigured == dpad)
|
||||
{
|
||||
// Persist button position by saving new place.
|
||||
saveControlPosition(mDpadBeingConfigured.getId(0),
|
||||
saveControlPosition(mDpadBeingConfigured.getLegacyId(),
|
||||
mDpadBeingConfigured.getBounds().left, mDpadBeingConfigured.getBounds().top,
|
||||
controller, orientation);
|
||||
mDpadBeingConfigured = null;
|
||||
|
@ -452,7 +463,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
case MotionEvent.ACTION_POINTER_UP:
|
||||
if (mJoystickBeingConfigured != null)
|
||||
{
|
||||
saveControlPosition(mJoystickBeingConfigured.getId(),
|
||||
saveControlPosition(mJoystickBeingConfigured.getLegacyId(),
|
||||
mJoystickBeingConfigured.getBounds().left,
|
||||
mJoystickBeingConfigured.getBounds().top, controller, orientation);
|
||||
mJoystickBeingConfigured = null;
|
||||
|
@ -464,6 +475,40 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
return true;
|
||||
}
|
||||
|
||||
public void onDestroy()
|
||||
{
|
||||
unregisterControllers();
|
||||
}
|
||||
|
||||
private void unregisterControllers()
|
||||
{
|
||||
if (mGameCubeRegistered)
|
||||
InputOverrider.unregisterGameCube(0);
|
||||
|
||||
if (mWiiRegistered)
|
||||
InputOverrider.unregisterWii(0);
|
||||
|
||||
mGameCubeRegistered = false;
|
||||
mWiiRegistered = false;
|
||||
}
|
||||
|
||||
private int getAnalogControlForTrigger(int control)
|
||||
{
|
||||
switch (control)
|
||||
{
|
||||
case ControlId.GCPAD_L_DIGITAL:
|
||||
return ControlId.GCPAD_L_ANALOG;
|
||||
case ControlId.GCPAD_R_DIGITAL:
|
||||
return ControlId.GCPAD_R_ANALOG;
|
||||
case ControlId.CLASSIC_L_DIGITAL:
|
||||
return ControlId.CLASSIC_L_ANALOG;
|
||||
case ControlId.CLASSIC_R_DIGITAL:
|
||||
return ControlId.CLASSIC_R_ANALOG;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private void setDpadState(InputOverlayDrawableDpad dpad, boolean up, boolean down, boolean left,
|
||||
boolean right)
|
||||
{
|
||||
|
@ -500,61 +545,70 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_0.getBooleanGlobal())
|
||||
{
|
||||
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.gcpad_a,
|
||||
R.drawable.gcpad_a_pressed, ButtonType.BUTTON_A, orientation));
|
||||
R.drawable.gcpad_a_pressed, ButtonType.BUTTON_A, ControlId.GCPAD_A_BUTTON,
|
||||
orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_1.getBooleanGlobal())
|
||||
{
|
||||
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.gcpad_b,
|
||||
R.drawable.gcpad_b_pressed, ButtonType.BUTTON_B, orientation));
|
||||
R.drawable.gcpad_b_pressed, ButtonType.BUTTON_B, ControlId.GCPAD_B_BUTTON,
|
||||
orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_2.getBooleanGlobal())
|
||||
{
|
||||
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.gcpad_x,
|
||||
R.drawable.gcpad_x_pressed, ButtonType.BUTTON_X, orientation));
|
||||
R.drawable.gcpad_x_pressed, ButtonType.BUTTON_X, ControlId.GCPAD_X_BUTTON,
|
||||
orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_3.getBooleanGlobal())
|
||||
{
|
||||
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.gcpad_y,
|
||||
R.drawable.gcpad_y_pressed, ButtonType.BUTTON_Y, orientation));
|
||||
R.drawable.gcpad_y_pressed, ButtonType.BUTTON_Y, ControlId.GCPAD_Y_BUTTON,
|
||||
orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_4.getBooleanGlobal())
|
||||
{
|
||||
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.gcpad_z,
|
||||
R.drawable.gcpad_z_pressed, ButtonType.BUTTON_Z, orientation));
|
||||
R.drawable.gcpad_z_pressed, ButtonType.BUTTON_Z, ControlId.GCPAD_Z_BUTTON,
|
||||
orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_5.getBooleanGlobal())
|
||||
{
|
||||
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.gcpad_start,
|
||||
R.drawable.gcpad_start_pressed, ButtonType.BUTTON_START, orientation));
|
||||
R.drawable.gcpad_start_pressed, ButtonType.BUTTON_START, ControlId.GCPAD_START_BUTTON,
|
||||
orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_6.getBooleanGlobal())
|
||||
{
|
||||
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.gcpad_l,
|
||||
R.drawable.gcpad_l_pressed, ButtonType.TRIGGER_L, orientation));
|
||||
R.drawable.gcpad_l_pressed, ButtonType.TRIGGER_L, ControlId.GCPAD_L_DIGITAL,
|
||||
orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_7.getBooleanGlobal())
|
||||
{
|
||||
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.gcpad_r,
|
||||
R.drawable.gcpad_r_pressed, ButtonType.TRIGGER_R, orientation));
|
||||
R.drawable.gcpad_r_pressed, ButtonType.TRIGGER_R, ControlId.GCPAD_R_DIGITAL,
|
||||
orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_8.getBooleanGlobal())
|
||||
{
|
||||
overlayDpads.add(initializeOverlayDpad(getContext(), R.drawable.gcwii_dpad,
|
||||
R.drawable.gcwii_dpad_pressed_one_direction,
|
||||
R.drawable.gcwii_dpad_pressed_two_directions,
|
||||
ButtonType.BUTTON_UP, ButtonType.BUTTON_DOWN,
|
||||
ButtonType.BUTTON_LEFT, ButtonType.BUTTON_RIGHT, orientation));
|
||||
ButtonType.BUTTON_UP, ControlId.GCPAD_DPAD_UP, ControlId.GCPAD_DPAD_DOWN,
|
||||
ControlId.GCPAD_DPAD_LEFT, ControlId.GCPAD_DPAD_RIGHT, orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_9.getBooleanGlobal())
|
||||
{
|
||||
overlayJoysticks.add(initializeOverlayJoystick(getContext(), R.drawable.gcwii_joystick_range,
|
||||
R.drawable.gcwii_joystick, R.drawable.gcwii_joystick_pressed, ButtonType.STICK_MAIN,
|
||||
orientation));
|
||||
ControlId.GCPAD_MAIN_STICK_X, ControlId.GCPAD_MAIN_STICK_Y, orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_10.getBooleanGlobal())
|
||||
{
|
||||
overlayJoysticks.add(initializeOverlayJoystick(getContext(), R.drawable.gcwii_joystick_range,
|
||||
R.drawable.gcpad_c, R.drawable.gcpad_c_pressed, ButtonType.STICK_C, orientation));
|
||||
R.drawable.gcpad_c, R.drawable.gcpad_c_pressed, ButtonType.STICK_C,
|
||||
ControlId.GCPAD_C_STICK_X, ControlId.GCPAD_C_STICK_Y, orientation));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -563,45 +617,52 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_0.getBooleanGlobal())
|
||||
{
|
||||
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.wiimote_a,
|
||||
R.drawable.wiimote_a_pressed, ButtonType.WIIMOTE_BUTTON_A, orientation));
|
||||
R.drawable.wiimote_a_pressed, ButtonType.WIIMOTE_BUTTON_A, ControlId.WIIMOTE_A_BUTTON,
|
||||
orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_1.getBooleanGlobal())
|
||||
{
|
||||
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.wiimote_b,
|
||||
R.drawable.wiimote_b_pressed, ButtonType.WIIMOTE_BUTTON_B, orientation));
|
||||
R.drawable.wiimote_b_pressed, ButtonType.WIIMOTE_BUTTON_B, ControlId.WIIMOTE_B_BUTTON,
|
||||
orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_2.getBooleanGlobal())
|
||||
{
|
||||
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.wiimote_one,
|
||||
R.drawable.wiimote_one_pressed, ButtonType.WIIMOTE_BUTTON_1, orientation));
|
||||
R.drawable.wiimote_one_pressed, ButtonType.WIIMOTE_BUTTON_1,
|
||||
ControlId.WIIMOTE_ONE_BUTTON, orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_3.getBooleanGlobal())
|
||||
{
|
||||
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.wiimote_two,
|
||||
R.drawable.wiimote_two_pressed, ButtonType.WIIMOTE_BUTTON_2, orientation));
|
||||
R.drawable.wiimote_two_pressed, ButtonType.WIIMOTE_BUTTON_2,
|
||||
ControlId.WIIMOTE_TWO_BUTTON, orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_4.getBooleanGlobal())
|
||||
{
|
||||
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.wiimote_plus,
|
||||
R.drawable.wiimote_plus_pressed, ButtonType.WIIMOTE_BUTTON_PLUS, orientation));
|
||||
R.drawable.wiimote_plus_pressed, ButtonType.WIIMOTE_BUTTON_PLUS,
|
||||
ControlId.WIIMOTE_PLUS_BUTTON, orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_5.getBooleanGlobal())
|
||||
{
|
||||
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.wiimote_minus,
|
||||
R.drawable.wiimote_minus_pressed, ButtonType.WIIMOTE_BUTTON_MINUS, orientation));
|
||||
R.drawable.wiimote_minus_pressed, ButtonType.WIIMOTE_BUTTON_MINUS,
|
||||
ControlId.WIIMOTE_MINUS_BUTTON, orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_6.getBooleanGlobal())
|
||||
{
|
||||
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.wiimote_home,
|
||||
R.drawable.wiimote_home_pressed, ButtonType.WIIMOTE_BUTTON_HOME, orientation));
|
||||
R.drawable.wiimote_home_pressed, ButtonType.WIIMOTE_BUTTON_HOME,
|
||||
ControlId.WIIMOTE_HOME_BUTTON, orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_7.getBooleanGlobal())
|
||||
{
|
||||
overlayDpads.add(initializeOverlayDpad(getContext(), R.drawable.gcwii_dpad,
|
||||
R.drawable.gcwii_dpad_pressed_one_direction,
|
||||
R.drawable.gcwii_dpad_pressed_two_directions,
|
||||
ButtonType.WIIMOTE_UP, ButtonType.WIIMOTE_DOWN,
|
||||
ButtonType.WIIMOTE_LEFT, ButtonType.WIIMOTE_RIGHT, orientation));
|
||||
ButtonType.WIIMOTE_UP, ControlId.WIIMOTE_DPAD_UP, ControlId.WIIMOTE_DPAD_DOWN,
|
||||
ControlId.WIIMOTE_DPAD_LEFT, ControlId.WIIMOTE_DPAD_RIGHT, orientation));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -610,18 +671,21 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_8.getBooleanGlobal())
|
||||
{
|
||||
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.nunchuk_c,
|
||||
R.drawable.nunchuk_c_pressed, ButtonType.NUNCHUK_BUTTON_C, orientation));
|
||||
R.drawable.nunchuk_c_pressed, ButtonType.NUNCHUK_BUTTON_C, ControlId.NUNCHUK_C_BUTTON,
|
||||
orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_9.getBooleanGlobal())
|
||||
{
|
||||
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.nunchuk_z,
|
||||
R.drawable.nunchuk_z_pressed, ButtonType.NUNCHUK_BUTTON_Z, orientation));
|
||||
R.drawable.nunchuk_z_pressed, ButtonType.NUNCHUK_BUTTON_Z, ControlId.NUNCHUK_Z_BUTTON,
|
||||
orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_10.getBooleanGlobal())
|
||||
{
|
||||
overlayJoysticks.add(initializeOverlayJoystick(getContext(), R.drawable.gcwii_joystick_range,
|
||||
R.drawable.gcwii_joystick, R.drawable.gcwii_joystick_pressed,
|
||||
ButtonType.NUNCHUK_STICK, orientation));
|
||||
ButtonType.NUNCHUK_STICK, ControlId.NUNCHUK_STICK_X, ControlId.NUNCHUK_STICK_Y,
|
||||
orientation));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -630,82 +694,97 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_0.getBooleanGlobal())
|
||||
{
|
||||
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.classic_a,
|
||||
R.drawable.classic_a_pressed, ButtonType.CLASSIC_BUTTON_A, orientation));
|
||||
R.drawable.classic_a_pressed, ButtonType.CLASSIC_BUTTON_A, ControlId.CLASSIC_A_BUTTON,
|
||||
orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_1.getBooleanGlobal())
|
||||
{
|
||||
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.classic_b,
|
||||
R.drawable.classic_b_pressed, ButtonType.CLASSIC_BUTTON_B, orientation));
|
||||
R.drawable.classic_b_pressed, ButtonType.CLASSIC_BUTTON_B, ControlId.CLASSIC_B_BUTTON,
|
||||
orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_2.getBooleanGlobal())
|
||||
{
|
||||
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.classic_x,
|
||||
R.drawable.classic_x_pressed, ButtonType.CLASSIC_BUTTON_X, orientation));
|
||||
R.drawable.classic_x_pressed, ButtonType.CLASSIC_BUTTON_X, ControlId.CLASSIC_X_BUTTON,
|
||||
orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_3.getBooleanGlobal())
|
||||
{
|
||||
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.classic_y,
|
||||
R.drawable.classic_y_pressed, ButtonType.CLASSIC_BUTTON_Y, orientation));
|
||||
R.drawable.classic_y_pressed, ButtonType.CLASSIC_BUTTON_Y, ControlId.CLASSIC_Y_BUTTON,
|
||||
orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_4.getBooleanGlobal())
|
||||
{
|
||||
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.wiimote_plus,
|
||||
R.drawable.wiimote_plus_pressed, ButtonType.CLASSIC_BUTTON_PLUS, orientation));
|
||||
R.drawable.wiimote_plus_pressed, ButtonType.CLASSIC_BUTTON_PLUS,
|
||||
ControlId.CLASSIC_PLUS_BUTTON, orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_5.getBooleanGlobal())
|
||||
{
|
||||
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.wiimote_minus,
|
||||
R.drawable.wiimote_minus_pressed, ButtonType.CLASSIC_BUTTON_MINUS, orientation));
|
||||
R.drawable.wiimote_minus_pressed, ButtonType.CLASSIC_BUTTON_MINUS,
|
||||
ControlId.CLASSIC_MINUS_BUTTON, orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_6.getBooleanGlobal())
|
||||
{
|
||||
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.wiimote_home,
|
||||
R.drawable.wiimote_home_pressed, ButtonType.CLASSIC_BUTTON_HOME, orientation));
|
||||
R.drawable.wiimote_home_pressed, ButtonType.CLASSIC_BUTTON_HOME,
|
||||
ControlId.CLASSIC_HOME_BUTTON, orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_7.getBooleanGlobal())
|
||||
{
|
||||
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.classic_l,
|
||||
R.drawable.classic_l_pressed, ButtonType.CLASSIC_TRIGGER_L, orientation));
|
||||
R.drawable.classic_l_pressed, ButtonType.CLASSIC_TRIGGER_L,
|
||||
ControlId.CLASSIC_L_DIGITAL, orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_8.getBooleanGlobal())
|
||||
{
|
||||
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.classic_r,
|
||||
R.drawable.classic_r_pressed, ButtonType.CLASSIC_TRIGGER_R, orientation));
|
||||
R.drawable.classic_r_pressed, ButtonType.CLASSIC_TRIGGER_R,
|
||||
ControlId.CLASSIC_R_DIGITAL, orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_9.getBooleanGlobal())
|
||||
{
|
||||
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.classic_zl,
|
||||
R.drawable.classic_zl_pressed, ButtonType.CLASSIC_BUTTON_ZL, orientation));
|
||||
R.drawable.classic_zl_pressed, ButtonType.CLASSIC_BUTTON_ZL,
|
||||
ControlId.CLASSIC_ZL_BUTTON, orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_10.getBooleanGlobal())
|
||||
{
|
||||
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.classic_zr,
|
||||
R.drawable.classic_zr_pressed, ButtonType.CLASSIC_BUTTON_ZR, orientation));
|
||||
R.drawable.classic_zr_pressed, ButtonType.CLASSIC_BUTTON_ZR,
|
||||
ControlId.CLASSIC_ZR_BUTTON, orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_11.getBooleanGlobal())
|
||||
{
|
||||
overlayDpads.add(initializeOverlayDpad(getContext(), R.drawable.gcwii_dpad,
|
||||
R.drawable.gcwii_dpad_pressed_one_direction,
|
||||
R.drawable.gcwii_dpad_pressed_two_directions,
|
||||
ButtonType.CLASSIC_DPAD_UP, ButtonType.CLASSIC_DPAD_DOWN,
|
||||
ButtonType.CLASSIC_DPAD_LEFT, ButtonType.CLASSIC_DPAD_RIGHT, orientation));
|
||||
ButtonType.CLASSIC_DPAD_UP, ControlId.CLASSIC_DPAD_UP, ControlId.CLASSIC_DPAD_DOWN,
|
||||
ControlId.CLASSIC_DPAD_LEFT, ControlId.CLASSIC_DPAD_RIGHT, orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_12.getBooleanGlobal())
|
||||
{
|
||||
overlayJoysticks.add(initializeOverlayJoystick(getContext(), R.drawable.gcwii_joystick_range,
|
||||
R.drawable.gcwii_joystick, R.drawable.gcwii_joystick_pressed,
|
||||
ButtonType.CLASSIC_STICK_LEFT, orientation));
|
||||
ButtonType.CLASSIC_STICK_LEFT, ControlId.CLASSIC_LEFT_STICK_X,
|
||||
ControlId.CLASSIC_LEFT_STICK_Y, orientation));
|
||||
}
|
||||
if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_13.getBooleanGlobal())
|
||||
{
|
||||
overlayJoysticks.add(initializeOverlayJoystick(getContext(), R.drawable.gcwii_joystick_range,
|
||||
R.drawable.gcwii_joystick, R.drawable.gcwii_joystick_pressed,
|
||||
ButtonType.CLASSIC_STICK_RIGHT, orientation));
|
||||
ButtonType.CLASSIC_STICK_RIGHT, ControlId.CLASSIC_RIGHT_STICK_X,
|
||||
ControlId.CLASSIC_RIGHT_STICK_Y, orientation));
|
||||
}
|
||||
}
|
||||
|
||||
public void refreshControls()
|
||||
{
|
||||
unregisterControllers();
|
||||
|
||||
// Remove all the overlay buttons from the HashSet.
|
||||
overlayButtons.removeAll(overlayButtons);
|
||||
overlayDpads.removeAll(overlayDpads);
|
||||
|
@ -734,6 +813,8 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
break;
|
||||
|
||||
case EMULATED_GAMECUBE_CONTROLLER:
|
||||
InputOverrider.registerGameCube(0);
|
||||
mGameCubeRegistered = true;
|
||||
addGameCubeOverlayControls(orientation);
|
||||
break;
|
||||
|
||||
|
@ -746,20 +827,28 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
switch (getConfiguredControllerType())
|
||||
{
|
||||
case OVERLAY_GAMECUBE:
|
||||
InputOverrider.registerGameCube(0);
|
||||
mGameCubeRegistered = true;
|
||||
addGameCubeOverlayControls(orientation);
|
||||
break;
|
||||
|
||||
case OVERLAY_WIIMOTE:
|
||||
case OVERLAY_WIIMOTE_SIDEWAYS:
|
||||
InputOverrider.registerWii(0);
|
||||
mWiiRegistered = true;
|
||||
addWiimoteOverlayControls(orientation);
|
||||
break;
|
||||
|
||||
case OVERLAY_WIIMOTE_NUNCHUK:
|
||||
InputOverrider.registerWii(0);
|
||||
mWiiRegistered = true;
|
||||
addWiimoteOverlayControls(orientation);
|
||||
addNunchukOverlayControls(orientation);
|
||||
break;
|
||||
|
||||
case OVERLAY_WIIMOTE_CLASSIC:
|
||||
InputOverrider.registerWii(0);
|
||||
mWiiRegistered = true;
|
||||
addClassicOverlayControls(orientation);
|
||||
break;
|
||||
|
||||
|
@ -768,6 +857,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
mIsFirstRun = false;
|
||||
invalidate();
|
||||
}
|
||||
|
@ -891,11 +981,12 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
* @param context The current {@link Context}.
|
||||
* @param defaultResId The resource ID of the {@link Drawable} to get the {@link Bitmap} of (Default State).
|
||||
* @param pressedResId The resource ID of the {@link Drawable} to get the {@link Bitmap} of (Pressed State).
|
||||
* @param buttonId Identifier for determining what type of button the initialized InputOverlayDrawableButton represents.
|
||||
* @param legacyId Legacy identifier for the button the InputOverlayDrawableButton represents.
|
||||
* @param control Control identifier for the button the InputOverlayDrawableButton represents.
|
||||
* @return An {@link InputOverlayDrawableButton} with the correct drawing bounds set.
|
||||
*/
|
||||
private static InputOverlayDrawableButton initializeOverlayButton(Context context,
|
||||
int defaultResId, int pressedResId, int buttonId, String orientation)
|
||||
int defaultResId, int pressedResId, int legacyId, int control, String orientation)
|
||||
{
|
||||
// Resources handle for fetching the initial Drawable resource.
|
||||
final Resources res = context.getResources();
|
||||
|
@ -907,7 +998,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
// Decide scale based on button ID and user preference
|
||||
float scale;
|
||||
|
||||
switch (buttonId)
|
||||
switch (legacyId)
|
||||
{
|
||||
case ButtonType.BUTTON_A:
|
||||
case ButtonType.WIIMOTE_BUTTON_B:
|
||||
|
@ -961,12 +1052,13 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
final Bitmap pressedStateBitmap =
|
||||
resizeBitmap(context, BitmapFactory.decodeResource(res, pressedResId), scale);
|
||||
final InputOverlayDrawableButton overlayDrawable =
|
||||
new InputOverlayDrawableButton(res, defaultStateBitmap, pressedStateBitmap, buttonId);
|
||||
new InputOverlayDrawableButton(res, defaultStateBitmap, pressedStateBitmap, legacyId,
|
||||
control);
|
||||
|
||||
// The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay.
|
||||
// These were set in the input overlay configuration menu.
|
||||
int drawableX = (int) sPrefs.getFloat(getXKey(buttonId, controller, orientation), 0f);
|
||||
int drawableY = (int) sPrefs.getFloat(getYKey(buttonId, controller, orientation), 0f);
|
||||
int drawableX = (int) sPrefs.getFloat(getXKey(legacyId, controller, orientation), 0f);
|
||||
int drawableY = (int) sPrefs.getFloat(getYKey(legacyId, controller, orientation), 0f);
|
||||
|
||||
int width = overlayDrawable.getWidth();
|
||||
int height = overlayDrawable.getHeight();
|
||||
|
@ -989,20 +1081,22 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
* @param defaultResId The {@link Bitmap} resource ID of the default sate.
|
||||
* @param pressedOneDirectionResId The {@link Bitmap} resource ID of the pressed sate in one direction.
|
||||
* @param pressedTwoDirectionsResId The {@link Bitmap} resource ID of the pressed sate in two directions.
|
||||
* @param buttonUp Identifier for the up button.
|
||||
* @param buttonDown Identifier for the down button.
|
||||
* @param buttonLeft Identifier for the left button.
|
||||
* @param buttonRight Identifier for the right button.
|
||||
* @param legacyId Legacy identifier for the up button.
|
||||
* @param upControl Control identifier for the up button.
|
||||
* @param downControl Control identifier for the down button.
|
||||
* @param leftControl Control identifier for the left button.
|
||||
* @param rightControl Control identifier for the right button.
|
||||
* @return the initialized {@link InputOverlayDrawableDpad}
|
||||
*/
|
||||
private static InputOverlayDrawableDpad initializeOverlayDpad(Context context,
|
||||
int defaultResId,
|
||||
int pressedOneDirectionResId,
|
||||
int pressedTwoDirectionsResId,
|
||||
int buttonUp,
|
||||
int buttonDown,
|
||||
int buttonLeft,
|
||||
int buttonRight,
|
||||
int legacyId,
|
||||
int upControl,
|
||||
int downControl,
|
||||
int leftControl,
|
||||
int rightControl,
|
||||
String orientation)
|
||||
{
|
||||
// Resources handle for fetching the initial Drawable resource.
|
||||
|
@ -1015,7 +1109,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
// Decide scale based on button ID and user preference
|
||||
float scale;
|
||||
|
||||
switch (buttonUp)
|
||||
switch (legacyId)
|
||||
{
|
||||
case ButtonType.BUTTON_UP:
|
||||
scale = 0.2375f;
|
||||
|
@ -1046,12 +1140,12 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
final InputOverlayDrawableDpad overlayDrawable =
|
||||
new InputOverlayDrawableDpad(res, defaultStateBitmap,
|
||||
pressedOneDirectionStateBitmap, pressedTwoDirectionsStateBitmap,
|
||||
buttonUp, buttonDown, buttonLeft, buttonRight);
|
||||
legacyId, upControl, downControl, leftControl, rightControl);
|
||||
|
||||
// The X and Y coordinates of the InputOverlayDrawableDpad on the InputOverlay.
|
||||
// These were set in the input overlay configuration menu.
|
||||
int drawableX = (int) sPrefs.getFloat(getXKey(buttonUp, controller, orientation), 0f);
|
||||
int drawableY = (int) sPrefs.getFloat(getYKey(buttonUp, controller, orientation), 0f);
|
||||
int drawableX = (int) sPrefs.getFloat(getXKey(legacyId, controller, orientation), 0f);
|
||||
int drawableY = (int) sPrefs.getFloat(getYKey(legacyId, controller, orientation), 0f);
|
||||
|
||||
int width = overlayDrawable.getWidth();
|
||||
int height = overlayDrawable.getHeight();
|
||||
|
@ -1074,11 +1168,14 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
* @param resOuter Resource ID for the outer image of the joystick (the static image that shows the circular bounds).
|
||||
* @param defaultResInner Resource ID for the default inner image of the joystick (the one you actually move around).
|
||||
* @param pressedResInner Resource ID for the pressed inner image of the joystick.
|
||||
* @param joystick Identifier for which joystick this is.
|
||||
* @param legacyId Legacy identifier (ButtonType) for which joystick this is.
|
||||
* @param xControl Control identifier for the X axis.
|
||||
* @param yControl Control identifier for the Y axis.
|
||||
* @return the initialized {@link InputOverlayDrawableJoystick}.
|
||||
*/
|
||||
private static InputOverlayDrawableJoystick initializeOverlayJoystick(Context context,
|
||||
int resOuter, int defaultResInner, int pressedResInner, int joystick, String orientation)
|
||||
int resOuter, int defaultResInner, int pressedResInner, int legacyId, int xControl,
|
||||
int yControl, String orientation)
|
||||
{
|
||||
// Resources handle for fetching the initial Drawable resource.
|
||||
final Resources res = context.getResources();
|
||||
|
@ -1100,13 +1197,13 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
|
||||
// The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay.
|
||||
// These were set in the input overlay configuration menu.
|
||||
int drawableX = (int) sPrefs.getFloat(getXKey(joystick, controller, orientation), 0f);
|
||||
int drawableY = (int) sPrefs.getFloat(getYKey(joystick, controller, orientation), 0f);
|
||||
int drawableX = (int) sPrefs.getFloat(getXKey(legacyId, controller, orientation), 0f);
|
||||
int drawableY = (int) sPrefs.getFloat(getYKey(legacyId, controller, orientation), 0f);
|
||||
|
||||
// Decide inner scale based on joystick ID
|
||||
float innerScale;
|
||||
|
||||
if (joystick == ButtonType.STICK_C)
|
||||
if (legacyId == ButtonType.STICK_C)
|
||||
{
|
||||
innerScale = 1.833f;
|
||||
}
|
||||
|
@ -1124,7 +1221,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
// Send the drawableId to the joystick so it can be referenced when saving control position.
|
||||
final InputOverlayDrawableJoystick overlayDrawable =
|
||||
new InputOverlayDrawableJoystick(res, bitmapOuter, bitmapInnerDefault,
|
||||
bitmapInnerPressed, outerRect, innerRect, joystick);
|
||||
bitmapInnerPressed, outerRect, innerRect, legacyId, xControl, yControl);
|
||||
|
||||
// Need to set the image's position
|
||||
overlayDrawable.setPosition(drawableX, drawableY);
|
||||
|
|
|
@ -18,8 +18,9 @@ import android.view.MotionEvent;
|
|||
*/
|
||||
public final class InputOverlayDrawableButton
|
||||
{
|
||||
// The ID identifying what type of button this Drawable represents.
|
||||
private int mButtonType;
|
||||
// The legacy ID identifying what type of button this Drawable represents.
|
||||
private int mLegacyId;
|
||||
private int mControl;
|
||||
private int mTrackId;
|
||||
private int mPreviousTouchX, mPreviousTouchY;
|
||||
private int mControlPositionX, mControlPositionY;
|
||||
|
@ -35,28 +36,33 @@ public final class InputOverlayDrawableButton
|
|||
* @param res {@link Resources} instance.
|
||||
* @param defaultStateBitmap {@link Bitmap} to use with the default state Drawable.
|
||||
* @param pressedStateBitmap {@link Bitmap} to use with the pressed state Drawable.
|
||||
* @param buttonType Identifier for this type of button.
|
||||
* @param legacyId Legacy identifier (ButtonType) for this type of button.
|
||||
* @param control Control ID for this type of button.
|
||||
*/
|
||||
public InputOverlayDrawableButton(Resources res, Bitmap defaultStateBitmap,
|
||||
Bitmap pressedStateBitmap, int buttonType)
|
||||
Bitmap pressedStateBitmap, int legacyId, int control)
|
||||
{
|
||||
mTrackId = -1;
|
||||
mDefaultStateBitmap = new BitmapDrawable(res, defaultStateBitmap);
|
||||
mPressedStateBitmap = new BitmapDrawable(res, pressedStateBitmap);
|
||||
mButtonType = buttonType;
|
||||
mLegacyId = legacyId;
|
||||
mControl = control;
|
||||
|
||||
mWidth = mDefaultStateBitmap.getIntrinsicWidth();
|
||||
mHeight = mDefaultStateBitmap.getIntrinsicHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this InputOverlayDrawableButton's button ID.
|
||||
*
|
||||
* @return this InputOverlayDrawableButton's button ID.
|
||||
* Gets this InputOverlayDrawableButton's legacy button ID.
|
||||
*/
|
||||
public int getId()
|
||||
public int getLegacyId()
|
||||
{
|
||||
return mButtonType;
|
||||
return mLegacyId;
|
||||
}
|
||||
|
||||
public int getControl()
|
||||
{
|
||||
return mControl;
|
||||
}
|
||||
|
||||
public void setTrackId(int trackId)
|
||||
|
|
|
@ -18,8 +18,9 @@ import android.view.MotionEvent;
|
|||
*/
|
||||
public final class InputOverlayDrawableDpad
|
||||
{
|
||||
// The ID identifying what type of button this Drawable represents.
|
||||
private int[] mButtonType = new int[4];
|
||||
// The legacy ID identifying what type of button this Drawable represents.
|
||||
private int mLegacyId;
|
||||
private int[] mControls = new int[4];
|
||||
private int mTrackId;
|
||||
private int mPreviousTouchX, mPreviousTouchY;
|
||||
private int mControlPositionX, mControlPositionY;
|
||||
|
@ -47,17 +48,15 @@ public final class InputOverlayDrawableDpad
|
|||
* @param defaultStateBitmap {@link Bitmap} of the default state.
|
||||
* @param pressedOneDirectionStateBitmap {@link Bitmap} of the pressed state in one direction.
|
||||
* @param pressedTwoDirectionsStateBitmap {@link Bitmap} of the pressed state in two direction.
|
||||
* @param buttonUp Identifier for the up button.
|
||||
* @param buttonDown Identifier for the down button.
|
||||
* @param buttonLeft Identifier for the left button.
|
||||
* @param buttonRight Identifier for the right button.
|
||||
* @param legacyId Legacy identifier (ButtonType) for the up button.
|
||||
* @param upControl Control identifier for the up button.
|
||||
* @param downControl Control identifier for the down button.
|
||||
* @param leftControl Control identifier for the left button.
|
||||
* @param rightControl Control identifier for the right button.
|
||||
*/
|
||||
public InputOverlayDrawableDpad(Resources res,
|
||||
Bitmap defaultStateBitmap,
|
||||
Bitmap pressedOneDirectionStateBitmap,
|
||||
Bitmap pressedTwoDirectionsStateBitmap,
|
||||
int buttonUp, int buttonDown,
|
||||
int buttonLeft, int buttonRight)
|
||||
public InputOverlayDrawableDpad(Resources res, Bitmap defaultStateBitmap,
|
||||
Bitmap pressedOneDirectionStateBitmap, Bitmap pressedTwoDirectionsStateBitmap,
|
||||
int legacyId, int upControl, int downControl, int leftControl, int rightControl)
|
||||
{
|
||||
mTrackId = -1;
|
||||
mDefaultStateBitmap = new BitmapDrawable(res, defaultStateBitmap);
|
||||
|
@ -67,10 +66,11 @@ public final class InputOverlayDrawableDpad
|
|||
mWidth = mDefaultStateBitmap.getIntrinsicWidth();
|
||||
mHeight = mDefaultStateBitmap.getIntrinsicHeight();
|
||||
|
||||
mButtonType[0] = buttonUp;
|
||||
mButtonType[1] = buttonDown;
|
||||
mButtonType[2] = buttonLeft;
|
||||
mButtonType[3] = buttonRight;
|
||||
mLegacyId = legacyId;
|
||||
mControls[0] = upControl;
|
||||
mControls[1] = downControl;
|
||||
mControls[2] = leftControl;
|
||||
mControls[3] = rightControl;
|
||||
}
|
||||
|
||||
public void draw(Canvas canvas)
|
||||
|
@ -127,14 +127,17 @@ public final class InputOverlayDrawableDpad
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets one of the InputOverlayDrawableDpad's button IDs.
|
||||
*
|
||||
* @return the requested InputOverlayDrawableDpad's button ID.
|
||||
*/
|
||||
public int getId(int direction)
|
||||
public int getLegacyId()
|
||||
{
|
||||
return mButtonType[direction];
|
||||
return mLegacyId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets one of the InputOverlayDrawableDpad's control IDs.
|
||||
*/
|
||||
public int getControl(int direction)
|
||||
{
|
||||
return mControls[direction];
|
||||
}
|
||||
|
||||
public void setTrackId(int trackId)
|
||||
|
|
|
@ -12,7 +12,7 @@ import android.graphics.Rect;
|
|||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import org.dolphinemu.dolphinemu.NativeLibrary;
|
||||
import org.dolphinemu.dolphinemu.features.input.model.InputOverrider;
|
||||
import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting;
|
||||
|
||||
/**
|
||||
|
@ -21,10 +21,12 @@ import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting;
|
|||
*/
|
||||
public final class InputOverlayDrawableJoystick
|
||||
{
|
||||
private final int[] axisIDs = {0, 0, 0, 0};
|
||||
private final float[] axises = {0f, 0f};
|
||||
private float mCurrentX = 0.0f;
|
||||
private float mCurrentY = 0.0f;
|
||||
private int trackId = -1;
|
||||
private final int mJoystickType;
|
||||
private final int mJoystickLegacyId;
|
||||
private final int mJoystickXControl;
|
||||
private final int mJoystickYControl;
|
||||
private int mControlPositionX, mControlPositionY;
|
||||
private int mPreviousTouchX, mPreviousTouchY;
|
||||
private final int mWidth;
|
||||
|
@ -47,16 +49,17 @@ public final class InputOverlayDrawableJoystick
|
|||
* @param bitmapInnerPressed {@link Bitmap} which represents the pressed inner movable part of the joystick.
|
||||
* @param rectOuter {@link Rect} which represents the outer joystick bounds.
|
||||
* @param rectInner {@link Rect} which represents the inner joystick bounds.
|
||||
* @param joystick Identifier for which joystick this is.
|
||||
* @param legacyId Legacy identifier (ButtonType) for which joystick this is.
|
||||
* @param xControl The control which the x value of the joystick will be written to.
|
||||
* @param yControl The control which the y value of the joystick will be written to.
|
||||
*/
|
||||
public InputOverlayDrawableJoystick(Resources res, Bitmap bitmapOuter, Bitmap bitmapInnerDefault,
|
||||
Bitmap bitmapInnerPressed, Rect rectOuter, Rect rectInner, int joystick)
|
||||
Bitmap bitmapInnerPressed, Rect rectOuter, Rect rectInner, int legacyId, int xControl,
|
||||
int yControl)
|
||||
{
|
||||
axisIDs[0] = joystick + 1;
|
||||
axisIDs[1] = joystick + 2;
|
||||
axisIDs[2] = joystick + 3;
|
||||
axisIDs[3] = joystick + 4;
|
||||
mJoystickType = joystick;
|
||||
mJoystickLegacyId = legacyId;
|
||||
mJoystickXControl = xControl;
|
||||
mJoystickYControl = yControl;
|
||||
|
||||
mOuterBitmap = new BitmapDrawable(res, bitmapOuter);
|
||||
mDefaultStateInnerBitmap = new BitmapDrawable(res, bitmapInnerDefault);
|
||||
|
@ -76,13 +79,13 @@ public final class InputOverlayDrawableJoystick
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets this InputOverlayDrawableJoystick's button ID.
|
||||
* Gets this InputOverlayDrawableJoystick's legacy ID.
|
||||
*
|
||||
* @return this InputOverlayDrawableJoystick's button ID.
|
||||
* @return this InputOverlayDrawableJoystick's legacy ID.
|
||||
*/
|
||||
public int getId()
|
||||
public int getLegacyId()
|
||||
{
|
||||
return mJoystickType;
|
||||
return mJoystickLegacyId;
|
||||
}
|
||||
|
||||
public void draw(Canvas canvas)
|
||||
|
@ -125,7 +128,7 @@ public final class InputOverlayDrawableJoystick
|
|||
{
|
||||
pressed = true;
|
||||
mPressedState = false;
|
||||
axises[0] = axises[1] = 0.0f;
|
||||
mCurrentX = mCurrentY = 0.0f;
|
||||
mOuterBitmap.setAlpha(mOpacity);
|
||||
mBoundsBoxBitmap.setAlpha(0);
|
||||
setVirtBounds(new Rect(mOrigBounds.left, mOrigBounds.top, mOrigBounds.right,
|
||||
|
@ -153,10 +156,8 @@ public final class InputOverlayDrawableJoystick
|
|||
maxX -= getVirtBounds().centerX();
|
||||
touchY -= getVirtBounds().centerY();
|
||||
maxY -= getVirtBounds().centerY();
|
||||
final float AxisX = touchX / maxX;
|
||||
final float AxisY = touchY / maxY;
|
||||
axises[0] = AxisY;
|
||||
axises[1] = AxisX;
|
||||
mCurrentX = touchX / maxX;
|
||||
mCurrentY = touchY / maxY;
|
||||
|
||||
SetInnerBounds();
|
||||
}
|
||||
|
@ -193,36 +194,40 @@ public final class InputOverlayDrawableJoystick
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public float[] getAxisValues()
|
||||
public float getX()
|
||||
{
|
||||
float[] joyaxises = {0f, 0f, 0f, 0f};
|
||||
joyaxises[1] = Math.min(axises[0], 1.0f);
|
||||
joyaxises[0] = Math.min(axises[0], 0.0f);
|
||||
joyaxises[3] = Math.min(axises[1], 1.0f);
|
||||
joyaxises[2] = Math.min(axises[1], 0.0f);
|
||||
return joyaxises;
|
||||
return mCurrentX;
|
||||
}
|
||||
|
||||
public int[] getAxisIDs()
|
||||
public float getY()
|
||||
{
|
||||
return axisIDs;
|
||||
return mCurrentY;
|
||||
}
|
||||
|
||||
public int getXControl()
|
||||
{
|
||||
return mJoystickXControl;
|
||||
}
|
||||
|
||||
public int getYControl()
|
||||
{
|
||||
return mJoystickYControl;
|
||||
}
|
||||
|
||||
private void SetInnerBounds()
|
||||
{
|
||||
double y = axises[0];
|
||||
double x = axises[1];
|
||||
double x = mCurrentX;
|
||||
double y = mCurrentY;
|
||||
|
||||
double angle = Math.atan2(y, x) + Math.PI + Math.PI;
|
||||
double radius = Math.hypot(y, x);
|
||||
double maxRadius = NativeLibrary.GetInputRadiusAtAngle(0, mJoystickType, angle);
|
||||
double maxRadius = InputOverrider.getGateRadiusAtAngle(0, mJoystickXControl, angle);
|
||||
if (radius > maxRadius)
|
||||
{
|
||||
y = maxRadius * Math.sin(angle);
|
||||
x = maxRadius * Math.cos(angle);
|
||||
axises[0] = (float) y;
|
||||
axises[1] = (float) x;
|
||||
mCurrentY = (float) y;
|
||||
mCurrentX = (float) x;
|
||||
}
|
||||
|
||||
int pixelX = getVirtBounds().centerX() + (int) (x * (getVirtBounds().width() / 2));
|
||||
|
|
|
@ -7,22 +7,20 @@ import android.os.Handler;
|
|||
import android.view.MotionEvent;
|
||||
|
||||
import org.dolphinemu.dolphinemu.NativeLibrary;
|
||||
import org.dolphinemu.dolphinemu.features.input.model.InputOverrider;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class InputOverlayPointer
|
||||
{
|
||||
public static final int DOUBLE_TAP_A = 0;
|
||||
public static final int DOUBLE_TAP_B = 1;
|
||||
public static final int DOUBLE_TAP_2 = 2;
|
||||
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[] oldaxes = {0f, 0f};
|
||||
private float mCurrentX = 0.0f;
|
||||
private float mCurrentY = 0.0f;
|
||||
private float mOldX = 0.0f;
|
||||
private float mOldY = 0.0f;
|
||||
|
||||
private float mGameCenterX;
|
||||
private float mGameCenterY;
|
||||
|
@ -36,7 +34,7 @@ public class InputOverlayPointer
|
|||
private boolean mRecenter;
|
||||
|
||||
private boolean doubleTap = false;
|
||||
private int doubleTapButton;
|
||||
private int mDoubleTapControl;
|
||||
private int trackId = -1;
|
||||
|
||||
public static ArrayList<Integer> DOUBLE_TAP_OPTIONS = new ArrayList<>();
|
||||
|
@ -49,9 +47,9 @@ public class InputOverlayPointer
|
|||
DOUBLE_TAP_OPTIONS.add(NativeLibrary.ButtonType.CLASSIC_BUTTON_A);
|
||||
}
|
||||
|
||||
public InputOverlayPointer(Rect surfacePosition, int button, int mode, boolean recenter)
|
||||
public InputOverlayPointer(Rect surfacePosition, int doubleTapControl, int mode, boolean recenter)
|
||||
{
|
||||
doubleTapButton = button;
|
||||
mDoubleTapControl = doubleTapControl;
|
||||
mMode = mode;
|
||||
mRecenter = recenter;
|
||||
|
||||
|
@ -112,15 +110,15 @@ public class InputOverlayPointer
|
|||
|
||||
if (mMode == MODE_FOLLOW)
|
||||
{
|
||||
axes[0] = (event.getY(event.findPointerIndex(trackId)) - mGameCenterY) * mGameHeightHalfInv;
|
||||
axes[1] = (event.getX(event.findPointerIndex(trackId)) - mGameCenterX) * mGameWidthHalfInv;
|
||||
mCurrentX = (event.getX(event.findPointerIndex(trackId)) - mGameCenterX) * mGameWidthHalfInv;
|
||||
mCurrentY = (event.getY(event.findPointerIndex(trackId)) - mGameCenterY) * mGameHeightHalfInv;
|
||||
}
|
||||
else if (mMode == MODE_DRAG)
|
||||
{
|
||||
axes[0] = oldaxes[0] +
|
||||
(event.getY(event.findPointerIndex(trackId)) - mTouchStartY) * mGameHeightHalfInv;
|
||||
axes[1] = oldaxes[1] +
|
||||
mCurrentX = mOldX +
|
||||
(event.getX(event.findPointerIndex(trackId)) - mTouchStartX) * mGameWidthHalfInv;
|
||||
mCurrentY = mOldY +
|
||||
(event.getY(event.findPointerIndex(trackId)) - mTouchStartY) * mGameHeightHalfInv;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,11 +128,9 @@ public class InputOverlayPointer
|
|||
{
|
||||
if (doubleTap)
|
||||
{
|
||||
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice,
|
||||
doubleTapButton, NativeLibrary.ButtonState.PRESSED);
|
||||
new Handler()
|
||||
.postDelayed(() -> NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice,
|
||||
doubleTapButton, NativeLibrary.ButtonState.RELEASED), 50);
|
||||
InputOverrider.setControlState(0, mDoubleTapControl, 1.0);
|
||||
new Handler().postDelayed(() -> InputOverrider.setControlState(0, mDoubleTapControl, 0.0),
|
||||
50);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -146,23 +142,23 @@ public class InputOverlayPointer
|
|||
|
||||
private void updateOldAxes()
|
||||
{
|
||||
oldaxes[0] = axes[0];
|
||||
oldaxes[1] = axes[1];
|
||||
mOldX = mCurrentX;
|
||||
mOldY = mCurrentY;
|
||||
}
|
||||
|
||||
private void reset()
|
||||
{
|
||||
axes[0] = axes[1] = oldaxes[0] = oldaxes[1] = 0f;
|
||||
mCurrentX = mCurrentY = mOldX = mOldY = 0.0f;
|
||||
}
|
||||
|
||||
public float[] getAxisValues()
|
||||
public float getX()
|
||||
{
|
||||
float[] iraxes = {0f, 0f, 0f, 0f};
|
||||
iraxes[1] = axes[0];
|
||||
iraxes[0] = axes[0];
|
||||
iraxes[3] = axes[1];
|
||||
iraxes[2] = axes[1];
|
||||
return iraxes;
|
||||
return mCurrentX;
|
||||
}
|
||||
|
||||
public float getY()
|
||||
{
|
||||
return mCurrentY;
|
||||
}
|
||||
|
||||
public void setMode(int mode)
|
||||
|
|
|
@ -10,6 +10,7 @@ add_library(main SHARED
|
|||
GameList/GameFile.cpp
|
||||
GameList/GameFile.h
|
||||
GameList/GameFileCache.cpp
|
||||
Input/InputOverrider.cpp
|
||||
IniFile.cpp
|
||||
MainAndroid.cpp
|
||||
RiivolutionPatches.cpp
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
// Copyright 2021 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "InputCommon/ControllerInterface/Touch/InputOverrider.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_dolphinemu_dolphinemu_features_input_model_InputOverrider_registerGameCube(
|
||||
JNIEnv*, jclass, int controller_index)
|
||||
{
|
||||
ciface::Touch::RegisterGameCubeInputOverrider(controller_index);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_dolphinemu_dolphinemu_features_input_model_InputOverrider_registerWii(JNIEnv*, jclass,
|
||||
int controller_index)
|
||||
{
|
||||
ciface::Touch::RegisterWiiInputOverrider(controller_index);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_dolphinemu_dolphinemu_features_input_model_InputOverrider_unregisterGameCube(
|
||||
JNIEnv*, jclass, int controller_index)
|
||||
{
|
||||
ciface::Touch::UnregisterGameCubeInputOverrider(controller_index);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_dolphinemu_dolphinemu_features_input_model_InputOverrider_unregisterWii(
|
||||
JNIEnv*, jclass, int controller_index)
|
||||
{
|
||||
ciface::Touch::UnregisterWiiInputOverrider(controller_index);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_dolphinemu_dolphinemu_features_input_model_InputOverrider_setControlState(
|
||||
JNIEnv*, jclass, int controller_index, int control, double state)
|
||||
{
|
||||
ciface::Touch::SetControlState(controller_index, static_cast<ciface::Touch::ControlID>(control),
|
||||
state);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_dolphinemu_dolphinemu_features_input_model_InputOverrider_clearControlState(
|
||||
JNIEnv*, jclass, int controller_index, int control)
|
||||
{
|
||||
ciface::Touch::ClearControlState(controller_index,
|
||||
static_cast<ciface::Touch::ControlID>(control));
|
||||
}
|
||||
|
||||
JNIEXPORT double JNICALL
|
||||
Java_org_dolphinemu_dolphinemu_features_input_model_InputOverrider_getGateRadiusAtAngle(
|
||||
JNIEnv*, jclass, int controller_index, int stick, double angle)
|
||||
{
|
||||
const auto casted_stick = static_cast<ciface::Touch::ControlID>(stick);
|
||||
return ciface::Touch::GetGateRadiusAtAngle(controller_index, casted_stick, angle);
|
||||
}
|
||||
};
|
|
@ -302,13 +302,6 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetMotionSen
|
|||
ciface::Android::SetMotionSensorsEnabled(accelerometer_enabled, gyroscope_enabled);
|
||||
}
|
||||
|
||||
JNIEXPORT double JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetInputRadiusAtAngle(
|
||||
JNIEnv*, jclass, int emu_pad_id, int stick, double angle)
|
||||
{
|
||||
const auto casted_stick = static_cast<ButtonManager::ButtonType>(stick);
|
||||
return ButtonManager::GetInputRadiusAtAngle(emu_pad_id, casted_stick, angle);
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetVersionString(JNIEnv* env,
|
||||
jclass)
|
||||
{
|
||||
|
|
|
@ -36,62 +36,47 @@ static const u16 trigger_bitmasks[] = {
|
|||
static const u16 dpad_bitmasks[] = {PAD_BUTTON_UP, PAD_BUTTON_DOWN, PAD_BUTTON_LEFT,
|
||||
PAD_BUTTON_RIGHT};
|
||||
|
||||
static const char* const named_buttons[] = {"A", "B", "X", "Y", "Z", "Start"};
|
||||
|
||||
static const char* const named_triggers[] = {
|
||||
// i18n: The left trigger button (labeled L on real controllers)
|
||||
_trans("L"),
|
||||
// i18n: The right trigger button (labeled R on real controllers)
|
||||
_trans("R"),
|
||||
// i18n: The left trigger button (labeled L on real controllers) used as an analog input
|
||||
_trans("L-Analog"),
|
||||
// i18n: The right trigger button (labeled R on real controllers) used as an analog input
|
||||
_trans("R-Analog")};
|
||||
|
||||
GCPad::GCPad(const unsigned int index) : m_index(index)
|
||||
{
|
||||
// buttons
|
||||
groups.emplace_back(m_buttons = new ControllerEmu::Buttons(_trans("Buttons")));
|
||||
for (const char* named_button : named_buttons)
|
||||
groups.emplace_back(m_buttons = new ControllerEmu::Buttons(BUTTONS_GROUP));
|
||||
for (const char* named_button : {A_BUTTON, B_BUTTON, X_BUTTON, Y_BUTTON, Z_BUTTON})
|
||||
{
|
||||
const bool is_start = named_button == std::string("Start");
|
||||
const ControllerEmu::Translatability translate =
|
||||
is_start ? ControllerEmu::Translate : ControllerEmu::DoNotTranslate;
|
||||
// i18n: The START/PAUSE button on GameCube controllers
|
||||
std::string ui_name = is_start ? _trans("START") : named_button;
|
||||
m_buttons->AddInput(translate, named_button, std::move(ui_name));
|
||||
m_buttons->AddInput(ControllerEmu::DoNotTranslate, named_button);
|
||||
}
|
||||
// i18n: The START/PAUSE button on GameCube controllers
|
||||
m_buttons->AddInput(ControllerEmu::Translate, START_BUTTON, _trans("START"));
|
||||
|
||||
// sticks
|
||||
groups.emplace_back(m_main_stick = new ControllerEmu::OctagonAnalogStick(
|
||||
"Main Stick", _trans("Control Stick"), MAIN_STICK_GATE_RADIUS));
|
||||
MAIN_STICK_GROUP, _trans("Control Stick"), MAIN_STICK_GATE_RADIUS));
|
||||
groups.emplace_back(m_c_stick = new ControllerEmu::OctagonAnalogStick(
|
||||
"C-Stick", _trans("C Stick"), C_STICK_GATE_RADIUS));
|
||||
C_STICK_GROUP, _trans("C Stick"), C_STICK_GATE_RADIUS));
|
||||
|
||||
// triggers
|
||||
groups.emplace_back(m_triggers = new ControllerEmu::MixedTriggers(_trans("Triggers")));
|
||||
for (const char* named_trigger : named_triggers)
|
||||
groups.emplace_back(m_triggers = new ControllerEmu::MixedTriggers(TRIGGERS_GROUP));
|
||||
for (const char* named_trigger : {L_DIGITAL, R_DIGITAL, L_ANALOG, R_ANALOG})
|
||||
{
|
||||
m_triggers->AddInput(ControllerEmu::Translate, named_trigger);
|
||||
}
|
||||
|
||||
// rumble
|
||||
groups.emplace_back(m_rumble = new ControllerEmu::ControlGroup(_trans("Rumble")));
|
||||
groups.emplace_back(m_rumble = new ControllerEmu::ControlGroup(RUMBLE_GROUP));
|
||||
m_rumble->AddOutput(ControllerEmu::Translate, _trans("Motor"));
|
||||
|
||||
// Microphone
|
||||
groups.emplace_back(m_mic = new ControllerEmu::Buttons(_trans("Microphone")));
|
||||
groups.emplace_back(m_mic = new ControllerEmu::Buttons(MIC_GROUP));
|
||||
m_mic->AddInput(ControllerEmu::Translate, _trans("Button"));
|
||||
|
||||
// dpad
|
||||
groups.emplace_back(m_dpad = new ControllerEmu::Buttons(_trans("D-Pad")));
|
||||
groups.emplace_back(m_dpad = new ControllerEmu::Buttons(DPAD_GROUP));
|
||||
for (const char* named_direction : named_directions)
|
||||
{
|
||||
m_dpad->AddInput(ControllerEmu::Translate, named_direction);
|
||||
}
|
||||
|
||||
// options
|
||||
groups.emplace_back(m_options = new ControllerEmu::ControlGroup(_trans("Options")));
|
||||
groups.emplace_back(m_options = new ControllerEmu::ControlGroup(OPTIONS_GROUP));
|
||||
m_options->AddSetting(
|
||||
&m_always_connected_setting,
|
||||
// i18n: Treat a controller as always being connected regardless of what
|
||||
|
@ -138,14 +123,15 @@ GCPadStatus GCPad::GetInput() const
|
|||
const auto lock = GetStateLock();
|
||||
GCPadStatus pad = {};
|
||||
|
||||
if (!(m_always_connected_setting.GetValue() || IsDefaultDeviceConnected()))
|
||||
if (!(m_always_connected_setting.GetValue() || IsDefaultDeviceConnected() ||
|
||||
m_input_override_function))
|
||||
{
|
||||
pad.isConnected = false;
|
||||
return pad;
|
||||
}
|
||||
|
||||
// buttons
|
||||
m_buttons->GetState(&pad.button, button_bitmasks);
|
||||
m_buttons->GetState(&pad.button, button_bitmasks, m_input_override_function);
|
||||
|
||||
// set analog A/B analog to full or w/e, prolly not needed
|
||||
if (pad.button & PAD_BUTTON_A)
|
||||
|
@ -154,20 +140,20 @@ GCPadStatus GCPad::GetInput() const
|
|||
pad.analogB = 0xFF;
|
||||
|
||||
// dpad
|
||||
m_dpad->GetState(&pad.button, dpad_bitmasks);
|
||||
m_dpad->GetState(&pad.button, dpad_bitmasks, m_input_override_function);
|
||||
|
||||
// sticks
|
||||
const auto main_stick_state = m_main_stick->GetState();
|
||||
const auto main_stick_state = m_main_stick->GetState(m_input_override_function);
|
||||
pad.stickX = MapFloat<u8>(main_stick_state.x, GCPadStatus::MAIN_STICK_CENTER_X, 1);
|
||||
pad.stickY = MapFloat<u8>(main_stick_state.y, GCPadStatus::MAIN_STICK_CENTER_Y, 1);
|
||||
|
||||
const auto c_stick_state = m_c_stick->GetState();
|
||||
const auto c_stick_state = m_c_stick->GetState(m_input_override_function);
|
||||
pad.substickX = MapFloat<u8>(c_stick_state.x, GCPadStatus::C_STICK_CENTER_X, 1);
|
||||
pad.substickY = MapFloat<u8>(c_stick_state.y, GCPadStatus::C_STICK_CENTER_Y, 1);
|
||||
|
||||
// triggers
|
||||
std::array<ControlState, 2> triggers;
|
||||
m_triggers->GetState(&pad.button, trigger_bitmasks, triggers.data());
|
||||
m_triggers->GetState(&pad.button, trigger_bitmasks, triggers.data(), m_input_override_function);
|
||||
pad.triggerLeft = MapFloat<u8>(triggers[0], 0);
|
||||
pad.triggerRight = MapFloat<u8>(triggers[1], 0);
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include "Common/Common.h"
|
||||
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
|
||||
#include "InputCommon/ControllerEmu/ControllerEmu.h"
|
||||
#include "InputCommon/ControllerEmu/Setting/NumericSetting.h"
|
||||
|
@ -49,6 +51,31 @@ public:
|
|||
static constexpr ControlState MAIN_STICK_GATE_RADIUS = 0.7937125;
|
||||
static constexpr ControlState C_STICK_GATE_RADIUS = 0.7221375;
|
||||
|
||||
static constexpr const char* BUTTONS_GROUP = _trans("Buttons");
|
||||
static constexpr const char* MAIN_STICK_GROUP = "Main Stick";
|
||||
static constexpr const char* C_STICK_GROUP = "C-Stick";
|
||||
static constexpr const char* DPAD_GROUP = _trans("D-Pad");
|
||||
static constexpr const char* TRIGGERS_GROUP = _trans("Triggers");
|
||||
static constexpr const char* RUMBLE_GROUP = _trans("Rumble");
|
||||
static constexpr const char* MIC_GROUP = _trans("Microphone");
|
||||
static constexpr const char* OPTIONS_GROUP = _trans("Options");
|
||||
|
||||
static constexpr const char* A_BUTTON = "A";
|
||||
static constexpr const char* B_BUTTON = "B";
|
||||
static constexpr const char* X_BUTTON = "X";
|
||||
static constexpr const char* Y_BUTTON = "Y";
|
||||
static constexpr const char* Z_BUTTON = "Z";
|
||||
static constexpr const char* START_BUTTON = "Start";
|
||||
|
||||
// i18n: The left trigger button (labeled L on real controllers)
|
||||
static constexpr const char* L_DIGITAL = _trans("L");
|
||||
// i18n: The right trigger button (labeled R on real controllers)
|
||||
static constexpr const char* R_DIGITAL = _trans("R");
|
||||
// i18n: The left trigger button (labeled L on real controllers) used as an analog input
|
||||
static constexpr const char* L_ANALOG = _trans("L-Analog");
|
||||
// i18n: The right trigger button (labeled R on real controllers) used as an analog input
|
||||
static constexpr const char* R_ANALOG = _trans("R-Analog");
|
||||
|
||||
private:
|
||||
ControllerEmu::Buttons* m_buttons;
|
||||
ControllerEmu::AnalogStick* m_main_stick;
|
||||
|
|
|
@ -119,8 +119,6 @@ int CSIDevice_GCController::RunBuffer(u8* buffer, int request_length)
|
|||
|
||||
void CSIDevice_GCController::HandleMoviePadStatus(int device_number, GCPadStatus* pad_status)
|
||||
{
|
||||
Movie::CallGCInputManip(pad_status, device_number);
|
||||
|
||||
Movie::SetPolledDevice();
|
||||
if (NetPlay_GetInput(device_number, pad_status))
|
||||
{
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <optional>
|
||||
|
||||
#include "Common/MathUtil.h"
|
||||
#include "Core/Config/SYSCONFSettings.h"
|
||||
|
@ -221,9 +222,10 @@ WiimoteCommon::AccelData ConvertAccelData(const Common::Vec3& accel, u16 zero_g,
|
|||
u16(std::clamp(std::lround(scaled_accel.z + zero_g), 0l, MAX_VALUE))});
|
||||
}
|
||||
|
||||
void EmulatePoint(MotionState* state, ControllerEmu::Cursor* ir_group, float time_elapsed)
|
||||
void EmulatePoint(MotionState* state, ControllerEmu::Cursor* ir_group,
|
||||
const ControllerEmu::InputOverrideFunction& override_func, float time_elapsed)
|
||||
{
|
||||
const auto cursor = ir_group->GetState(true);
|
||||
const auto cursor = ir_group->GetState(true, override_func);
|
||||
|
||||
if (!cursor.IsVisible())
|
||||
{
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "InputCommon/ControllerEmu/ControlGroup/IMUCursor.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/IMUGyroscope.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/Tilt.h"
|
||||
#include "InputCommon/ControllerEmu/ControllerEmu.h"
|
||||
|
||||
namespace WiimoteEmu
|
||||
{
|
||||
|
@ -81,7 +82,8 @@ void ApproachAngleWithAccel(RotationalState* state, const Common::Vec3& target,
|
|||
void EmulateShake(PositionalState* state, ControllerEmu::Shake* shake_group, float time_elapsed);
|
||||
void EmulateTilt(RotationalState* state, ControllerEmu::Tilt* tilt_group, float time_elapsed);
|
||||
void EmulateSwing(MotionState* state, ControllerEmu::Force* swing_group, float time_elapsed);
|
||||
void EmulatePoint(MotionState* state, ControllerEmu::Cursor* ir_group, float time_elapsed);
|
||||
void EmulatePoint(MotionState* state, ControllerEmu::Cursor* ir_group,
|
||||
const ControllerEmu::InputOverrideFunction& override_func, float time_elapsed);
|
||||
void EmulateIMUCursor(IMUCursorState* state, ControllerEmu::IMUCursor* imu_ir_group,
|
||||
ControllerEmu::IMUAccelerometer* imu_accelerometer_group,
|
||||
ControllerEmu::IMUGyroscope* imu_gyroscope_group, float time_elapsed);
|
||||
|
|
|
@ -39,34 +39,11 @@ constexpr std::array<u16, 9> classic_button_bitmasks{{
|
|||
Classic::BUTTON_HOME,
|
||||
}};
|
||||
|
||||
constexpr std::array<std::string_view, 9> classic_button_names{{
|
||||
"A",
|
||||
"B",
|
||||
"X",
|
||||
"Y",
|
||||
"ZL",
|
||||
"ZR",
|
||||
"-",
|
||||
"+",
|
||||
"Home",
|
||||
}};
|
||||
|
||||
constexpr std::array<u16, 2> classic_trigger_bitmasks{{
|
||||
Classic::TRIGGER_L,
|
||||
Classic::TRIGGER_R,
|
||||
}};
|
||||
|
||||
constexpr std::array<const char*, 4> classic_trigger_names{{
|
||||
// i18n: The left trigger button (labeled L on real controllers)
|
||||
_trans("L"),
|
||||
// i18n: The right trigger button (labeled R on real controllers)
|
||||
_trans("R"),
|
||||
// i18n: The left trigger button (labeled L on real controllers) used as an analog input
|
||||
_trans("L-Analog"),
|
||||
// i18n: The right trigger button (labeled R on real controllers) used as an analog input
|
||||
_trans("R-Analog"),
|
||||
}};
|
||||
|
||||
constexpr std::array<u16, 4> classic_dpad_bitmasks{{
|
||||
Classic::PAD_UP,
|
||||
Classic::PAD_DOWN,
|
||||
|
@ -77,30 +54,30 @@ constexpr std::array<u16, 4> classic_dpad_bitmasks{{
|
|||
Classic::Classic() : Extension1stParty("Classic", _trans("Classic Controller"))
|
||||
{
|
||||
// buttons
|
||||
groups.emplace_back(m_buttons = new ControllerEmu::Buttons(_trans("Buttons")));
|
||||
for (auto& button_name : classic_button_names)
|
||||
groups.emplace_back(m_buttons = new ControllerEmu::Buttons(BUTTONS_GROUP));
|
||||
for (auto& button_name :
|
||||
{A_BUTTON, B_BUTTON, X_BUTTON, Y_BUTTON, ZL_BUTTON, ZR_BUTTON, MINUS_BUTTON, PLUS_BUTTON})
|
||||
{
|
||||
std::string_view ui_name = (button_name == "Home") ? "HOME" : button_name;
|
||||
m_buttons->AddInput(ControllerEmu::DoNotTranslate, std::string(button_name),
|
||||
std::string(ui_name));
|
||||
m_buttons->AddInput(ControllerEmu::DoNotTranslate, button_name);
|
||||
}
|
||||
m_buttons->AddInput(ControllerEmu::DoNotTranslate, HOME_BUTTON, "HOME");
|
||||
|
||||
// sticks
|
||||
constexpr auto gate_radius = ControlState(STICK_GATE_RADIUS) / CAL_STICK_RANGE;
|
||||
constexpr auto gate_radius = ControlState(STICK_GATE_RADIUS) / CAL_STICK_RADIUS;
|
||||
groups.emplace_back(m_left_stick =
|
||||
new ControllerEmu::OctagonAnalogStick(_trans("Left Stick"), gate_radius));
|
||||
groups.emplace_back(
|
||||
m_right_stick = new ControllerEmu::OctagonAnalogStick(_trans("Right Stick"), gate_radius));
|
||||
new ControllerEmu::OctagonAnalogStick(LEFT_STICK_GROUP, gate_radius));
|
||||
groups.emplace_back(m_right_stick =
|
||||
new ControllerEmu::OctagonAnalogStick(RIGHT_STICK_GROUP, gate_radius));
|
||||
|
||||
// triggers
|
||||
groups.emplace_back(m_triggers = new ControllerEmu::MixedTriggers(_trans("Triggers")));
|
||||
for (const char* trigger_name : classic_trigger_names)
|
||||
groups.emplace_back(m_triggers = new ControllerEmu::MixedTriggers(TRIGGERS_GROUP));
|
||||
for (const char* trigger_name : {L_DIGITAL, R_DIGITAL, L_ANALOG, R_ANALOG})
|
||||
{
|
||||
m_triggers->AddInput(ControllerEmu::Translate, trigger_name);
|
||||
}
|
||||
|
||||
// dpad
|
||||
groups.emplace_back(m_dpad = new ControllerEmu::Buttons(_trans("D-Pad")));
|
||||
groups.emplace_back(m_dpad = new ControllerEmu::Buttons(DPAD_GROUP));
|
||||
for (const char* named_direction : named_directions)
|
||||
{
|
||||
m_dpad->AddInput(ControllerEmu::Translate, named_direction);
|
||||
|
@ -113,20 +90,22 @@ void Classic::BuildDesiredExtensionState(DesiredExtensionState* target_state)
|
|||
|
||||
// left stick
|
||||
{
|
||||
const ControllerEmu::AnalogStick::StateData left_stick_state = m_left_stick->GetState();
|
||||
const ControllerEmu::AnalogStick::StateData left_stick_state =
|
||||
m_left_stick->GetState(m_input_override_function);
|
||||
|
||||
const u8 x = static_cast<u8>(LEFT_STICK_CENTER + (left_stick_state.x * LEFT_STICK_RADIUS));
|
||||
const u8 y = static_cast<u8>(LEFT_STICK_CENTER + (left_stick_state.y * LEFT_STICK_RADIUS));
|
||||
const u8 x = MapFloat<u8>(left_stick_state.x, LEFT_STICK_CENTER, 0, LEFT_STICK_RANGE);
|
||||
const u8 y = MapFloat<u8>(left_stick_state.y, LEFT_STICK_CENTER, 0, LEFT_STICK_RANGE);
|
||||
|
||||
classic_data.SetLeftStick({x, y});
|
||||
}
|
||||
|
||||
// right stick
|
||||
{
|
||||
const ControllerEmu::AnalogStick::StateData right_stick_data = m_right_stick->GetState();
|
||||
const ControllerEmu::AnalogStick::StateData right_stick_data =
|
||||
m_right_stick->GetState(m_input_override_function);
|
||||
|
||||
const u8 x = static_cast<u8>(RIGHT_STICK_CENTER + (right_stick_data.x * RIGHT_STICK_RADIUS));
|
||||
const u8 y = static_cast<u8>(RIGHT_STICK_CENTER + (right_stick_data.y * RIGHT_STICK_RADIUS));
|
||||
const u8 x = MapFloat<u8>(right_stick_data.x, RIGHT_STICK_CENTER, 0, RIGHT_STICK_RANGE);
|
||||
const u8 y = MapFloat<u8>(right_stick_data.y, RIGHT_STICK_CENTER, 0, RIGHT_STICK_RANGE);
|
||||
|
||||
classic_data.SetRightStick({x, y});
|
||||
}
|
||||
|
@ -135,19 +114,20 @@ void Classic::BuildDesiredExtensionState(DesiredExtensionState* target_state)
|
|||
|
||||
// triggers
|
||||
{
|
||||
ControlState trigs[2] = {0, 0};
|
||||
m_triggers->GetState(&buttons, classic_trigger_bitmasks.data(), trigs);
|
||||
ControlState triggers[2] = {0, 0};
|
||||
m_triggers->GetState(&buttons, classic_trigger_bitmasks.data(), triggers,
|
||||
m_input_override_function);
|
||||
|
||||
const u8 lt = static_cast<u8>(trigs[0] * TRIGGER_RANGE);
|
||||
const u8 rt = static_cast<u8>(trigs[1] * TRIGGER_RANGE);
|
||||
const u8 lt = MapFloat<u8>(triggers[0], 0, 0, TRIGGER_RANGE);
|
||||
const u8 rt = MapFloat<u8>(triggers[1], 0, 0, TRIGGER_RANGE);
|
||||
|
||||
classic_data.SetLeftTrigger(lt);
|
||||
classic_data.SetRightTrigger(rt);
|
||||
}
|
||||
|
||||
// buttons and dpad
|
||||
m_buttons->GetState(&buttons, classic_button_bitmasks.data());
|
||||
m_dpad->GetState(&buttons, classic_dpad_bitmasks.data());
|
||||
m_buttons->GetState(&buttons, classic_button_bitmasks.data(), m_input_override_function);
|
||||
m_dpad->GetState(&buttons, classic_dpad_bitmasks.data(), m_input_override_function);
|
||||
|
||||
classic_data.SetButtons(buttons);
|
||||
|
||||
|
|
|
@ -205,16 +205,42 @@ public:
|
|||
static constexpr u8 STICK_GATE_RADIUS = 0x61;
|
||||
|
||||
static constexpr u8 CAL_STICK_CENTER = 0x80;
|
||||
static constexpr u8 CAL_STICK_RANGE = 0x7f;
|
||||
static constexpr u8 CAL_STICK_RADIUS = 0x7f;
|
||||
static constexpr u8 CAL_STICK_RANGE = 0xff;
|
||||
|
||||
static constexpr u8 LEFT_STICK_CENTER = CAL_STICK_CENTER >> (CAL_STICK_BITS - LEFT_STICK_BITS);
|
||||
static constexpr u8 LEFT_STICK_RADIUS = CAL_STICK_RANGE >> (CAL_STICK_BITS - LEFT_STICK_BITS);
|
||||
static constexpr u8 LEFT_STICK_RANGE = CAL_STICK_RANGE >> (CAL_STICK_BITS - LEFT_STICK_BITS);
|
||||
|
||||
static constexpr u8 RIGHT_STICK_CENTER = CAL_STICK_CENTER >> (CAL_STICK_BITS - RIGHT_STICK_BITS);
|
||||
static constexpr u8 RIGHT_STICK_RADIUS = CAL_STICK_RANGE >> (CAL_STICK_BITS - RIGHT_STICK_BITS);
|
||||
static constexpr u8 RIGHT_STICK_RANGE = CAL_STICK_RANGE >> (CAL_STICK_BITS - RIGHT_STICK_BITS);
|
||||
|
||||
static constexpr u8 TRIGGER_RANGE = 0x1F;
|
||||
|
||||
static constexpr const char* BUTTONS_GROUP = _trans("Buttons");
|
||||
static constexpr const char* LEFT_STICK_GROUP = _trans("Left Stick");
|
||||
static constexpr const char* RIGHT_STICK_GROUP = _trans("Right Stick");
|
||||
static constexpr const char* TRIGGERS_GROUP = _trans("Triggers");
|
||||
static constexpr const char* DPAD_GROUP = _trans("D-Pad");
|
||||
|
||||
static constexpr const char* A_BUTTON = "A";
|
||||
static constexpr const char* B_BUTTON = "B";
|
||||
static constexpr const char* X_BUTTON = "X";
|
||||
static constexpr const char* Y_BUTTON = "Y";
|
||||
static constexpr const char* ZL_BUTTON = "ZL";
|
||||
static constexpr const char* ZR_BUTTON = "ZR";
|
||||
static constexpr const char* MINUS_BUTTON = "-";
|
||||
static constexpr const char* PLUS_BUTTON = "+";
|
||||
static constexpr const char* HOME_BUTTON = "Home";
|
||||
|
||||
// i18n: The left trigger button (labeled L on real controllers)
|
||||
static constexpr const char* L_DIGITAL = _trans("L");
|
||||
// i18n: The right trigger button (labeled R on real controllers)
|
||||
static constexpr const char* R_DIGITAL = _trans("R");
|
||||
// i18n: The left trigger button (labeled L on real controllers) used as an analog input
|
||||
static constexpr const char* L_ANALOG = _trans("L-Analog");
|
||||
// i18n: The right trigger button (labeled R on real controllers) used as an analog input
|
||||
static constexpr const char* R_ANALOG = _trans("R-Analog");
|
||||
|
||||
private:
|
||||
ControllerEmu::Buttons* m_buttons;
|
||||
ControllerEmu::MixedTriggers* m_triggers;
|
||||
|
|
|
@ -44,12 +44,12 @@ void DrawsomeTablet::BuildDesiredExtensionState(DesiredExtensionState* target_st
|
|||
// the "Drawsome" game expects you to go "off screen" a bit to access some menu items.
|
||||
constexpr u16 MIN_Y = 0x15ff + 0x100;
|
||||
constexpr u16 MAX_Y = 0x00;
|
||||
constexpr double CENTER_X = (MAX_X + MIN_X) / 2.0;
|
||||
constexpr double CENTER_Y = (MAX_Y + MIN_Y) / 2.0;
|
||||
constexpr u16 CENTER_X = (MAX_X + MIN_X + 1) / 2;
|
||||
constexpr u16 CENTER_Y = (MAX_Y + MIN_Y + 1) / 2;
|
||||
|
||||
const auto stylus_state = m_stylus->GetState();
|
||||
const auto stylus_x = u16(std::lround(CENTER_X + stylus_state.x * (MAX_X - CENTER_X)));
|
||||
const auto stylus_y = u16(std::lround(CENTER_Y + stylus_state.y * (MAX_Y - CENTER_Y)));
|
||||
const auto stylus_state = m_stylus->GetState(m_input_override_function);
|
||||
const u16 stylus_x = MapFloat<u16>(stylus_state.x, CENTER_X, MIN_X, MAX_X);
|
||||
const u16 stylus_y = MapFloat<u16>(-stylus_state.y, CENTER_Y, MAX_Y, MIN_Y);
|
||||
|
||||
tablet_data.stylus_x1 = u8(stylus_x);
|
||||
tablet_data.stylus_x2 = u8(stylus_x >> 8);
|
||||
|
@ -74,8 +74,8 @@ void DrawsomeTablet::BuildDesiredExtensionState(DesiredExtensionState* target_st
|
|||
// Pressure (0 - 0x7ff):
|
||||
constexpr u16 MAX_PRESSURE = 0x7ff;
|
||||
|
||||
const auto touch_state = m_touch->GetState();
|
||||
const auto pressure = u16(std::lround(touch_state.data[0] * MAX_PRESSURE));
|
||||
const auto touch_state = m_touch->GetState(m_input_override_function);
|
||||
const u16 pressure = MapFloat<u16>(touch_state.data[0], 0, 0, MAX_PRESSURE);
|
||||
|
||||
tablet_data.pressure1 = u8(pressure);
|
||||
tablet_data.pressure2 = u8(pressure >> 8);
|
||||
|
|
|
@ -84,17 +84,20 @@ void Drums::BuildDesiredExtensionState(DesiredExtensionState* target_state)
|
|||
DesiredState& state = target_state->data.emplace<DesiredState>();
|
||||
|
||||
{
|
||||
const ControllerEmu::AnalogStick::StateData stick_state = m_stick->GetState();
|
||||
const ControllerEmu::AnalogStick::StateData stick_state =
|
||||
m_stick->GetState(m_input_override_function);
|
||||
|
||||
state.stick_x = MapFloat<u8>(stick_state.x, STICK_CENTER, STICK_MIN, STICK_MAX);
|
||||
state.stick_y = MapFloat<u8>(stick_state.y, STICK_CENTER, STICK_MIN, STICK_MAX);
|
||||
state.stick_x = MapFloat(stick_state.x, STICK_CENTER, STICK_MIN, STICK_MAX);
|
||||
state.stick_y = MapFloat(stick_state.y, STICK_CENTER, STICK_MIN, STICK_MAX);
|
||||
}
|
||||
|
||||
state.buttons = 0;
|
||||
m_buttons->GetState(&state.buttons, drum_button_bitmasks.data());
|
||||
m_buttons->GetState(&state.buttons, drum_button_bitmasks.data(), m_input_override_function);
|
||||
|
||||
state.drum_pads = 0;
|
||||
m_pads->GetState(&state.drum_pads, drum_pad_bitmasks.data());
|
||||
m_pads->GetState(&state.drum_pads, drum_pad_bitmasks.data(), m_input_override_function);
|
||||
|
||||
state.softness = u8(7 - std::lround(m_hit_strength_setting.GetValue() * 7 / 100));
|
||||
}
|
||||
|
|
|
@ -101,17 +101,19 @@ void Guitar::BuildDesiredExtensionState(DesiredExtensionState* target_state)
|
|||
|
||||
// stick
|
||||
{
|
||||
const ControllerEmu::AnalogStick::StateData stick_state = m_stick->GetState();
|
||||
const ControllerEmu::AnalogStick::StateData stick_state =
|
||||
m_stick->GetState(m_input_override_function);
|
||||
|
||||
guitar_data.sx = static_cast<u8>((stick_state.x * STICK_RADIUS) + STICK_CENTER);
|
||||
guitar_data.sy = static_cast<u8>((stick_state.y * STICK_RADIUS) + STICK_CENTER);
|
||||
guitar_data.sx = MapFloat<u8>(stick_state.x, STICK_CENTER, 0, STICK_RANGE);
|
||||
guitar_data.sy = MapFloat<u8>(stick_state.y, STICK_CENTER, 0, STICK_RANGE);
|
||||
}
|
||||
|
||||
// slider bar
|
||||
if (m_slider_bar->controls[0]->control_ref->BoundCount() &&
|
||||
m_slider_bar->controls[1]->control_ref->BoundCount())
|
||||
{
|
||||
const ControllerEmu::Slider::StateData slider_data = m_slider_bar->GetState();
|
||||
const ControllerEmu::Slider::StateData slider_data =
|
||||
m_slider_bar->GetState(m_input_override_function);
|
||||
|
||||
guitar_data.sb = s_slider_bar_control_codes.lower_bound(slider_data.value)->second;
|
||||
}
|
||||
|
@ -122,17 +124,18 @@ void Guitar::BuildDesiredExtensionState(DesiredExtensionState* target_state)
|
|||
}
|
||||
|
||||
// whammy bar
|
||||
const ControllerEmu::Triggers::StateData whammy_state = m_whammy->GetState();
|
||||
guitar_data.whammy = static_cast<u8>(whammy_state.data[0] * 0x1F);
|
||||
const ControllerEmu::Triggers::StateData whammy_state =
|
||||
m_whammy->GetState(m_input_override_function);
|
||||
guitar_data.whammy = MapFloat<u8>(whammy_state.data[0], 0, 0, 0x1F);
|
||||
|
||||
// buttons
|
||||
m_buttons->GetState(&guitar_data.bt, guitar_button_bitmasks.data());
|
||||
m_buttons->GetState(&guitar_data.bt, guitar_button_bitmasks.data(), m_input_override_function);
|
||||
|
||||
// frets
|
||||
m_frets->GetState(&guitar_data.bt, guitar_fret_bitmasks.data());
|
||||
m_frets->GetState(&guitar_data.bt, guitar_fret_bitmasks.data(), m_input_override_function);
|
||||
|
||||
// strum
|
||||
m_strum->GetState(&guitar_data.bt, guitar_strum_bitmasks.data());
|
||||
m_strum->GetState(&guitar_data.bt, guitar_strum_bitmasks.data(), m_input_override_function);
|
||||
|
||||
// flip button bits
|
||||
guitar_data.bt ^= 0xFFFF;
|
||||
|
|
|
@ -69,6 +69,7 @@ public:
|
|||
|
||||
static const u8 STICK_CENTER = 0x20;
|
||||
static const u8 STICK_RADIUS = 0x1f;
|
||||
static const u8 STICK_RANGE = 0x3f;
|
||||
|
||||
// TODO: Test real hardware. Is this accurate?
|
||||
static const u8 STICK_GATE_RADIUS = 0x16;
|
||||
|
|
|
@ -37,14 +37,13 @@ constexpr std::array<u8, 2> nunchuk_button_bitmasks{{
|
|||
Nunchuk::Nunchuk() : Extension1stParty(_trans("Nunchuk"))
|
||||
{
|
||||
// buttons
|
||||
groups.emplace_back(m_buttons = new ControllerEmu::Buttons(_trans("Buttons")));
|
||||
m_buttons->AddInput(ControllerEmu::DoNotTranslate, "C");
|
||||
m_buttons->AddInput(ControllerEmu::DoNotTranslate, "Z");
|
||||
groups.emplace_back(m_buttons = new ControllerEmu::Buttons(BUTTONS_GROUP));
|
||||
m_buttons->AddInput(ControllerEmu::DoNotTranslate, C_BUTTON);
|
||||
m_buttons->AddInput(ControllerEmu::DoNotTranslate, Z_BUTTON);
|
||||
|
||||
// stick
|
||||
constexpr auto gate_radius = ControlState(STICK_GATE_RADIUS) / STICK_RADIUS;
|
||||
groups.emplace_back(m_stick =
|
||||
new ControllerEmu::OctagonAnalogStick(_trans("Stick"), gate_radius));
|
||||
groups.emplace_back(m_stick = new ControllerEmu::OctagonAnalogStick(STICK_GROUP, gate_radius));
|
||||
|
||||
// swing
|
||||
groups.emplace_back(m_swing = new ControllerEmu::Force(_trans("Swing")));
|
||||
|
@ -59,7 +58,7 @@ Nunchuk::Nunchuk() : Extension1stParty(_trans("Nunchuk"))
|
|||
|
||||
// accelerometer
|
||||
groups.emplace_back(m_imu_accelerometer = new ControllerEmu::IMUAccelerometer(
|
||||
"IMUAccelerometer", _trans("Accelerometer")));
|
||||
ACCELEROMETER_GROUP, _trans("Accelerometer")));
|
||||
}
|
||||
|
||||
void Nunchuk::BuildDesiredExtensionState(DesiredExtensionState* target_state)
|
||||
|
@ -67,16 +66,20 @@ void Nunchuk::BuildDesiredExtensionState(DesiredExtensionState* target_state)
|
|||
DataFormat nc_data = {};
|
||||
|
||||
// stick
|
||||
const ControllerEmu::AnalogStick::StateData stick_state = m_stick->GetState();
|
||||
nc_data.jx = u8(STICK_CENTER + stick_state.x * STICK_RADIUS);
|
||||
nc_data.jy = u8(STICK_CENTER + stick_state.y * STICK_RADIUS);
|
||||
bool override_occurred = false;
|
||||
const ControllerEmu::AnalogStick::StateData stick_state =
|
||||
m_stick->GetState(m_input_override_function, &override_occurred);
|
||||
nc_data.jx = MapFloat<u8>(stick_state.x, STICK_CENTER, 0, STICK_RANGE);
|
||||
nc_data.jy = MapFloat<u8>(stick_state.y, STICK_CENTER, 0, STICK_RANGE);
|
||||
|
||||
if (!override_occurred)
|
||||
{
|
||||
// Some terribly coded games check whether to move with a check like
|
||||
//
|
||||
// if (x != 0 && y != 0)
|
||||
// do_movement(x, y);
|
||||
//
|
||||
// With keyboard controls, these games break if you simply hit
|
||||
// With keyboard controls, these games break if you simply hit one
|
||||
// of the axes. Adjust this if you're hitting one of the axes so that
|
||||
// we slightly tweak the other axis.
|
||||
if (nc_data.jx != STICK_CENTER || nc_data.jy != STICK_CENTER)
|
||||
|
@ -86,10 +89,11 @@ void Nunchuk::BuildDesiredExtensionState(DesiredExtensionState* target_state)
|
|||
if (nc_data.jy == STICK_CENTER)
|
||||
++nc_data.jy;
|
||||
}
|
||||
}
|
||||
|
||||
// buttons
|
||||
u8 buttons = 0;
|
||||
m_buttons->GetState(&buttons, nunchuk_button_bitmasks.data());
|
||||
m_buttons->GetState(&buttons, nunchuk_button_bitmasks.data(), m_input_override_function);
|
||||
nc_data.SetButtons(buttons);
|
||||
|
||||
// Acceleration data:
|
||||
|
@ -108,6 +112,8 @@ void Nunchuk::BuildDesiredExtensionState(DesiredExtensionState* target_state)
|
|||
// shake
|
||||
accel += m_shake_state.acceleration;
|
||||
|
||||
accel = Wiimote::OverrideVec3(m_imu_accelerometer, accel, m_input_override_function);
|
||||
|
||||
// Calibration values are 8-bit but we want 10-bit precision, so << 2.
|
||||
const auto acc = ConvertAccelData(accel, ACCEL_ZERO_G << 2, ACCEL_ONE_G << 2);
|
||||
nc_data.SetAccel(acc.value);
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
#include <array>
|
||||
|
||||
#include "Common/Common.h"
|
||||
|
||||
#include "Core/HW/WiimoteCommon/WiimoteReport.h"
|
||||
#include "Core/HW/WiimoteEmu/Dynamics.h"
|
||||
#include "Core/HW/WiimoteEmu/Extension/Extension.h"
|
||||
|
@ -156,6 +158,8 @@ public:
|
|||
|
||||
ControllerEmu::ControlGroup* GetGroup(NunchukGroup group);
|
||||
|
||||
void LoadDefaults(const ControllerInterface& ciface) override;
|
||||
|
||||
static constexpr u8 BUTTON_C = 0x02;
|
||||
static constexpr u8 BUTTON_Z = 0x01;
|
||||
|
||||
|
@ -166,8 +170,14 @@ public:
|
|||
|
||||
static constexpr u8 STICK_CENTER = 0x80;
|
||||
static constexpr u8 STICK_RADIUS = 0x7F;
|
||||
static constexpr u8 STICK_RANGE = 0xFF;
|
||||
|
||||
void LoadDefaults(const ControllerInterface& ciface) override;
|
||||
static constexpr const char* BUTTONS_GROUP = _trans("Buttons");
|
||||
static constexpr const char* STICK_GROUP = _trans("Stick");
|
||||
static constexpr const char* ACCELEROMETER_GROUP = "IMUAccelerometer";
|
||||
|
||||
static constexpr const char* C_BUTTON = "C";
|
||||
static constexpr const char* Z_BUTTON = "Z";
|
||||
|
||||
private:
|
||||
ControllerEmu::Tilt* m_tilt;
|
||||
|
|
|
@ -64,8 +64,9 @@ void Shinkansen::BuildDesiredExtensionState(DesiredExtensionState* target_state)
|
|||
// guesses).
|
||||
const u8 brake_values[] = {0, 53, 79, 105, 132, 159, 187, 217, 250};
|
||||
const u8 power_values[] = {255, 229, 208, 189, 170, 153, 135, 118, 101, 85, 68, 51, 35, 17};
|
||||
state.brake = brake_values[size_t(analog[0] * (sizeof(brake_values) - 1))];
|
||||
state.power = power_values[size_t(analog[1] * (sizeof(power_values) - 1))];
|
||||
// Not casting from size_t would trigger a static assert in MapFloat due to its use of llround
|
||||
state.brake = brake_values[MapFloat(analog[0], 0, 0, static_cast<int>(sizeof(brake_values) - 1))];
|
||||
state.power = power_values[MapFloat(analog[1], 0, 0, static_cast<int>(sizeof(power_values) - 1))];
|
||||
|
||||
// Note: This currently assumes a little-endian host.
|
||||
const u16 button_bitmasks[] = {
|
||||
|
|
|
@ -54,8 +54,8 @@ void TaTaCon::BuildDesiredExtensionState(DesiredExtensionState* target_state)
|
|||
{
|
||||
DataFormat tatacon_data = {};
|
||||
|
||||
m_center->GetState(&tatacon_data.state, center_bitmasks.data());
|
||||
m_rim->GetState(&tatacon_data.state, rim_bitmasks.data());
|
||||
m_center->GetState(&tatacon_data.state, center_bitmasks.data(), m_input_override_function);
|
||||
m_rim->GetState(&tatacon_data.state, rim_bitmasks.data(), m_input_override_function);
|
||||
|
||||
// Flip button bits.
|
||||
tatacon_data.state ^= 0xff;
|
||||
|
|
|
@ -86,16 +86,17 @@ void Turntable::BuildDesiredExtensionState(DesiredExtensionState* target_state)
|
|||
|
||||
// stick
|
||||
{
|
||||
const ControllerEmu::AnalogStick::StateData stick_state = m_stick->GetState();
|
||||
const ControllerEmu::AnalogStick::StateData stick_state =
|
||||
m_stick->GetState(m_input_override_function);
|
||||
|
||||
tt_data.sx = static_cast<u8>((stick_state.x * STICK_RADIUS) + STICK_CENTER);
|
||||
tt_data.sy = static_cast<u8>((stick_state.y * STICK_RADIUS) + STICK_CENTER);
|
||||
tt_data.sx = MapFloat<u8>(stick_state.x, STICK_CENTER, 0, STICK_RANGE);
|
||||
tt_data.sy = MapFloat<u8>(stick_state.y, STICK_CENTER, 0, STICK_RANGE);
|
||||
}
|
||||
|
||||
// left table
|
||||
{
|
||||
const ControllerEmu::Slider::StateData lt = m_left_table->GetState();
|
||||
const s8 tt = static_cast<s8>(lt.value * TABLE_RANGE);
|
||||
const ControllerEmu::Slider::StateData lt = m_left_table->GetState(m_input_override_function);
|
||||
const s8 tt = MapFloat<u8>(lt.value, 0, 0, TABLE_RANGE);
|
||||
|
||||
tt_data.ltable1 = tt;
|
||||
tt_data.ltable2 = tt >> 5;
|
||||
|
@ -103,8 +104,8 @@ void Turntable::BuildDesiredExtensionState(DesiredExtensionState* target_state)
|
|||
|
||||
// right table
|
||||
{
|
||||
const ControllerEmu::Slider::StateData rt = m_right_table->GetState();
|
||||
const s8 tt = static_cast<s8>(rt.value * TABLE_RANGE);
|
||||
const ControllerEmu::Slider::StateData rt = m_right_table->GetState(m_input_override_function);
|
||||
const s8 tt = MapFloat<u8>(rt.value, 0, 0, TABLE_RANGE);
|
||||
|
||||
tt_data.rtable1 = tt;
|
||||
tt_data.rtable2 = tt >> 1;
|
||||
|
@ -114,8 +115,8 @@ void Turntable::BuildDesiredExtensionState(DesiredExtensionState* target_state)
|
|||
|
||||
// effect dial
|
||||
{
|
||||
const auto dial_state = m_effect_dial->GetState();
|
||||
const u8 dial = static_cast<u8>(dial_state.value * EFFECT_DIAL_RANGE) + EFFECT_DIAL_CENTER;
|
||||
const auto dial_state = m_effect_dial->GetState(m_input_override_function);
|
||||
const u8 dial = MapFloat<u8>(dial_state.value, EFFECT_DIAL_CENTER, 0, EFFECT_DIAL_RANGE);
|
||||
|
||||
tt_data.dial1 = dial;
|
||||
tt_data.dial2 = dial >> 3;
|
||||
|
@ -123,13 +124,13 @@ void Turntable::BuildDesiredExtensionState(DesiredExtensionState* target_state)
|
|||
|
||||
// crossfade slider
|
||||
{
|
||||
const ControllerEmu::Slider::StateData cfs = m_crossfade->GetState();
|
||||
const ControllerEmu::Slider::StateData cfs = m_crossfade->GetState(m_input_override_function);
|
||||
|
||||
tt_data.slider = static_cast<u8>((cfs.value * CROSSFADE_RANGE) + CROSSFADE_CENTER);
|
||||
tt_data.slider = MapFloat<u8>(cfs.value, CROSSFADE_CENTER, 0, CROSSFADE_RANGE);
|
||||
}
|
||||
|
||||
// buttons
|
||||
m_buttons->GetState(&tt_data.bt, turntable_button_bitmasks.data());
|
||||
m_buttons->GetState(&tt_data.bt, turntable_button_bitmasks.data(), m_input_override_function);
|
||||
|
||||
// flip button bits :/
|
||||
tt_data.bt ^= (BUTTON_L_GREEN | BUTTON_L_RED | BUTTON_L_BLUE | BUTTON_R_GREEN | BUTTON_R_RED |
|
||||
|
|
|
@ -78,6 +78,7 @@ public:
|
|||
static constexpr int STICK_BIT_COUNT = 6;
|
||||
static constexpr u8 STICK_CENTER = (1 << STICK_BIT_COUNT) / 2;
|
||||
static constexpr u8 STICK_RADIUS = STICK_CENTER - 1;
|
||||
static constexpr u8 STICK_RANGE = (1 << STICK_BIT_COUNT) - 1;
|
||||
// TODO: Test real hardware. Is this accurate?
|
||||
static constexpr u8 STICK_GATE_RADIUS = 0x16;
|
||||
|
||||
|
@ -86,11 +87,11 @@ public:
|
|||
|
||||
static constexpr int EFFECT_DIAL_BIT_COUNT = 5;
|
||||
static constexpr u8 EFFECT_DIAL_CENTER = (1 << EFFECT_DIAL_BIT_COUNT) / 2;
|
||||
static constexpr u8 EFFECT_DIAL_RANGE = EFFECT_DIAL_CENTER - 1;
|
||||
static constexpr u8 EFFECT_DIAL_RANGE = (1 << EFFECT_DIAL_BIT_COUNT) - 1;
|
||||
|
||||
static constexpr int CROSSFADE_BIT_COUNT = 4;
|
||||
static constexpr u8 CROSSFADE_CENTER = (1 << CROSSFADE_BIT_COUNT) / 2;
|
||||
static constexpr u8 CROSSFADE_RANGE = CROSSFADE_CENTER - 1;
|
||||
static constexpr u8 CROSSFADE_RANGE = (1 << CROSSFADE_BIT_COUNT) - 1;
|
||||
|
||||
private:
|
||||
ControllerEmu::Buttons* m_buttons;
|
||||
|
|
|
@ -5,11 +5,13 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/Common.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Config/Config.h"
|
||||
#include "Common/FileUtil.h"
|
||||
|
@ -63,10 +65,6 @@ static const u16 dpad_bitmasks[] = {Wiimote::PAD_UP, Wiimote::PAD_DOWN, Wiimote:
|
|||
static const u16 dpad_sideways_bitmasks[] = {Wiimote::PAD_RIGHT, Wiimote::PAD_LEFT, Wiimote::PAD_UP,
|
||||
Wiimote::PAD_DOWN};
|
||||
|
||||
constexpr std::array<std::string_view, 7> named_buttons{
|
||||
"A", "B", "1", "2", "-", "+", "Home",
|
||||
};
|
||||
|
||||
void Wiimote::Reset()
|
||||
{
|
||||
const bool want_determinism = Core::WantsDeterminism();
|
||||
|
@ -211,24 +209,23 @@ void Wiimote::Reset()
|
|||
Wiimote::Wiimote(const unsigned int index) : m_index(index), m_bt_device_index(index)
|
||||
{
|
||||
// Buttons
|
||||
groups.emplace_back(m_buttons = new ControllerEmu::Buttons(_trans("Buttons")));
|
||||
for (auto& named_button : named_buttons)
|
||||
groups.emplace_back(m_buttons = new ControllerEmu::Buttons(BUTTONS_GROUP));
|
||||
for (auto& named_button : {A_BUTTON, B_BUTTON, ONE_BUTTON, TWO_BUTTON, MINUS_BUTTON, PLUS_BUTTON})
|
||||
{
|
||||
std::string_view ui_name = (named_button == "Home") ? "HOME" : named_button;
|
||||
m_buttons->AddInput(ControllerEmu::DoNotTranslate, std::string(named_button),
|
||||
std::string(ui_name));
|
||||
m_buttons->AddInput(ControllerEmu::DoNotTranslate, named_button);
|
||||
}
|
||||
m_buttons->AddInput(ControllerEmu::DoNotTranslate, HOME_BUTTON, "HOME");
|
||||
|
||||
// Pointing (IR)
|
||||
// i18n: "Point" refers to the action of pointing a Wii Remote.
|
||||
groups.emplace_back(m_ir = new ControllerEmu::Cursor("IR", _trans("Point")));
|
||||
groups.emplace_back(m_ir = new ControllerEmu::Cursor(IR_GROUP, _trans("Point")));
|
||||
groups.emplace_back(m_swing = new ControllerEmu::Force(_trans("Swing")));
|
||||
groups.emplace_back(m_tilt = new ControllerEmu::Tilt(_trans("Tilt")));
|
||||
groups.emplace_back(m_shake = new ControllerEmu::Shake(_trans("Shake")));
|
||||
groups.emplace_back(m_imu_accelerometer = new ControllerEmu::IMUAccelerometer(
|
||||
"IMUAccelerometer", _trans("Accelerometer")));
|
||||
ACCELEROMETER_GROUP, _trans("Accelerometer")));
|
||||
groups.emplace_back(m_imu_gyroscope =
|
||||
new ControllerEmu::IMUGyroscope("IMUGyroscope", _trans("Gyroscope")));
|
||||
new ControllerEmu::IMUGyroscope(GYROSCOPE_GROUP, _trans("Gyroscope")));
|
||||
groups.emplace_back(m_imu_ir = new ControllerEmu::IMUCursor("IMUIR", _trans("Point")));
|
||||
|
||||
const auto fov_default =
|
||||
|
@ -272,7 +269,7 @@ Wiimote::Wiimote(const unsigned int index) : m_index(index), m_bt_device_index(i
|
|||
m_rumble->AddOutput(ControllerEmu::Translate, _trans("Motor"));
|
||||
|
||||
// D-Pad
|
||||
groups.emplace_back(m_dpad = new ControllerEmu::Buttons(_trans("D-Pad")));
|
||||
groups.emplace_back(m_dpad = new ControllerEmu::Buttons(DPAD_GROUP));
|
||||
for (const char* named_direction : named_directions)
|
||||
{
|
||||
m_dpad->AddInput(ControllerEmu::Translate, named_direction);
|
||||
|
@ -458,9 +455,10 @@ void Wiimote::BuildDesiredWiimoteState(DesiredWiimoteState* target_state)
|
|||
|
||||
// Fetch pressed buttons from user input.
|
||||
target_state->buttons.hex = 0;
|
||||
m_buttons->GetState(&target_state->buttons.hex, button_bitmasks);
|
||||
m_buttons->GetState(&target_state->buttons.hex, button_bitmasks, m_input_override_function);
|
||||
m_dpad->GetState(&target_state->buttons.hex,
|
||||
IsSideways() ? dpad_sideways_bitmasks : dpad_bitmasks);
|
||||
IsSideways() ? dpad_sideways_bitmasks : dpad_bitmasks,
|
||||
m_input_override_function);
|
||||
|
||||
// Calculate accelerometer state.
|
||||
// Calibration values are 8-bit but we want 10-bit precision, so << 2.
|
||||
|
@ -628,9 +626,6 @@ void Wiimote::SendDataReport(const DesiredWiimoteState& target_state)
|
|||
std::fill_n(ext_data, ext_size, u8(0xff));
|
||||
}
|
||||
}
|
||||
|
||||
Movie::CallWiiInputManip(rpt_builder, m_bt_device_index, m_active_extension,
|
||||
GetExtensionEncryptionKey());
|
||||
}
|
||||
|
||||
Movie::CheckWiimoteStatus(m_bt_device_index, rpt_builder, m_active_extension,
|
||||
|
@ -651,8 +646,9 @@ ButtonData Wiimote::GetCurrentlyPressedButtons()
|
|||
const auto lock = GetStateLock();
|
||||
|
||||
ButtonData buttons{};
|
||||
m_buttons->GetState(&buttons.hex, button_bitmasks);
|
||||
m_dpad->GetState(&buttons.hex, IsSideways() ? dpad_sideways_bitmasks : dpad_bitmasks);
|
||||
m_buttons->GetState(&buttons.hex, button_bitmasks, m_input_override_function);
|
||||
m_dpad->GetState(&buttons.hex, IsSideways() ? dpad_sideways_bitmasks : dpad_bitmasks,
|
||||
m_input_override_function);
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
@ -789,7 +785,7 @@ void Wiimote::StepDynamics()
|
|||
{
|
||||
EmulateSwing(&m_swing_state, m_swing, 1.f / ::Wiimote::UPDATE_FREQ);
|
||||
EmulateTilt(&m_tilt_state, m_tilt, 1.f / ::Wiimote::UPDATE_FREQ);
|
||||
EmulatePoint(&m_point_state, m_ir, 1.f / ::Wiimote::UPDATE_FREQ);
|
||||
EmulatePoint(&m_point_state, m_ir, m_input_override_function, 1.f / ::Wiimote::UPDATE_FREQ);
|
||||
EmulateShake(&m_shake_state, m_shake, 1.f / ::Wiimote::UPDATE_FREQ);
|
||||
EmulateIMUCursor(&m_imu_cursor_state, m_imu_ir, m_imu_accelerometer, m_imu_gyroscope,
|
||||
1.f / ::Wiimote::UPDATE_FREQ);
|
||||
|
@ -831,20 +827,87 @@ Common::Quaternion Wiimote::GetOrientation() const
|
|||
Common::Quaternion::RotateX(float(MathUtil::TAU / 4 * IsUpright()));
|
||||
}
|
||||
|
||||
std::optional<Common::Vec3> Wiimote::OverrideVec3(const ControllerEmu::ControlGroup* control_group,
|
||||
std::optional<Common::Vec3> optional_vec) const
|
||||
{
|
||||
bool has_value = optional_vec.has_value();
|
||||
Common::Vec3 vec = has_value ? *optional_vec : Common::Vec3{};
|
||||
|
||||
if (m_input_override_function)
|
||||
{
|
||||
if (const std::optional<ControlState> x_override = m_input_override_function(
|
||||
control_group->name, ControllerEmu::ReshapableInput::X_INPUT_OVERRIDE, vec.x))
|
||||
{
|
||||
has_value = true;
|
||||
vec.x = *x_override;
|
||||
}
|
||||
|
||||
if (const std::optional<ControlState> y_override = m_input_override_function(
|
||||
control_group->name, ControllerEmu::ReshapableInput::Y_INPUT_OVERRIDE, vec.y))
|
||||
{
|
||||
has_value = true;
|
||||
vec.y = *y_override;
|
||||
}
|
||||
|
||||
if (const std::optional<ControlState> z_override = m_input_override_function(
|
||||
control_group->name, ControllerEmu::ReshapableInput::Z_INPUT_OVERRIDE, vec.z))
|
||||
{
|
||||
has_value = true;
|
||||
vec.z = *z_override;
|
||||
}
|
||||
}
|
||||
|
||||
return has_value ? std::make_optional(vec) : std::nullopt;
|
||||
}
|
||||
|
||||
Common::Vec3 Wiimote::OverrideVec3(const ControllerEmu::ControlGroup* control_group,
|
||||
Common::Vec3 vec) const
|
||||
{
|
||||
return OverrideVec3(control_group, vec, m_input_override_function);
|
||||
}
|
||||
|
||||
Common::Vec3
|
||||
Wiimote::OverrideVec3(const ControllerEmu::ControlGroup* control_group, Common::Vec3 vec,
|
||||
const ControllerEmu::InputOverrideFunction& input_override_function)
|
||||
{
|
||||
if (input_override_function)
|
||||
{
|
||||
if (const std::optional<ControlState> x_override = input_override_function(
|
||||
control_group->name, ControllerEmu::ReshapableInput::X_INPUT_OVERRIDE, vec.x))
|
||||
{
|
||||
vec.x = *x_override;
|
||||
}
|
||||
|
||||
if (const std::optional<ControlState> y_override = input_override_function(
|
||||
control_group->name, ControllerEmu::ReshapableInput::Y_INPUT_OVERRIDE, vec.y))
|
||||
{
|
||||
vec.y = *y_override;
|
||||
}
|
||||
|
||||
if (const std::optional<ControlState> z_override = input_override_function(
|
||||
control_group->name, ControllerEmu::ReshapableInput::Z_INPUT_OVERRIDE, vec.z))
|
||||
{
|
||||
vec.z = *z_override;
|
||||
}
|
||||
}
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
Common::Vec3 Wiimote::GetTotalAcceleration() const
|
||||
{
|
||||
if (const auto accel = m_imu_accelerometer->GetState())
|
||||
return GetAcceleration(*accel);
|
||||
const Common::Vec3 default_accel = Common::Vec3(0, 0, float(GRAVITY_ACCELERATION));
|
||||
const Common::Vec3 accel = m_imu_accelerometer->GetState().value_or(default_accel);
|
||||
|
||||
return GetAcceleration();
|
||||
return OverrideVec3(m_imu_accelerometer, GetAcceleration(accel));
|
||||
}
|
||||
|
||||
Common::Vec3 Wiimote::GetTotalAngularVelocity() const
|
||||
{
|
||||
if (const auto ang_vel = m_imu_gyroscope->GetState())
|
||||
return GetAngularVelocity(*ang_vel);
|
||||
const Common::Vec3 default_ang_vel = {};
|
||||
const Common::Vec3 ang_vel = m_imu_gyroscope->GetState().value_or(default_ang_vel);
|
||||
|
||||
return GetAngularVelocity();
|
||||
return OverrideVec3(m_imu_gyroscope, GetAngularVelocity(ang_vel));
|
||||
}
|
||||
|
||||
Common::Matrix44 Wiimote::GetTotalTransformation() const
|
||||
|
|
|
@ -5,8 +5,11 @@
|
|||
|
||||
#include <array>
|
||||
#include <numeric>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "Common/Common.h"
|
||||
|
||||
#include "Core/HW/WiimoteCommon/WiimoteReport.h"
|
||||
|
||||
#include "Core/HW/WiimoteEmu/Camera.h"
|
||||
|
@ -112,6 +115,20 @@ public:
|
|||
static constexpr u16 BUTTON_MINUS = 0x1000;
|
||||
static constexpr u16 BUTTON_HOME = 0x8000;
|
||||
|
||||
static constexpr const char* BUTTONS_GROUP = _trans("Buttons");
|
||||
static constexpr const char* DPAD_GROUP = _trans("D-Pad");
|
||||
static constexpr const char* ACCELEROMETER_GROUP = "IMUAccelerometer";
|
||||
static constexpr const char* GYROSCOPE_GROUP = "IMUGyroscope";
|
||||
static constexpr const char* IR_GROUP = "IR";
|
||||
|
||||
static constexpr const char* A_BUTTON = "A";
|
||||
static constexpr const char* B_BUTTON = "B";
|
||||
static constexpr const char* ONE_BUTTON = "1";
|
||||
static constexpr const char* TWO_BUTTON = "2";
|
||||
static constexpr const char* MINUS_BUTTON = "-";
|
||||
static constexpr const char* PLUS_BUTTON = "+";
|
||||
static constexpr const char* HOME_BUTTON = "Home";
|
||||
|
||||
explicit Wiimote(unsigned int index);
|
||||
~Wiimote();
|
||||
|
||||
|
@ -146,6 +163,10 @@ public:
|
|||
// Active extension number is exposed for TAS.
|
||||
ExtensionNumber GetActiveExtensionNumber() const;
|
||||
|
||||
static Common::Vec3
|
||||
OverrideVec3(const ControllerEmu::ControlGroup* control_group, Common::Vec3 vec,
|
||||
const ControllerEmu::InputOverrideFunction& input_override_function);
|
||||
|
||||
private:
|
||||
// Used only for error generation:
|
||||
static constexpr u8 EEPROM_I2C_ADDR = 0x50;
|
||||
|
@ -161,11 +182,10 @@ private:
|
|||
void BuildDesiredWiimoteState(DesiredWiimoteState* target_state);
|
||||
|
||||
// Returns simulated accelerometer data in m/s^2.
|
||||
Common::Vec3 GetAcceleration(
|
||||
Common::Vec3 extra_acceleration = Common::Vec3(0, 0, float(GRAVITY_ACCELERATION))) const;
|
||||
Common::Vec3 GetAcceleration(Common::Vec3 extra_acceleration) const;
|
||||
|
||||
// Returns simulated gyroscope data in radians/s.
|
||||
Common::Vec3 GetAngularVelocity(Common::Vec3 extra_angular_velocity = {}) const;
|
||||
Common::Vec3 GetAngularVelocity(Common::Vec3 extra_angular_velocity) const;
|
||||
|
||||
// Returns the transformation of the world around the wiimote.
|
||||
// Used for simulating camera data and for rotating acceleration data.
|
||||
|
@ -176,6 +196,10 @@ private:
|
|||
// Returns the world rotation from the effects of sideways/upright settings.
|
||||
Common::Quaternion GetOrientation() const;
|
||||
|
||||
std::optional<Common::Vec3> OverrideVec3(const ControllerEmu::ControlGroup* control_group,
|
||||
std::optional<Common::Vec3> optional_vec) const;
|
||||
Common::Vec3 OverrideVec3(const ControllerEmu::ControlGroup* control_group,
|
||||
Common::Vec3 vec) const;
|
||||
Common::Vec3 GetTotalAcceleration() const;
|
||||
Common::Vec3 GetTotalAngularVelocity() const;
|
||||
Common::Matrix44 GetTotalTransformation() const;
|
||||
|
|
|
@ -122,9 +122,6 @@ static bool s_bPolled = false;
|
|||
static std::mutex s_input_display_lock;
|
||||
static std::string s_InputDisplay[8];
|
||||
|
||||
static GCManipFunction s_gc_manip_func;
|
||||
static WiiManipFunction s_wii_manip_func;
|
||||
|
||||
static std::string s_current_file_name;
|
||||
|
||||
static void GetSettings();
|
||||
|
@ -1426,28 +1423,6 @@ void SaveRecording(const std::string& filename)
|
|||
Core::DisplayMessage(fmt::format("Failed to save {}", filename), 2000);
|
||||
}
|
||||
|
||||
void SetGCInputManip(GCManipFunction func)
|
||||
{
|
||||
s_gc_manip_func = std::move(func);
|
||||
}
|
||||
void SetWiiInputManip(WiiManipFunction func)
|
||||
{
|
||||
s_wii_manip_func = std::move(func);
|
||||
}
|
||||
|
||||
// NOTE: CPU Thread
|
||||
void CallGCInputManip(GCPadStatus* PadStatus, int controllerID)
|
||||
{
|
||||
if (s_gc_manip_func)
|
||||
s_gc_manip_func(PadStatus, controllerID);
|
||||
}
|
||||
// NOTE: CPU Thread
|
||||
void CallWiiInputManip(DataReportBuilder& rpt, int controllerID, int ext, const EncryptionKey& key)
|
||||
{
|
||||
if (s_wii_manip_func)
|
||||
s_wii_manip_func(rpt, controllerID, ext, key);
|
||||
}
|
||||
|
||||
// NOTE: GPU Thread
|
||||
void SetGraphicsConfig()
|
||||
{
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
@ -200,14 +199,4 @@ std::string GetInputDisplay();
|
|||
std::string GetRTCDisplay();
|
||||
std::string GetRerecords();
|
||||
|
||||
// Done this way to avoid mixing of core and gui code
|
||||
using GCManipFunction = std::function<void(GCPadStatus*, int)>;
|
||||
using WiiManipFunction = std::function<void(WiimoteCommon::DataReportBuilder&, int, int,
|
||||
const WiimoteEmu::EncryptionKey&)>;
|
||||
|
||||
void SetGCInputManip(GCManipFunction);
|
||||
void SetWiiInputManip(WiiManipFunction);
|
||||
void CallGCInputManip(GCPadStatus* PadStatus, int controllerID);
|
||||
void CallWiiInputManip(WiimoteCommon::DataReportBuilder& rpt, int controllerID, int ext,
|
||||
const WiimoteEmu::EncryptionKey& key);
|
||||
} // namespace Movie
|
||||
|
|
|
@ -403,15 +403,6 @@ void MainWindow::CreateComponents()
|
|||
m_wii_tas_input_windows[i] = new WiiTASInputWindow(nullptr, i);
|
||||
}
|
||||
|
||||
Movie::SetGCInputManip([this](GCPadStatus* pad_status, int controller_id) {
|
||||
m_gc_tas_input_windows[controller_id]->GetValues(pad_status);
|
||||
});
|
||||
|
||||
Movie::SetWiiInputManip([this](WiimoteCommon::DataReportBuilder& rpt, int controller_id, int ext,
|
||||
const WiimoteEmu::EncryptionKey& key) {
|
||||
m_wii_tas_input_windows[controller_id]->GetValues(rpt, ext, key);
|
||||
});
|
||||
|
||||
m_jit_widget = new JITWidget(this);
|
||||
m_log_widget = new LogWidget(this);
|
||||
m_log_config_widget = new LogConfigWidget(this);
|
||||
|
|
|
@ -13,18 +13,25 @@
|
|||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
#include "Core/HW/GCPad.h"
|
||||
#include "Core/HW/GCPadEmu.h"
|
||||
|
||||
#include "DolphinQt/TAS/TASCheckBox.h"
|
||||
|
||||
#include "InputCommon/GCPadStatus.h"
|
||||
#include "InputCommon/ControllerEmu/ControllerEmu.h"
|
||||
#include "InputCommon/InputConfig.h"
|
||||
|
||||
GCTASInputWindow::GCTASInputWindow(QWidget* parent, int num) : TASInputWindow(parent)
|
||||
GCTASInputWindow::GCTASInputWindow(QWidget* parent, int controller_id)
|
||||
: TASInputWindow(parent), m_controller_id(controller_id)
|
||||
{
|
||||
setWindowTitle(tr("GameCube TAS Input %1").arg(num + 1));
|
||||
setWindowTitle(tr("GameCube TAS Input %1").arg(controller_id + 1));
|
||||
|
||||
m_main_stick_box = CreateStickInputs(tr("Main Stick"), m_x_main_stick_value, m_y_main_stick_value,
|
||||
255, 255, Qt::Key_F, Qt::Key_G);
|
||||
m_c_stick_box = CreateStickInputs(tr("C Stick"), m_x_c_stick_value, m_y_c_stick_value, 255, 255,
|
||||
Qt::Key_H, Qt::Key_J);
|
||||
m_main_stick_box = CreateStickInputs(tr("Main Stick"), GCPad::MAIN_STICK_GROUP, &m_overrider,
|
||||
m_x_main_stick_value, m_y_main_stick_value, 1, 1, 255, 255,
|
||||
Qt::Key_F, Qt::Key_G);
|
||||
m_c_stick_box =
|
||||
CreateStickInputs(tr("C Stick"), GCPad::C_STICK_GROUP, &m_overrider, m_x_c_stick_value,
|
||||
m_y_c_stick_value, 1, 1, 255, 255, Qt::Key_H, Qt::Key_J);
|
||||
|
||||
auto* top_layout = new QHBoxLayout;
|
||||
top_layout->addWidget(m_main_stick_box);
|
||||
|
@ -33,27 +40,43 @@ GCTASInputWindow::GCTASInputWindow(QWidget* parent, int num) : TASInputWindow(pa
|
|||
m_triggers_box = new QGroupBox(tr("Triggers"));
|
||||
|
||||
auto* l_trigger_layout =
|
||||
CreateSliderValuePairLayout(tr("Left"), m_l_trigger_value, 0, 255, Qt::Key_N, m_triggers_box);
|
||||
auto* r_trigger_layout = CreateSliderValuePairLayout(tr("Right"), m_r_trigger_value, 0, 255,
|
||||
Qt::Key_M, m_triggers_box);
|
||||
CreateSliderValuePairLayout(tr("Left"), GCPad::TRIGGERS_GROUP, GCPad::L_ANALOG, &m_overrider,
|
||||
m_l_trigger_value, 0, 0, 0, 255, Qt::Key_N, m_triggers_box);
|
||||
|
||||
auto* r_trigger_layout =
|
||||
CreateSliderValuePairLayout(tr("Right"), GCPad::TRIGGERS_GROUP, GCPad::R_ANALOG, &m_overrider,
|
||||
m_r_trigger_value, 0, 0, 0, 255, Qt::Key_M, m_triggers_box);
|
||||
|
||||
auto* triggers_layout = new QVBoxLayout;
|
||||
triggers_layout->addLayout(l_trigger_layout);
|
||||
triggers_layout->addLayout(r_trigger_layout);
|
||||
m_triggers_box->setLayout(triggers_layout);
|
||||
|
||||
m_a_button = CreateButton(QStringLiteral("&A"));
|
||||
m_b_button = CreateButton(QStringLiteral("&B"));
|
||||
m_x_button = CreateButton(QStringLiteral("&X"));
|
||||
m_y_button = CreateButton(QStringLiteral("&Y"));
|
||||
m_z_button = CreateButton(QStringLiteral("&Z"));
|
||||
m_l_button = CreateButton(QStringLiteral("&L"));
|
||||
m_r_button = CreateButton(QStringLiteral("&R"));
|
||||
m_start_button = CreateButton(QStringLiteral("&START"));
|
||||
m_left_button = CreateButton(QStringLiteral("L&eft"));
|
||||
m_up_button = CreateButton(QStringLiteral("&Up"));
|
||||
m_down_button = CreateButton(QStringLiteral("&Down"));
|
||||
m_right_button = CreateButton(QStringLiteral("R&ight"));
|
||||
m_a_button =
|
||||
CreateButton(QStringLiteral("&A"), GCPad::BUTTONS_GROUP, GCPad::A_BUTTON, &m_overrider);
|
||||
m_b_button =
|
||||
CreateButton(QStringLiteral("&B"), GCPad::BUTTONS_GROUP, GCPad::B_BUTTON, &m_overrider);
|
||||
m_x_button =
|
||||
CreateButton(QStringLiteral("&X"), GCPad::BUTTONS_GROUP, GCPad::X_BUTTON, &m_overrider);
|
||||
m_y_button =
|
||||
CreateButton(QStringLiteral("&Y"), GCPad::BUTTONS_GROUP, GCPad::Y_BUTTON, &m_overrider);
|
||||
m_z_button =
|
||||
CreateButton(QStringLiteral("&Z"), GCPad::BUTTONS_GROUP, GCPad::Z_BUTTON, &m_overrider);
|
||||
m_start_button = CreateButton(QStringLiteral("&START"), GCPad::BUTTONS_GROUP, GCPad::START_BUTTON,
|
||||
&m_overrider);
|
||||
|
||||
m_l_button =
|
||||
CreateButton(QStringLiteral("&L"), GCPad::TRIGGERS_GROUP, GCPad::L_DIGITAL, &m_overrider);
|
||||
m_r_button =
|
||||
CreateButton(QStringLiteral("&R"), GCPad::TRIGGERS_GROUP, GCPad::R_DIGITAL, &m_overrider);
|
||||
|
||||
m_left_button =
|
||||
CreateButton(QStringLiteral("L&eft"), GCPad::DPAD_GROUP, DIRECTION_LEFT, &m_overrider);
|
||||
m_up_button = CreateButton(QStringLiteral("&Up"), GCPad::DPAD_GROUP, DIRECTION_UP, &m_overrider);
|
||||
m_down_button =
|
||||
CreateButton(QStringLiteral("&Down"), GCPad::DPAD_GROUP, DIRECTION_DOWN, &m_overrider);
|
||||
m_right_button =
|
||||
CreateButton(QStringLiteral("R&ight"), GCPad::DPAD_GROUP, DIRECTION_RIGHT, &m_overrider);
|
||||
|
||||
auto* buttons_layout = new QGridLayout;
|
||||
buttons_layout->addWidget(m_a_button, 0, 0);
|
||||
|
@ -84,40 +107,14 @@ GCTASInputWindow::GCTASInputWindow(QWidget* parent, int num) : TASInputWindow(pa
|
|||
setLayout(layout);
|
||||
}
|
||||
|
||||
void GCTASInputWindow::GetValues(GCPadStatus* pad)
|
||||
void GCTASInputWindow::hideEvent(QHideEvent* event)
|
||||
{
|
||||
if (!isVisible())
|
||||
return;
|
||||
|
||||
GetButton<u16>(m_a_button, pad->button, PAD_BUTTON_A);
|
||||
GetButton<u16>(m_b_button, pad->button, PAD_BUTTON_B);
|
||||
GetButton<u16>(m_x_button, pad->button, PAD_BUTTON_X);
|
||||
GetButton<u16>(m_y_button, pad->button, PAD_BUTTON_Y);
|
||||
GetButton<u16>(m_z_button, pad->button, PAD_TRIGGER_Z);
|
||||
GetButton<u16>(m_l_button, pad->button, PAD_TRIGGER_L);
|
||||
GetButton<u16>(m_r_button, pad->button, PAD_TRIGGER_R);
|
||||
GetButton<u16>(m_left_button, pad->button, PAD_BUTTON_LEFT);
|
||||
GetButton<u16>(m_up_button, pad->button, PAD_BUTTON_UP);
|
||||
GetButton<u16>(m_down_button, pad->button, PAD_BUTTON_DOWN);
|
||||
GetButton<u16>(m_right_button, pad->button, PAD_BUTTON_RIGHT);
|
||||
GetButton<u16>(m_start_button, pad->button, PAD_BUTTON_START);
|
||||
|
||||
if (m_a_button->isChecked())
|
||||
pad->analogA = 0xFF;
|
||||
else
|
||||
pad->analogA = 0x00;
|
||||
|
||||
if (m_b_button->isChecked())
|
||||
pad->analogB = 0xFF;
|
||||
else
|
||||
pad->analogB = 0x00;
|
||||
|
||||
GetSpinBoxU8(m_l_trigger_value, pad->triggerLeft);
|
||||
GetSpinBoxU8(m_r_trigger_value, pad->triggerRight);
|
||||
|
||||
GetSpinBoxU8(m_x_main_stick_value, pad->stickX);
|
||||
GetSpinBoxU8(m_y_main_stick_value, pad->stickY);
|
||||
|
||||
GetSpinBoxU8(m_x_c_stick_value, pad->substickX);
|
||||
GetSpinBoxU8(m_y_c_stick_value, pad->substickY);
|
||||
Pad::GetConfig()->GetController(m_controller_id)->ClearInputOverrideFunction();
|
||||
}
|
||||
|
||||
void GCTASInputWindow::showEvent(QShowEvent* event)
|
||||
{
|
||||
Pad::GetConfig()
|
||||
->GetController(m_controller_id)
|
||||
->SetInputOverrideFunction(m_overrider.GetInputOverrideFunction());
|
||||
}
|
||||
|
|
|
@ -6,18 +6,25 @@
|
|||
#include "DolphinQt/TAS/TASInputWindow.h"
|
||||
|
||||
class QGroupBox;
|
||||
class QHideEvent;
|
||||
class QShowEvent;
|
||||
class QSpinBox;
|
||||
class TASCheckBox;
|
||||
struct GCPadStatus;
|
||||
|
||||
class GCTASInputWindow : public TASInputWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit GCTASInputWindow(QWidget* parent, int num);
|
||||
void GetValues(GCPadStatus* pad);
|
||||
explicit GCTASInputWindow(QWidget* parent, int controller_id);
|
||||
|
||||
void hideEvent(QHideEvent* event) override;
|
||||
void showEvent(QShowEvent* event) override;
|
||||
|
||||
private:
|
||||
int m_controller_id;
|
||||
|
||||
InputOverrider m_overrider;
|
||||
|
||||
TASCheckBox* m_a_button;
|
||||
TASCheckBox* m_b_button;
|
||||
TASCheckBox* m_x_button;
|
||||
|
|
|
@ -54,8 +54,8 @@ void IRWidget::paintEvent(QPaintEvent* event)
|
|||
painter.drawLine(PADDING + w / 2, PADDING, PADDING + w / 2, PADDING + h);
|
||||
|
||||
// convert from value space to widget space
|
||||
u16 x = PADDING + (w - (m_x * w) / ir_max_x);
|
||||
u16 y = PADDING + ((m_y * h) / ir_max_y);
|
||||
u16 x = PADDING + ((m_x * w) / ir_max_x);
|
||||
u16 y = PADDING + (h - (m_y * h) / ir_max_y);
|
||||
|
||||
painter.drawLine(PADDING + w / 2, PADDING + h / 2, x, y);
|
||||
|
||||
|
@ -87,8 +87,8 @@ void IRWidget::handleMouseEvent(QMouseEvent* event)
|
|||
else
|
||||
{
|
||||
// convert from widget space to value space
|
||||
int new_x = ir_max_x - (event->pos().x() * ir_max_x) / width();
|
||||
int new_y = (event->pos().y() * ir_max_y) / height();
|
||||
int new_x = (event->pos().x() * ir_max_x) / width();
|
||||
int new_y = ir_max_y - (event->pos().y() * ir_max_y) / height();
|
||||
|
||||
m_x = std::max(0, std::min(static_cast<int>(ir_max_x), new_x));
|
||||
m_y = std::max(0, std::min(static_cast<int>(ir_max_y), new_y));
|
||||
|
|
|
@ -34,5 +34,7 @@ private:
|
|||
};
|
||||
|
||||
// Should be part of class but fails to compile on mac os
|
||||
static const u16 ir_min_x = 0;
|
||||
static const u16 ir_min_y = 0;
|
||||
static const u16 ir_max_x = 1023;
|
||||
static const u16 ir_max_y = 767;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "DolphinQt/TAS/TASInputWindow.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <utility>
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QGroupBox>
|
||||
|
@ -23,7 +24,23 @@
|
|||
#include "DolphinQt/TAS/TASCheckBox.h"
|
||||
#include "DolphinQt/TAS/TASSlider.h"
|
||||
|
||||
#include "InputCommon/GCPadStatus.h"
|
||||
#include "InputCommon/ControllerEmu/ControllerEmu.h"
|
||||
#include "InputCommon/ControllerEmu/StickGate.h"
|
||||
|
||||
void InputOverrider::AddFunction(std::string_view group_name, std::string_view control_name,
|
||||
OverrideFunction function)
|
||||
{
|
||||
m_functions.emplace(std::make_pair(group_name, control_name), std::move(function));
|
||||
}
|
||||
|
||||
ControllerEmu::InputOverrideFunction InputOverrider::GetInputOverrideFunction() const
|
||||
{
|
||||
return [this](std::string_view group_name, std::string_view control_name,
|
||||
ControlState controller_state) {
|
||||
const auto it = m_functions.find(std::make_pair(group_name, control_name));
|
||||
return it != m_functions.end() ? it->second(controller_state) : std::nullopt;
|
||||
};
|
||||
}
|
||||
|
||||
TASInputWindow::TASInputWindow(QWidget* parent) : QDialog(parent)
|
||||
{
|
||||
|
@ -63,13 +80,22 @@ int TASInputWindow::GetTurboReleaseFrames() const
|
|||
return m_turbo_release_frames->value();
|
||||
}
|
||||
|
||||
TASCheckBox* TASInputWindow::CreateButton(const QString& name)
|
||||
TASCheckBox* TASInputWindow::CreateButton(const QString& text, std::string_view group_name,
|
||||
std::string_view control_name, InputOverrider* overrider)
|
||||
{
|
||||
return new TASCheckBox(name, this);
|
||||
TASCheckBox* checkbox = new TASCheckBox(text, this);
|
||||
|
||||
overrider->AddFunction(group_name, control_name, [this, checkbox](ControlState controller_state) {
|
||||
return GetButton(checkbox, controller_state);
|
||||
});
|
||||
|
||||
return checkbox;
|
||||
}
|
||||
|
||||
QGroupBox* TASInputWindow::CreateStickInputs(QString name, QSpinBox*& x_value, QSpinBox*& y_value,
|
||||
u16 max_x, u16 max_y, Qt::Key x_shortcut_key,
|
||||
QGroupBox* TASInputWindow::CreateStickInputs(const QString& text, std::string_view group_name,
|
||||
InputOverrider* overrider, QSpinBox*& x_value,
|
||||
QSpinBox*& y_value, u16 min_x, u16 min_y, u16 max_x,
|
||||
u16 max_y, Qt::Key x_shortcut_key,
|
||||
Qt::Key y_shortcut_key)
|
||||
{
|
||||
const QKeySequence x_shortcut_key_sequence = QKeySequence(Qt::ALT | x_shortcut_key);
|
||||
|
@ -77,7 +103,7 @@ QGroupBox* TASInputWindow::CreateStickInputs(QString name, QSpinBox*& x_value, Q
|
|||
|
||||
auto* box =
|
||||
new QGroupBox(QStringLiteral("%1 (%2/%3)")
|
||||
.arg(name, x_shortcut_key_sequence.toString(QKeySequence::NativeText),
|
||||
.arg(text, x_shortcut_key_sequence.toString(QKeySequence::NativeText),
|
||||
y_shortcut_key_sequence.toString(QKeySequence::NativeText)));
|
||||
|
||||
const int x_default = static_cast<int>(std::round(max_x / 2.));
|
||||
|
@ -112,33 +138,72 @@ QGroupBox* TASInputWindow::CreateStickInputs(QString name, QSpinBox*& x_value, Q
|
|||
layout->addLayout(visual_layout);
|
||||
box->setLayout(layout);
|
||||
|
||||
overrider->AddFunction(group_name, ControllerEmu::ReshapableInput::X_INPUT_OVERRIDE,
|
||||
[this, x_value, x_default, min_x, max_x](ControlState controller_state) {
|
||||
return GetSpinBox(x_value, x_default, min_x, max_x, controller_state);
|
||||
});
|
||||
|
||||
overrider->AddFunction(group_name, ControllerEmu::ReshapableInput::Y_INPUT_OVERRIDE,
|
||||
[this, y_value, y_default, min_y, max_y](ControlState controller_state) {
|
||||
return GetSpinBox(y_value, y_default, min_y, max_y, controller_state);
|
||||
});
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
QBoxLayout* TASInputWindow::CreateSliderValuePairLayout(QString name, QSpinBox*& value,
|
||||
int default_, u16 max, Qt::Key shortcut_key,
|
||||
QWidget* shortcut_widget, bool invert)
|
||||
QBoxLayout* TASInputWindow::CreateSliderValuePairLayout(
|
||||
const QString& text, std::string_view group_name, std::string_view control_name,
|
||||
InputOverrider* overrider, QSpinBox*& value, u16 zero, int default_, u16 min, u16 max,
|
||||
Qt::Key shortcut_key, QWidget* shortcut_widget, std::optional<ControlState> scale)
|
||||
{
|
||||
const QKeySequence shortcut_key_sequence = QKeySequence(Qt::ALT | shortcut_key);
|
||||
|
||||
auto* label = new QLabel(QStringLiteral("%1 (%2)").arg(
|
||||
name, shortcut_key_sequence.toString(QKeySequence::NativeText)));
|
||||
text, shortcut_key_sequence.toString(QKeySequence::NativeText)));
|
||||
|
||||
QBoxLayout* layout = new QHBoxLayout;
|
||||
layout->addWidget(label);
|
||||
|
||||
value = CreateSliderValuePair(layout, default_, max, shortcut_key_sequence, Qt::Horizontal,
|
||||
shortcut_widget, invert);
|
||||
value = CreateSliderValuePair(group_name, control_name, overrider, layout, zero, default_, min,
|
||||
max, shortcut_key_sequence, Qt::Horizontal, shortcut_widget, scale);
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
QSpinBox* TASInputWindow::CreateSliderValuePair(
|
||||
std::string_view group_name, std::string_view control_name, InputOverrider* overrider,
|
||||
QBoxLayout* layout, u16 zero, int default_, u16 min, u16 max,
|
||||
QKeySequence shortcut_key_sequence, Qt::Orientation orientation, QWidget* shortcut_widget,
|
||||
std::optional<ControlState> scale)
|
||||
{
|
||||
QSpinBox* value = CreateSliderValuePair(layout, default_, max, shortcut_key_sequence, orientation,
|
||||
shortcut_widget);
|
||||
|
||||
InputOverrider::OverrideFunction func;
|
||||
if (scale)
|
||||
{
|
||||
func = [this, value, zero, scale](ControlState controller_state) {
|
||||
return GetSpinBox(value, zero, controller_state, *scale);
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
func = [this, value, zero, min, max](ControlState controller_state) {
|
||||
return GetSpinBox(value, zero, min, max, controller_state);
|
||||
};
|
||||
}
|
||||
|
||||
overrider->AddFunction(group_name, control_name, std::move(func));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// The shortcut_widget argument needs to specify the container widget that will be hidden/shown.
|
||||
// This is done to avoid ambigous shortcuts
|
||||
QSpinBox* TASInputWindow::CreateSliderValuePair(QBoxLayout* layout, int default_, u16 max,
|
||||
QKeySequence shortcut_key_sequence,
|
||||
Qt::Orientation orientation,
|
||||
QWidget* shortcut_widget, bool invert)
|
||||
QWidget* shortcut_widget)
|
||||
{
|
||||
auto* value = new QSpinBox();
|
||||
value->setRange(0, 99999);
|
||||
|
@ -151,7 +216,6 @@ QSpinBox* TASInputWindow::CreateSliderValuePair(QBoxLayout* layout, int default_
|
|||
slider->setRange(0, max);
|
||||
slider->setValue(default_);
|
||||
slider->setFocusPolicy(Qt::ClickFocus);
|
||||
slider->setInvertedAppearance(invert);
|
||||
|
||||
connect(slider, &QSlider::valueChanged, value, &QSpinBox::setValue);
|
||||
connect(value, qOverload<int>(&QSpinBox::valueChanged), slider, &QSlider::setValue);
|
||||
|
@ -170,10 +234,10 @@ QSpinBox* TASInputWindow::CreateSliderValuePair(QBoxLayout* layout, int default_
|
|||
return value;
|
||||
}
|
||||
|
||||
template <typename UX>
|
||||
void TASInputWindow::GetButton(TASCheckBox* checkbox, UX& buttons, UX mask)
|
||||
std::optional<ControlState> TASInputWindow::GetButton(TASCheckBox* checkbox,
|
||||
ControlState controller_state)
|
||||
{
|
||||
const bool pressed = (buttons & mask) != 0;
|
||||
const bool pressed = std::llround(controller_state) > 0;
|
||||
if (m_use_controller->isChecked())
|
||||
{
|
||||
if (pressed)
|
||||
|
@ -188,50 +252,54 @@ void TASInputWindow::GetButton(TASCheckBox* checkbox, UX& buttons, UX mask)
|
|||
}
|
||||
}
|
||||
|
||||
if (checkbox->GetValue())
|
||||
buttons |= mask;
|
||||
else
|
||||
buttons &= ~mask;
|
||||
return checkbox->GetValue() ? 1.0 : 0.0;
|
||||
}
|
||||
template void TASInputWindow::GetButton<u8>(TASCheckBox* button, u8& pad, u8 mask);
|
||||
template void TASInputWindow::GetButton<u16>(TASCheckBox* button, u16& pad, u16 mask);
|
||||
|
||||
void TASInputWindow::GetSpinBoxU8(QSpinBox* spin, u8& controller_value)
|
||||
std::optional<ControlState> TASInputWindow::GetSpinBox(QSpinBox* spin, u16 zero, u16 min, u16 max,
|
||||
ControlState controller_state)
|
||||
{
|
||||
const u16 controller_value =
|
||||
ControllerEmu::EmulatedController::MapFloat<u16>(controller_state, zero, 0, max);
|
||||
|
||||
if (m_use_controller->isChecked())
|
||||
{
|
||||
if (!m_spinbox_most_recent_values_u8.count(spin) ||
|
||||
m_spinbox_most_recent_values_u8[spin] != controller_value)
|
||||
if (!m_spinbox_most_recent_values.count(spin) ||
|
||||
m_spinbox_most_recent_values[spin] != controller_value)
|
||||
{
|
||||
QueueOnObjectBlocking(spin, [spin, controller_value] { spin->setValue(controller_value); });
|
||||
}
|
||||
|
||||
m_spinbox_most_recent_values_u8[spin] = controller_value;
|
||||
m_spinbox_most_recent_values[spin] = controller_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_spinbox_most_recent_values_u8.clear();
|
||||
m_spinbox_most_recent_values.clear();
|
||||
}
|
||||
|
||||
controller_value = spin->value();
|
||||
return ControllerEmu::EmulatedController::MapToFloat<ControlState, u16>(spin->value(), zero, min,
|
||||
max);
|
||||
}
|
||||
|
||||
void TASInputWindow::GetSpinBoxU16(QSpinBox* spin, u16& controller_value)
|
||||
std::optional<ControlState> TASInputWindow::GetSpinBox(QSpinBox* spin, u16 zero,
|
||||
ControlState controller_state,
|
||||
ControlState scale)
|
||||
{
|
||||
const u16 controller_value = static_cast<u16>(std::llround(controller_state * scale + zero));
|
||||
|
||||
if (m_use_controller->isChecked())
|
||||
{
|
||||
if (!m_spinbox_most_recent_values_u16.count(spin) ||
|
||||
m_spinbox_most_recent_values_u16[spin] != controller_value)
|
||||
if (!m_spinbox_most_recent_values.count(spin) ||
|
||||
m_spinbox_most_recent_values[spin] != controller_value)
|
||||
{
|
||||
QueueOnObjectBlocking(spin, [spin, controller_value] { spin->setValue(controller_value); });
|
||||
}
|
||||
|
||||
m_spinbox_most_recent_values_u16[spin] = controller_value;
|
||||
m_spinbox_most_recent_values[spin] = controller_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_spinbox_most_recent_values_u16.clear();
|
||||
m_spinbox_most_recent_values.clear();
|
||||
}
|
||||
|
||||
controller_value = spin->value();
|
||||
return (spin->value() - zero) / scale;
|
||||
}
|
||||
|
|
|
@ -3,11 +3,18 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
struct GCPadStatus;
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
|
||||
#include "InputCommon/ControllerInterface/CoreDevice.h"
|
||||
|
||||
class QBoxLayout;
|
||||
class QCheckBox;
|
||||
class QDialog;
|
||||
|
@ -16,6 +23,20 @@ class QSpinBox;
|
|||
class QString;
|
||||
class TASCheckBox;
|
||||
|
||||
class InputOverrider final
|
||||
{
|
||||
public:
|
||||
using OverrideFunction = std::function<std::optional<ControlState>(ControlState)>;
|
||||
|
||||
void AddFunction(std::string_view group_name, std::string_view control_name,
|
||||
OverrideFunction function);
|
||||
|
||||
ControllerEmu::InputOverrideFunction GetInputOverrideFunction() const;
|
||||
|
||||
private:
|
||||
std::map<std::pair<std::string_view, std::string_view>, OverrideFunction> m_functions;
|
||||
};
|
||||
|
||||
class TASInputWindow : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -26,19 +47,25 @@ public:
|
|||
int GetTurboReleaseFrames() const;
|
||||
|
||||
protected:
|
||||
TASCheckBox* CreateButton(const QString& name);
|
||||
QGroupBox* CreateStickInputs(QString name, QSpinBox*& x_value, QSpinBox*& y_value, u16 max_x,
|
||||
u16 max_y, Qt::Key x_shortcut_key, Qt::Key y_shortcut_key);
|
||||
QBoxLayout* CreateSliderValuePairLayout(QString name, QSpinBox*& value, int default_, u16 max,
|
||||
Qt::Key shortcut_key, QWidget* shortcut_widget,
|
||||
bool invert = false);
|
||||
TASCheckBox* CreateButton(const QString& text, std::string_view group_name,
|
||||
std::string_view control_name, InputOverrider* overrider);
|
||||
QGroupBox* CreateStickInputs(const QString& text, std::string_view group_name,
|
||||
InputOverrider* overrider, QSpinBox*& x_value, QSpinBox*& y_value,
|
||||
u16 min_x, u16 min_y, u16 max_x, u16 max_y, Qt::Key x_shortcut_key,
|
||||
Qt::Key y_shortcut_key);
|
||||
QBoxLayout* CreateSliderValuePairLayout(const QString& text, std::string_view group_name,
|
||||
std::string_view control_name, InputOverrider* overrider,
|
||||
QSpinBox*& value, u16 zero, int default_, u16 min,
|
||||
u16 max, Qt::Key shortcut_key, QWidget* shortcut_widget,
|
||||
std::optional<ControlState> scale = {});
|
||||
QSpinBox* CreateSliderValuePair(std::string_view group_name, std::string_view control_name,
|
||||
InputOverrider* overrider, QBoxLayout* layout, u16 zero,
|
||||
int default_, u16 min, u16 max,
|
||||
QKeySequence shortcut_key_sequence, Qt::Orientation orientation,
|
||||
QWidget* shortcut_widget, std::optional<ControlState> scale = {});
|
||||
QSpinBox* CreateSliderValuePair(QBoxLayout* layout, int default_, u16 max,
|
||||
QKeySequence shortcut_key_sequence, Qt::Orientation orientation,
|
||||
QWidget* shortcut_widget, bool invert = false);
|
||||
template <typename UX>
|
||||
void GetButton(TASCheckBox* button, UX& pad, UX mask);
|
||||
void GetSpinBoxU8(QSpinBox* spin, u8& controller_value);
|
||||
void GetSpinBoxU16(QSpinBox* spin, u16& controller_value);
|
||||
QWidget* shortcut_widget);
|
||||
|
||||
QGroupBox* m_settings_box;
|
||||
QCheckBox* m_use_controller;
|
||||
|
@ -46,7 +73,12 @@ protected:
|
|||
QSpinBox* m_turbo_release_frames;
|
||||
|
||||
private:
|
||||
std::optional<ControlState> GetButton(TASCheckBox* checkbox, ControlState controller_state);
|
||||
std::optional<ControlState> GetSpinBox(QSpinBox* spin, u16 zero, u16 min, u16 max,
|
||||
ControlState controller_state);
|
||||
std::optional<ControlState> GetSpinBox(QSpinBox* spin, u16 zero, ControlState controller_state,
|
||||
ControlState scale);
|
||||
|
||||
std::map<TASCheckBox*, bool> m_checkbox_set_by_controller;
|
||||
std::map<QSpinBox*, u8> m_spinbox_most_recent_values_u8;
|
||||
std::map<QSpinBox*, u8> m_spinbox_most_recent_values_u16;
|
||||
std::map<QSpinBox*, u16> m_spinbox_most_recent_values;
|
||||
};
|
||||
|
|
|
@ -15,18 +15,14 @@
|
|||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/MathUtil.h"
|
||||
|
||||
#include "Core/Core.h"
|
||||
#include "Core/HW/WiimoteCommon/DataReport.h"
|
||||
#include "Core/HW/WiimoteEmu/Encryption.h"
|
||||
#include "Core/HW/WiimoteEmu/Extension/Classic.h"
|
||||
#include "Core/HW/WiimoteEmu/Extension/Nunchuk.h"
|
||||
|
||||
#include "Core/HW/Wiimote.h"
|
||||
#include "Core/HW/WiimoteEmu/Extension/Classic.h"
|
||||
#include "Core/HW/WiimoteEmu/Extension/Extension.h"
|
||||
#include "Core/HW/WiimoteEmu/Extension/Nunchuk.h"
|
||||
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
|
||||
|
||||
#include "Core/HW/WiimoteEmu/Camera.h"
|
||||
#include "Core/HW/WiimoteReal/WiimoteReal.h"
|
||||
|
||||
#include "DolphinQt/QtUtils/AspectRatioWidget.h"
|
||||
|
@ -34,6 +30,9 @@
|
|||
#include "DolphinQt/TAS/IRWidget.h"
|
||||
#include "DolphinQt/TAS/TASCheckBox.h"
|
||||
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/Attachments.h"
|
||||
#include "InputCommon/ControllerEmu/ControllerEmu.h"
|
||||
#include "InputCommon/ControllerEmu/StickGate.h"
|
||||
#include "InputCommon/InputConfig.h"
|
||||
|
||||
using namespace WiimoteCommon;
|
||||
|
@ -48,21 +47,25 @@ WiiTASInputWindow::WiiTASInputWindow(QWidget* parent, int num) : TASInputWindow(
|
|||
ir_x_shortcut_key_sequence.toString(QKeySequence::NativeText),
|
||||
ir_y_shortcut_key_sequence.toString(QKeySequence::NativeText)));
|
||||
|
||||
const int ir_x_default = static_cast<int>(std::round(ir_max_x / 2.));
|
||||
const int ir_y_default = static_cast<int>(std::round(ir_max_y / 2.));
|
||||
const int ir_x_center = static_cast<int>(std::round(ir_max_x / 2.));
|
||||
const int ir_y_center = static_cast<int>(std::round(ir_max_y / 2.));
|
||||
|
||||
auto* x_layout = new QHBoxLayout;
|
||||
m_ir_x_value = CreateSliderValuePair(x_layout, ir_x_default, ir_max_x, ir_x_shortcut_key_sequence,
|
||||
Qt::Horizontal, m_ir_box, true);
|
||||
m_ir_x_value = CreateSliderValuePair(
|
||||
WiimoteEmu::Wiimote::IR_GROUP, ControllerEmu::ReshapableInput::X_INPUT_OVERRIDE,
|
||||
&m_wiimote_overrider, x_layout, ir_x_center, ir_x_center, ir_min_x, ir_max_x,
|
||||
ir_x_shortcut_key_sequence, Qt::Horizontal, m_ir_box);
|
||||
|
||||
auto* y_layout = new QVBoxLayout;
|
||||
m_ir_y_value = CreateSliderValuePair(y_layout, ir_y_default, ir_max_y, ir_y_shortcut_key_sequence,
|
||||
Qt::Vertical, m_ir_box, true);
|
||||
m_ir_y_value = CreateSliderValuePair(
|
||||
WiimoteEmu::Wiimote::IR_GROUP, ControllerEmu::ReshapableInput::Y_INPUT_OVERRIDE,
|
||||
&m_wiimote_overrider, y_layout, ir_y_center, ir_y_center, ir_min_y, ir_max_y,
|
||||
ir_y_shortcut_key_sequence, Qt::Vertical, m_ir_box);
|
||||
m_ir_y_value->setMaximumWidth(60);
|
||||
|
||||
auto* visual = new IRWidget(this);
|
||||
visual->SetX(ir_x_default);
|
||||
visual->SetY(ir_y_default);
|
||||
visual->SetX(ir_x_center);
|
||||
visual->SetY(ir_y_center);
|
||||
|
||||
connect(m_ir_x_value, qOverload<int>(&QSpinBox::valueChanged), visual, &IRWidget::SetX);
|
||||
connect(m_ir_y_value, qOverload<int>(&QSpinBox::valueChanged), visual, &IRWidget::SetY);
|
||||
|
@ -80,16 +83,19 @@ WiiTASInputWindow::WiiTASInputWindow(QWidget* parent, int num) : TASInputWindow(
|
|||
ir_layout->addLayout(visual_layout);
|
||||
m_ir_box->setLayout(ir_layout);
|
||||
|
||||
m_nunchuk_stick_box = CreateStickInputs(tr("Nunchuk Stick"), m_nunchuk_stick_x_value,
|
||||
m_nunchuk_stick_y_value, 255, 255, Qt::Key_X, Qt::Key_Y);
|
||||
m_nunchuk_stick_box = CreateStickInputs(
|
||||
tr("Nunchuk Stick"), WiimoteEmu::Nunchuk::STICK_GROUP, &m_nunchuk_overrider,
|
||||
m_nunchuk_stick_x_value, m_nunchuk_stick_y_value, 0, 0, 255, 255, Qt::Key_X, Qt::Key_Y);
|
||||
|
||||
m_classic_left_stick_box =
|
||||
CreateStickInputs(tr("Left Stick"), m_classic_left_stick_x_value,
|
||||
m_classic_left_stick_y_value, 63, 63, Qt::Key_F, Qt::Key_G);
|
||||
CreateStickInputs(tr("Left Stick"), WiimoteEmu::Classic::LEFT_STICK_GROUP,
|
||||
&m_classic_overrider, m_classic_left_stick_x_value,
|
||||
m_classic_left_stick_y_value, 0, 0, 63, 63, Qt::Key_F, Qt::Key_G);
|
||||
|
||||
m_classic_right_stick_box =
|
||||
CreateStickInputs(tr("Right Stick"), m_classic_right_stick_x_value,
|
||||
m_classic_right_stick_y_value, 31, 31, Qt::Key_Q, Qt::Key_W);
|
||||
CreateStickInputs(tr("Right Stick"), WiimoteEmu::Classic::RIGHT_STICK_GROUP,
|
||||
&m_classic_overrider, m_classic_right_stick_x_value,
|
||||
m_classic_right_stick_y_value, 0, 0, 31, 31, Qt::Key_Q, Qt::Key_W);
|
||||
|
||||
// Need to enforce the same minimum width because otherwise the different lengths in the labels
|
||||
// used on the QGroupBox will cause the StickWidgets to have different sizes.
|
||||
|
@ -104,18 +110,33 @@ WiiTASInputWindow::WiiTASInputWindow(QWidget* parent, int num) : TASInputWindow(
|
|||
top_layout->addWidget(m_classic_left_stick_box);
|
||||
top_layout->addWidget(m_classic_right_stick_box);
|
||||
|
||||
constexpr u16 ACCEL_ZERO_G = WiimoteEmu::Wiimote::ACCEL_ZERO_G << 2;
|
||||
constexpr u16 ACCEL_ONE_G = WiimoteEmu::Wiimote::ACCEL_ONE_G << 2;
|
||||
constexpr u16 ACCEL_MIN = 0;
|
||||
constexpr u16 ACCEL_MAX = (1 << 10) - 1;
|
||||
constexpr double ACCEL_SCALE = (ACCEL_ONE_G - ACCEL_ZERO_G) / MathUtil::GRAVITY_ACCELERATION;
|
||||
|
||||
auto* remote_orientation_x_layout =
|
||||
// i18n: Refers to a 3D axis (used when mapping motion controls)
|
||||
CreateSliderValuePairLayout(tr("X"), m_remote_orientation_x_value, 512, 1023, Qt::Key_Q,
|
||||
m_remote_orientation_box);
|
||||
CreateSliderValuePairLayout(tr("X"), WiimoteEmu::Wiimote::ACCELEROMETER_GROUP,
|
||||
ControllerEmu::ReshapableInput::X_INPUT_OVERRIDE,
|
||||
&m_wiimote_overrider, m_remote_orientation_x_value, ACCEL_ZERO_G,
|
||||
ACCEL_ZERO_G, ACCEL_MIN, ACCEL_MAX, Qt::Key_Q,
|
||||
m_remote_orientation_box, ACCEL_SCALE);
|
||||
auto* remote_orientation_y_layout =
|
||||
// i18n: Refers to a 3D axis (used when mapping motion controls)
|
||||
CreateSliderValuePairLayout(tr("Y"), m_remote_orientation_y_value, 512, 1023, Qt::Key_W,
|
||||
m_remote_orientation_box);
|
||||
CreateSliderValuePairLayout(tr("Y"), WiimoteEmu::Wiimote::ACCELEROMETER_GROUP,
|
||||
ControllerEmu::ReshapableInput::Y_INPUT_OVERRIDE,
|
||||
&m_wiimote_overrider, m_remote_orientation_y_value, ACCEL_ZERO_G,
|
||||
ACCEL_ZERO_G, ACCEL_MIN, ACCEL_MAX, Qt::Key_W,
|
||||
m_remote_orientation_box, ACCEL_SCALE);
|
||||
auto* remote_orientation_z_layout =
|
||||
// i18n: Refers to a 3D axis (used when mapping motion controls)
|
||||
CreateSliderValuePairLayout(tr("Z"), m_remote_orientation_z_value, 616, 1023, Qt::Key_E,
|
||||
m_remote_orientation_box);
|
||||
CreateSliderValuePairLayout(tr("Z"), WiimoteEmu::Wiimote::ACCELEROMETER_GROUP,
|
||||
ControllerEmu::ReshapableInput::Z_INPUT_OVERRIDE,
|
||||
&m_wiimote_overrider, m_remote_orientation_z_value, ACCEL_ZERO_G,
|
||||
ACCEL_ONE_G, ACCEL_MIN, ACCEL_MAX, Qt::Key_E,
|
||||
m_remote_orientation_box, ACCEL_SCALE);
|
||||
|
||||
auto* remote_orientation_layout = new QVBoxLayout;
|
||||
remote_orientation_layout->addLayout(remote_orientation_x_layout);
|
||||
|
@ -127,15 +148,24 @@ WiiTASInputWindow::WiiTASInputWindow(QWidget* parent, int num) : TASInputWindow(
|
|||
|
||||
auto* nunchuk_orientation_x_layout =
|
||||
// i18n: Refers to a 3D axis (used when mapping motion controls)
|
||||
CreateSliderValuePairLayout(tr("X"), m_nunchuk_orientation_x_value, 512, 1023, Qt::Key_I,
|
||||
CreateSliderValuePairLayout(tr("X"), WiimoteEmu::Nunchuk::ACCELEROMETER_GROUP,
|
||||
ControllerEmu::ReshapableInput::X_INPUT_OVERRIDE,
|
||||
&m_nunchuk_overrider, m_nunchuk_orientation_x_value, ACCEL_ZERO_G,
|
||||
ACCEL_ZERO_G, ACCEL_MIN, ACCEL_MAX, Qt::Key_I,
|
||||
m_nunchuk_orientation_box);
|
||||
auto* nunchuk_orientation_y_layout =
|
||||
// i18n: Refers to a 3D axis (used when mapping motion controls)
|
||||
CreateSliderValuePairLayout(tr("Y"), m_nunchuk_orientation_y_value, 512, 1023, Qt::Key_O,
|
||||
CreateSliderValuePairLayout(tr("Y"), WiimoteEmu::Nunchuk::ACCELEROMETER_GROUP,
|
||||
ControllerEmu::ReshapableInput::Y_INPUT_OVERRIDE,
|
||||
&m_nunchuk_overrider, m_nunchuk_orientation_y_value, ACCEL_ZERO_G,
|
||||
ACCEL_ZERO_G, ACCEL_MIN, ACCEL_MAX, Qt::Key_O,
|
||||
m_nunchuk_orientation_box);
|
||||
auto* nunchuk_orientation_z_layout =
|
||||
// i18n: Refers to a 3D axis (used when mapping motion controls)
|
||||
CreateSliderValuePairLayout(tr("Z"), m_nunchuk_orientation_z_value, 512, 1023, Qt::Key_P,
|
||||
CreateSliderValuePairLayout(tr("Z"), WiimoteEmu::Nunchuk::ACCELEROMETER_GROUP,
|
||||
ControllerEmu::ReshapableInput::Z_INPUT_OVERRIDE,
|
||||
&m_nunchuk_overrider, m_nunchuk_orientation_z_value, ACCEL_ZERO_G,
|
||||
ACCEL_ONE_G, ACCEL_MIN, ACCEL_MAX, Qt::Key_P,
|
||||
m_nunchuk_orientation_box);
|
||||
|
||||
auto* nunchuk_orientation_layout = new QVBoxLayout;
|
||||
|
@ -145,29 +175,46 @@ WiiTASInputWindow::WiiTASInputWindow(QWidget* parent, int num) : TASInputWindow(
|
|||
m_nunchuk_orientation_box->setLayout(nunchuk_orientation_layout);
|
||||
|
||||
m_triggers_box = new QGroupBox(tr("Triggers"));
|
||||
auto* l_trigger_layout = CreateSliderValuePairLayout(tr("Left"), m_left_trigger_value, 0, 31,
|
||||
Qt::Key_N, m_triggers_box);
|
||||
auto* r_trigger_layout = CreateSliderValuePairLayout(tr("Right"), m_right_trigger_value, 0, 31,
|
||||
Qt::Key_M, m_triggers_box);
|
||||
auto* l_trigger_layout = CreateSliderValuePairLayout(
|
||||
tr("Left"), WiimoteEmu::Classic::TRIGGERS_GROUP, WiimoteEmu::Classic::L_ANALOG,
|
||||
&m_classic_overrider, m_left_trigger_value, 0, 0, 0, 31, Qt::Key_N, m_triggers_box);
|
||||
auto* r_trigger_layout = CreateSliderValuePairLayout(
|
||||
tr("Right"), WiimoteEmu::Classic::TRIGGERS_GROUP, WiimoteEmu::Classic::R_ANALOG,
|
||||
&m_classic_overrider, m_right_trigger_value, 0, 0, 0, 31, Qt::Key_M, m_triggers_box);
|
||||
|
||||
auto* triggers_layout = new QVBoxLayout;
|
||||
triggers_layout->addLayout(l_trigger_layout);
|
||||
triggers_layout->addLayout(r_trigger_layout);
|
||||
m_triggers_box->setLayout(triggers_layout);
|
||||
|
||||
m_a_button = CreateButton(QStringLiteral("&A"));
|
||||
m_b_button = CreateButton(QStringLiteral("&B"));
|
||||
m_1_button = CreateButton(QStringLiteral("&1"));
|
||||
m_2_button = CreateButton(QStringLiteral("&2"));
|
||||
m_plus_button = CreateButton(QStringLiteral("&+"));
|
||||
m_minus_button = CreateButton(QStringLiteral("&-"));
|
||||
m_home_button = CreateButton(QStringLiteral("&HOME"));
|
||||
m_left_button = CreateButton(QStringLiteral("&Left"));
|
||||
m_up_button = CreateButton(QStringLiteral("&Up"));
|
||||
m_down_button = CreateButton(QStringLiteral("&Down"));
|
||||
m_right_button = CreateButton(QStringLiteral("&Right"));
|
||||
m_c_button = CreateButton(QStringLiteral("&C"));
|
||||
m_z_button = CreateButton(QStringLiteral("&Z"));
|
||||
m_a_button = CreateButton(QStringLiteral("&A"), WiimoteEmu::Wiimote::BUTTONS_GROUP,
|
||||
WiimoteEmu::Wiimote::A_BUTTON, &m_wiimote_overrider);
|
||||
m_b_button = CreateButton(QStringLiteral("&B"), WiimoteEmu::Wiimote::BUTTONS_GROUP,
|
||||
WiimoteEmu::Wiimote::B_BUTTON, &m_wiimote_overrider);
|
||||
m_1_button = CreateButton(QStringLiteral("&1"), WiimoteEmu::Wiimote::BUTTONS_GROUP,
|
||||
WiimoteEmu::Wiimote::ONE_BUTTON, &m_wiimote_overrider);
|
||||
m_2_button = CreateButton(QStringLiteral("&2"), WiimoteEmu::Wiimote::BUTTONS_GROUP,
|
||||
WiimoteEmu::Wiimote::TWO_BUTTON, &m_wiimote_overrider);
|
||||
m_plus_button = CreateButton(QStringLiteral("&+"), WiimoteEmu::Wiimote::BUTTONS_GROUP,
|
||||
WiimoteEmu::Wiimote::PLUS_BUTTON, &m_wiimote_overrider);
|
||||
m_minus_button = CreateButton(QStringLiteral("&-"), WiimoteEmu::Wiimote::BUTTONS_GROUP,
|
||||
WiimoteEmu::Wiimote::MINUS_BUTTON, &m_wiimote_overrider);
|
||||
m_home_button = CreateButton(QStringLiteral("&HOME"), WiimoteEmu::Wiimote::BUTTONS_GROUP,
|
||||
WiimoteEmu::Wiimote::HOME_BUTTON, &m_wiimote_overrider);
|
||||
|
||||
m_left_button = CreateButton(QStringLiteral("&Left"), WiimoteEmu::Wiimote::DPAD_GROUP,
|
||||
DIRECTION_LEFT, &m_wiimote_overrider);
|
||||
m_up_button = CreateButton(QStringLiteral("&Up"), WiimoteEmu::Wiimote::DPAD_GROUP, DIRECTION_UP,
|
||||
&m_wiimote_overrider);
|
||||
m_down_button = CreateButton(QStringLiteral("&Down"), WiimoteEmu::Wiimote::DPAD_GROUP,
|
||||
DIRECTION_DOWN, &m_wiimote_overrider);
|
||||
m_right_button = CreateButton(QStringLiteral("&Right"), WiimoteEmu::Wiimote::DPAD_GROUP,
|
||||
DIRECTION_RIGHT, &m_wiimote_overrider);
|
||||
|
||||
m_c_button = CreateButton(QStringLiteral("&C"), WiimoteEmu::Nunchuk::BUTTONS_GROUP,
|
||||
WiimoteEmu::Nunchuk::C_BUTTON, &m_nunchuk_overrider);
|
||||
m_z_button = CreateButton(QStringLiteral("&Z"), WiimoteEmu::Nunchuk::BUTTONS_GROUP,
|
||||
WiimoteEmu::Nunchuk::Z_BUTTON, &m_nunchuk_overrider);
|
||||
|
||||
auto* buttons_layout = new QGridLayout;
|
||||
buttons_layout->addWidget(m_a_button, 0, 0);
|
||||
|
@ -196,21 +243,38 @@ WiiTASInputWindow::WiiTASInputWindow(QWidget* parent, int num) : TASInputWindow(
|
|||
m_nunchuk_buttons_box = new QGroupBox(tr("Nunchuk Buttons"));
|
||||
m_nunchuk_buttons_box->setLayout(nunchuk_buttons_layout);
|
||||
|
||||
m_classic_a_button = CreateButton(QStringLiteral("&A"));
|
||||
m_classic_b_button = CreateButton(QStringLiteral("&B"));
|
||||
m_classic_x_button = CreateButton(QStringLiteral("&X"));
|
||||
m_classic_y_button = CreateButton(QStringLiteral("&Y"));
|
||||
m_classic_l_button = CreateButton(QStringLiteral("&L"));
|
||||
m_classic_r_button = CreateButton(QStringLiteral("&R"));
|
||||
m_classic_zl_button = CreateButton(QStringLiteral("&ZL"));
|
||||
m_classic_zr_button = CreateButton(QStringLiteral("ZR"));
|
||||
m_classic_plus_button = CreateButton(QStringLiteral("&+"));
|
||||
m_classic_minus_button = CreateButton(QStringLiteral("&-"));
|
||||
m_classic_home_button = CreateButton(QStringLiteral("&HOME"));
|
||||
m_classic_left_button = CreateButton(QStringLiteral("L&eft"));
|
||||
m_classic_up_button = CreateButton(QStringLiteral("&Up"));
|
||||
m_classic_down_button = CreateButton(QStringLiteral("&Down"));
|
||||
m_classic_right_button = CreateButton(QStringLiteral("R&ight"));
|
||||
m_classic_a_button = CreateButton(QStringLiteral("&A"), WiimoteEmu::Classic::BUTTONS_GROUP,
|
||||
WiimoteEmu::Classic::A_BUTTON, &m_classic_overrider);
|
||||
m_classic_b_button = CreateButton(QStringLiteral("&B"), WiimoteEmu::Classic::BUTTONS_GROUP,
|
||||
WiimoteEmu::Classic::B_BUTTON, &m_classic_overrider);
|
||||
m_classic_x_button = CreateButton(QStringLiteral("&X"), WiimoteEmu::Classic::BUTTONS_GROUP,
|
||||
WiimoteEmu::Classic::X_BUTTON, &m_classic_overrider);
|
||||
m_classic_y_button = CreateButton(QStringLiteral("&Y"), WiimoteEmu::Classic::BUTTONS_GROUP,
|
||||
WiimoteEmu::Classic::Y_BUTTON, &m_classic_overrider);
|
||||
m_classic_zl_button = CreateButton(QStringLiteral("&ZL"), WiimoteEmu::Classic::BUTTONS_GROUP,
|
||||
WiimoteEmu::Classic::ZL_BUTTON, &m_classic_overrider);
|
||||
m_classic_zr_button = CreateButton(QStringLiteral("ZR"), WiimoteEmu::Classic::BUTTONS_GROUP,
|
||||
WiimoteEmu::Classic::ZR_BUTTON, &m_classic_overrider);
|
||||
m_classic_plus_button = CreateButton(QStringLiteral("&+"), WiimoteEmu::Classic::BUTTONS_GROUP,
|
||||
WiimoteEmu::Classic::PLUS_BUTTON, &m_classic_overrider);
|
||||
m_classic_minus_button = CreateButton(QStringLiteral("&-"), WiimoteEmu::Classic::BUTTONS_GROUP,
|
||||
WiimoteEmu::Classic::MINUS_BUTTON, &m_classic_overrider);
|
||||
m_classic_home_button = CreateButton(QStringLiteral("&HOME"), WiimoteEmu::Classic::BUTTONS_GROUP,
|
||||
WiimoteEmu::Classic::HOME_BUTTON, &m_classic_overrider);
|
||||
|
||||
m_classic_l_button = CreateButton(QStringLiteral("&L"), WiimoteEmu::Classic::TRIGGERS_GROUP,
|
||||
WiimoteEmu::Classic::L_DIGITAL, &m_classic_overrider);
|
||||
m_classic_r_button = CreateButton(QStringLiteral("&R"), WiimoteEmu::Classic::TRIGGERS_GROUP,
|
||||
WiimoteEmu::Classic::R_DIGITAL, &m_classic_overrider);
|
||||
|
||||
m_classic_left_button = CreateButton(QStringLiteral("L&eft"), WiimoteEmu::Classic::DPAD_GROUP,
|
||||
DIRECTION_LEFT, &m_classic_overrider);
|
||||
m_classic_up_button = CreateButton(QStringLiteral("&Up"), WiimoteEmu::Classic::DPAD_GROUP,
|
||||
DIRECTION_UP, &m_classic_overrider);
|
||||
m_classic_down_button = CreateButton(QStringLiteral("&Down"), WiimoteEmu::Classic::DPAD_GROUP,
|
||||
DIRECTION_DOWN, &m_classic_overrider);
|
||||
m_classic_right_button = CreateButton(QStringLiteral("R&ight"), WiimoteEmu::Classic::DPAD_GROUP,
|
||||
DIRECTION_RIGHT, &m_classic_overrider);
|
||||
|
||||
auto* classic_buttons_layout = new QGridLayout;
|
||||
classic_buttons_layout->addWidget(m_classic_a_button, 0, 0);
|
||||
|
@ -247,11 +311,9 @@ WiiTASInputWindow::WiiTASInputWindow(QWidget* parent, int num) : TASInputWindow(
|
|||
|
||||
setLayout(layout);
|
||||
|
||||
u8 ext = 0;
|
||||
if (Core::IsRunning())
|
||||
{
|
||||
ext = static_cast<WiimoteEmu::Wiimote*>(Wiimote::GetConfig()->GetController(num))
|
||||
->GetActiveExtensionNumber();
|
||||
m_active_extension = GetWiimote()->GetActiveExtensionNumber();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -261,16 +323,35 @@ WiiTASInputWindow::WiiTASInputWindow(QWidget* parent, int num) : TASInputWindow(
|
|||
ini.GetIfExists("Wiimote" + std::to_string(num + 1), "Extension", &extension);
|
||||
|
||||
if (extension == "Nunchuk")
|
||||
ext = 1;
|
||||
if (extension == "Classic")
|
||||
ext = 2;
|
||||
m_active_extension = WiimoteEmu::ExtensionNumber::NUNCHUK;
|
||||
else if (extension == "Classic")
|
||||
m_active_extension = WiimoteEmu::ExtensionNumber::CLASSIC;
|
||||
else
|
||||
m_active_extension = WiimoteEmu::ExtensionNumber::NONE;
|
||||
}
|
||||
UpdateExt(ext);
|
||||
UpdateExt();
|
||||
}
|
||||
|
||||
void WiiTASInputWindow::UpdateExt(u8 ext)
|
||||
WiimoteEmu::Wiimote* WiiTASInputWindow::GetWiimote()
|
||||
{
|
||||
if (ext == 1)
|
||||
return static_cast<WiimoteEmu::Wiimote*>(Wiimote::GetConfig()->GetController(m_num));
|
||||
}
|
||||
|
||||
ControllerEmu::Attachments* WiiTASInputWindow::GetAttachments()
|
||||
{
|
||||
return static_cast<ControllerEmu::Attachments*>(
|
||||
GetWiimote()->GetWiimoteGroup(WiimoteEmu::WiimoteGroup::Attachments));
|
||||
}
|
||||
|
||||
WiimoteEmu::Extension* WiiTASInputWindow::GetExtension()
|
||||
{
|
||||
return static_cast<WiimoteEmu::Extension*>(
|
||||
GetAttachments()->GetAttachmentList()[m_active_extension].get());
|
||||
}
|
||||
|
||||
void WiiTASInputWindow::UpdateExt()
|
||||
{
|
||||
if (m_active_extension == WiimoteEmu::ExtensionNumber::NUNCHUK)
|
||||
{
|
||||
setWindowTitle(tr("Wii TAS Input %1 - Wii Remote + Nunchuk").arg(m_num + 1));
|
||||
m_ir_box->show();
|
||||
|
@ -284,7 +365,7 @@ void WiiTASInputWindow::UpdateExt(u8 ext)
|
|||
m_remote_buttons_box->show();
|
||||
m_classic_buttons_box->hide();
|
||||
}
|
||||
else if (ext == 2)
|
||||
else if (m_active_extension == WiimoteEmu::ExtensionNumber::CLASSIC)
|
||||
{
|
||||
setWindowTitle(tr("Wii TAS Input %1 - Classic Controller").arg(m_num + 1));
|
||||
m_ir_box->hide();
|
||||
|
@ -314,183 +395,22 @@ void WiiTASInputWindow::UpdateExt(u8 ext)
|
|||
}
|
||||
}
|
||||
|
||||
void WiiTASInputWindow::GetValues(DataReportBuilder& rpt, int ext,
|
||||
const WiimoteEmu::EncryptionKey& key)
|
||||
void WiiTASInputWindow::hideEvent(QHideEvent* event)
|
||||
{
|
||||
if (!isVisible())
|
||||
return;
|
||||
|
||||
UpdateExt(ext);
|
||||
|
||||
if (m_remote_buttons_box->isVisible() && rpt.HasCore())
|
||||
{
|
||||
DataReportBuilder::CoreData core;
|
||||
rpt.GetCoreData(&core);
|
||||
|
||||
using EmuWiimote = WiimoteEmu::Wiimote;
|
||||
|
||||
u16& buttons = core.hex;
|
||||
GetButton<u16>(m_a_button, buttons, EmuWiimote::BUTTON_A);
|
||||
GetButton<u16>(m_b_button, buttons, EmuWiimote::BUTTON_B);
|
||||
GetButton<u16>(m_1_button, buttons, EmuWiimote::BUTTON_ONE);
|
||||
GetButton<u16>(m_2_button, buttons, EmuWiimote::BUTTON_TWO);
|
||||
GetButton<u16>(m_plus_button, buttons, EmuWiimote::BUTTON_PLUS);
|
||||
GetButton<u16>(m_minus_button, buttons, EmuWiimote::BUTTON_MINUS);
|
||||
GetButton<u16>(m_home_button, buttons, EmuWiimote::BUTTON_HOME);
|
||||
GetButton<u16>(m_left_button, buttons, EmuWiimote::PAD_LEFT);
|
||||
GetButton<u16>(m_up_button, buttons, EmuWiimote::PAD_UP);
|
||||
GetButton<u16>(m_down_button, buttons, EmuWiimote::PAD_DOWN);
|
||||
GetButton<u16>(m_right_button, buttons, EmuWiimote::PAD_RIGHT);
|
||||
|
||||
rpt.SetCoreData(core);
|
||||
GetWiimote()->ClearInputOverrideFunction();
|
||||
GetExtension()->ClearInputOverrideFunction();
|
||||
}
|
||||
|
||||
if (m_remote_orientation_box->isVisible() && rpt.HasAccel())
|
||||
void WiiTASInputWindow::showEvent(QShowEvent* event)
|
||||
{
|
||||
// FYI: Interleaved reports may behave funky as not all data is always available.
|
||||
WiimoteEmu::Wiimote* wiimote = GetWiimote();
|
||||
|
||||
AccelData accel;
|
||||
rpt.GetAccelData(&accel);
|
||||
if (m_active_extension != WiimoteEmu::ExtensionNumber::CLASSIC)
|
||||
wiimote->SetInputOverrideFunction(m_wiimote_overrider.GetInputOverrideFunction());
|
||||
|
||||
GetSpinBoxU16(m_remote_orientation_x_value, accel.value.x);
|
||||
GetSpinBoxU16(m_remote_orientation_y_value, accel.value.y);
|
||||
GetSpinBoxU16(m_remote_orientation_z_value, accel.value.z);
|
||||
if (m_active_extension == WiimoteEmu::ExtensionNumber::NUNCHUK)
|
||||
GetExtension()->SetInputOverrideFunction(m_nunchuk_overrider.GetInputOverrideFunction());
|
||||
|
||||
rpt.SetAccelData(accel);
|
||||
}
|
||||
|
||||
if (m_ir_box->isVisible() && rpt.HasIR() && !m_use_controller->isChecked())
|
||||
{
|
||||
u8* const ir_data = rpt.GetIRDataPtr();
|
||||
|
||||
u16 y = m_ir_y_value->value();
|
||||
std::array<u16, 4> x;
|
||||
x[0] = m_ir_x_value->value();
|
||||
x[1] = x[0] + 100;
|
||||
x[2] = x[0] - 10;
|
||||
x[3] = x[1] + 10;
|
||||
|
||||
// FYI: This check is not entirely foolproof.
|
||||
// TODO: IR "full" mode not implemented.
|
||||
u8 mode = WiimoteEmu::CameraLogic::IR_MODE_BASIC;
|
||||
|
||||
if (rpt.GetIRDataSize() == sizeof(WiimoteEmu::IRExtended) * 4)
|
||||
mode = WiimoteEmu::CameraLogic::IR_MODE_EXTENDED;
|
||||
else if (rpt.GetIRDataSize() == sizeof(WiimoteEmu::IRFull) * 2)
|
||||
mode = WiimoteEmu::CameraLogic::IR_MODE_FULL;
|
||||
|
||||
if (mode == WiimoteEmu::CameraLogic::IR_MODE_BASIC)
|
||||
{
|
||||
memset(ir_data, 0xFF, sizeof(WiimoteEmu::IRBasic) * 2);
|
||||
auto* const ir_basic = reinterpret_cast<WiimoteEmu::IRBasic*>(ir_data);
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
if (x[i * 2] < 1024 && y < 768)
|
||||
{
|
||||
ir_basic[i].x1 = static_cast<u8>(x[i * 2]);
|
||||
ir_basic[i].x1hi = x[i * 2] >> 8;
|
||||
|
||||
ir_basic[i].y1 = static_cast<u8>(y);
|
||||
ir_basic[i].y1hi = y >> 8;
|
||||
}
|
||||
if (x[i * 2 + 1] < 1024 && y < 768)
|
||||
{
|
||||
ir_basic[i].x2 = static_cast<u8>(x[i * 2 + 1]);
|
||||
ir_basic[i].x2hi = x[i * 2 + 1] >> 8;
|
||||
|
||||
ir_basic[i].y2 = static_cast<u8>(y);
|
||||
ir_basic[i].y2hi = y >> 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: this code doesnt work, resulting in no IR TAS inputs in e.g. wii sports menu when no
|
||||
// remote extension is used
|
||||
memset(ir_data, 0xFF, sizeof(WiimoteEmu::IRExtended) * 4);
|
||||
auto* const ir_extended = reinterpret_cast<WiimoteEmu::IRExtended*>(ir_data);
|
||||
for (size_t i = 0; i < x.size(); ++i)
|
||||
{
|
||||
if (x[i] < 1024 && y < 768)
|
||||
{
|
||||
ir_extended[i].x = static_cast<u8>(x[i]);
|
||||
ir_extended[i].xhi = x[i] >> 8;
|
||||
|
||||
ir_extended[i].y = static_cast<u8>(y);
|
||||
ir_extended[i].yhi = y >> 8;
|
||||
|
||||
ir_extended[i].size = 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rpt.HasExt() && m_nunchuk_stick_box->isVisible())
|
||||
{
|
||||
u8* const ext_data = rpt.GetExtDataPtr();
|
||||
|
||||
auto& nunchuk = *reinterpret_cast<WiimoteEmu::Nunchuk::DataFormat*>(ext_data);
|
||||
|
||||
GetSpinBoxU8(m_nunchuk_stick_x_value, nunchuk.jx);
|
||||
GetSpinBoxU8(m_nunchuk_stick_y_value, nunchuk.jy);
|
||||
|
||||
auto accel = nunchuk.GetAccel().value;
|
||||
GetSpinBoxU16(m_nunchuk_orientation_x_value, accel.x);
|
||||
GetSpinBoxU16(m_nunchuk_orientation_y_value, accel.y);
|
||||
GetSpinBoxU16(m_nunchuk_orientation_z_value, accel.z);
|
||||
nunchuk.SetAccel(accel);
|
||||
|
||||
u8 bt = nunchuk.GetButtons();
|
||||
GetButton<u8>(m_c_button, bt, WiimoteEmu::Nunchuk::BUTTON_C);
|
||||
GetButton<u8>(m_z_button, bt, WiimoteEmu::Nunchuk::BUTTON_Z);
|
||||
nunchuk.SetButtons(bt);
|
||||
|
||||
key.Encrypt(reinterpret_cast<u8*>(&nunchuk), 0, sizeof(nunchuk));
|
||||
}
|
||||
|
||||
if (m_classic_left_stick_box->isVisible())
|
||||
{
|
||||
u8* const ext_data = rpt.GetExtDataPtr();
|
||||
|
||||
auto& cc = *reinterpret_cast<WiimoteEmu::Classic::DataFormat*>(ext_data);
|
||||
key.Decrypt(reinterpret_cast<u8*>(&cc), 0, sizeof(cc));
|
||||
|
||||
u16 bt = cc.GetButtons();
|
||||
GetButton<u16>(m_classic_a_button, bt, WiimoteEmu::Classic::BUTTON_A);
|
||||
GetButton<u16>(m_classic_b_button, bt, WiimoteEmu::Classic::BUTTON_B);
|
||||
GetButton<u16>(m_classic_x_button, bt, WiimoteEmu::Classic::BUTTON_X);
|
||||
GetButton<u16>(m_classic_y_button, bt, WiimoteEmu::Classic::BUTTON_Y);
|
||||
GetButton<u16>(m_classic_plus_button, bt, WiimoteEmu::Classic::BUTTON_PLUS);
|
||||
GetButton<u16>(m_classic_minus_button, bt, WiimoteEmu::Classic::BUTTON_MINUS);
|
||||
GetButton<u16>(m_classic_l_button, bt, WiimoteEmu::Classic::TRIGGER_L);
|
||||
GetButton<u16>(m_classic_r_button, bt, WiimoteEmu::Classic::TRIGGER_R);
|
||||
GetButton<u16>(m_classic_zl_button, bt, WiimoteEmu::Classic::BUTTON_ZL);
|
||||
GetButton<u16>(m_classic_zr_button, bt, WiimoteEmu::Classic::BUTTON_ZR);
|
||||
GetButton<u16>(m_classic_home_button, bt, WiimoteEmu::Classic::BUTTON_HOME);
|
||||
GetButton<u16>(m_classic_left_button, bt, WiimoteEmu::Classic::PAD_LEFT);
|
||||
GetButton<u16>(m_classic_up_button, bt, WiimoteEmu::Classic::PAD_UP);
|
||||
GetButton<u16>(m_classic_down_button, bt, WiimoteEmu::Classic::PAD_DOWN);
|
||||
GetButton<u16>(m_classic_right_button, bt, WiimoteEmu::Classic::PAD_RIGHT);
|
||||
cc.SetButtons(bt);
|
||||
|
||||
auto right_stick = cc.GetRightStick().value;
|
||||
GetSpinBoxU8(m_classic_right_stick_x_value, right_stick.x);
|
||||
GetSpinBoxU8(m_classic_right_stick_y_value, right_stick.y);
|
||||
cc.SetRightStick(right_stick);
|
||||
|
||||
auto left_stick = cc.GetLeftStick().value;
|
||||
GetSpinBoxU8(m_classic_left_stick_x_value, left_stick.x);
|
||||
GetSpinBoxU8(m_classic_left_stick_y_value, left_stick.y);
|
||||
cc.SetLeftStick(left_stick);
|
||||
|
||||
u8 rt = cc.GetRightTrigger().value;
|
||||
GetSpinBoxU8(m_right_trigger_value, rt);
|
||||
cc.SetRightTrigger(rt);
|
||||
|
||||
u8 lt = cc.GetLeftTrigger().value;
|
||||
GetSpinBoxU8(m_left_trigger_value, lt);
|
||||
cc.SetLeftTrigger(lt);
|
||||
|
||||
key.Encrypt(reinterpret_cast<u8*>(&cc), 0, sizeof(cc));
|
||||
}
|
||||
if (m_active_extension == WiimoteEmu::ExtensionNumber::CLASSIC)
|
||||
GetExtension()->SetInputOverrideFunction(m_classic_overrider.GetInputOverrideFunction());
|
||||
}
|
||||
|
|
|
@ -5,31 +5,48 @@
|
|||
|
||||
#include "DolphinQt/TAS/TASInputWindow.h"
|
||||
|
||||
namespace WiimoteCommon
|
||||
{
|
||||
class DataReportBuilder;
|
||||
}
|
||||
#include "Core/HW/WiimoteEmu/ExtensionPort.h"
|
||||
|
||||
class QGroupBox;
|
||||
class QHideEvent;
|
||||
class QShowEvent;
|
||||
class QSpinBox;
|
||||
class TASCheckBox;
|
||||
|
||||
namespace WiimoteEmu
|
||||
{
|
||||
class EncryptionKey;
|
||||
}
|
||||
class Extension;
|
||||
class Wiimote;
|
||||
} // namespace WiimoteEmu
|
||||
|
||||
class QGroupBox;
|
||||
class QSpinBox;
|
||||
class TASCheckBox;
|
||||
namespace ControllerEmu
|
||||
{
|
||||
class Attachments;
|
||||
}
|
||||
|
||||
class WiiTASInputWindow : public TASInputWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit WiiTASInputWindow(QWidget* parent, int num);
|
||||
void GetValues(WiimoteCommon::DataReportBuilder& rpt, int ext,
|
||||
const WiimoteEmu::EncryptionKey& key);
|
||||
|
||||
void hideEvent(QHideEvent* event) override;
|
||||
void showEvent(QShowEvent* event) override;
|
||||
|
||||
private:
|
||||
void UpdateExt(u8 ext);
|
||||
WiimoteEmu::Wiimote* GetWiimote();
|
||||
ControllerEmu::Attachments* GetAttachments();
|
||||
WiimoteEmu::Extension* GetExtension();
|
||||
|
||||
void UpdateExt();
|
||||
|
||||
WiimoteEmu::ExtensionNumber m_active_extension;
|
||||
int m_num;
|
||||
|
||||
InputOverrider m_wiimote_overrider;
|
||||
InputOverrider m_nunchuk_overrider;
|
||||
InputOverrider m_classic_overrider;
|
||||
|
||||
TASCheckBox* m_a_button;
|
||||
TASCheckBox* m_b_button;
|
||||
TASCheckBox* m_1_button;
|
||||
|
|
|
@ -140,6 +140,8 @@ elseif(ANDROID)
|
|||
ControllerInterface/Android/Android.h
|
||||
ControllerInterface/Touch/ButtonManager.cpp
|
||||
ControllerInterface/Touch/ButtonManager.h
|
||||
ControllerInterface/Touch/InputOverrider.cpp
|
||||
ControllerInterface/Touch/InputOverrider.h
|
||||
ControllerInterface/Touch/Touchscreen.cpp
|
||||
ControllerInterface/Touch/Touchscreen.h
|
||||
)
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "InputCommon/ControllerEmu/ControlGroup/AnalogStick.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <optional>
|
||||
|
||||
#include "Common/Common.h"
|
||||
#include "Common/MathUtil.h"
|
||||
|
@ -48,6 +49,34 @@ AnalogStick::StateData AnalogStick::GetState() const
|
|||
return GetReshapableState(true);
|
||||
}
|
||||
|
||||
AnalogStick::StateData AnalogStick::GetState(const InputOverrideFunction& override_func) const
|
||||
{
|
||||
bool override_occurred = false;
|
||||
return GetState(override_func, &override_occurred);
|
||||
}
|
||||
|
||||
AnalogStick::StateData AnalogStick::GetState(const InputOverrideFunction& override_func,
|
||||
bool* override_occurred) const
|
||||
{
|
||||
StateData state = GetState();
|
||||
if (!override_func)
|
||||
return state;
|
||||
|
||||
if (const std::optional<ControlState> x_override = override_func(name, X_INPUT_OVERRIDE, state.x))
|
||||
{
|
||||
state.x = *x_override;
|
||||
*override_occurred = true;
|
||||
}
|
||||
|
||||
if (const std::optional<ControlState> y_override = override_func(name, Y_INPUT_OVERRIDE, state.y))
|
||||
{
|
||||
state.y = *y_override;
|
||||
*override_occurred = true;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
ControlState AnalogStick::GetGateRadiusAtAngle(double ang) const
|
||||
{
|
||||
return m_stick_gate->GetRadiusAtAngle(ang);
|
||||
|
|
|
@ -21,6 +21,8 @@ public:
|
|||
ControlState GetGateRadiusAtAngle(double ang) const override;
|
||||
|
||||
StateData GetState() const;
|
||||
StateData GetState(const InputOverrideFunction& override_func) const;
|
||||
StateData GetState(const InputOverrideFunction& override_func, bool* override_occurred) const;
|
||||
|
||||
private:
|
||||
Control* GetModifierInput() const override;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
|
||||
#include "InputCommon/ControlReference/ControlReference.h"
|
||||
|
@ -24,5 +25,21 @@ public:
|
|||
for (auto& control : controls)
|
||||
*buttons |= *(bitmasks++) * control->GetState<bool>();
|
||||
}
|
||||
|
||||
template <typename C>
|
||||
void GetState(C* const buttons, const C* bitmasks,
|
||||
const InputOverrideFunction& override_func) const
|
||||
{
|
||||
if (!override_func)
|
||||
return GetState(buttons, bitmasks);
|
||||
|
||||
for (auto& control : controls)
|
||||
{
|
||||
ControlState state = control->GetState();
|
||||
if (std::optional<ControlState> state_override = override_func(name, control->name, state))
|
||||
state = *state_override;
|
||||
*buttons |= *(bitmasks++) * (std::lround(state) > 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace ControllerEmu
|
||||
|
|
|
@ -5,14 +5,18 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/IniFile.h"
|
||||
#include "InputCommon/ControllerEmu/Control/Control.h"
|
||||
#include "InputCommon/ControllerInterface/CoreDevice.h"
|
||||
|
||||
namespace ControllerEmu
|
||||
{
|
||||
|
@ -27,6 +31,9 @@ class NumericSetting;
|
|||
template <typename T>
|
||||
class SettingValue;
|
||||
|
||||
using InputOverrideFunction = std::function<std::optional<ControlState>(
|
||||
const std::string_view group_name, const std::string_view control_name, ControlState state)>;
|
||||
|
||||
enum class GroupType
|
||||
{
|
||||
Other,
|
||||
|
|
|
@ -82,15 +82,28 @@ ControlState Cursor::GetGateRadiusAtAngle(double ang) const
|
|||
|
||||
Cursor::StateData Cursor::GetState(const bool adjusted)
|
||||
{
|
||||
if (!adjusted)
|
||||
{
|
||||
const auto raw_input = GetReshapableState(false);
|
||||
|
||||
return {raw_input.x, raw_input.y};
|
||||
const ReshapeData input = GetReshapableState(adjusted);
|
||||
const StateData state = adjusted ? UpdateState(input) : StateData{input.x, input.y};
|
||||
return state;
|
||||
}
|
||||
|
||||
const auto input = GetReshapableState(true);
|
||||
Cursor::StateData Cursor::GetState(const bool adjusted,
|
||||
const ControllerEmu::InputOverrideFunction& override_func)
|
||||
{
|
||||
StateData state = GetState(adjusted);
|
||||
if (!override_func)
|
||||
return state;
|
||||
|
||||
if (const std::optional<ControlState> x_override = override_func(name, X_INPUT_OVERRIDE, state.x))
|
||||
state.x = *x_override;
|
||||
if (const std::optional<ControlState> y_override = override_func(name, Y_INPUT_OVERRIDE, state.y))
|
||||
state.y = *y_override;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
Cursor::StateData Cursor::UpdateState(Cursor::ReshapeData input)
|
||||
{
|
||||
// TODO: Using system time is ugly.
|
||||
// Kill this after state is moved into wiimote rather than this class.
|
||||
const auto now = Clock::now();
|
||||
|
|
|
@ -29,6 +29,7 @@ public:
|
|||
|
||||
// Modifies the state
|
||||
StateData GetState(bool adjusted);
|
||||
StateData GetState(bool adjusted, const ControllerEmu::InputOverrideFunction& override_func);
|
||||
|
||||
// Yaw movement in radians.
|
||||
ControlState GetTotalYaw() const;
|
||||
|
@ -40,6 +41,8 @@ public:
|
|||
ControlState GetVerticalOffset() const;
|
||||
|
||||
private:
|
||||
Cursor::StateData UpdateState(Cursor::ReshapeData input);
|
||||
|
||||
// This is used to reduce the cursor speed for relative input
|
||||
// to something that makes sense with the default range.
|
||||
static constexpr double STEP_PER_SEC = 0.01 * 200;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
@ -63,6 +64,53 @@ void MixedTriggers::GetState(u16* const digital, const u16* bitmasks, ControlSta
|
|||
}
|
||||
}
|
||||
|
||||
void MixedTriggers::GetState(u16* digital, const u16* bitmasks, ControlState* analog,
|
||||
const InputOverrideFunction& override_func, bool adjusted) const
|
||||
{
|
||||
if (!override_func)
|
||||
return GetState(digital, bitmasks, analog, adjusted);
|
||||
|
||||
const ControlState threshold = GetThreshold();
|
||||
ControlState deadzone = GetDeadzone();
|
||||
|
||||
// Return raw values. (used in UI)
|
||||
if (!adjusted)
|
||||
{
|
||||
deadzone = 0.0;
|
||||
}
|
||||
|
||||
const int trigger_count = int(controls.size() / 2);
|
||||
for (int i = 0; i != trigger_count; ++i)
|
||||
{
|
||||
bool button_bool = false;
|
||||
const ControlState button_value = ApplyDeadzone(controls[i]->GetState(), deadzone);
|
||||
ControlState analog_value = ApplyDeadzone(controls[trigger_count + i]->GetState(), deadzone);
|
||||
|
||||
// Apply threshold:
|
||||
if (button_value > threshold)
|
||||
{
|
||||
analog_value = 1.0;
|
||||
button_bool = true;
|
||||
}
|
||||
|
||||
if (const std::optional<ControlState> button_override =
|
||||
override_func(name, controls[i]->name, static_cast<ControlState>(button_bool)))
|
||||
{
|
||||
button_bool = std::lround(*button_override) > 0;
|
||||
}
|
||||
|
||||
if (const std::optional<ControlState> analog_override =
|
||||
override_func(name, controls[trigger_count + i]->name, analog_value))
|
||||
{
|
||||
analog_value = *analog_override;
|
||||
}
|
||||
|
||||
if (button_bool)
|
||||
*digital |= bitmasks[i];
|
||||
analog[i] = std::min(analog_value, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
ControlState MixedTriggers::GetDeadzone() const
|
||||
{
|
||||
return m_deadzone_setting.GetValue() / 100;
|
||||
|
|
|
@ -17,6 +17,8 @@ public:
|
|||
|
||||
void GetState(u16* digital, const u16* bitmasks, ControlState* analog,
|
||||
bool adjusted = true) const;
|
||||
void GetState(u16* digital, const u16* bitmasks, ControlState* analog,
|
||||
const InputOverrideFunction& override_func, bool adjusted = true) const;
|
||||
|
||||
ControlState GetDeadzone() const;
|
||||
ControlState GetThreshold() const;
|
||||
|
|
|
@ -35,4 +35,21 @@ Slider::StateData Slider::GetState() const
|
|||
|
||||
return {std::clamp(ApplyDeadzone(state, deadzone), -1.0, 1.0)};
|
||||
}
|
||||
|
||||
Slider::StateData Slider::GetState(const InputOverrideFunction& override_func) const
|
||||
{
|
||||
if (!override_func)
|
||||
return GetState();
|
||||
|
||||
const ControlState deadzone = m_deadzone_setting.GetValue() / 100;
|
||||
ControlState state = controls[1]->GetState() - controls[0]->GetState();
|
||||
|
||||
state = ApplyDeadzone(state, deadzone);
|
||||
|
||||
if (std::optional<ControlState> state_override = override_func(name, X_INPUT_OVERRIDE, state))
|
||||
state = *state_override;
|
||||
|
||||
return {std::clamp(state, -1.0, 1.0)};
|
||||
}
|
||||
|
||||
} // namespace ControllerEmu
|
||||
|
|
|
@ -23,6 +23,9 @@ public:
|
|||
explicit Slider(const std::string& name_);
|
||||
|
||||
StateData GetState() const;
|
||||
StateData GetState(const InputOverrideFunction& override_func) const;
|
||||
|
||||
static constexpr const char* X_INPUT_OVERRIDE = "X";
|
||||
|
||||
private:
|
||||
SettingValue<double> m_deadzone_setting;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "Common/Common.h"
|
||||
|
@ -31,4 +32,25 @@ Triggers::StateData Triggers::GetState() const
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
Triggers::StateData Triggers::GetState(const InputOverrideFunction& override_func) const
|
||||
{
|
||||
if (!override_func)
|
||||
return GetState();
|
||||
|
||||
const size_t trigger_count = controls.size();
|
||||
const ControlState deadzone = m_deadzone_setting.GetValue() / 100;
|
||||
|
||||
StateData result(trigger_count);
|
||||
for (size_t i = 0; i < trigger_count; ++i)
|
||||
{
|
||||
ControlState state = ApplyDeadzone(controls[i]->GetState(), deadzone);
|
||||
if (std::optional<ControlState> state_override = override_func(name, controls[i]->name, state))
|
||||
state = *state_override;
|
||||
result.data[i] = std::min(state, 1.0);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace ControllerEmu
|
||||
|
|
|
@ -26,6 +26,7 @@ public:
|
|||
explicit Triggers(const std::string& name);
|
||||
|
||||
StateData GetState() const;
|
||||
StateData GetState(const InputOverrideFunction& override_func) const;
|
||||
|
||||
private:
|
||||
SettingValue<double> m_deadzone_setting;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "Common/IniFile.h"
|
||||
|
||||
|
@ -176,4 +177,15 @@ void EmulatedController::LoadDefaults(const ControllerInterface& ciface)
|
|||
SetDefaultDevice(default_device_string);
|
||||
}
|
||||
}
|
||||
|
||||
void EmulatedController::SetInputOverrideFunction(InputOverrideFunction override_func)
|
||||
{
|
||||
m_input_override_function = std::move(override_func);
|
||||
}
|
||||
|
||||
void EmulatedController::ClearInputOverrideFunction()
|
||||
{
|
||||
m_input_override_function = {};
|
||||
}
|
||||
|
||||
} // namespace ControllerEmu
|
||||
|
|
|
@ -15,12 +15,18 @@
|
|||
#include "Common/IniFile.h"
|
||||
#include "Common/MathUtil.h"
|
||||
#include "InputCommon/ControlReference/ExpressionParser.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
|
||||
#include "InputCommon/ControllerInterface/CoreDevice.h"
|
||||
|
||||
class ControllerInterface;
|
||||
|
||||
const char* const named_directions[] = {_trans("Up"), _trans("Down"), _trans("Left"),
|
||||
_trans("Right")};
|
||||
constexpr const char* DIRECTION_UP = _trans("Up");
|
||||
constexpr const char* DIRECTION_DOWN = _trans("Down");
|
||||
constexpr const char* DIRECTION_LEFT = _trans("Left");
|
||||
constexpr const char* DIRECTION_RIGHT = _trans("Right");
|
||||
|
||||
constexpr const char* named_directions[] = {DIRECTION_UP, DIRECTION_DOWN, DIRECTION_LEFT,
|
||||
DIRECTION_RIGHT};
|
||||
|
||||
class ControlReference;
|
||||
|
||||
|
@ -184,6 +190,9 @@ public:
|
|||
void SetDefaultDevice(const std::string& device);
|
||||
void SetDefaultDevice(ciface::Core::DeviceQualifier devq);
|
||||
|
||||
void SetInputOverrideFunction(InputOverrideFunction override_func);
|
||||
void ClearInputOverrideFunction();
|
||||
|
||||
void UpdateReferences(const ControllerInterface& devi);
|
||||
void UpdateSingleControlReference(const ControllerInterface& devi, ControlReference* ref);
|
||||
|
||||
|
@ -200,7 +209,7 @@ public:
|
|||
|
||||
std::vector<std::unique_ptr<ControlGroup>> groups;
|
||||
|
||||
// Maps a float from -1.0..+1.0 to an integer of the provided values.
|
||||
// Maps a float from -1.0..+1.0 to an integer in the provided range.
|
||||
template <typename T, typename F>
|
||||
static T MapFloat(F input_value, T zero_value, T neg_1_value = std::numeric_limits<T>::min(),
|
||||
T pos_1_value = std::numeric_limits<T>::max())
|
||||
|
@ -223,11 +232,28 @@ public:
|
|||
return T(std::llround((zero_value - neg_1_value) * input_value + zero_value));
|
||||
}
|
||||
|
||||
// The inverse of the function above.
|
||||
// Maps an integer in the provided range to a float in the range -1.0..1.0.
|
||||
template <typename F, typename T>
|
||||
static F MapToFloat(T input_value, T zero_value, T neg_1_value = std::numeric_limits<T>::min(),
|
||||
T pos_1_value = std::numeric_limits<T>::max())
|
||||
{
|
||||
static_assert(std::is_integral<T>(), "T is only sane for int types.");
|
||||
static_assert(std::is_floating_point<F>(), "F is only sane for float types.");
|
||||
|
||||
if (input_value >= zero_value)
|
||||
return F(input_value - zero_value) / F(pos_1_value - zero_value);
|
||||
else
|
||||
return -F(zero_value - input_value) / F(zero_value - neg_1_value);
|
||||
}
|
||||
|
||||
protected:
|
||||
// TODO: Wiimote attachments actually end up using their parent controller value for this,
|
||||
// so theirs won't be used (and thus shouldn't even exist).
|
||||
ciface::ExpressionParser::ControlEnvironment::VariableContainer m_expression_vars;
|
||||
|
||||
InputOverrideFunction m_input_override_function;
|
||||
|
||||
void UpdateReferences(ciface::ExpressionParser::ControlEnvironment& env);
|
||||
|
||||
private:
|
||||
|
|
|
@ -106,6 +106,10 @@ public:
|
|||
const ReshapeData& GetCenter() const;
|
||||
void SetCenter(ReshapeData center);
|
||||
|
||||
static constexpr const char* X_INPUT_OVERRIDE = "X";
|
||||
static constexpr const char* Y_INPUT_OVERRIDE = "Y";
|
||||
static constexpr const char* Z_INPUT_OVERRIDE = "Z";
|
||||
|
||||
protected:
|
||||
ReshapeData Reshape(ControlState x, ControlState y, ControlState modifier = 0.0,
|
||||
ControlState clamp = 1.0) const;
|
||||
|
|
|
@ -9,23 +9,11 @@
|
|||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/IniFile.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Common/Thread.h"
|
||||
|
||||
#include "Core/Core.h"
|
||||
#include "Core/HW/GCPad.h"
|
||||
#include "Core/HW/GCPadEmu.h"
|
||||
#include "Core/HW/Wiimote.h"
|
||||
#include "Core/HW/WiimoteEmu/Extension/Classic.h"
|
||||
#include "Core/HW/WiimoteEmu/Extension/Nunchuk.h"
|
||||
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
|
||||
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
|
||||
#include "InputCommon/ControllerEmu/StickGate.h"
|
||||
|
||||
namespace ButtonManager
|
||||
{
|
||||
namespace
|
||||
|
@ -700,39 +688,6 @@ float GetAxisValue(int pad_id, ButtonType axis)
|
|||
return value;
|
||||
}
|
||||
|
||||
double GetInputRadiusAtAngle(int pad_id, ButtonType stick, double angle)
|
||||
{
|
||||
// To avoid a crash, don't access controllers before they've been initialized by the boot process
|
||||
if (!Core::IsRunningAndStarted())
|
||||
return 0;
|
||||
|
||||
ControllerEmu::ControlGroup* group;
|
||||
|
||||
switch (stick)
|
||||
{
|
||||
case STICK_MAIN:
|
||||
group = Pad::GetGroup(pad_id, PadGroup::MainStick);
|
||||
break;
|
||||
case STICK_C:
|
||||
group = Pad::GetGroup(pad_id, PadGroup::CStick);
|
||||
break;
|
||||
case NUNCHUK_STICK:
|
||||
group = Wiimote::GetNunchukGroup(pad_id, WiimoteEmu::NunchukGroup::Stick);
|
||||
break;
|
||||
case CLASSIC_STICK_LEFT:
|
||||
group = Wiimote::GetClassicGroup(pad_id, WiimoteEmu::ClassicGroup::LeftStick);
|
||||
break;
|
||||
case CLASSIC_STICK_RIGHT:
|
||||
group = Wiimote::GetClassicGroup(pad_id, WiimoteEmu::ClassicGroup::RightStick);
|
||||
break;
|
||||
default:
|
||||
ASSERT(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return static_cast<ControllerEmu::ReshapableInput*>(group)->GetInputRadiusAtAngle(angle);
|
||||
}
|
||||
|
||||
bool GamepadEvent(const std::string& dev, int button, int action)
|
||||
{
|
||||
auto it = m_controllers.find(dev);
|
||||
|
|
|
@ -272,9 +272,6 @@ void Init(const std::string&);
|
|||
bool GetButtonPressed(int pad_id, ButtonType button);
|
||||
float GetAxisValue(int pad_id, ButtonType axis);
|
||||
|
||||
// emu_pad_id is numbered 0 to 3 for both GC pads and Wiimotes
|
||||
double GetInputRadiusAtAngle(int emu_pad_id, ButtonType stick, double angle);
|
||||
|
||||
bool GamepadEvent(const std::string& dev, int button, int action);
|
||||
void GamepadAxisEvent(const std::string& dev, int axis, float value);
|
||||
|
||||
|
|
|
@ -0,0 +1,272 @@
|
|||
// Copyright 2021 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "InputCommon/ControllerInterface/Touch/InputOverrider.h"
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include "Common/Assert.h"
|
||||
|
||||
#include "Core/HW/GCPad.h"
|
||||
#include "Core/HW/GCPadEmu.h"
|
||||
#include "Core/HW/Wiimote.h"
|
||||
#include "Core/HW/WiimoteEmu/Extension/Classic.h"
|
||||
#include "Core/HW/WiimoteEmu/Extension/Nunchuk.h"
|
||||
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
|
||||
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/Attachments.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
|
||||
#include "InputCommon/ControllerEmu/ControllerEmu.h"
|
||||
#include "InputCommon/ControllerEmu/StickGate.h"
|
||||
#include "InputCommon/ControllerInterface/CoreDevice.h"
|
||||
#include "InputCommon/InputConfig.h"
|
||||
|
||||
namespace ciface::Touch
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct InputState
|
||||
{
|
||||
ControlState normal_state = 0;
|
||||
ControlState override_state = 0;
|
||||
bool overriding = false;
|
||||
};
|
||||
|
||||
using ControlsMap = std::map<std::pair<std::string_view, std::string_view>, ControlID>;
|
||||
using StateArray = std::array<InputState, ControlID::NUMBER_OF_CONTROLS>;
|
||||
|
||||
std::array<StateArray, 4> s_state_arrays;
|
||||
|
||||
const ControlsMap s_gcpad_controls_map = {{
|
||||
{{GCPad::BUTTONS_GROUP, GCPad::A_BUTTON}, ControlID::GCPAD_A_BUTTON},
|
||||
{{GCPad::BUTTONS_GROUP, GCPad::B_BUTTON}, ControlID::GCPAD_B_BUTTON},
|
||||
{{GCPad::BUTTONS_GROUP, GCPad::X_BUTTON}, ControlID::GCPAD_X_BUTTON},
|
||||
{{GCPad::BUTTONS_GROUP, GCPad::Y_BUTTON}, ControlID::GCPAD_Y_BUTTON},
|
||||
{{GCPad::BUTTONS_GROUP, GCPad::Z_BUTTON}, ControlID::GCPAD_Z_BUTTON},
|
||||
{{GCPad::BUTTONS_GROUP, GCPad::START_BUTTON}, ControlID::GCPAD_START_BUTTON},
|
||||
{{GCPad::DPAD_GROUP, DIRECTION_UP}, ControlID::GCPAD_DPAD_UP},
|
||||
{{GCPad::DPAD_GROUP, DIRECTION_DOWN}, ControlID::GCPAD_DPAD_DOWN},
|
||||
{{GCPad::DPAD_GROUP, DIRECTION_LEFT}, ControlID::GCPAD_DPAD_LEFT},
|
||||
{{GCPad::DPAD_GROUP, DIRECTION_RIGHT}, ControlID::GCPAD_DPAD_RIGHT},
|
||||
{{GCPad::TRIGGERS_GROUP, GCPad::L_DIGITAL}, ControlID::GCPAD_L_DIGITAL},
|
||||
{{GCPad::TRIGGERS_GROUP, GCPad::R_DIGITAL}, ControlID::GCPAD_R_DIGITAL},
|
||||
{{GCPad::TRIGGERS_GROUP, GCPad::L_ANALOG}, ControlID::GCPAD_L_ANALOG},
|
||||
{{GCPad::TRIGGERS_GROUP, GCPad::R_ANALOG}, ControlID::GCPAD_R_ANALOG},
|
||||
{{GCPad::MAIN_STICK_GROUP, ControllerEmu::ReshapableInput::X_INPUT_OVERRIDE},
|
||||
ControlID::GCPAD_MAIN_STICK_X},
|
||||
{{GCPad::MAIN_STICK_GROUP, ControllerEmu::ReshapableInput::Y_INPUT_OVERRIDE},
|
||||
ControlID::GCPAD_MAIN_STICK_Y},
|
||||
{{GCPad::C_STICK_GROUP, ControllerEmu::ReshapableInput::X_INPUT_OVERRIDE},
|
||||
ControlID::GCPAD_C_STICK_X},
|
||||
{{GCPad::C_STICK_GROUP, ControllerEmu::ReshapableInput::Y_INPUT_OVERRIDE},
|
||||
ControlID::GCPAD_C_STICK_Y},
|
||||
}};
|
||||
|
||||
const ControlsMap s_wiimote_controls_map = {{
|
||||
{{WiimoteEmu::Wiimote::BUTTONS_GROUP, WiimoteEmu::Wiimote::A_BUTTON},
|
||||
ControlID::WIIMOTE_A_BUTTON},
|
||||
{{WiimoteEmu::Wiimote::BUTTONS_GROUP, WiimoteEmu::Wiimote::B_BUTTON},
|
||||
ControlID::WIIMOTE_B_BUTTON},
|
||||
{{WiimoteEmu::Wiimote::BUTTONS_GROUP, WiimoteEmu::Wiimote::ONE_BUTTON},
|
||||
ControlID::WIIMOTE_ONE_BUTTON},
|
||||
{{WiimoteEmu::Wiimote::BUTTONS_GROUP, WiimoteEmu::Wiimote::TWO_BUTTON},
|
||||
ControlID::WIIMOTE_TWO_BUTTON},
|
||||
{{WiimoteEmu::Wiimote::BUTTONS_GROUP, WiimoteEmu::Wiimote::PLUS_BUTTON},
|
||||
ControlID::WIIMOTE_PLUS_BUTTON},
|
||||
{{WiimoteEmu::Wiimote::BUTTONS_GROUP, WiimoteEmu::Wiimote::MINUS_BUTTON},
|
||||
ControlID::WIIMOTE_MINUS_BUTTON},
|
||||
{{WiimoteEmu::Wiimote::BUTTONS_GROUP, WiimoteEmu::Wiimote::HOME_BUTTON},
|
||||
ControlID::WIIMOTE_HOME_BUTTON},
|
||||
{{WiimoteEmu::Wiimote::DPAD_GROUP, DIRECTION_UP}, ControlID::WIIMOTE_DPAD_UP},
|
||||
{{WiimoteEmu::Wiimote::DPAD_GROUP, DIRECTION_DOWN}, ControlID::WIIMOTE_DPAD_DOWN},
|
||||
{{WiimoteEmu::Wiimote::DPAD_GROUP, DIRECTION_LEFT}, ControlID::WIIMOTE_DPAD_LEFT},
|
||||
{{WiimoteEmu::Wiimote::DPAD_GROUP, DIRECTION_RIGHT}, ControlID::WIIMOTE_DPAD_RIGHT},
|
||||
{{WiimoteEmu::Wiimote::IR_GROUP, ControllerEmu::ReshapableInput::X_INPUT_OVERRIDE},
|
||||
ControlID::WIIMOTE_IR_X},
|
||||
{{WiimoteEmu::Wiimote::IR_GROUP, ControllerEmu::ReshapableInput::Y_INPUT_OVERRIDE},
|
||||
ControlID::WIIMOTE_IR_Y},
|
||||
}};
|
||||
|
||||
const ControlsMap s_nunchuk_controls_map = {{
|
||||
{{WiimoteEmu::Nunchuk::BUTTONS_GROUP, WiimoteEmu::Nunchuk::C_BUTTON},
|
||||
ControlID::NUNCHUK_C_BUTTON},
|
||||
{{WiimoteEmu::Nunchuk::BUTTONS_GROUP, WiimoteEmu::Nunchuk::Z_BUTTON},
|
||||
ControlID::NUNCHUK_Z_BUTTON},
|
||||
{{WiimoteEmu::Nunchuk::STICK_GROUP, ControllerEmu::ReshapableInput::X_INPUT_OVERRIDE},
|
||||
ControlID::NUNCHUK_STICK_X},
|
||||
{{WiimoteEmu::Nunchuk::STICK_GROUP, ControllerEmu::ReshapableInput::Y_INPUT_OVERRIDE},
|
||||
ControlID::NUNCHUK_STICK_Y},
|
||||
}};
|
||||
|
||||
const ControlsMap s_classic_controls_map = {{
|
||||
{{WiimoteEmu::Classic::BUTTONS_GROUP, WiimoteEmu::Classic::A_BUTTON},
|
||||
ControlID::CLASSIC_A_BUTTON},
|
||||
{{WiimoteEmu::Classic::BUTTONS_GROUP, WiimoteEmu::Classic::B_BUTTON},
|
||||
ControlID::CLASSIC_B_BUTTON},
|
||||
{{WiimoteEmu::Classic::BUTTONS_GROUP, WiimoteEmu::Classic::X_BUTTON},
|
||||
ControlID::CLASSIC_X_BUTTON},
|
||||
{{WiimoteEmu::Classic::BUTTONS_GROUP, WiimoteEmu::Classic::Y_BUTTON},
|
||||
ControlID::CLASSIC_Y_BUTTON},
|
||||
{{WiimoteEmu::Classic::BUTTONS_GROUP, WiimoteEmu::Classic::ZL_BUTTON},
|
||||
ControlID::CLASSIC_ZL_BUTTON},
|
||||
{{WiimoteEmu::Classic::BUTTONS_GROUP, WiimoteEmu::Classic::ZR_BUTTON},
|
||||
ControlID::CLASSIC_ZR_BUTTON},
|
||||
{{WiimoteEmu::Classic::BUTTONS_GROUP, WiimoteEmu::Classic::PLUS_BUTTON},
|
||||
ControlID::CLASSIC_PLUS_BUTTON},
|
||||
{{WiimoteEmu::Classic::BUTTONS_GROUP, WiimoteEmu::Classic::MINUS_BUTTON},
|
||||
ControlID::CLASSIC_MINUS_BUTTON},
|
||||
{{WiimoteEmu::Classic::BUTTONS_GROUP, WiimoteEmu::Classic::HOME_BUTTON},
|
||||
ControlID::CLASSIC_HOME_BUTTON},
|
||||
{{WiimoteEmu::Classic::DPAD_GROUP, DIRECTION_UP}, ControlID::CLASSIC_DPAD_UP},
|
||||
{{WiimoteEmu::Classic::DPAD_GROUP, DIRECTION_DOWN}, ControlID::CLASSIC_DPAD_DOWN},
|
||||
{{WiimoteEmu::Classic::DPAD_GROUP, DIRECTION_LEFT}, ControlID::CLASSIC_DPAD_LEFT},
|
||||
{{WiimoteEmu::Classic::DPAD_GROUP, DIRECTION_RIGHT}, ControlID::CLASSIC_DPAD_RIGHT},
|
||||
{{WiimoteEmu::Classic::TRIGGERS_GROUP, WiimoteEmu::Classic::L_DIGITAL},
|
||||
ControlID::CLASSIC_L_DIGITAL},
|
||||
{{WiimoteEmu::Classic::TRIGGERS_GROUP, WiimoteEmu::Classic::R_DIGITAL},
|
||||
ControlID::CLASSIC_R_DIGITAL},
|
||||
{{WiimoteEmu::Classic::TRIGGERS_GROUP, WiimoteEmu::Classic::L_ANALOG},
|
||||
ControlID::CLASSIC_L_ANALOG},
|
||||
{{WiimoteEmu::Classic::TRIGGERS_GROUP, WiimoteEmu::Classic::R_ANALOG},
|
||||
ControlID::CLASSIC_R_ANALOG},
|
||||
{{WiimoteEmu::Classic::LEFT_STICK_GROUP, ControllerEmu::ReshapableInput::X_INPUT_OVERRIDE},
|
||||
ControlID::CLASSIC_LEFT_STICK_X},
|
||||
{{WiimoteEmu::Classic::LEFT_STICK_GROUP, ControllerEmu::ReshapableInput::Y_INPUT_OVERRIDE},
|
||||
ControlID::CLASSIC_LEFT_STICK_Y},
|
||||
{{WiimoteEmu::Classic::RIGHT_STICK_GROUP, ControllerEmu::ReshapableInput::X_INPUT_OVERRIDE},
|
||||
ControlID::CLASSIC_RIGHT_STICK_X},
|
||||
{{WiimoteEmu::Classic::RIGHT_STICK_GROUP, ControllerEmu::ReshapableInput::Y_INPUT_OVERRIDE},
|
||||
ControlID::CLASSIC_RIGHT_STICK_Y},
|
||||
}};
|
||||
|
||||
ControllerEmu::InputOverrideFunction GetInputOverrideFunction(const ControlsMap& controls_map,
|
||||
size_t i)
|
||||
{
|
||||
StateArray& state_array = s_state_arrays[i];
|
||||
|
||||
return [&](std::string_view group_name, std::string_view control_name,
|
||||
ControlState controller_state) -> std::optional<ControlState> {
|
||||
const auto it = controls_map.find(std::make_pair(group_name, control_name));
|
||||
if (it == controls_map.end())
|
||||
return std::nullopt;
|
||||
|
||||
const ControlID control = it->second;
|
||||
InputState& input_state = state_array[control];
|
||||
if (input_state.normal_state != controller_state)
|
||||
{
|
||||
input_state.normal_state = controller_state;
|
||||
input_state.overriding = false;
|
||||
}
|
||||
|
||||
return input_state.overriding ? std::make_optional(input_state.override_state) : std::nullopt;
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void RegisterGameCubeInputOverrider(int controller_index)
|
||||
{
|
||||
Pad::GetConfig()
|
||||
->GetController(controller_index)
|
||||
->SetInputOverrideFunction(GetInputOverrideFunction(s_gcpad_controls_map, controller_index));
|
||||
}
|
||||
|
||||
void RegisterWiiInputOverrider(int controller_index)
|
||||
{
|
||||
auto* wiimote =
|
||||
static_cast<WiimoteEmu::Wiimote*>(Wiimote::GetConfig()->GetController(controller_index));
|
||||
|
||||
wiimote->SetInputOverrideFunction(
|
||||
GetInputOverrideFunction(s_wiimote_controls_map, controller_index));
|
||||
|
||||
auto& attachments = static_cast<ControllerEmu::Attachments*>(
|
||||
wiimote->GetWiimoteGroup(WiimoteEmu::WiimoteGroup::Attachments))
|
||||
->GetAttachmentList();
|
||||
|
||||
attachments[WiimoteEmu::ExtensionNumber::NUNCHUK]->SetInputOverrideFunction(
|
||||
GetInputOverrideFunction(s_nunchuk_controls_map, controller_index));
|
||||
attachments[WiimoteEmu::ExtensionNumber::CLASSIC]->SetInputOverrideFunction(
|
||||
GetInputOverrideFunction(s_classic_controls_map, controller_index));
|
||||
}
|
||||
|
||||
void UnregisterGameCubeInputOverrider(int controller_index)
|
||||
{
|
||||
Pad::GetConfig()->GetController(controller_index)->ClearInputOverrideFunction();
|
||||
|
||||
for (size_t i = ControlID::FIRST_GC_CONTROL; i <= ControlID::LAST_GC_CONTROL; ++i)
|
||||
s_state_arrays[controller_index][i].overriding = false;
|
||||
}
|
||||
|
||||
void UnregisterWiiInputOverrider(int controller_index)
|
||||
{
|
||||
auto* wiimote =
|
||||
static_cast<WiimoteEmu::Wiimote*>(Wiimote::GetConfig()->GetController(controller_index));
|
||||
|
||||
wiimote->ClearInputOverrideFunction();
|
||||
|
||||
auto& attachments = static_cast<ControllerEmu::Attachments*>(
|
||||
wiimote->GetWiimoteGroup(WiimoteEmu::WiimoteGroup::Attachments))
|
||||
->GetAttachmentList();
|
||||
|
||||
attachments[WiimoteEmu::ExtensionNumber::NUNCHUK]->ClearInputOverrideFunction();
|
||||
attachments[WiimoteEmu::ExtensionNumber::CLASSIC]->ClearInputOverrideFunction();
|
||||
|
||||
for (size_t i = ControlID::FIRST_WII_CONTROL; i <= ControlID::LAST_WII_CONTROL; ++i)
|
||||
s_state_arrays[controller_index][i].overriding = false;
|
||||
}
|
||||
|
||||
void SetControlState(int controller_index, ControlID control, double state)
|
||||
{
|
||||
InputState& input_state = s_state_arrays[controller_index][control];
|
||||
|
||||
input_state.override_state = state;
|
||||
input_state.overriding = true;
|
||||
}
|
||||
|
||||
void ClearControlState(int controller_index, ControlID control)
|
||||
{
|
||||
InputState& input_state = s_state_arrays[controller_index][control];
|
||||
|
||||
input_state.overriding = false;
|
||||
}
|
||||
|
||||
double GetGateRadiusAtAngle(int controller_index, ControlID stick, double angle)
|
||||
{
|
||||
ControllerEmu::ControlGroup* group;
|
||||
|
||||
switch (stick)
|
||||
{
|
||||
case ControlID::GCPAD_MAIN_STICK_X:
|
||||
case ControlID::GCPAD_MAIN_STICK_Y:
|
||||
group = Pad::GetGroup(controller_index, PadGroup::MainStick);
|
||||
break;
|
||||
case ControlID::GCPAD_C_STICK_X:
|
||||
case ControlID::GCPAD_C_STICK_Y:
|
||||
group = Pad::GetGroup(controller_index, PadGroup::CStick);
|
||||
break;
|
||||
case ControlID::NUNCHUK_STICK_X:
|
||||
case ControlID::NUNCHUK_STICK_Y:
|
||||
group = Wiimote::GetNunchukGroup(controller_index, WiimoteEmu::NunchukGroup::Stick);
|
||||
break;
|
||||
case ControlID::CLASSIC_LEFT_STICK_X:
|
||||
case ControlID::CLASSIC_LEFT_STICK_Y:
|
||||
group = Wiimote::GetClassicGroup(controller_index, WiimoteEmu::ClassicGroup::LeftStick);
|
||||
break;
|
||||
case ControlID::CLASSIC_RIGHT_STICK_X:
|
||||
case ControlID::CLASSIC_RIGHT_STICK_Y:
|
||||
group = Wiimote::GetClassicGroup(controller_index, WiimoteEmu::ClassicGroup::RightStick);
|
||||
break;
|
||||
default:
|
||||
ASSERT(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return static_cast<ControllerEmu::ReshapableInput*>(group)->GetGateRadiusAtAngle(angle);
|
||||
}
|
||||
} // namespace ciface::Touch
|
|
@ -0,0 +1,89 @@
|
|||
// Copyright 2021 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace ciface::Touch
|
||||
{
|
||||
enum ControlID
|
||||
{
|
||||
GCPAD_A_BUTTON = 0,
|
||||
GCPAD_B_BUTTON = 1,
|
||||
GCPAD_X_BUTTON = 2,
|
||||
GCPAD_Y_BUTTON = 3,
|
||||
GCPAD_Z_BUTTON = 4,
|
||||
GCPAD_START_BUTTON = 5,
|
||||
GCPAD_DPAD_UP = 6,
|
||||
GCPAD_DPAD_DOWN = 7,
|
||||
GCPAD_DPAD_LEFT = 8,
|
||||
GCPAD_DPAD_RIGHT = 9,
|
||||
GCPAD_L_DIGITAL = 10,
|
||||
GCPAD_R_DIGITAL = 11,
|
||||
GCPAD_L_ANALOG = 12,
|
||||
GCPAD_R_ANALOG = 13,
|
||||
GCPAD_MAIN_STICK_X = 14,
|
||||
GCPAD_MAIN_STICK_Y = 15,
|
||||
GCPAD_C_STICK_X = 16,
|
||||
GCPAD_C_STICK_Y = 17,
|
||||
|
||||
WIIMOTE_A_BUTTON = 18,
|
||||
WIIMOTE_B_BUTTON = 19,
|
||||
WIIMOTE_ONE_BUTTON = 20,
|
||||
WIIMOTE_TWO_BUTTON = 21,
|
||||
WIIMOTE_PLUS_BUTTON = 22,
|
||||
WIIMOTE_MINUS_BUTTON = 23,
|
||||
WIIMOTE_HOME_BUTTON = 24,
|
||||
WIIMOTE_DPAD_UP = 25,
|
||||
WIIMOTE_DPAD_DOWN = 26,
|
||||
WIIMOTE_DPAD_LEFT = 27,
|
||||
WIIMOTE_DPAD_RIGHT = 28,
|
||||
WIIMOTE_IR_X = 29,
|
||||
WIIMOTE_IR_Y = 30,
|
||||
|
||||
NUNCHUK_C_BUTTON = 31,
|
||||
NUNCHUK_Z_BUTTON = 32,
|
||||
NUNCHUK_STICK_X = 33,
|
||||
NUNCHUK_STICK_Y = 34,
|
||||
|
||||
CLASSIC_A_BUTTON = 35,
|
||||
CLASSIC_B_BUTTON = 36,
|
||||
CLASSIC_X_BUTTON = 37,
|
||||
CLASSIC_Y_BUTTON = 38,
|
||||
CLASSIC_ZL_BUTTON = 39,
|
||||
CLASSIC_ZR_BUTTON = 40,
|
||||
CLASSIC_PLUS_BUTTON = 41,
|
||||
CLASSIC_MINUS_BUTTON = 42,
|
||||
CLASSIC_HOME_BUTTON = 43,
|
||||
CLASSIC_DPAD_UP = 44,
|
||||
CLASSIC_DPAD_DOWN = 45,
|
||||
CLASSIC_DPAD_LEFT = 46,
|
||||
CLASSIC_DPAD_RIGHT = 47,
|
||||
CLASSIC_L_DIGITAL = 48,
|
||||
CLASSIC_R_DIGITAL = 49,
|
||||
CLASSIC_L_ANALOG = 50,
|
||||
CLASSIC_R_ANALOG = 51,
|
||||
CLASSIC_LEFT_STICK_X = 52,
|
||||
CLASSIC_LEFT_STICK_Y = 53,
|
||||
CLASSIC_RIGHT_STICK_X = 54,
|
||||
CLASSIC_RIGHT_STICK_Y = 55,
|
||||
|
||||
NUMBER_OF_CONTROLS,
|
||||
|
||||
FIRST_GC_CONTROL = GCPAD_A_BUTTON,
|
||||
LAST_GC_CONTROL = GCPAD_C_STICK_Y,
|
||||
FIRST_WII_CONTROL = WIIMOTE_A_BUTTON,
|
||||
LAST_WII_CONTROL = CLASSIC_RIGHT_STICK_Y,
|
||||
|
||||
};
|
||||
void RegisterGameCubeInputOverrider(int controller_index);
|
||||
void RegisterWiiInputOverrider(int controller_index);
|
||||
void UnregisterGameCubeInputOverrider(int controller_index);
|
||||
void UnregisterWiiInputOverrider(int controller_index);
|
||||
|
||||
void SetControlState(int controller_index, ControlID control, double state);
|
||||
void ClearControlState(int controller_index, ControlID control);
|
||||
|
||||
// Angle is in radians and should be non-negative
|
||||
double GetGateRadiusAtAngle(int controller_index, ControlID stick, double angle);
|
||||
} // namespace ciface::Touch
|
Loading…
Reference in New Issue