diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/frontend/input.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/hid/controllers/npad.cpp | 51 | ||||
| -rw-r--r-- | src/input_common/sdl/sdl_impl.cpp | 54 |
3 files changed, 72 insertions, 35 deletions
diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h index 277b70e53..fb2ce2514 100644 --- a/src/core/frontend/input.h +++ b/src/core/frontend/input.h | |||
| @@ -33,7 +33,7 @@ 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 { | 36 | virtual bool SetRumblePlay(f32 amp_low, f32 freq_low, f32 amp_high, f32 freq_high) const { |
| 37 | return {}; | 37 | return {}; |
| 38 | } | 38 | } |
| 39 | }; | 39 | }; |
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 924f209c0..cc54b164d 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp | |||
| @@ -698,16 +698,57 @@ void Controller_NPad::VibrateController(const std::vector<DeviceHandle>& vibrati | |||
| 698 | continue; | 698 | continue; |
| 699 | } | 699 | } |
| 700 | 700 | ||
| 701 | // Filter out vibrations with equivalent values to reduce unnecessary state changes. | ||
| 702 | if (vibration_values[i].amp_low == | ||
| 703 | latest_vibration_values[npad_index][device_index].amp_low && | ||
| 704 | vibration_values[i].amp_high == | ||
| 705 | latest_vibration_values[npad_index][device_index].amp_high) { | ||
| 706 | continue; | ||
| 707 | } | ||
| 708 | |||
| 709 | // Filter out non-zero vibrations that are within 0.015625 absolute amplitude of each other. | ||
| 710 | if ((vibration_values[i].amp_low != 0.0f || vibration_values[i].amp_high != 0.0f) && | ||
| 711 | (latest_vibration_values[npad_index][device_index].amp_low != 0.0f || | ||
| 712 | latest_vibration_values[npad_index][device_index].amp_high != 0.0f) && | ||
| 713 | (abs(vibration_values[i].amp_low - | ||
| 714 | latest_vibration_values[npad_index][device_index].amp_low) < 0.015625f && | ||
| 715 | abs(vibration_values[i].amp_high - | ||
| 716 | latest_vibration_values[npad_index][device_index].amp_high) < 0.015625f)) { | ||
| 717 | continue; | ||
| 718 | } | ||
| 719 | |||
| 701 | using namespace Settings::NativeButton; | 720 | using namespace Settings::NativeButton; |
| 702 | const auto& button_state = buttons[npad_index]; | 721 | const auto& button_state = buttons[npad_index]; |
| 703 | 722 | ||
| 704 | // TODO: Vibrate left/right vibration motors independently if possible. | 723 | // TODO: Vibrate left/right vibration motors independently if possible. |
| 705 | button_state[A - BUTTON_HID_BEGIN]->SetRumblePlay( | 724 | const bool success = button_state[A - BUTTON_HID_BEGIN]->SetRumblePlay( |
| 706 | vibration_values[i].amp_high * Settings::values.vibration_strength.GetValue() / 100, | ||
| 707 | vibration_values[i].amp_low * Settings::values.vibration_strength.GetValue() / 100, | 725 | vibration_values[i].amp_low * Settings::values.vibration_strength.GetValue() / 100, |
| 708 | vibration_values[i].freq_high, vibration_values[i].freq_low); | 726 | vibration_values[i].freq_low, |
| 709 | 727 | vibration_values[i].amp_high * Settings::values.vibration_strength.GetValue() / 100, | |
| 710 | latest_vibration_values[npad_index][device_index] = vibration_values[i]; | 728 | vibration_values[i].freq_high); |
| 729 | |||
| 730 | if (success) { | ||
| 731 | switch (connected_controllers[npad_index].type) { | ||
| 732 | case NPadControllerType::None: | ||
| 733 | UNREACHABLE(); | ||
| 734 | break; | ||
| 735 | case NPadControllerType::ProController: | ||
| 736 | case NPadControllerType::Handheld: | ||
| 737 | case NPadControllerType::JoyDual: | ||
| 738 | // Since we can't vibrate motors independently yet, we can reduce state changes by | ||
| 739 | // assigning all 3 device indices the current vibration value. | ||
| 740 | latest_vibration_values[npad_index][0] = vibration_values[i]; | ||
| 741 | latest_vibration_values[npad_index][1] = vibration_values[i]; | ||
| 742 | latest_vibration_values[npad_index][2] = vibration_values[i]; | ||
| 743 | break; | ||
| 744 | case NPadControllerType::JoyLeft: | ||
| 745 | case NPadControllerType::JoyRight: | ||
| 746 | case NPadControllerType::Pokeball: | ||
| 747 | default: | ||
| 748 | latest_vibration_values[npad_index][device_index] = vibration_values[i]; | ||
| 749 | break; | ||
| 750 | } | ||
| 751 | } | ||
| 711 | } | 752 | } |
| 712 | } | 753 | } |
| 713 | 754 | ||
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp index 10883e2d9..18fb2ac5e 100644 --- a/src/input_common/sdl/sdl_impl.cpp +++ b/src/input_common/sdl/sdl_impl.cpp | |||
| @@ -80,30 +80,24 @@ public: | |||
| 80 | return static_cast<float>(state.axes.at(axis)) / (32767.0f * range); | 80 | return static_cast<float>(state.axes.at(axis)) / (32767.0f * range); |
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | bool RumblePlay(f32 amp_low, f32 amp_high, u32 time) { | 83 | bool RumblePlay(u16 amp_low, u16 amp_high) { |
| 84 | const u16 raw_amp_low = static_cast<u16>(amp_low * 0xFFFF); | 84 | using std::chrono::duration_cast; |
| 85 | const u16 raw_amp_high = static_cast<u16>(amp_high * 0xFFFF); | 85 | using std::chrono::milliseconds; |
| 86 | // Lower drastically the number of state changes | 86 | using std::chrono::steady_clock; |
| 87 | if (raw_amp_low >> 11 == last_state_rumble_low >> 11 && | 87 | |
| 88 | raw_amp_high >> 11 == last_state_rumble_high >> 11) { | 88 | // Prevent vibrations less than 10ms apart from each other. |
| 89 | if (raw_amp_low + raw_amp_high != 0 || | 89 | if (duration_cast<milliseconds>(steady_clock::now() - last_vibration) < milliseconds(10)) { |
| 90 | last_state_rumble_low + last_state_rumble_high == 0) { | 90 | return false; |
| 91 | return false; | 91 | }; |
| 92 | } | 92 | |
| 93 | } | 93 | last_vibration = steady_clock::now(); |
| 94 | // Don't change state if last vibration was < 20ms | 94 | |
| 95 | const auto now = std::chrono::system_clock::now(); | 95 | if (sdl_controller != nullptr) { |
| 96 | if (std::chrono::duration_cast<std::chrono::milliseconds>(now - last_vibration) < | 96 | return SDL_GameControllerRumble(sdl_controller.get(), amp_low, amp_high, 0) == 0; |
| 97 | std::chrono::milliseconds(20)) { | 97 | } else if (sdl_joystick != nullptr) { |
| 98 | return raw_amp_low + raw_amp_high == 0; | 98 | return SDL_JoystickRumble(sdl_joystick.get(), amp_low, amp_high, 0) == 0; |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | last_vibration = now; | ||
| 102 | last_state_rumble_low = raw_amp_low; | ||
| 103 | last_state_rumble_high = raw_amp_high; | ||
| 104 | if (sdl_joystick) { | ||
| 105 | SDL_JoystickRumble(sdl_joystick.get(), raw_amp_low, raw_amp_high, time); | ||
| 106 | } | ||
| 107 | return false; | 101 | return false; |
| 108 | } | 102 | } |
| 109 | 103 | ||
| @@ -172,13 +166,13 @@ private: | |||
| 172 | } state; | 166 | } state; |
| 173 | std::string guid; | 167 | std::string guid; |
| 174 | int port; | 168 | int port; |
| 175 | u16 last_state_rumble_high = 0; | ||
| 176 | u16 last_state_rumble_low = 0; | ||
| 177 | std::chrono::time_point<std::chrono::system_clock> last_vibration; | ||
| 178 | std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick; | 169 | std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick; |
| 179 | std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller; | 170 | std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller; |
| 180 | mutable std::mutex mutex; | 171 | mutable std::mutex mutex; |
| 181 | 172 | ||
| 173 | // This is the timepoint of the last vibration and is used to ensure vibrations are 10ms apart. | ||
| 174 | std::chrono::steady_clock::time_point last_vibration; | ||
| 175 | |||
| 182 | // Motion is initialized without PID values as motion input is not aviable for SDL2 | 176 | // Motion is initialized without PID values as motion input is not aviable for SDL2 |
| 183 | MotionInput motion{0.0f, 0.0f, 0.0f}; | 177 | MotionInput motion{0.0f, 0.0f, 0.0f}; |
| 184 | }; | 178 | }; |
| @@ -327,10 +321,12 @@ public: | |||
| 327 | return joystick->GetButton(button); | 321 | return joystick->GetButton(button); |
| 328 | } | 322 | } |
| 329 | 323 | ||
| 330 | bool SetRumblePlay(f32 amp_high, f32 amp_low, f32 freq_high, f32 freq_low) const override { | 324 | bool SetRumblePlay(f32 amp_low, f32 freq_low, f32 amp_high, f32 freq_high) const override { |
| 331 | const f32 new_amp_low = pow(amp_low, 0.5f) * (3.0f - 2.0f * pow(amp_low, 0.15f)); | 325 | const u16 processed_amp_low = |
| 332 | const f32 new_amp_high = pow(amp_high, 0.5f) * (3.0f - 2.0f * pow(amp_high, 0.15f)); | 326 | static_cast<u16>(pow(amp_low, 0.5f) * (3.0f - 2.0f * pow(amp_low, 0.15f)) * 0xFFFF); |
| 333 | return joystick->RumblePlay(new_amp_low, new_amp_high, 250); | 327 | const u16 processed_amp_high = |
| 328 | static_cast<u16>(pow(amp_high, 0.5f) * (3.0f - 2.0f * pow(amp_high, 0.15f)) * 0xFFFF); | ||
| 329 | return joystick->RumblePlay(processed_amp_low, processed_amp_high); | ||
| 334 | } | 330 | } |
| 335 | 331 | ||
| 336 | private: | 332 | private: |