diff options
| -rw-r--r-- | src/core/hid/emulated_controller.cpp | 80 | ||||
| -rw-r--r-- | src/core/hid/emulated_controller.h | 12 | ||||
| -rw-r--r-- | src/core/hid/input_converter.cpp | 14 | ||||
| -rw-r--r-- | src/core/hid/input_converter.h | 10 | ||||
| -rw-r--r-- | src/input_common/drivers/joycon.cpp | 11 | ||||
| -rw-r--r-- | src/input_common/input_engine.cpp | 37 | ||||
| -rw-r--r-- | src/input_common/input_engine.h | 6 | ||||
| -rw-r--r-- | src/input_common/input_poller.cpp | 67 | ||||
| -rw-r--r-- | src/input_common/input_poller.h | 11 | 
9 files changed, 246 insertions, 2 deletions
| diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 128101e8c..89638cb85 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -93,6 +93,7 @@ void EmulatedController::ReloadFromSettings() {          motion_params[index] = Common::ParamPackage(player.motions[index]);      } +    controller.color_values = {};      controller.colors_state.fullkey = {          .body = GetNpadColor(player.body_color_left),          .button = GetNpadColor(player.button_color_left), @@ -132,6 +133,11 @@ void EmulatedController::LoadDevices() {      trigger_params[LeftIndex] = button_params[Settings::NativeButton::ZL];      trigger_params[RightIndex] = button_params[Settings::NativeButton::ZR]; +    color_params[LeftIndex] = left_joycon; +    color_params[RightIndex] = right_joycon; +    color_params[LeftIndex].Set("color", true); +    color_params[RightIndex].Set("color", true); +      battery_params[LeftIndex] = left_joycon;      battery_params[RightIndex] = right_joycon;      battery_params[LeftIndex].Set("battery", true); @@ -160,6 +166,7 @@ void EmulatedController::LoadDevices() {                             Common::Input::CreateInputDevice);      std::ranges::transform(battery_params, battery_devices.begin(),                             Common::Input::CreateInputDevice); +    std::ranges::transform(color_params, color_devices.begin(), Common::Input::CreateInputDevice);      camera_devices = Common::Input::CreateInputDevice(camera_params);      ring_analog_device = Common::Input::CreateInputDevice(ring_params);      nfc_devices = Common::Input::CreateInputDevice(nfc_params); @@ -324,6 +331,19 @@ void EmulatedController::ReloadInput() {          battery_devices[index]->ForceUpdate();      } +    for (std::size_t index = 0; index < color_devices.size(); ++index) { +        if (!color_devices[index]) { +            continue; +        } +        color_devices[index]->SetCallback({ +            .on_change = +                [this, index](const Common::Input::CallbackStatus& callback) { +                    SetColors(callback, index); +                }, +        }); +        color_devices[index]->ForceUpdate(); +    } +      for (std::size_t index = 0; index < motion_devices.size(); ++index) {          if (!motion_devices[index]) {              continue; @@ -429,6 +449,9 @@ void EmulatedController::UnloadInput() {      for (auto& battery : battery_devices) {          battery.reset();      } +    for (auto& color : color_devices) { +        color.reset(); +    }      for (auto& output : output_devices) {          output.reset();      } @@ -458,6 +481,11 @@ void EmulatedController::EnableConfiguration() {  void EmulatedController::DisableConfiguration() {      is_configuring = false; +    // Get Joycon colors before turning on the controller +    for (const auto& color_device : color_devices) { +        color_device->ForceUpdate(); +    } +      // Apply temporary npad type to the real controller      if (tmp_npad_type != npad_type) {          if (is_connected) { @@ -926,6 +954,58 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback      TriggerOnChange(ControllerTriggerType::Motion, true);  } +void EmulatedController::SetColors(const Common::Input::CallbackStatus& callback, +                                   std::size_t index) { +    if (index >= controller.color_values.size()) { +        return; +    } +    std::unique_lock lock{mutex}; +    controller.color_values[index] = TransformToColor(callback); + +    if (is_configuring) { +        lock.unlock(); +        TriggerOnChange(ControllerTriggerType::Color, false); +        return; +    } + +    if (controller.color_values[index].body == 0) { +        return; +    } + +    controller.colors_state.fullkey = { +        .body = GetNpadColor(controller.color_values[index].body), +        .button = GetNpadColor(controller.color_values[index].buttons), +    }; +    if (npad_type == NpadStyleIndex::ProController) { +        controller.colors_state.left = { +            .body = GetNpadColor(controller.color_values[index].left_grip), +            .button = GetNpadColor(controller.color_values[index].buttons), +        }; +        controller.colors_state.right = { +            .body = GetNpadColor(controller.color_values[index].right_grip), +            .button = GetNpadColor(controller.color_values[index].buttons), +        }; +    } else { +        switch (index) { +        case LeftIndex: +            controller.colors_state.left = { +                .body = GetNpadColor(controller.color_values[index].body), +                .button = GetNpadColor(controller.color_values[index].buttons), +            }; +            break; +        case RightIndex: +            controller.colors_state.right = { +                .body = GetNpadColor(controller.color_values[index].body), +                .button = GetNpadColor(controller.color_values[index].buttons), +            }; +            break; +        } +    } + +    lock.unlock(); +    TriggerOnChange(ControllerTriggerType::Color, true); +} +  void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callback,                                      std::size_t index) {      if (index >= controller.battery_values.size()) { diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index aed331a1a..d044cc36b 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -35,6 +35,8 @@ using ControllerMotionDevices =      std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeMotion::NumMotions>;  using TriggerDevices =      std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeTrigger::NumTriggers>; +using ColorDevices = +    std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;  using BatteryDevices =      std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;  using CameraDevices = std::unique_ptr<Common::Input::InputDevice>; @@ -46,6 +48,7 @@ using ButtonParams = std::array<Common::ParamPackage, Settings::NativeButton::Nu  using StickParams = std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs>;  using ControllerMotionParams = std::array<Common::ParamPackage, Settings::NativeMotion::NumMotions>;  using TriggerParams = std::array<Common::ParamPackage, Settings::NativeTrigger::NumTriggers>; +using ColorParams = std::array<Common::ParamPackage, max_emulated_controllers>;  using BatteryParams = std::array<Common::ParamPackage, max_emulated_controllers>;  using CameraParams = Common::ParamPackage;  using RingAnalogParams = Common::ParamPackage; @@ -458,6 +461,13 @@ private:      void SetMotion(const Common::Input::CallbackStatus& callback, std::size_t index);      /** +     * Updates the color status of the controller +     * @param callback A CallbackStatus containing the color status +     * @param index color ID of the to be updated +     */ +    void SetColors(const Common::Input::CallbackStatus& callback, std::size_t index); + +    /**       * Updates the battery status of the controller       * @param callback A CallbackStatus containing the battery status       * @param index battery ID of the to be updated @@ -515,6 +525,7 @@ private:      ControllerMotionParams motion_params;      TriggerParams trigger_params;      BatteryParams battery_params; +    ColorParams color_params;      CameraParams camera_params;      RingAnalogParams ring_params;      NfcParams nfc_params; @@ -525,6 +536,7 @@ private:      ControllerMotionDevices motion_devices;      TriggerDevices trigger_devices;      BatteryDevices battery_devices; +    ColorDevices color_devices;      CameraDevices camera_devices;      RingAnalogDevice ring_analog_device;      NfcDevices nfc_devices; diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index 502692875..d7e253044 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp @@ -304,6 +304,20 @@ Common::Input::NfcStatus TransformToNfc(const Common::Input::CallbackStatus& cal      return nfc;  } +Common::Input::BodyColorStatus TransformToColor(const Common::Input::CallbackStatus& callback) { +    Common::Input::BodyColorStatus color{}; +    switch (callback.type) { +    case Common::Input::InputType::Color: +        color = callback.color_status; +        break; +    default: +        LOG_ERROR(Input, "Conversion from type {} to color not implemented", callback.type); +        break; +    } + +    return color; +} +  void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value) {      const auto& properties = analog.properties;      float& raw_value = analog.raw_value; diff --git a/src/core/hid/input_converter.h b/src/core/hid/input_converter.h index b7eb6e660..c51c03e57 100644 --- a/src/core/hid/input_converter.h +++ b/src/core/hid/input_converter.h @@ -88,11 +88,19 @@ Common::Input::CameraStatus TransformToCamera(const Common::Input::CallbackStatu   * Converts raw input data into a valid nfc status.   *   * @param callback Supported callbacks: Nfc. - * @return A valid CameraObject object. + * @return A valid data tag vector.   */  Common::Input::NfcStatus TransformToNfc(const Common::Input::CallbackStatus& callback);  /** + * Converts raw input data into a valid color status. + * + * @param callback Supported callbacks: Color. + * @return A valid Color object. + */ +Common::Input::BodyColorStatus TransformToColor(const Common::Input::CallbackStatus& callback); + +/**   * Converts raw analog data into a valid analog value   * @param analog An analog object containing raw data and properties   * @param clamp_value determines if the value needs to be clamped between -1.0f and 1.0f. diff --git a/src/input_common/drivers/joycon.cpp b/src/input_common/drivers/joycon.cpp index 1fca11d34..c6f78c989 100644 --- a/src/input_common/drivers/joycon.cpp +++ b/src/input_common/drivers/joycon.cpp @@ -335,7 +335,16 @@ void Joycons::OnBatteryUpdate(std::size_t port, Joycon::ControllerType type,  }  void Joycons::OnColorUpdate(std::size_t port, Joycon::ControllerType type, -                            const Joycon::Color& value) {} +                            const Joycon::Color& value) { +    const auto identifier = GetIdentifier(port, type); +    Common::Input::BodyColorStatus color{ +        .body = value.body, +        .buttons = value.buttons, +        .left_grip = value.left_grip, +        .right_grip = value.right_grip, +    }; +    SetColor(identifier, color); +}  void Joycons::OnButtonUpdate(std::size_t port, Joycon::ControllerType type, int id, bool value) {      const auto identifier = GetIdentifier(port, type); diff --git a/src/input_common/input_engine.cpp b/src/input_common/input_engine.cpp index 61cfd0911..91aa96aa7 100644 --- a/src/input_common/input_engine.cpp +++ b/src/input_common/input_engine.cpp @@ -79,6 +79,17 @@ void InputEngine::SetBattery(const PadIdentifier& identifier, Common::Input::Bat      TriggerOnBatteryChange(identifier, value);  } +void InputEngine::SetColor(const PadIdentifier& identifier, Common::Input::BodyColorStatus value) { +    { +        std::scoped_lock lock{mutex}; +        ControllerData& controller = controller_list.at(identifier); +        if (!configuring) { +            controller.color = value; +        } +    } +    TriggerOnColorChange(identifier, value); +} +  void InputEngine::SetMotion(const PadIdentifier& identifier, int motion, const BasicMotion& value) {      {          std::scoped_lock lock{mutex}; @@ -176,6 +187,18 @@ Common::Input::BatteryLevel InputEngine::GetBattery(const PadIdentifier& identif      return controller.battery;  } +Common::Input::BodyColorStatus InputEngine::GetColor(const PadIdentifier& identifier) const { +    std::scoped_lock lock{mutex}; +    const auto controller_iter = controller_list.find(identifier); +    if (controller_iter == controller_list.cend()) { +        LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.RawString(), +                  identifier.pad, identifier.port); +        return {}; +    } +    const ControllerData& controller = controller_iter->second; +    return controller.color; +} +  BasicMotion InputEngine::GetMotion(const PadIdentifier& identifier, int motion) const {      std::scoped_lock lock{mutex};      const auto controller_iter = controller_list.find(identifier); @@ -328,6 +351,20 @@ void InputEngine::TriggerOnBatteryChange(const PadIdentifier& identifier,      }  } +void InputEngine::TriggerOnColorChange(const PadIdentifier& identifier, +                                       [[maybe_unused]] Common::Input::BodyColorStatus value) { +    std::scoped_lock lock{mutex_callback}; +    for (const auto& poller_pair : callback_list) { +        const InputIdentifier& poller = poller_pair.second; +        if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Color, 0)) { +            continue; +        } +        if (poller.callback.on_change) { +            poller.callback.on_change(); +        } +    } +} +  void InputEngine::TriggerOnMotionChange(const PadIdentifier& identifier, int motion,                                          const BasicMotion& value) {      std::scoped_lock lock{mutex_callback}; diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index 6cbcf5207..6301c5719 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -40,6 +40,7 @@ enum class EngineInputType {      Battery,      Button,      Camera, +    Color,      HatButton,      Motion,      Nfc, @@ -199,6 +200,7 @@ public:      bool GetHatButton(const PadIdentifier& identifier, int button, u8 direction) const;      f32 GetAxis(const PadIdentifier& identifier, int axis) const;      Common::Input::BatteryLevel GetBattery(const PadIdentifier& identifier) const; +    Common::Input::BodyColorStatus GetColor(const PadIdentifier& identifier) const;      BasicMotion GetMotion(const PadIdentifier& identifier, int motion) const;      Common::Input::CameraStatus GetCamera(const PadIdentifier& identifier) const;      Common::Input::NfcStatus GetNfc(const PadIdentifier& identifier) const; @@ -212,6 +214,7 @@ protected:      void SetHatButton(const PadIdentifier& identifier, int button, u8 value);      void SetAxis(const PadIdentifier& identifier, int axis, f32 value);      void SetBattery(const PadIdentifier& identifier, Common::Input::BatteryLevel value); +    void SetColor(const PadIdentifier& identifier, Common::Input::BodyColorStatus value);      void SetMotion(const PadIdentifier& identifier, int motion, const BasicMotion& value);      void SetCamera(const PadIdentifier& identifier, const Common::Input::CameraStatus& value);      void SetNfc(const PadIdentifier& identifier, const Common::Input::NfcStatus& value); @@ -227,6 +230,7 @@ private:          std::unordered_map<int, float> axes;          std::unordered_map<int, BasicMotion> motions;          Common::Input::BatteryLevel battery{}; +        Common::Input::BodyColorStatus color{};          Common::Input::CameraStatus camera{};          Common::Input::NfcStatus nfc{};      }; @@ -235,6 +239,8 @@ private:      void TriggerOnHatButtonChange(const PadIdentifier& identifier, int button, u8 value);      void TriggerOnAxisChange(const PadIdentifier& identifier, int axis, f32 value);      void TriggerOnBatteryChange(const PadIdentifier& identifier, Common::Input::BatteryLevel value); +    void TriggerOnColorChange(const PadIdentifier& identifier, +                              Common::Input::BodyColorStatus value);      void TriggerOnMotionChange(const PadIdentifier& identifier, int motion,                                 const BasicMotion& value);      void TriggerOnCameraChange(const PadIdentifier& identifier, diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index fb8be42e2..368ffbdd5 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp @@ -498,6 +498,58 @@ private:      InputEngine* input_engine;  }; +class InputFromColor final : public Common::Input::InputDevice { +public: +    explicit InputFromColor(PadIdentifier identifier_, InputEngine* input_engine_) +        : identifier(identifier_), input_engine(input_engine_) { +        UpdateCallback engine_callback{[this]() { OnChange(); }}; +        const InputIdentifier input_identifier{ +            .identifier = identifier, +            .type = EngineInputType::Color, +            .index = 0, +            .callback = engine_callback, +        }; +        last_color_value = {}; +        callback_key = input_engine->SetCallback(input_identifier); +    } + +    ~InputFromColor() override { +        input_engine->DeleteCallback(callback_key); +    } + +    Common::Input::BodyColorStatus GetStatus() const { +        return input_engine->GetColor(identifier); +    } + +    void ForceUpdate() override { +        const Common::Input::CallbackStatus status{ +            .type = Common::Input::InputType::Color, +            .color_status = GetStatus(), +        }; + +        last_color_value = status.color_status; +        TriggerOnChange(status); +    } + +    void OnChange() { +        const Common::Input::CallbackStatus status{ +            .type = Common::Input::InputType::Color, +            .color_status = GetStatus(), +        }; + +        if (status.color_status.body != last_color_value.body) { +            last_color_value = status.color_status; +            TriggerOnChange(status); +        } +    } + +private: +    const PadIdentifier identifier; +    int callback_key; +    Common::Input::BodyColorStatus last_color_value; +    InputEngine* input_engine; +}; +  class InputFromMotion final : public Common::Input::InputDevice {  public:      explicit InputFromMotion(PadIdentifier identifier_, int motion_sensor_, float gyro_threshold_, @@ -966,6 +1018,18 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateBatteryDevice(      return std::make_unique<InputFromBattery>(identifier, input_engine.get());  } +std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateColorDevice( +    const Common::ParamPackage& params) { +    const PadIdentifier identifier = { +        .guid = Common::UUID{params.Get("guid", "")}, +        .port = static_cast<std::size_t>(params.Get("port", 0)), +        .pad = static_cast<std::size_t>(params.Get("pad", 0)), +    }; + +    input_engine->PreSetController(identifier); +    return std::make_unique<InputFromColor>(identifier, input_engine.get()); +} +  std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateMotionDevice(      Common::ParamPackage params) {      const PadIdentifier identifier = { @@ -1053,6 +1117,9 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::Create(      if (params.Has("battery")) {          return CreateBatteryDevice(params);      } +    if (params.Has("color")) { +        return CreateColorDevice(params); +    }      if (params.Has("camera")) {          return CreateCameraDevice(params);      } diff --git a/src/input_common/input_poller.h b/src/input_common/input_poller.h index d7db13ce4..e097e254c 100644 --- a/src/input_common/input_poller.h +++ b/src/input_common/input_poller.h @@ -191,6 +191,17 @@ private:          const Common::ParamPackage& params);      /** +     * Creates a color device from the parameters given. +     * @param params contains parameters for creating the device: +     *               - "guid": text string for identifying controllers +     *               - "port": port of the connected device +     *               - "pad": slot of the connected controller +     * @returns a unique input device with the parameters specified +     */ +    std::unique_ptr<Common::Input::InputDevice> CreateColorDevice( +        const Common::ParamPackage& params); + +    /**       * Creates a motion device from the parameters given.       * @param params contains parameters for creating the device:       *               - "axis_x": the controller horizontal axis id to bind with the input | 
