From 97704b8da9866a4e529515f5793309ce5f199840 Mon Sep 17 00:00:00 2001
From: german77 <juangerman-13@hotmail.com>
Date: Sun, 5 Mar 2023 12:44:39 -0600
Subject: [PATCH] input_common: joycon: Add stick input from passive reports

---
 .../helpers/joycon_protocol/joycon_types.h    | 12 +++
 .../helpers/joycon_protocol/poller.cpp        | 95 +++++++++++++------
 .../helpers/joycon_protocol/poller.h          |  9 +-
 3 files changed, 84 insertions(+), 32 deletions(-)

diff --git a/src/input_common/helpers/joycon_protocol/joycon_types.h b/src/input_common/helpers/joycon_protocol/joycon_types.h
index b91934990..2e50a99a8 100644
--- a/src/input_common/helpers/joycon_protocol/joycon_types.h
+++ b/src/input_common/helpers/joycon_protocol/joycon_types.h
@@ -95,6 +95,18 @@ enum class PasivePadButton : u32 {
     ZL_ZR = 0x8000,
 };
 
+enum class PasivePadStick : u8 {
+    Right = 0x00,
+    RightDown = 0x01,
+    Down = 0x02,
+    DownLeft = 0x03,
+    Left = 0x04,
+    LeftUp = 0x05,
+    Up = 0x06,
+    UpRight = 0x07,
+    Neutral = 0x08,
+};
+
 enum class OutputReport : u8 {
     RUMBLE_AND_SUBCMD = 0x01,
     FW_UPDATE_PKT = 0x03,
diff --git a/src/input_common/helpers/joycon_protocol/poller.cpp b/src/input_common/helpers/joycon_protocol/poller.cpp
index 9bb15e935..ab48352b8 100644
--- a/src/input_common/helpers/joycon_protocol/poller.cpp
+++ b/src/input_common/helpers/joycon_protocol/poller.cpp
@@ -12,7 +12,7 @@ JoyconPoller::JoyconPoller(ControllerType device_type_, JoyStickCalibration left
     : device_type{device_type_}, left_stick_calibration{left_stick_calibration_},
       right_stick_calibration{right_stick_calibration_}, motion_calibration{motion_calibration_} {}
 
-void JoyconPoller::SetCallbacks(const Joycon::JoyconCallbacks& callbacks_) {
+void JoyconPoller::SetCallbacks(const JoyconCallbacks& callbacks_) {
     callbacks = std::move(callbacks_);
 }
 
@@ -22,13 +22,13 @@ void JoyconPoller::ReadActiveMode(std::span<u8> buffer, const MotionStatus& moti
     memcpy(&data, buffer.data(), sizeof(InputReportActive));
 
     switch (device_type) {
-    case Joycon::ControllerType::Left:
+    case ControllerType::Left:
         UpdateActiveLeftPadInput(data, motion_status);
         break;
-    case Joycon::ControllerType::Right:
+    case ControllerType::Right:
         UpdateActiveRightPadInput(data, motion_status);
         break;
-    case Joycon::ControllerType::Pro:
+    case ControllerType::Pro:
         UpdateActiveProPadInput(data, motion_status);
         break;
     default:
@@ -47,13 +47,13 @@ void JoyconPoller::ReadPassiveMode(std::span<u8> buffer) {
     memcpy(&data, buffer.data(), sizeof(InputReportPassive));
 
     switch (device_type) {
-    case Joycon::ControllerType::Left:
+    case ControllerType::Left:
         UpdatePasiveLeftPadInput(data);
         break;
-    case Joycon::ControllerType::Right:
+    case ControllerType::Right:
         UpdatePasiveRightPadInput(data);
         break;
-    case Joycon::ControllerType::Pro:
+    case ControllerType::Pro:
         UpdatePasiveProPadInput(data);
         break;
     default:
@@ -211,13 +211,11 @@ void JoyconPoller::UpdateActiveProPadInput(const InputReportActive& input,
 }
 
 void JoyconPoller::UpdatePasiveLeftPadInput(const InputReportPassive& input) {
-    static constexpr std::array<Joycon::PasivePadButton, 11> left_buttons{
-        Joycon::PasivePadButton::Down_A, Joycon::PasivePadButton::Right_X,
-        Joycon::PasivePadButton::Left_B, Joycon::PasivePadButton::Up_Y,
-        Joycon::PasivePadButton::SL,     Joycon::PasivePadButton::SR,
-        Joycon::PasivePadButton::L_R,    Joycon::PasivePadButton::ZL_ZR,
-        Joycon::PasivePadButton::Minus,  Joycon::PasivePadButton::Capture,
-        Joycon::PasivePadButton::StickL,
+    static constexpr std::array<PasivePadButton, 11> left_buttons{
+        PasivePadButton::Down_A,  PasivePadButton::Right_X, PasivePadButton::Left_B,
+        PasivePadButton::Up_Y,    PasivePadButton::SL,      PasivePadButton::SR,
+        PasivePadButton::L_R,     PasivePadButton::ZL_ZR,   PasivePadButton::Minus,
+        PasivePadButton::Capture, PasivePadButton::StickL,
     };
 
     for (auto left_button : left_buttons) {
@@ -225,16 +223,19 @@ void JoyconPoller::UpdatePasiveLeftPadInput(const InputReportPassive& input) {
         const int button = static_cast<int>(left_button);
         callbacks.on_button_data(button, button_status);
     }
+
+    const auto [left_axis_x, left_axis_y] =
+        GetPassiveAxisValue(static_cast<PasivePadStick>(input.stick_state));
+    callbacks.on_stick_data(static_cast<int>(PadAxes::LeftStickX), left_axis_x);
+    callbacks.on_stick_data(static_cast<int>(PadAxes::LeftStickY), left_axis_y);
 }
 
 void JoyconPoller::UpdatePasiveRightPadInput(const InputReportPassive& input) {
-    static constexpr std::array<Joycon::PasivePadButton, 11> right_buttons{
-        Joycon::PasivePadButton::Down_A, Joycon::PasivePadButton::Right_X,
-        Joycon::PasivePadButton::Left_B, Joycon::PasivePadButton::Up_Y,
-        Joycon::PasivePadButton::SL,     Joycon::PasivePadButton::SR,
-        Joycon::PasivePadButton::L_R,    Joycon::PasivePadButton::ZL_ZR,
-        Joycon::PasivePadButton::Plus,   Joycon::PasivePadButton::Home,
-        Joycon::PasivePadButton::StickR,
+    static constexpr std::array<PasivePadButton, 11> right_buttons{
+        PasivePadButton::Down_A, PasivePadButton::Right_X, PasivePadButton::Left_B,
+        PasivePadButton::Up_Y,   PasivePadButton::SL,      PasivePadButton::SR,
+        PasivePadButton::L_R,    PasivePadButton::ZL_ZR,   PasivePadButton::Plus,
+        PasivePadButton::Home,   PasivePadButton::StickR,
     };
 
     for (auto right_button : right_buttons) {
@@ -242,17 +243,20 @@ void JoyconPoller::UpdatePasiveRightPadInput(const InputReportPassive& input) {
         const int button = static_cast<int>(right_button);
         callbacks.on_button_data(button, button_status);
     }
+
+    const auto [right_axis_x, right_axis_y] =
+        GetPassiveAxisValue(static_cast<PasivePadStick>(input.stick_state));
+    callbacks.on_stick_data(static_cast<int>(PadAxes::RightStickX), right_axis_x);
+    callbacks.on_stick_data(static_cast<int>(PadAxes::RightStickY), right_axis_y);
 }
 
 void JoyconPoller::UpdatePasiveProPadInput(const InputReportPassive& input) {
-    static constexpr std::array<Joycon::PasivePadButton, 14> pro_buttons{
-        Joycon::PasivePadButton::Down_A,  Joycon::PasivePadButton::Right_X,
-        Joycon::PasivePadButton::Left_B,  Joycon::PasivePadButton::Up_Y,
-        Joycon::PasivePadButton::SL,      Joycon::PasivePadButton::SR,
-        Joycon::PasivePadButton::L_R,     Joycon::PasivePadButton::ZL_ZR,
-        Joycon::PasivePadButton::Minus,   Joycon::PasivePadButton::Plus,
-        Joycon::PasivePadButton::Capture, Joycon::PasivePadButton::Home,
-        Joycon::PasivePadButton::StickL,  Joycon::PasivePadButton::StickR,
+    static constexpr std::array<PasivePadButton, 14> pro_buttons{
+        PasivePadButton::Down_A, PasivePadButton::Right_X, PasivePadButton::Left_B,
+        PasivePadButton::Up_Y,   PasivePadButton::SL,      PasivePadButton::SR,
+        PasivePadButton::L_R,    PasivePadButton::ZL_ZR,   PasivePadButton::Minus,
+        PasivePadButton::Plus,   PasivePadButton::Capture, PasivePadButton::Home,
+        PasivePadButton::StickL, PasivePadButton::StickR,
     };
 
     for (auto pro_button : pro_buttons) {
@@ -260,6 +264,15 @@ void JoyconPoller::UpdatePasiveProPadInput(const InputReportPassive& input) {
         const int button = static_cast<int>(pro_button);
         callbacks.on_button_data(button, button_status);
     }
+
+    const auto [left_axis_x, left_axis_y] =
+        GetPassiveAxisValue(static_cast<PasivePadStick>(input.stick_state && 0xf));
+    const auto [right_axis_x, right_axis_y] =
+        GetPassiveAxisValue(static_cast<PasivePadStick>(input.stick_state >> 4));
+    callbacks.on_stick_data(static_cast<int>(PadAxes::LeftStickX), left_axis_x);
+    callbacks.on_stick_data(static_cast<int>(PadAxes::LeftStickY), left_axis_y);
+    callbacks.on_stick_data(static_cast<int>(PadAxes::RightStickX), right_axis_x);
+    callbacks.on_stick_data(static_cast<int>(PadAxes::RightStickY), right_axis_y);
 }
 
 f32 JoyconPoller::GetAxisValue(u16 raw_value, Joycon::JoyStickAxisCalibration calibration) const {
@@ -270,6 +283,30 @@ f32 JoyconPoller::GetAxisValue(u16 raw_value, Joycon::JoyStickAxisCalibration ca
     return value / calibration.min;
 }
 
+std::pair<f32, f32> JoyconPoller::GetPassiveAxisValue(PasivePadStick raw_value) const {
+    switch (raw_value) {
+    case PasivePadStick::Right:
+        return {1.0f, 0.0f};
+    case PasivePadStick::RightDown:
+        return {1.0f, -1.0f};
+    case PasivePadStick::Down:
+        return {0.0f, -1.0f};
+    case PasivePadStick::DownLeft:
+        return {-1.0f, -1.0f};
+    case PasivePadStick::Left:
+        return {-1.0f, 0.0f};
+    case PasivePadStick::LeftUp:
+        return {-1.0f, 1.0f};
+    case PasivePadStick::Up:
+        return {0.0f, 1.0f};
+    case PasivePadStick::UpRight:
+        return {1.0f, 1.0f};
+    case PasivePadStick::Neutral:
+    default:
+        return {0.0f, 0.0f};
+    }
+}
+
 f32 JoyconPoller::GetAccelerometerValue(s16 raw, const MotionSensorCalibration& cal,
                                         AccelerometerSensitivity sensitivity) const {
     const f32 value = raw * (1.0f / (cal.scale - cal.offset)) * 4;
diff --git a/src/input_common/helpers/joycon_protocol/poller.h b/src/input_common/helpers/joycon_protocol/poller.h
index 354d41dad..5c897f070 100644
--- a/src/input_common/helpers/joycon_protocol/poller.h
+++ b/src/input_common/helpers/joycon_protocol/poller.h
@@ -22,7 +22,7 @@ public:
                  JoyStickCalibration right_stick_calibration_,
                  MotionCalibration motion_calibration_);
 
-    void SetCallbacks(const Joycon::JoyconCallbacks& callbacks_);
+    void SetCallbacks(const JoyconCallbacks& callbacks_);
 
     /// Handles data from passive packages
     void ReadPassiveMode(std::span<u8> buffer);
@@ -51,7 +51,10 @@ private:
     void UpdatePasiveProPadInput(const InputReportPassive& buffer);
 
     /// Returns a calibrated joystick axis from raw axis data
-    f32 GetAxisValue(u16 raw_value, Joycon::JoyStickAxisCalibration calibration) const;
+    f32 GetAxisValue(u16 raw_value, JoyStickAxisCalibration calibration) const;
+
+    /// Returns a digital joystick axis from passive axis data
+    std::pair<f32, f32> GetPassiveAxisValue(PasivePadStick raw_value) const;
 
     /// Returns a calibrated accelerometer axis from raw motion data
     f32 GetAccelerometerValue(s16 raw, const MotionSensorCalibration& cal,
@@ -75,7 +78,7 @@ private:
     JoyStickCalibration right_stick_calibration{};
     MotionCalibration motion_calibration{};
 
-    Joycon::JoyconCallbacks callbacks{};
+    JoyconCallbacks callbacks{};
 };
 
 } // namespace InputCommon::Joycon