diff options
| -rw-r--r-- | src/common/input.h | 2 | ||||
| -rw-r--r-- | src/core/hid/emulated_controller.cpp | 75 | ||||
| -rw-r--r-- | src/core/hid/emulated_controller.h | 6 | ||||
| -rw-r--r-- | src/core/hle/service/hid/controllers/npad.cpp | 3 | ||||
| -rw-r--r-- | src/input_common/input_poller.cpp | 30 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_input_player.cpp | 17 | 
6 files changed, 115 insertions, 18 deletions
| diff --git a/src/common/input.h b/src/common/input.h index d61cd7ca8..b5748a6c8 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -130,6 +130,8 @@ struct ButtonStatus {      bool inverted{};      // Press once to activate, press again to release      bool toggle{}; +    // Spams the button when active +    bool turbo{};      // Internal lock for the toggle status      bool locked{};  }; diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 0e06468da..631aa6ad2 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -12,6 +12,7 @@  namespace Core::HID {  constexpr s32 HID_JOYSTICK_MAX = 0x7fff;  constexpr s32 HID_TRIGGER_MAX = 0x7fff; +constexpr u32 TURBO_BUTTON_DELAY = 4;  // Use a common UUID for TAS and Virtual Gamepad  constexpr Common::UUID TAS_UUID =      Common::UUID{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xA5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; @@ -447,6 +448,7 @@ void EmulatedController::ReloadInput() {                  },          });      } +    turbo_button_state = 0;  }  void EmulatedController::UnloadInput() { @@ -687,6 +689,7 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback      }      current_status.toggle = new_status.toggle; +    current_status.turbo = new_status.turbo;      current_status.uuid = uuid;      // Update button status with current @@ -1548,7 +1551,7 @@ NpadButtonState EmulatedController::GetNpadButtons() const {      if (is_configuring) {          return {};      } -    return controller.npad_button_state; +    return {controller.npad_button_state.raw & GetTurboButtonMask()};  }  DebugPadButton EmulatedController::GetDebugPadButtons() const { @@ -1656,4 +1659,74 @@ void EmulatedController::DeleteCallback(int key) {      }      callback_list.erase(iterator);  } + +void EmulatedController::TurboButtonUpdate() { +    turbo_button_state = (turbo_button_state + 1) % (TURBO_BUTTON_DELAY * 2); +} + +NpadButton EmulatedController::GetTurboButtonMask() const { +    // Apply no mask when disabled +    if (turbo_button_state < TURBO_BUTTON_DELAY) { +        return {NpadButton::All}; +    } + +    NpadButtonState button_mask{}; +    for (std::size_t index = 0; index < controller.button_values.size(); ++index) { +        if (!controller.button_values[index].turbo) { +            continue; +        } + +        switch (index) { +        case Settings::NativeButton::A: +            button_mask.a.Assign(1); +            break; +        case Settings::NativeButton::B: +            button_mask.b.Assign(1); +            break; +        case Settings::NativeButton::X: +            button_mask.x.Assign(1); +            break; +        case Settings::NativeButton::Y: +            button_mask.y.Assign(1); +            break; +        case Settings::NativeButton::L: +            button_mask.l.Assign(1); +            break; +        case Settings::NativeButton::R: +            button_mask.r.Assign(1); +            break; +        case Settings::NativeButton::ZL: +            button_mask.zl.Assign(1); +            break; +        case Settings::NativeButton::ZR: +            button_mask.zr.Assign(1); +            break; +        case Settings::NativeButton::DLeft: +            button_mask.left.Assign(1); +            break; +        case Settings::NativeButton::DUp: +            button_mask.up.Assign(1); +            break; +        case Settings::NativeButton::DRight: +            button_mask.right.Assign(1); +            break; +        case Settings::NativeButton::DDown: +            button_mask.down.Assign(1); +            break; +        case Settings::NativeButton::SL: +            button_mask.left_sl.Assign(1); +            button_mask.right_sl.Assign(1); +            break; +        case Settings::NativeButton::SR: +            button_mask.left_sr.Assign(1); +            button_mask.right_sr.Assign(1); +            break; +        default: +            break; +        } +    } + +    return static_cast<NpadButton>(~button_mask.raw); +} +  } // namespace Core::HID diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index 3ac77b2b5..b02bf35c4 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -411,6 +411,9 @@ public:       */      void DeleteCallback(int key); +    /// Swaps the state of the turbo buttons +    void TurboButtonUpdate(); +  private:      /// creates input devices from params      void LoadDevices(); @@ -511,6 +514,8 @@ private:       */      void TriggerOnChange(ControllerTriggerType type, bool is_service_update); +    NpadButton GetTurboButtonMask() const; +      const NpadIdType npad_id_type;      NpadStyleIndex npad_type{NpadStyleIndex::None};      NpadStyleIndex original_npad_type{NpadStyleIndex::None}; @@ -520,6 +525,7 @@ private:      bool system_buttons_enabled{true};      f32 motion_sensitivity{0.01f};      bool force_update_motion{false}; +    u32 turbo_button_state{0};      // Temporary values to avoid doing changes while the controller is in configuring mode      NpadStyleIndex tmp_npad_type{NpadStyleIndex::None}; diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 5713f1288..3afda9e3f 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -428,6 +428,9 @@ void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) {          return;      } +    // This function is unique to yuzu for the turbo buttons to work properly +    controller.device->TurboButtonUpdate(); +      auto& pad_entry = controller.npad_pad_state;      auto& trigger_entry = controller.npad_trigger_state;      const auto button_state = controller.device->GetNpadButtons(); diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index 15cbf7e5f..8c6a6521a 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp @@ -16,10 +16,10 @@ public:  class InputFromButton final : public Common::Input::InputDevice {  public: -    explicit InputFromButton(PadIdentifier identifier_, int button_, bool toggle_, bool inverted_, -                             InputEngine* input_engine_) -        : identifier(identifier_), button(button_), toggle(toggle_), inverted(inverted_), -          input_engine(input_engine_) { +    explicit InputFromButton(PadIdentifier identifier_, int button_, bool turbo_, bool toggle_, +                             bool inverted_, InputEngine* input_engine_) +        : identifier(identifier_), button(button_), turbo(turbo_), toggle(toggle_), +          inverted(inverted_), input_engine(input_engine_) {          UpdateCallback engine_callback{[this]() { OnChange(); }};          const InputIdentifier input_identifier{              .identifier = identifier, @@ -40,6 +40,7 @@ public:              .value = input_engine->GetButton(identifier, button),              .inverted = inverted,              .toggle = toggle, +            .turbo = turbo,          };      } @@ -68,6 +69,7 @@ public:  private:      const PadIdentifier identifier;      const int button; +    const bool turbo;      const bool toggle;      const bool inverted;      int callback_key; @@ -77,10 +79,10 @@ private:  class InputFromHatButton final : public Common::Input::InputDevice {  public: -    explicit InputFromHatButton(PadIdentifier identifier_, int button_, u8 direction_, bool toggle_, -                                bool inverted_, InputEngine* input_engine_) -        : identifier(identifier_), button(button_), direction(direction_), toggle(toggle_), -          inverted(inverted_), input_engine(input_engine_) { +    explicit InputFromHatButton(PadIdentifier identifier_, int button_, u8 direction_, bool turbo_, +                                bool toggle_, bool inverted_, InputEngine* input_engine_) +        : identifier(identifier_), button(button_), direction(direction_), turbo(turbo_), +          toggle(toggle_), inverted(inverted_), input_engine(input_engine_) {          UpdateCallback engine_callback{[this]() { OnChange(); }};          const InputIdentifier input_identifier{              .identifier = identifier, @@ -101,6 +103,7 @@ public:              .value = input_engine->GetHatButton(identifier, button, direction),              .inverted = inverted,              .toggle = toggle, +            .turbo = turbo,          };      } @@ -130,6 +133,7 @@ private:      const PadIdentifier identifier;      const int button;      const u8 direction; +    const bool turbo;      const bool toggle;      const bool inverted;      int callback_key; @@ -853,14 +857,15 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateButtonDevice(      const auto keyboard_key = params.Get("code", 0);      const auto toggle = params.Get("toggle", false) != 0;      const auto inverted = params.Get("inverted", false) != 0; +    const auto turbo = params.Get("turbo", false) != 0;      input_engine->PreSetController(identifier);      input_engine->PreSetButton(identifier, button_id);      input_engine->PreSetButton(identifier, keyboard_key);      if (keyboard_key != 0) { -        return std::make_unique<InputFromButton>(identifier, keyboard_key, toggle, inverted, +        return std::make_unique<InputFromButton>(identifier, keyboard_key, turbo, toggle, inverted,                                                   input_engine.get());      } -    return std::make_unique<InputFromButton>(identifier, button_id, toggle, inverted, +    return std::make_unique<InputFromButton>(identifier, button_id, turbo, toggle, inverted,                                               input_engine.get());  } @@ -876,11 +881,12 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateHatButtonDevice(      const auto direction = input_engine->GetHatButtonId(params.Get("direction", ""));      const auto toggle = params.Get("toggle", false) != 0;      const auto inverted = params.Get("inverted", false) != 0; +    const auto turbo = params.Get("turbo", false) != 0;      input_engine->PreSetController(identifier);      input_engine->PreSetHatButton(identifier, button_id); -    return std::make_unique<InputFromHatButton>(identifier, button_id, direction, toggle, inverted, -                                                input_engine.get()); +    return std::make_unique<InputFromHatButton>(identifier, button_id, direction, turbo, toggle, +                                                inverted, input_engine.get());  }  std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateStickDevice( diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 4b7e3b01b..723690e71 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -182,12 +182,13 @@ QString ConfigureInputPlayer::ButtonToText(const Common::ParamPackage& param) {      const QString toggle = QString::fromStdString(param.Get("toggle", false) ? "~" : "");      const QString inverted = QString::fromStdString(param.Get("inverted", false) ? "!" : "");      const QString invert = QString::fromStdString(param.Get("invert", "+") == "-" ? "-" : ""); +    const QString turbo = QString::fromStdString(param.Get("turbo", false) ? "$" : "");      const auto common_button_name = input_subsystem->GetButtonName(param);      // Retrieve the names from Qt      if (param.Get("engine", "") == "keyboard") {          const QString button_str = GetKeyName(param.Get("code", 0)); -        return QObject::tr("%1%2%3").arg(toggle, inverted, button_str); +        return QObject::tr("%1%2%3%4").arg(turbo, toggle, inverted, button_str);      }      if (common_button_name == Common::Input::ButtonNames::Invalid) { @@ -201,7 +202,7 @@ QString ConfigureInputPlayer::ButtonToText(const Common::ParamPackage& param) {      if (common_button_name == Common::Input::ButtonNames::Value) {          if (param.Has("hat")) {              const QString hat = GetDirectionName(param.Get("direction", "")); -            return QObject::tr("%1%2Hat %3").arg(toggle, inverted, hat); +            return QObject::tr("%1%2%3Hat %4").arg(turbo, toggle, inverted, hat);          }          if (param.Has("axis")) {              const QString axis = QString::fromStdString(param.Get("axis", "")); @@ -219,13 +220,13 @@ QString ConfigureInputPlayer::ButtonToText(const Common::ParamPackage& param) {          }          if (param.Has("button")) {              const QString button = QString::fromStdString(param.Get("button", "")); -            return QObject::tr("%1%2Button %3").arg(toggle, inverted, button); +            return QObject::tr("%1%2%3Button %4").arg(turbo, toggle, inverted, button);          }      }      QString button_name = GetButtonName(common_button_name);      if (param.Has("hat")) { -        return QObject::tr("%1%2Hat %3").arg(toggle, inverted, button_name); +        return QObject::tr("%1%2%3Hat %4").arg(turbo, toggle, inverted, button_name);      }      if (param.Has("axis")) {          return QObject::tr("%1%2Axis %3").arg(toggle, inverted, button_name); @@ -234,7 +235,7 @@ QString ConfigureInputPlayer::ButtonToText(const Common::ParamPackage& param) {          return QObject::tr("%1%2Axis %3").arg(toggle, inverted, button_name);      }      if (param.Has("button")) { -        return QObject::tr("%1%2Button %3").arg(toggle, inverted, button_name); +        return QObject::tr("%1%2%3Button %4").arg(turbo, toggle, inverted, button_name);      }      return QObject::tr("[unknown]"); @@ -395,6 +396,12 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i                              button_map[button_id]->setText(ButtonToText(param));                              emulated_controller->SetButtonParam(button_id, param);                          }); +                        context_menu.addAction(tr("Turbo button"), [&] { +                            const bool turbo_value = !param.Get("turbo", false); +                            param.Set("turbo", turbo_value); +                            button_map[button_id]->setText(ButtonToText(param)); +                            emulated_controller->SetButtonParam(button_id, param); +                        });                      }                      if (param.Has("axis")) {                          context_menu.addAction(tr("Invert axis"), [&] { | 
