diff options
| author | 2020-07-10 21:20:50 -0500 | |
|---|---|---|
| committer | 2020-09-29 10:38:25 -0400 | |
| commit | ab88c2f6112edba35bfa91ee8864e760728d16e8 (patch) | |
| tree | 4c7647f97153276733896cbc6e35d929db926b82 | |
| parent | Merge pull request #4719 from lioncash/audio-warn (diff) | |
| download | yuzu-ab88c2f6112edba35bfa91ee8864e760728d16e8.tar.gz yuzu-ab88c2f6112edba35bfa91ee8864e760728d16e8.tar.xz yuzu-ab88c2f6112edba35bfa91ee8864e760728d16e8.zip | |
First implementation of controller rumble
Diffstat (limited to '')
| -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 620386cd1..83c3beab6 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp | |||
| @@ -609,20 +609,31 @@ void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) | |||
| 609 | } | 609 | } |
| 610 | } | 610 | } |
| 611 | 611 | ||
| 612 | void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids, | 612 | void Controller_NPad::VibrateController(const std::vector<u32>& controllers, |
| 613 | const std::vector<Vibration>& vibrations) { | 613 | const std::vector<Vibration>& vibrations) { |
| 614 | LOG_DEBUG(Service_HID, "(STUBBED) called"); | 614 | LOG_TRACE(Service_HID, "called"); |
| 615 | 615 | ||
| 616 | if (!Settings::values.vibration_enabled || !can_controllers_vibrate) { | 616 | if (!Settings::values.vibration_enabled || !can_controllers_vibrate) { |
| 617 | return; | 617 | return; |
| 618 | } | 618 | } |
| 619 | for (std::size_t i = 0; i < controller_ids.size(); i++) { | 619 | bool success = true; |
| 620 | std::size_t controller_pos = NPadIdToIndex(static_cast<u32>(i)); | 620 | for (std::size_t i = 0; i < controllers.size(); ++i) { |
| 621 | if (connected_controllers[controller_pos].is_connected) { | 621 | if (!connected_controllers[i].is_connected) { |
| 622 | // TODO(ogniK): Vibrate the physical controller | 622 | continue; |
| 623 | } | ||
| 624 | using namespace Settings::NativeButton; | ||
| 625 | const auto& button_state = buttons[i]; | ||
| 626 | if (button_state[A - BUTTON_HID_BEGIN]) { | ||
| 627 | if (button_state[A - BUTTON_HID_BEGIN]->SetRumblePlay( | ||
| 628 | vibrations[0].amp_high, vibrations[0].amp_low, vibrations[0].freq_high, | ||
| 629 | vibrations[0].freq_low)) { | ||
| 630 | success = false; | ||
| 631 | } | ||
| 623 | } | 632 | } |
| 624 | } | 633 | } |
| 625 | last_processed_vibration = vibrations.back(); | 634 | if (success) { |
| 635 | last_processed_vibration = vibrations.back(); | ||
| 636 | } | ||
| 626 | } | 637 | } |
| 627 | 638 | ||
| 628 | Controller_NPad::Vibration Controller_NPad::GetLastVibration() const { | 639 | 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 654d97c3f..0cff6821f 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h | |||
| @@ -121,7 +121,7 @@ public: | |||
| 121 | 121 | ||
| 122 | void SetNpadMode(u32 npad_id, NPadAssignments assignment_mode); | 122 | void SetNpadMode(u32 npad_id, NPadAssignments assignment_mode); |
| 123 | 123 | ||
| 124 | void VibrateController(const std::vector<u32>& controller_ids, | 124 | void VibrateController(const std::vector<u32>& controllers, |
| 125 | const std::vector<Vibration>& vibrations); | 125 | const std::vector<Vibration>& vibrations); |
| 126 | 126 | ||
| 127 | Vibration GetLastVibration() const; | 127 | Vibration GetLastVibration() const; |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 395e83b3f..dc198791d 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -802,18 +802,18 @@ void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) { | |||
| 802 | 802 | ||
| 803 | void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) { | 803 | void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) { |
| 804 | IPC::RequestParser rp{ctx}; | 804 | IPC::RequestParser rp{ctx}; |
| 805 | const auto controller_id{rp.Pop<u32>()}; | 805 | const auto controller{rp.Pop<u32>()}; |
| 806 | const auto vibration_values{rp.PopRaw<Controller_NPad::Vibration>()}; | 806 | const auto vibration_values{rp.PopRaw<Controller_NPad::Vibration>()}; |
| 807 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 807 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 808 | 808 | ||
| 809 | LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", controller_id, | 809 | LOG_DEBUG(Service_HID, "called, controller={}, applet_resource_user_id={}", controller, |
| 810 | applet_resource_user_id); | 810 | applet_resource_user_id); |
| 811 | 811 | ||
| 812 | IPC::ResponseBuilder rb{ctx, 2}; | 812 | IPC::ResponseBuilder rb{ctx, 2}; |
| 813 | rb.Push(RESULT_SUCCESS); | 813 | rb.Push(RESULT_SUCCESS); |
| 814 | 814 | ||
| 815 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 815 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 816 | .VibrateController({controller_id}, {vibration_values}); | 816 | .VibrateController({controller}, {vibration_values}); |
| 817 | } | 817 | } |
| 818 | 818 | ||
| 819 | void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) { | 819 | void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) { |
| @@ -831,8 +831,6 @@ void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) { | |||
| 831 | 831 | ||
| 832 | std::memcpy(controller_list.data(), controllers.data(), controllers.size()); | 832 | std::memcpy(controller_list.data(), controllers.data(), controllers.size()); |
| 833 | std::memcpy(vibration_list.data(), vibrations.data(), vibrations.size()); | 833 | std::memcpy(vibration_list.data(), vibrations.data(), vibrations.size()); |
| 834 | std::transform(controller_list.begin(), controller_list.end(), controller_list.begin(), | ||
| 835 | [](u32 controller_id) { return controller_id - 3; }); | ||
| 836 | 834 | ||
| 837 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 835 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 838 | .VibrateController(controller_list, vibration_list); | 836 | .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; |