From 48b6d41f1b95cd61d6c60c3db1a5b89ac788a66a Mon Sep 17 00:00:00 2001 From: german77 Date: Thu, 22 Jul 2021 19:59:26 -0500 Subject: [PATCH] input_common: Improve SDL joystick and hide toggle option --- src/input_common/main.cpp | 8 +- src/input_common/mouse/mouse_poller.cpp | 1 + src/input_common/sdl/sdl_impl.cpp | 87 ++++++++++++++----- .../configuration/configure_input_player.cpp | 13 +-- 4 files changed, 76 insertions(+), 33 deletions(-) diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 8de3d4520e..ff23230f00 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -304,10 +304,10 @@ std::vector> InputSubsystem::GetPollers([ } std::string GenerateKeyboardParam(int key_code) { - Common::ParamPackage param{ - {"engine", "keyboard"}, - {"code", std::to_string(key_code)}, - }; + Common::ParamPackage param; + param.Set("engine", "keyboard"); + param.Set("code", key_code); + param.Set("toggle", false); return param.Serialize(); } diff --git a/src/input_common/mouse/mouse_poller.cpp b/src/input_common/mouse/mouse_poller.cpp index efcdd85d2c..090b26972d 100644 --- a/src/input_common/mouse/mouse_poller.cpp +++ b/src/input_common/mouse/mouse_poller.cpp @@ -57,6 +57,7 @@ Common::ParamPackage MouseButtonFactory::GetNextInput() const { if (pad.button != MouseInput::MouseButton::Undefined) { params.Set("engine", "mouse"); params.Set("button", static_cast(pad.button)); + params.Set("toggle", false); return params; } } diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp index 70a0ba09c6..f1f950d8a7 100644 --- a/src/input_common/sdl/sdl_impl.cpp +++ b/src/input_common/sdl/sdl_impl.cpp @@ -82,6 +82,12 @@ public: state.buttons.insert_or_assign(button, value); } + void PreSetButton(int button) { + if (!state.buttons.contains(button)) { + SetButton(button, false); + } + } + void SetMotion(SDL_ControllerSensorEvent event) { constexpr float gravity_constant = 9.80665f; std::lock_guard lock{mutex}; @@ -155,9 +161,16 @@ public: state.axes.insert_or_assign(axis, value); } - float GetAxis(int axis, float range) const { + void PreSetAxis(int axis) { + if (!state.axes.contains(axis)) { + SetAxis(axis, 0); + } + } + + float GetAxis(int axis, float range, float offset) const { std::lock_guard lock{mutex}; - return static_cast(state.axes.at(axis)) / (32767.0f * range); + const float value = static_cast(state.axes.at(axis)) / 32767.0f; + return (value + offset) / range; } bool RumblePlay(u16 amp_low, u16 amp_high) { @@ -174,9 +187,10 @@ public: return false; } - std::tuple GetAnalog(int axis_x, int axis_y, float range) const { - float x = GetAxis(axis_x, range); - float y = GetAxis(axis_y, range); + std::tuple GetAnalog(int axis_x, int axis_y, float range, float offset_x, + float offset_y) const { + float x = GetAxis(axis_x, range, offset_x); + float y = GetAxis(axis_y, range, offset_y); y = -y; // 3DS uses an y-axis inverse from SDL // Make sure the coordinates are in the unit circle, @@ -483,7 +497,7 @@ public: trigger_if_greater(trigger_if_greater_) {} bool GetStatus() const override { - const float axis_value = joystick->GetAxis(axis, 1.0f); + const float axis_value = joystick->GetAxis(axis, 1.0f, 0.0f); if (trigger_if_greater) { return axis_value > threshold; } @@ -500,12 +514,14 @@ private: class SDLAnalog final : public Input::AnalogDevice { public: explicit SDLAnalog(std::shared_ptr joystick_, int axis_x_, int axis_y_, - bool invert_x_, bool invert_y_, float deadzone_, float range_) + bool invert_x_, bool invert_y_, float deadzone_, float range_, + float offset_x_, float offset_y_) : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), invert_x(invert_x_), - invert_y(invert_y_), deadzone(deadzone_), range(range_) {} + invert_y(invert_y_), deadzone(deadzone_), range(range_), offset_x(offset_x_), + offset_y(offset_y_) {} std::tuple GetStatus() const override { - auto [x, y] = joystick->GetAnalog(axis_x, axis_y, range); + auto [x, y] = joystick->GetAnalog(axis_x, axis_y, range, offset_x, offset_y); const float r = std::sqrt((x * x) + (y * y)); if (invert_x) { x = -x; @@ -522,8 +538,8 @@ public: } std::tuple GetRawStatus() const override { - const float x = joystick->GetAxis(axis_x, range); - const float y = joystick->GetAxis(axis_y, range); + const float x = joystick->GetAxis(axis_x, range, offset_x); + const float y = joystick->GetAxis(axis_y, range, offset_y); return {x, -y}; } @@ -555,6 +571,8 @@ private: const bool invert_y; const float deadzone; const float range; + const float offset_x; + const float offset_y; }; class SDLVibration final : public Input::VibrationDevice { @@ -621,7 +639,7 @@ public: trigger_if_greater(trigger_if_greater_) {} Input::MotionStatus GetStatus() const override { - const float axis_value = joystick->GetAxis(axis, 1.0f); + const float axis_value = joystick->GetAxis(axis, 1.0f, 0.0f); bool trigger = axis_value < threshold; if (trigger_if_greater) { trigger = axis_value > threshold; @@ -720,13 +738,13 @@ public: LOG_ERROR(Input, "Unknown direction {}", direction_name); } // This is necessary so accessing GetAxis with axis won't crash - joystick->SetAxis(axis, 0); + joystick->PreSetAxis(axis); return std::make_unique(joystick, axis, threshold, trigger_if_greater); } const int button = params.Get("button", 0); // This is necessary so accessing GetButton with button won't crash - joystick->SetButton(button, false); + joystick->PreSetButton(button); return std::make_unique(joystick, button, toggle); } @@ -757,13 +775,15 @@ public: const std::string invert_y_value = params.Get("invert_y", "+"); const bool invert_x = invert_x_value == "-"; const bool invert_y = invert_y_value == "-"; + const float offset_x = params.Get("offset_x", 0.0f); + const float offset_y = params.Get("offset_y", 0.0f); auto joystick = state.GetSDLJoystickByGUID(guid, port); // This is necessary so accessing GetAxis with axis_x and axis_y won't crash - joystick->SetAxis(axis_x, 0); - joystick->SetAxis(axis_y, 0); + joystick->PreSetAxis(axis_x); + joystick->PreSetAxis(axis_y); return std::make_unique(joystick, axis_x, axis_y, invert_x, invert_y, deadzone, - range); + range, offset_x, offset_y); } private: @@ -844,13 +864,13 @@ public: LOG_ERROR(Input, "Unknown direction {}", direction_name); } // This is necessary so accessing GetAxis with axis won't crash - joystick->SetAxis(axis, 0); + joystick->PreSetAxis(axis); return std::make_unique(joystick, axis, threshold, trigger_if_greater); } const int button = params.Get("button", 0); // This is necessary so accessing GetButton with button won't crash - joystick->SetButton(button, false); + joystick->PreSetButton(button); return std::make_unique(joystick, button); } @@ -995,6 +1015,7 @@ Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid params.Set("port", port); params.Set("guid", std::move(guid)); params.Set("button", button); + params.Set("toggle", false); return params; } @@ -1134,13 +1155,15 @@ Common::ParamPackage BuildParamPackageForBinding(int port, const std::string& gu } Common::ParamPackage BuildParamPackageForAnalog(int port, const std::string& guid, int axis_x, - int axis_y) { + int axis_y, float offset_x, float offset_y) { Common::ParamPackage params; params.Set("engine", "sdl"); params.Set("port", port); params.Set("guid", guid); params.Set("axis_x", axis_x); params.Set("axis_y", axis_y); + params.Set("offset_x", offset_x); + params.Set("offset_y", offset_y); params.Set("invert_x", "+"); params.Set("invert_y", "+"); return params; @@ -1342,24 +1365,39 @@ AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& pa const auto& binding_left_y = SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY); if (params.Has("guid2")) { + joystick2->PreSetAxis(binding_left_x.value.axis); + joystick2->PreSetAxis(binding_left_y.value.axis); + const auto left_offset_x = -joystick2->GetAxis(binding_left_x.value.axis, 1.0f, 0); + const auto left_offset_y = -joystick2->GetAxis(binding_left_y.value.axis, 1.0f, 0); mapping.insert_or_assign( Settings::NativeAnalog::LStick, BuildParamPackageForAnalog(joystick2->GetPort(), joystick2->GetGUID(), - binding_left_x.value.axis, binding_left_y.value.axis)); + binding_left_x.value.axis, binding_left_y.value.axis, + left_offset_x, left_offset_y)); } else { + joystick->PreSetAxis(binding_left_x.value.axis); + joystick->PreSetAxis(binding_left_y.value.axis); + const auto left_offset_x = -joystick->GetAxis(binding_left_x.value.axis, 1.0f, 0); + const auto left_offset_y = -joystick->GetAxis(binding_left_y.value.axis, 1.0f, 0); mapping.insert_or_assign( Settings::NativeAnalog::LStick, BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), - binding_left_x.value.axis, binding_left_y.value.axis)); + binding_left_x.value.axis, binding_left_y.value.axis, + left_offset_x, left_offset_y)); } const auto& binding_right_x = SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX); const auto& binding_right_y = SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY); + joystick->PreSetAxis(binding_right_x.value.axis); + joystick->PreSetAxis(binding_right_y.value.axis); + const auto right_offset_x = -joystick->GetAxis(binding_right_x.value.axis, 1.0f, 0); + const auto right_offset_y = -joystick->GetAxis(binding_right_y.value.axis, 1.0f, 0); mapping.insert_or_assign(Settings::NativeAnalog::RStick, BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), binding_right_x.value.axis, - binding_right_y.value.axis)); + binding_right_y.value.axis, right_offset_x, + right_offset_y)); return mapping; } @@ -1563,8 +1601,9 @@ public: } if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) { + // Set offset to zero since the joystick is not on center auto params = BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), - first_axis, axis); + first_axis, axis, 0, 0); first_axis = -1; return params; } diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 6b9bd05f18..7527c068b9 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -309,11 +309,14 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i buttons_param[button_id].Clear(); button_map[button_id]->setText(tr("[not set]")); }); - context_menu.addAction(tr("Toggle button"), [&] { - const bool toggle_value = !buttons_param[button_id].Get("toggle", false); - buttons_param[button_id].Set("toggle", toggle_value); - button_map[button_id]->setText(ButtonToText(buttons_param[button_id])); - }); + if (buttons_param[button_id].Has("toggle")) { + context_menu.addAction(tr("Toggle button"), [&] { + const bool toggle_value = + !buttons_param[button_id].Get("toggle", false); + buttons_param[button_id].Set("toggle", toggle_value); + button_map[button_id]->setText(ButtonToText(buttons_param[button_id])); + }); + } if (buttons_param[button_id].Has("threshold")) { context_menu.addAction(tr("Set threshold"), [&] { const int button_threshold = static_cast(