diff options
| author | 2020-09-30 21:24:11 +1000 | |
|---|---|---|
| committer | 2020-09-30 21:24:11 +1000 | |
| commit | 4d0ae1a17a031488eadfa9133dac157fb71900c0 (patch) | |
| tree | 166c4c4e09b828b4c987c6aacf00f5a041a79588 /src | |
| parent | Merge pull request #4726 from lioncash/applet (diff) | |
| parent | First implementation of controller rumble (diff) | |
| download | yuzu-4d0ae1a17a031488eadfa9133dac157fb71900c0.tar.gz yuzu-4d0ae1a17a031488eadfa9133dac157fb71900c0.tar.xz yuzu-4d0ae1a17a031488eadfa9133dac157fb71900c0.zip | |
Merge pull request #4291 from german77/ImplementControllerRumble
input_common: First implementation of controller rumble
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/frontend/input.h | 3 | ||||
| -rw-r--r-- | src/core/hle/service/hid/controllers/npad.cpp | 25 | ||||
| -rw-r--r-- | src/core/hle/service/hid/controllers/npad.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/hid/hid.cpp | 8 | ||||
| -rw-r--r-- | src/input_common/sdl/sdl_impl.cpp | 39 |
5 files changed, 63 insertions, 14 deletions
diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h index 9da0d2829..277b70e53 100644 --- a/src/core/frontend/input.h +++ b/src/core/frontend/input.h | |||
| @@ -33,6 +33,9 @@ public: | |||
| 33 | virtual bool GetAnalogDirectionStatus(AnalogDirection direction) const { | 33 | virtual bool GetAnalogDirectionStatus(AnalogDirection direction) const { |
| 34 | return {}; | 34 | return {}; |
| 35 | } | 35 | } |
| 36 | virtual bool SetRumblePlay(f32 amp_high, f32 amp_low, f32 freq_high, f32 freq_low) const { | ||
| 37 | return {}; | ||
| 38 | } | ||
| 36 | }; | 39 | }; |
| 37 | 40 | ||
| 38 | /// An abstract class template for a factory that can create input devices. | 41 | /// An abstract class template for a factory that can create input devices. |
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index e34ee519e..fb007767d 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp | |||
| @@ -665,20 +665,31 @@ void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) | |||
| 665 | } | 665 | } |
| 666 | } | 666 | } |
| 667 | 667 | ||
| 668 | void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids, | 668 | void Controller_NPad::VibrateController(const std::vector<u32>& controllers, |
| 669 | const std::vector<Vibration>& vibrations) { | 669 | const std::vector<Vibration>& vibrations) { |
| 670 | LOG_DEBUG(Service_HID, "(STUBBED) called"); | 670 | LOG_TRACE(Service_HID, "called"); |
| 671 | 671 | ||
| 672 | if (!Settings::values.vibration_enabled || !can_controllers_vibrate) { | 672 | if (!Settings::values.vibration_enabled || !can_controllers_vibrate) { |
| 673 | return; | 673 | return; |
| 674 | } | 674 | } |
| 675 | for (std::size_t i = 0; i < controller_ids.size(); i++) { | 675 | bool success = true; |
| 676 | std::size_t controller_pos = NPadIdToIndex(static_cast<u32>(i)); | 676 | for (std::size_t i = 0; i < controllers.size(); ++i) { |
| 677 | if (connected_controllers[controller_pos].is_connected) { | 677 | if (!connected_controllers[i].is_connected) { |
| 678 | // TODO(ogniK): Vibrate the physical controller | 678 | continue; |
| 679 | } | ||
| 680 | using namespace Settings::NativeButton; | ||
| 681 | const auto& button_state = buttons[i]; | ||
| 682 | if (button_state[A - BUTTON_HID_BEGIN]) { | ||
| 683 | if (button_state[A - BUTTON_HID_BEGIN]->SetRumblePlay( | ||
| 684 | vibrations[0].amp_high, vibrations[0].amp_low, vibrations[0].freq_high, | ||
| 685 | vibrations[0].freq_low)) { | ||
| 686 | success = false; | ||
| 687 | } | ||
| 679 | } | 688 | } |
| 680 | } | 689 | } |
| 681 | last_processed_vibration = vibrations.back(); | 690 | if (success) { |
| 691 | last_processed_vibration = vibrations.back(); | ||
| 692 | } | ||
| 682 | } | 693 | } |
| 683 | 694 | ||
| 684 | Controller_NPad::Vibration Controller_NPad::GetLastVibration() const { | 695 | Controller_NPad::Vibration Controller_NPad::GetLastVibration() const { |
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 0fa7455ba..e65277c7b 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h | |||
| @@ -125,7 +125,7 @@ public: | |||
| 125 | 125 | ||
| 126 | void SetNpadMode(u32 npad_id, NPadAssignments assignment_mode); | 126 | void SetNpadMode(u32 npad_id, NPadAssignments assignment_mode); |
| 127 | 127 | ||
| 128 | void VibrateController(const std::vector<u32>& controller_ids, | 128 | void VibrateController(const std::vector<u32>& controllers, |
| 129 | const std::vector<Vibration>& vibrations); | 129 | const std::vector<Vibration>& vibrations); |
| 130 | 130 | ||
| 131 | Vibration GetLastVibration() const; | 131 | Vibration GetLastVibration() const; |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 9a7e5e265..90a71ab1c 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -817,18 +817,18 @@ void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) { | |||
| 817 | 817 | ||
| 818 | void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) { | 818 | void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) { |
| 819 | IPC::RequestParser rp{ctx}; | 819 | IPC::RequestParser rp{ctx}; |
| 820 | const auto controller_id{rp.Pop<u32>()}; | 820 | const auto controller{rp.Pop<u32>()}; |
| 821 | const auto vibration_values{rp.PopRaw<Controller_NPad::Vibration>()}; | 821 | const auto vibration_values{rp.PopRaw<Controller_NPad::Vibration>()}; |
| 822 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 822 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 823 | 823 | ||
| 824 | LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", controller_id, | 824 | LOG_DEBUG(Service_HID, "called, controller={}, applet_resource_user_id={}", controller, |
| 825 | applet_resource_user_id); | 825 | applet_resource_user_id); |
| 826 | 826 | ||
| 827 | IPC::ResponseBuilder rb{ctx, 2}; | 827 | IPC::ResponseBuilder rb{ctx, 2}; |
| 828 | rb.Push(RESULT_SUCCESS); | 828 | rb.Push(RESULT_SUCCESS); |
| 829 | 829 | ||
| 830 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 830 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 831 | .VibrateController({controller_id}, {vibration_values}); | 831 | .VibrateController({controller}, {vibration_values}); |
| 832 | } | 832 | } |
| 833 | 833 | ||
| 834 | void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) { | 834 | void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) { |
| @@ -846,8 +846,6 @@ void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) { | |||
| 846 | 846 | ||
| 847 | std::memcpy(controller_list.data(), controllers.data(), controllers.size()); | 847 | std::memcpy(controller_list.data(), controllers.data(), controllers.size()); |
| 848 | std::memcpy(vibration_list.data(), vibrations.data(), vibrations.size()); | 848 | std::memcpy(vibration_list.data(), vibrations.data(), vibrations.size()); |
| 849 | std::transform(controller_list.begin(), controller_list.end(), controller_list.begin(), | ||
| 850 | [](u32 controller_id) { return controller_id - 3; }); | ||
| 851 | 849 | ||
| 852 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 850 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 853 | .VibrateController(controller_list, vibration_list); | 851 | .VibrateController(controller_list, vibration_list); |
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp index a9e676f4b..27a96c18b 100644 --- a/src/input_common/sdl/sdl_impl.cpp +++ b/src/input_common/sdl/sdl_impl.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <array> | 6 | #include <array> |
| 7 | #include <atomic> | 7 | #include <atomic> |
| 8 | #include <chrono> | ||
| 8 | #include <cmath> | 9 | #include <cmath> |
| 9 | #include <functional> | 10 | #include <functional> |
| 10 | #include <mutex> | 11 | #include <mutex> |
| @@ -78,6 +79,33 @@ public: | |||
| 78 | return state.axes.at(axis) / (32767.0f * range); | 79 | return state.axes.at(axis) / (32767.0f * range); |
| 79 | } | 80 | } |
| 80 | 81 | ||
| 82 | bool RumblePlay(f32 amp_low, f32 amp_high, int time) { | ||
| 83 | const u16 raw_amp_low = static_cast<u16>(amp_low * 0xFFFF); | ||
| 84 | const u16 raw_amp_high = static_cast<u16>(amp_high * 0xFFFF); | ||
| 85 | // Lower drastically the number of state changes | ||
| 86 | if (raw_amp_low >> 11 == last_state_rumble_low >> 11 && | ||
| 87 | raw_amp_high >> 11 == last_state_rumble_high >> 11) { | ||
| 88 | if (raw_amp_low + raw_amp_high != 0 || | ||
| 89 | last_state_rumble_low + last_state_rumble_high == 0) { | ||
| 90 | return false; | ||
| 91 | } | ||
| 92 | } | ||
| 93 | // Don't change state if last vibration was < 20ms | ||
| 94 | const auto now = std::chrono::system_clock::now(); | ||
| 95 | if (std::chrono::duration_cast<std::chrono::milliseconds>(now - last_vibration) < | ||
| 96 | std::chrono::milliseconds(20)) { | ||
| 97 | return raw_amp_low + raw_amp_high == 0; | ||
| 98 | } | ||
| 99 | |||
| 100 | last_vibration = now; | ||
| 101 | last_state_rumble_low = raw_amp_low; | ||
| 102 | last_state_rumble_high = raw_amp_high; | ||
| 103 | if (sdl_joystick) { | ||
| 104 | SDL_JoystickRumble(sdl_joystick.get(), raw_amp_low, raw_amp_high, time); | ||
| 105 | } | ||
| 106 | return false; | ||
| 107 | } | ||
| 108 | |||
| 81 | std::tuple<float, float> GetAnalog(int axis_x, int axis_y, float range) const { | 109 | std::tuple<float, float> GetAnalog(int axis_x, int axis_y, float range) const { |
| 82 | float x = GetAxis(axis_x, range); | 110 | float x = GetAxis(axis_x, range); |
| 83 | float y = GetAxis(axis_y, range); | 111 | float y = GetAxis(axis_y, range); |
| @@ -139,6 +167,9 @@ private: | |||
| 139 | } state; | 167 | } state; |
| 140 | std::string guid; | 168 | std::string guid; |
| 141 | int port; | 169 | int port; |
| 170 | u16 last_state_rumble_high; | ||
| 171 | u16 last_state_rumble_low; | ||
| 172 | std::chrono::time_point<std::chrono::system_clock> last_vibration; | ||
| 142 | std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick; | 173 | std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick; |
| 143 | std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller; | 174 | std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller; |
| 144 | mutable std::mutex mutex; | 175 | mutable std::mutex mutex; |
| @@ -207,7 +238,7 @@ void SDLState::InitJoystick(int joystick_index) { | |||
| 207 | sdl_gamecontroller = SDL_GameControllerOpen(joystick_index); | 238 | sdl_gamecontroller = SDL_GameControllerOpen(joystick_index); |
| 208 | } | 239 | } |
| 209 | if (!sdl_joystick) { | 240 | if (!sdl_joystick) { |
| 210 | LOG_ERROR(Input, "failed to open joystick {}", joystick_index); | 241 | LOG_ERROR(Input, "Failed to open joystick {}", joystick_index); |
| 211 | return; | 242 | return; |
| 212 | } | 243 | } |
| 213 | const std::string guid = GetGUID(sdl_joystick); | 244 | const std::string guid = GetGUID(sdl_joystick); |
| @@ -303,6 +334,12 @@ public: | |||
| 303 | return joystick->GetButton(button); | 334 | return joystick->GetButton(button); |
| 304 | } | 335 | } |
| 305 | 336 | ||
| 337 | bool SetRumblePlay(f32 amp_high, f32 amp_low, f32 freq_high, f32 freq_low) const override { | ||
| 338 | const f32 new_amp_low = pow(amp_low, 0.5f) * (3.0f - 2.0f * pow(amp_low, 0.15f)); | ||
| 339 | const f32 new_amp_high = pow(amp_high, 0.5f) * (3.0f - 2.0f * pow(amp_high, 0.15f)); | ||
| 340 | return joystick->RumblePlay(new_amp_low, new_amp_high, 250); | ||
| 341 | } | ||
| 342 | |||
| 306 | private: | 343 | private: |
| 307 | std::shared_ptr<SDLJoystick> joystick; | 344 | std::shared_ptr<SDLJoystick> joystick; |
| 308 | int button; | 345 | int button; |