From 5ceaf344ce02931da897c943048b5e653050038b Mon Sep 17 00:00:00 2001
From: emmauss <emmausssss@gmail.com>
Date: Wed, 4 Aug 2021 21:08:33 +0000
Subject: [PATCH] Clamp controller sticks to circle, instead of square (#2493)

* clamp controller sticks to circle, instead of square

* fix deadzone

* addressed comments
---
 Ryujinx.Input/HLE/NpadController.cs | 66 ++++++++++++++++++-----------
 1 file changed, 42 insertions(+), 24 deletions(-)

diff --git a/Ryujinx.Input/HLE/NpadController.cs b/Ryujinx.Input/HLE/NpadController.cs
index 701d76c1f..3559b015c 100644
--- a/Ryujinx.Input/HLE/NpadController.cs
+++ b/Ryujinx.Input/HLE/NpadController.cs
@@ -343,28 +343,6 @@ namespace Ryujinx.Input.HLE
             }
         }
 
-        private static short ClampAxis(float value)
-        {
-            if (value <= -short.MaxValue)
-            {
-                return -short.MaxValue;
-            }
-            else
-            {
-                return (short)(value * short.MaxValue);
-            }
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        private static JoystickPosition ApplyDeadzone(float x, float y, float deadzone)
-        {
-            return new JoystickPosition
-            {
-                Dx = ClampAxis(MathF.Abs(x) > deadzone ? x : 0.0f),
-                Dy = ClampAxis(MathF.Abs(y) > deadzone ? y : 0.0f)
-            };
-        }
-
         public GamepadInput GetHLEInputState()
         {
             GamepadInput state = new GamepadInput();
@@ -400,13 +378,53 @@ namespace Ryujinx.Input.HLE
                 (float leftAxisX, float leftAxisY) = State.GetStick(StickInputId.Left);
                 (float rightAxisX, float rightAxisY) = State.GetStick(StickInputId.Right);
 
-                state.LStick = ApplyDeadzone(leftAxisX, leftAxisY, controllerConfig.DeadzoneLeft);
-                state.RStick = ApplyDeadzone(rightAxisX, rightAxisY, controllerConfig.DeadzoneRight);
+                state.LStick = ClampToCircle(ApplyDeadzone(leftAxisX, leftAxisY, controllerConfig.DeadzoneLeft));
+                state.RStick = ClampToCircle(ApplyDeadzone(rightAxisX, rightAxisY, controllerConfig.DeadzoneRight));
             }
 
             return state;
         }
 
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        private static JoystickPosition ApplyDeadzone(float x, float y, float deadzone)
+        {
+            return new JoystickPosition
+            {
+                Dx = ClampAxis(MathF.Abs(x) > deadzone ? x : 0.0f),
+                Dy = ClampAxis(MathF.Abs(y) > deadzone ? y : 0.0f)
+            };
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        private static short ClampAxis(float value)
+        {
+            if (value <= -short.MaxValue)
+            {
+                return -short.MaxValue;
+            }
+            else
+            {
+                return (short)(value * short.MaxValue);
+            }
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        private static JoystickPosition ClampToCircle(JoystickPosition position)
+        {
+            Vector2 point = new Vector2(position.Dx, position.Dy);
+
+            if (point.Length() > short.MaxValue)
+            {
+                point = point / point.Length() * short.MaxValue;
+            }
+
+            return new JoystickPosition
+            {
+                Dx = (int)point.X,
+                Dy = (int)point.Y
+            };
+        }
+
         public SixAxisInput GetHLEMotionState(bool isJoyconRightPair = false)
         {
             float[] orientationForHLE = new float[9];