From 7ad423923dddb5e037d54e70cb066b03f8346dec Mon Sep 17 00:00:00 2001 From: Ameer Date: Mon, 6 Jul 2020 21:58:31 -0400 Subject: [PATCH 1/5] Save origin state of GC controller analog features, compare against origin for input detection --- src/input_common/gcadapter/gc_adapter.cpp | 72 +++++++++++++++++------ src/input_common/gcadapter/gc_adapter.h | 11 ++-- src/input_common/gcadapter/gc_poller.cpp | 17 ++++-- 3 files changed, 72 insertions(+), 28 deletions(-) diff --git a/src/input_common/gcadapter/gc_adapter.cpp b/src/input_common/gcadapter/gc_adapter.cpp index b39d2a3fb4..8465309d0b 100644 --- a/src/input_common/gcadapter/gc_adapter.cpp +++ b/src/input_common/gcadapter/gc_adapter.cpp @@ -25,19 +25,15 @@ Adapter::Adapter() { current_status = NO_ADAPTER_DETECTED; libusb_init(&libusb_ctx); + get_origin.fill(true); StartScanThread(); } GCPadStatus Adapter::GetPadStatus(int port, const std::array& adapter_payload) { GCPadStatus pad = {}; - bool get_origin = false; ControllerTypes type = ControllerTypes(adapter_payload[1 + (9 * port)] >> 4); - if (type != ControllerTypes::None) { - get_origin = true; - } - adapter_controllers_status[port] = type; static constexpr std::array b1_buttons{ @@ -69,16 +65,22 @@ GCPadStatus Adapter::GetPadStatus(int port, const std::array& adapter_pa } } - if (get_origin) { - pad.button |= PAD_GET_ORIGIN; - } - pad.stick_x = adapter_payload[1 + (9 * port) + 3]; pad.stick_y = adapter_payload[1 + (9 * port) + 4]; pad.substick_x = adapter_payload[1 + (9 * port) + 5]; pad.substick_y = adapter_payload[1 + (9 * port) + 6]; pad.trigger_left = adapter_payload[1 + (9 * port) + 7]; pad.trigger_right = adapter_payload[1 + (9 * port) + 8]; + + if (get_origin[port]) { + origin_status[port].stick_x = pad.stick_x; + origin_status[port].stick_y = pad.stick_y; + origin_status[port].substick_x = pad.substick_x; + origin_status[port].substick_y = pad.substick_y; + origin_status[port].trigger_left = pad.trigger_left; + origin_status[port].trigger_right = pad.trigger_right; + get_origin[port] = false; + } } return pad; } @@ -127,31 +129,31 @@ void Adapter::Read() { for (std::size_t port = 0; port < pads.size(); ++port) { pads[port] = GetPadStatus(port, adapter_payload_copy); if (DeviceConnected(port) && configuring) { - if (pads[port].button != PAD_GET_ORIGIN) { + if (pads[port].button != 0) { pad_queue[port].Push(pads[port]); } // Accounting for a threshold here because of some controller variance - if (pads[port].stick_x > pads[port].MAIN_STICK_CENTER_X + pads[port].THRESHOLD || - pads[port].stick_x < pads[port].MAIN_STICK_CENTER_X - pads[port].THRESHOLD) { + if (pads[port].stick_x > origin_status[port].stick_x + pads[port].THRESHOLD || + pads[port].stick_x < origin_status[port].stick_x - pads[port].THRESHOLD) { pads[port].axis = GCAdapter::PadAxes::StickX; pads[port].axis_value = pads[port].stick_x; pad_queue[port].Push(pads[port]); } - if (pads[port].stick_y > pads[port].MAIN_STICK_CENTER_Y + pads[port].THRESHOLD || - pads[port].stick_y < pads[port].MAIN_STICK_CENTER_Y - pads[port].THRESHOLD) { + if (pads[port].stick_y > origin_status[port].stick_y + pads[port].THRESHOLD || + pads[port].stick_y < origin_status[port].stick_y - pads[port].THRESHOLD) { pads[port].axis = GCAdapter::PadAxes::StickY; pads[port].axis_value = pads[port].stick_y; pad_queue[port].Push(pads[port]); } - if (pads[port].substick_x > pads[port].C_STICK_CENTER_X + pads[port].THRESHOLD || - pads[port].substick_x < pads[port].C_STICK_CENTER_X - pads[port].THRESHOLD) { + if (pads[port].substick_x > origin_status[port].substick_x + pads[port].THRESHOLD || + pads[port].substick_x < origin_status[port].substick_x - pads[port].THRESHOLD) { pads[port].axis = GCAdapter::PadAxes::SubstickX; pads[port].axis_value = pads[port].substick_x; pad_queue[port].Push(pads[port]); } - if (pads[port].substick_y > pads[port].C_STICK_CENTER_Y + pads[port].THRESHOLD || - pads[port].substick_y < pads[port].C_STICK_CENTER_Y - pads[port].THRESHOLD) { + if (pads[port].substick_y > origin_status[port].substick_y + pads[port].THRESHOLD || + pads[port].substick_y < origin_status[port].substick_y - pads[port].THRESHOLD) { pads[port].axis = GCAdapter::PadAxes::SubstickY; pads[port].axis_value = pads[port].substick_y; pad_queue[port].Push(pads[port]); @@ -325,6 +327,7 @@ void Adapter::Reset() { adapter_input_thread.join(); adapter_controllers_status.fill(ControllerTypes::None); + get_origin.fill(true); current_status = NO_ADAPTER_DETECTED; if (usb_adapter_handle) { @@ -347,6 +350,7 @@ void Adapter::ResetDeviceType(int port) { } void Adapter::BeginConfiguration() { + get_origin.fill(true); for (auto& pq : pad_queue) { pq.Clear(); } @@ -376,4 +380,36 @@ const std::array& Adapter::GetPadState() const { return state; } +int Adapter::GetOriginValue(int port, int axis) { + const PadAxes padaxis = static_cast(axis); + if (padaxis == PadAxes::StickX) + return origin_status[port].stick_x; + if (padaxis == PadAxes::StickY) + return origin_status[port].stick_y; + if (padaxis == PadAxes::SubstickX) + return origin_status[port].substick_x; + if (padaxis == PadAxes::SubstickY) + return origin_status[port].substick_x; + if (padaxis == PadAxes::TriggerLeft) + return origin_status[port].trigger_left; + if (padaxis == PadAxes::TriggerRight) + return origin_status[port].trigger_right; +} + +const int Adapter::GetOriginValue(int port, int axis) const { + const PadAxes padaxis = static_cast(axis); + if (padaxis == PadAxes::StickX) + return origin_status[port].stick_x; + if (padaxis == PadAxes::StickY) + return origin_status[port].stick_y; + if (padaxis == PadAxes::SubstickX) + return origin_status[port].substick_x; + if (padaxis == PadAxes::SubstickY) + return origin_status[port].substick_x; + if (padaxis == PadAxes::TriggerLeft) + return origin_status[port].trigger_left; + if (padaxis == PadAxes::TriggerRight) + return origin_status[port].trigger_right; +} + } // namespace GCAdapter diff --git a/src/input_common/gcadapter/gc_adapter.h b/src/input_common/gcadapter/gc_adapter.h index 0ea6263ebd..8b08d667dc 100644 --- a/src/input_common/gcadapter/gc_adapter.h +++ b/src/input_common/gcadapter/gc_adapter.h @@ -13,12 +13,6 @@ namespace GCAdapter { -enum { - PAD_USE_ORIGIN = 0x0080, - PAD_GET_ORIGIN = 0x2000, - PAD_ERR_STATUS = 0x8000, -}; - enum class PadButton { PAD_BUTTON_LEFT = 0x0001, PAD_BUTTON_RIGHT = 0x0002, @@ -102,6 +96,9 @@ public: std::array& GetPadState(); const std::array& GetPadState() const; + int GetOriginValue(int port, int axis); + const int GetOriginValue(int port, int axis) const; + private: GCPadStatus GetPadStatus(int port, const std::array& adapter_payload); @@ -155,6 +152,8 @@ private: std::array, 4> pad_queue; std::array state; + std::array get_origin; + std::array origin_status; }; } // namespace GCAdapter diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp index 385ce84301..c9bb7e571b 100644 --- a/src/input_common/gcadapter/gc_poller.cpp +++ b/src/input_common/gcadapter/gc_poller.cpp @@ -34,7 +34,7 @@ public: explicit GCAxisButton(int port_, int axis_, float threshold_, bool trigger_if_greater_, GCAdapter::Adapter* adapter) : port(port_), axis(axis_), threshold(threshold_), trigger_if_greater(trigger_if_greater_), - gcadapter(adapter) { + gcadapter(adapter), origin_value(adapter->GetOriginValue(port_, axis_)) { // L/R triggers range is only in positive direction beginning near 0 // 0.0 threshold equates to near half trigger press, but threshold accounts for variability. if (axis > 3) { @@ -43,7 +43,8 @@ public: } bool GetStatus() const override { - const float axis_value = (gcadapter->GetPadState()[port].axes.at(axis) - 128.0f) / 128.0f; + const float current_axis_value = gcadapter->GetPadState()[port].axes.at(axis); + const float axis_value = (current_axis_value - origin_value) / 128.0f; if (trigger_if_greater) { // TODO: Might be worthwile to set a slider for the trigger threshold. It is currently // always set to 0.5 in configure_input_player.cpp ZL/ZR HandleClick @@ -58,6 +59,7 @@ private: float threshold; bool trigger_if_greater; GCAdapter::Adapter* gcadapter; + const float origin_value; }; GCButtonFactory::GCButtonFactory(std::shared_ptr adapter_) @@ -144,14 +146,19 @@ void GCButtonFactory::EndConfiguration() { class GCAnalog final : public Input::AnalogDevice { public: GCAnalog(int port_, int axis_x_, int axis_y_, float deadzone_, GCAdapter::Adapter* adapter) - : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter) {} + : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter), + origin_value_x(adapter->GetOriginValue(port_, axis_x_)), + origin_value_y(adapter->GetOriginValue(port_, axis_y_)) {} float GetAxis(int axis) const { std::lock_guard lock{mutex}; // division is not by a perfect 128 to account for some variance in center location // e.g. my device idled at 131 in X, 120 in Y, and full range of motion was in range // [20-230] - return (gcadapter->GetPadState()[port].axes.at(axis) - 128.0f) / 95.0f; + if (axis % 2 == 0) + return (gcadapter->GetPadState()[port].axes.at(axis) - origin_value_x) / 95.0f; + else + return (gcadapter->GetPadState()[port].axes.at(axis) - origin_value_y) / 95.0f; } std::pair GetAnalog(int axis_x, int axis_y) const { @@ -201,6 +208,8 @@ private: const int axis_x; const int axis_y; const float deadzone; + const float origin_value_x; + const float origin_value_y; mutable std::mutex mutex; GCAdapter::Adapter* gcadapter; }; From 86abff48e1212498a3f6361012062458d8ae24ba Mon Sep 17 00:00:00 2001 From: Ameer Date: Mon, 6 Jul 2020 22:09:07 -0400 Subject: [PATCH 2/5] Recalibrate reconnected controllers --- src/input_common/gcadapter/gc_adapter.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/input_common/gcadapter/gc_adapter.cpp b/src/input_common/gcadapter/gc_adapter.cpp index 8465309d0b..f173a018ac 100644 --- a/src/input_common/gcadapter/gc_adapter.cpp +++ b/src/input_common/gcadapter/gc_adapter.cpp @@ -49,6 +49,11 @@ GCPadStatus Adapter::GetPadStatus(int port, const std::array& adapter_pa PadButton::PAD_TRIGGER_L, }; + if (adapter_controllers_status[port] == ControllerTypes::None && !get_origin[port]) { + // Controller may have been disconnected, recalibrate if reconnected. + get_origin[port] = true; + } + if (adapter_controllers_status[port] != ControllerTypes::None) { const u8 b1 = adapter_payload[1 + (9 * port) + 1]; const u8 b2 = adapter_payload[1 + (9 * port) + 2]; From e3253b5f1896605f94d661cae1a7333522b6aee8 Mon Sep 17 00:00:00 2001 From: Ameer Date: Mon, 6 Jul 2020 23:01:57 -0400 Subject: [PATCH 3/5] Brace the code! Fix compile error due to class member construction order --- src/input_common/gcadapter/gc_adapter.cpp | 39 ++++++++++++++++------- src/input_common/gcadapter/gc_poller.cpp | 7 ++-- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/input_common/gcadapter/gc_adapter.cpp b/src/input_common/gcadapter/gc_adapter.cpp index f173a018ac..b43b737598 100644 --- a/src/input_common/gcadapter/gc_adapter.cpp +++ b/src/input_common/gcadapter/gc_adapter.cpp @@ -386,35 +386,50 @@ const std::array& Adapter::GetPadState() const { } int Adapter::GetOriginValue(int port, int axis) { + // TODO: perhaps place stick statuses into an array in PadStatus const PadAxes padaxis = static_cast(axis); - if (padaxis == PadAxes::StickX) + if (padaxis == PadAxes::StickX) { return origin_status[port].stick_x; - if (padaxis == PadAxes::StickY) + } + if (padaxis == PadAxes::StickY) { return origin_status[port].stick_y; - if (padaxis == PadAxes::SubstickX) + } + if (padaxis == PadAxes::SubstickX) { return origin_status[port].substick_x; - if (padaxis == PadAxes::SubstickY) + } + if (padaxis == PadAxes::SubstickY) { return origin_status[port].substick_x; - if (padaxis == PadAxes::TriggerLeft) + } + if (padaxis == PadAxes::TriggerLeft) { return origin_status[port].trigger_left; - if (padaxis == PadAxes::TriggerRight) + } + if (padaxis == PadAxes::TriggerRight) { return origin_status[port].trigger_right; + } + return 0; } const int Adapter::GetOriginValue(int port, int axis) const { const PadAxes padaxis = static_cast(axis); - if (padaxis == PadAxes::StickX) + if (padaxis == PadAxes::StickX) { return origin_status[port].stick_x; - if (padaxis == PadAxes::StickY) + } + if (padaxis == PadAxes::StickY) { return origin_status[port].stick_y; - if (padaxis == PadAxes::SubstickX) + } + if (padaxis == PadAxes::SubstickX) { return origin_status[port].substick_x; - if (padaxis == PadAxes::SubstickY) + } + if (padaxis == PadAxes::SubstickY) { return origin_status[port].substick_x; - if (padaxis == PadAxes::TriggerLeft) + } + if (padaxis == PadAxes::TriggerLeft) { return origin_status[port].trigger_left; - if (padaxis == PadAxes::TriggerRight) + } + if (padaxis == PadAxes::TriggerRight) { return origin_status[port].trigger_right; + } + return 0; } } // namespace GCAdapter diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp index c9bb7e571b..ed99f98b49 100644 --- a/src/input_common/gcadapter/gc_poller.cpp +++ b/src/input_common/gcadapter/gc_poller.cpp @@ -155,10 +155,11 @@ public: // division is not by a perfect 128 to account for some variance in center location // e.g. my device idled at 131 in X, 120 in Y, and full range of motion was in range // [20-230] - if (axis % 2 == 0) + if (axis % 2 == 0) { return (gcadapter->GetPadState()[port].axes.at(axis) - origin_value_x) / 95.0f; - else + } else { return (gcadapter->GetPadState()[port].axes.at(axis) - origin_value_y) / 95.0f; + } } std::pair GetAnalog(int axis_x, int axis_y) const { @@ -208,10 +209,10 @@ private: const int axis_x; const int axis_y; const float deadzone; + GCAdapter::Adapter* gcadapter; const float origin_value_x; const float origin_value_y; mutable std::mutex mutex; - GCAdapter::Adapter* gcadapter; }; /// An analog device factory that creates analog devices from GC Adapter From b57475887be5879347d5fda425676d0bd2e2a3d3 Mon Sep 17 00:00:00 2001 From: Ameer Date: Tue, 7 Jul 2020 12:20:59 -0400 Subject: [PATCH 4/5] Address PR feedback, fix axis button thresholding --- src/input_common/gcadapter/gc_adapter.cpp | 60 +++++++---------------- src/input_common/gcadapter/gc_adapter.h | 3 +- src/input_common/gcadapter/gc_poller.cpp | 15 ++---- 3 files changed, 21 insertions(+), 57 deletions(-) diff --git a/src/input_common/gcadapter/gc_adapter.cpp b/src/input_common/gcadapter/gc_adapter.cpp index b43b737598..f1c280e2e6 100644 --- a/src/input_common/gcadapter/gc_adapter.cpp +++ b/src/input_common/gcadapter/gc_adapter.cpp @@ -385,51 +385,25 @@ const std::array& Adapter::GetPadState() const { return state; } -int Adapter::GetOriginValue(int port, int axis) { - // TODO: perhaps place stick statuses into an array in PadStatus - const PadAxes padaxis = static_cast(axis); - if (padaxis == PadAxes::StickX) { - return origin_status[port].stick_x; - } - if (padaxis == PadAxes::StickY) { - return origin_status[port].stick_y; - } - if (padaxis == PadAxes::SubstickX) { - return origin_status[port].substick_x; - } - if (padaxis == PadAxes::SubstickY) { - return origin_status[port].substick_x; - } - if (padaxis == PadAxes::TriggerLeft) { - return origin_status[port].trigger_left; - } - if (padaxis == PadAxes::TriggerRight) { - return origin_status[port].trigger_right; - } - return 0; -} +int Adapter::GetOriginValue(int port, int axis) const { + const auto& status = origin_status[port]; -const int Adapter::GetOriginValue(int port, int axis) const { - const PadAxes padaxis = static_cast(axis); - if (padaxis == PadAxes::StickX) { - return origin_status[port].stick_x; + switch (static_cast(axis)) { + case PadAxes::StickX: + return status.stick_x; + case PadAxes::StickY: + return status.stick_y; + case PadAxes::SubstickX: + return status.substick_x; + case PadAxes::SubstickY: + return status.substick_y; + case PadAxes::TriggerLeft: + return status.trigger_left; + case PadAxes::TriggerRight: + return status.trigger_right; + default: + return 0; } - if (padaxis == PadAxes::StickY) { - return origin_status[port].stick_y; - } - if (padaxis == PadAxes::SubstickX) { - return origin_status[port].substick_x; - } - if (padaxis == PadAxes::SubstickY) { - return origin_status[port].substick_x; - } - if (padaxis == PadAxes::TriggerLeft) { - return origin_status[port].trigger_left; - } - if (padaxis == PadAxes::TriggerRight) { - return origin_status[port].trigger_right; - } - return 0; } } // namespace GCAdapter diff --git a/src/input_common/gcadapter/gc_adapter.h b/src/input_common/gcadapter/gc_adapter.h index 8b08d667dc..cb9d73a8ec 100644 --- a/src/input_common/gcadapter/gc_adapter.h +++ b/src/input_common/gcadapter/gc_adapter.h @@ -96,8 +96,7 @@ public: std::array& GetPadState(); const std::array& GetPadState() const; - int GetOriginValue(int port, int axis); - const int GetOriginValue(int port, int axis) const; + int GetOriginValue(int port, int axis) const; private: GCPadStatus GetPadStatus(int port, const std::array& adapter_payload); diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp index ed99f98b49..ad321e933b 100644 --- a/src/input_common/gcadapter/gc_poller.cpp +++ b/src/input_common/gcadapter/gc_poller.cpp @@ -34,13 +34,7 @@ public: explicit GCAxisButton(int port_, int axis_, float threshold_, bool trigger_if_greater_, GCAdapter::Adapter* adapter) : port(port_), axis(axis_), threshold(threshold_), trigger_if_greater(trigger_if_greater_), - gcadapter(adapter), origin_value(adapter->GetOriginValue(port_, axis_)) { - // L/R triggers range is only in positive direction beginning near 0 - // 0.0 threshold equates to near half trigger press, but threshold accounts for variability. - if (axis > 3) { - threshold *= -0.5; - } - } + gcadapter(adapter), origin_value(adapter->GetOriginValue(port_, axis_)) {} bool GetStatus() const override { const float current_axis_value = gcadapter->GetPadState()[port].axes.at(axis); @@ -152,14 +146,11 @@ public: float GetAxis(int axis) const { std::lock_guard lock{mutex}; + const auto origin_value = axis % 2 == 0 ? origin_value_x : origin_value_y; // division is not by a perfect 128 to account for some variance in center location // e.g. my device idled at 131 in X, 120 in Y, and full range of motion was in range // [20-230] - if (axis % 2 == 0) { - return (gcadapter->GetPadState()[port].axes.at(axis) - origin_value_x) / 95.0f; - } else { - return (gcadapter->GetPadState()[port].axes.at(axis) - origin_value_y) / 95.0f; - } + return (gcadapter->GetPadState()[port].axes.at(axis) - origin_value) / 95.0f; } std::pair GetAnalog(int axis_x, int axis_y) const { From 042c6602a057c990bf2eeec31b88c48e987050c7 Mon Sep 17 00:00:00 2001 From: Ameer Date: Fri, 10 Jul 2020 11:07:43 -0400 Subject: [PATCH 5/5] Break out of scan loop if can't find adapter on first run --- src/input_common/gcadapter/gc_adapter.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/input_common/gcadapter/gc_adapter.cpp b/src/input_common/gcadapter/gc_adapter.cpp index 38cf02f7eb..05607e0334 100644 --- a/src/input_common/gcadapter/gc_adapter.cpp +++ b/src/input_common/gcadapter/gc_adapter.cpp @@ -243,6 +243,9 @@ void Adapter::Setup() { } libusb_free_device_list(devices, 1); } + // Break out of the ScanThreadFunc() loop that is constantly looking for the device + // Assumes user has GC adapter plugged in before launch to use the adapter + detect_thread_running = false; } bool Adapter::CheckDeviceAccess(libusb_device* device) {