diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java index 3751385be8..24ec356751 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java @@ -269,6 +269,9 @@ 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); + public static native void NewGameIniFile(); public static native void LoadGameIniFile(String gameId); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableJoystick.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableJoystick.java index 55f6347096..a32155686e 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableJoystick.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableJoystick.java @@ -14,6 +14,8 @@ import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.view.MotionEvent; +import org.dolphinemu.dolphinemu.NativeLibrary; + /** * Custom {@link BitmapDrawable} that is capable * of storing it's own ID. @@ -214,21 +216,27 @@ public final class InputOverlayDrawableJoystick private void SetInnerBounds() { - int X = getVirtBounds().centerX() + (int) ((axises[1]) * (getVirtBounds().width() / 2)); - int Y = getVirtBounds().centerY() + (int) ((axises[0]) * (getVirtBounds().height() / 2)); + double y = axises[0]; + double x = axises[1]; - if (X > getVirtBounds().centerX() + (getVirtBounds().width() / 2)) - X = getVirtBounds().centerX() + (getVirtBounds().width() / 2); - if (X < getVirtBounds().centerX() - (getVirtBounds().width() / 2)) - X = getVirtBounds().centerX() - (getVirtBounds().width() / 2); - if (Y > getVirtBounds().centerY() + (getVirtBounds().height() / 2)) - Y = getVirtBounds().centerY() + (getVirtBounds().height() / 2); - if (Y < getVirtBounds().centerY() - (getVirtBounds().height() / 2)) - Y = getVirtBounds().centerY() - (getVirtBounds().height() / 2); + double angle = Math.atan2(y, x) + Math.PI + Math.PI; + double radius = Math.hypot(y, x); + double maxRadius = NativeLibrary.GetInputRadiusAtAngle(0, mJoystickType, angle); + if (radius > maxRadius) + { + y = maxRadius * Math.sin(angle); + x = maxRadius * Math.cos(angle); + axises[0] = (float) y; + axises[1] = (float) x; + } + + int pixelX = getVirtBounds().centerX() + (int) (x * (getVirtBounds().width() / 2)); + int pixelY = getVirtBounds().centerY() + (int) (y * (getVirtBounds().height() / 2)); int width = mPressedStateInnerBitmap.getBounds().width() / 2; int height = mPressedStateInnerBitmap.getBounds().height() / 2; - mDefaultStateInnerBitmap.setBounds(X - width, Y - height, X + width, Y + height); + mDefaultStateInnerBitmap.setBounds(pixelX - width, pixelY - height, pixelX + width, + pixelY + height); mPressedStateInnerBitmap.setBounds(mDefaultStateInnerBitmap.getBounds()); } diff --git a/Source/Android/jni/MainAndroid.cpp b/Source/Android/jni/MainAndroid.cpp index 469d719869..eb9e02c32b 100644 --- a/Source/Android/jni/MainAndroid.cpp +++ b/Source/Android/jni/MainAndroid.cpp @@ -201,6 +201,8 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_onGamePadMov JNIEnv* env, jobject obj, jstring jDevice, jint Axis, jfloat Value); JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetMotionSensorsEnabled( JNIEnv* env, jobject obj, jboolean accelerometer_enabled, jboolean gyroscope_enabled); +JNIEXPORT double JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetInputRadiusAtAngle( + JNIEnv* env, jobject obj, int emu_pad_id, int stick, double angle); JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetVersionString(JNIEnv* env, jobject obj); JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetGitRevision(JNIEnv* env, @@ -315,6 +317,13 @@ 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* env, jobject obj, int emu_pad_id, int stick, double angle) +{ + const auto casted_stick = static_cast(stick); + return ButtonManager::GetInputRadiusAtAngle(emu_pad_id, casted_stick, angle); +} + JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetVersionString(JNIEnv* env, jobject obj) { diff --git a/Source/Core/InputCommon/ControllerInterface/Touch/ButtonManager.cpp b/Source/Core/InputCommon/ControllerInterface/Touch/ButtonManager.cpp index 22b05952f6..75f69b8823 100644 --- a/Source/Core/InputCommon/ControllerInterface/Touch/ButtonManager.cpp +++ b/Source/Core/InputCommon/ControllerInterface/Touch/ButtonManager.cpp @@ -8,10 +8,22 @@ #include #include +#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" #include "InputCommon/ControllerInterface/Touch/ButtonManager.h" namespace ButtonManager @@ -688,6 +700,39 @@ 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(group)->GetInputRadiusAtAngle(angle); +} + bool GamepadEvent(const std::string& dev, int button, int action) { auto it = m_controllers.find(dev); diff --git a/Source/Core/InputCommon/ControllerInterface/Touch/ButtonManager.h b/Source/Core/InputCommon/ControllerInterface/Touch/ButtonManager.h index 5d6a19ef78..2139c2e2ca 100644 --- a/Source/Core/InputCommon/ControllerInterface/Touch/ButtonManager.h +++ b/Source/Core/InputCommon/ControllerInterface/Touch/ButtonManager.h @@ -268,9 +268,16 @@ public: }; void Init(const std::string&); + +// pad_id is numbered 0 to 3 for GC pads and 4 to 7 for Wiimotes 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); + void Shutdown(); } // namespace ButtonManager