diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/frontend/input.h | 7 | ||||
| -rw-r--r-- | src/core/hle/service/hid/controllers/npad.cpp | 48 | ||||
| -rw-r--r-- | src/core/hle/service/hid/controllers/npad.h | 11 | ||||
| -rw-r--r-- | src/core/hle/service/hid/hid.cpp | 1 | ||||
| -rw-r--r-- | src/input_common/gcadapter/gc_adapter.cpp | 6 | ||||
| -rw-r--r-- | src/input_common/gcadapter/gc_adapter.h | 4 | ||||
| -rw-r--r-- | src/input_common/gcadapter/gc_poller.cpp | 50 | ||||
| -rw-r--r-- | src/input_common/gcadapter/gc_poller.h | 11 | ||||
| -rw-r--r-- | src/input_common/main.cpp | 5 | ||||
| -rw-r--r-- | src/input_common/sdl/sdl_impl.cpp | 74 | ||||
| -rw-r--r-- | src/input_common/sdl/sdl_impl.h | 2 | ||||
| -rw-r--r-- | src/input_common/settings.cpp | 21 | ||||
| -rw-r--r-- | src/input_common/settings.h | 32 | ||||
| -rw-r--r-- | src/yuzu/applets/controller.cpp | 2 | ||||
| -rw-r--r-- | src/yuzu/configuration/config.cpp | 61 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_input_player.cpp | 7 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_vibration.cpp | 80 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_vibration.h | 3 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 3 |
19 files changed, 327 insertions, 101 deletions
diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h index fb2ce2514..25ac5af46 100644 --- a/src/core/frontend/input.h +++ b/src/core/frontend/input.h | |||
| @@ -122,6 +122,13 @@ using ButtonDevice = InputDevice<bool>; | |||
| 122 | using AnalogDevice = InputDevice<std::tuple<float, float>>; | 122 | using AnalogDevice = InputDevice<std::tuple<float, float>>; |
| 123 | 123 | ||
| 124 | /** | 124 | /** |
| 125 | * A vibration device is an input device that returns an unsigned byte as status. | ||
| 126 | * It represents whether the vibration device supports vibration or not. | ||
| 127 | * If the status returns 1, it supports vibration. Otherwise, it does not support vibration. | ||
| 128 | */ | ||
| 129 | using VibrationDevice = InputDevice<u8>; | ||
| 130 | |||
| 131 | /** | ||
| 125 | * A motion status is an object that returns a tuple of accelerometer state vector, | 132 | * A motion status is an object that returns a tuple of accelerometer state vector, |
| 126 | * gyroscope state vector, rotation state vector and orientation state matrix. | 133 | * gyroscope state vector, rotation state vector and orientation state matrix. |
| 127 | * | 134 | * |
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index dc9954377..27099de24 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp | |||
| @@ -271,6 +271,10 @@ void Controller_NPad::OnLoadInputDevices() { | |||
| 271 | std::transform(players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, | 271 | std::transform(players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, |
| 272 | players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_END, | 272 | players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_END, |
| 273 | sticks[i].begin(), Input::CreateDevice<Input::AnalogDevice>); | 273 | sticks[i].begin(), Input::CreateDevice<Input::AnalogDevice>); |
| 274 | std::transform(players[i].vibrations.begin() + | ||
| 275 | Settings::NativeVibration::VIBRATION_HID_BEGIN, | ||
| 276 | players[i].vibrations.begin() + Settings::NativeVibration::VIBRATION_HID_END, | ||
| 277 | vibrations[i].begin(), Input::CreateDevice<Input::VibrationDevice>); | ||
| 274 | std::transform(players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_BEGIN, | 278 | std::transform(players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_BEGIN, |
| 275 | players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_END, | 279 | players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_END, |
| 276 | motions[i].begin(), Input::CreateDevice<Input::MotionDevice>); | 280 | motions[i].begin(), Input::CreateDevice<Input::MotionDevice>); |
| @@ -278,8 +282,10 @@ void Controller_NPad::OnLoadInputDevices() { | |||
| 278 | } | 282 | } |
| 279 | 283 | ||
| 280 | void Controller_NPad::OnRelease() { | 284 | void Controller_NPad::OnRelease() { |
| 281 | for (std::size_t index = 0; index < connected_controllers.size(); ++index) { | 285 | for (std::size_t npad_idx = 0; npad_idx < vibrations.size(); ++npad_idx) { |
| 282 | VibrateControllerAtIndex(index, {}); | 286 | for (std::size_t device_idx = 0; device_idx < vibrations[npad_idx].size(); ++device_idx) { |
| 287 | VibrateControllerAtIndex(npad_idx, device_idx); | ||
| 288 | } | ||
| 283 | } | 289 | } |
| 284 | } | 290 | } |
| 285 | 291 | ||
| @@ -674,9 +680,9 @@ void Controller_NPad::SetNpadMode(u32 npad_id, NpadAssignments assignment_mode) | |||
| 674 | } | 680 | } |
| 675 | } | 681 | } |
| 676 | 682 | ||
| 677 | bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index, | 683 | bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index, std::size_t device_index, |
| 678 | const VibrationValue& vibration_value) { | 684 | const VibrationValue& vibration_value) { |
| 679 | if (!connected_controllers[npad_index].is_connected) { | 685 | if (!connected_controllers[npad_index].is_connected || !vibrations[npad_index][device_index]) { |
| 680 | return false; | 686 | return false; |
| 681 | } | 687 | } |
| 682 | 688 | ||
| @@ -686,10 +692,7 @@ bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index, | |||
| 686 | return false; | 692 | return false; |
| 687 | } | 693 | } |
| 688 | 694 | ||
| 689 | using namespace Settings::NativeButton; | 695 | return vibrations[npad_index][device_index]->SetRumblePlay( |
| 690 | const auto& button_state = buttons[npad_index]; | ||
| 691 | |||
| 692 | return button_state[A - BUTTON_HID_BEGIN]->SetRumblePlay( | ||
| 693 | std::min(vibration_value.amp_low * player.vibration_strength / 100.0f, 1.0f), | 696 | std::min(vibration_value.amp_low * player.vibration_strength / 100.0f, 1.0f), |
| 694 | vibration_value.freq_low, | 697 | vibration_value.freq_low, |
| 695 | std::min(vibration_value.amp_high * player.vibration_strength / 100.0f, 1.0f), | 698 | std::min(vibration_value.amp_high * player.vibration_strength / 100.0f, 1.0f), |
| @@ -717,6 +720,11 @@ void Controller_NPad::VibrateControllers(const std::vector<DeviceHandle>& vibrat | |||
| 717 | continue; | 720 | continue; |
| 718 | } | 721 | } |
| 719 | 722 | ||
| 723 | if (vibration_device_handles[i].device_index == DeviceIndex::None) { | ||
| 724 | UNREACHABLE_MSG("DeviceIndex should never be None!"); | ||
| 725 | continue; | ||
| 726 | } | ||
| 727 | |||
| 720 | // Some games try to send mismatched parameters in the device handle, block these. | 728 | // Some games try to send mismatched parameters in the device handle, block these. |
| 721 | if ((connected_controllers[npad_index].type == NPadControllerType::JoyLeft && | 729 | if ((connected_controllers[npad_index].type == NPadControllerType::JoyLeft && |
| 722 | (vibration_device_handles[i].npad_type == NpadType::JoyconRight || | 730 | (vibration_device_handles[i].npad_type == NpadType::JoyconRight || |
| @@ -747,28 +755,8 @@ void Controller_NPad::VibrateControllers(const std::vector<DeviceHandle>& vibrat | |||
| 747 | continue; | 755 | continue; |
| 748 | } | 756 | } |
| 749 | 757 | ||
| 750 | // TODO: Vibrate left/right vibration motors independently if possible. | 758 | if (VibrateControllerAtIndex(npad_index, device_index, vibration_values[i])) { |
| 751 | if (VibrateControllerAtIndex(npad_index, vibration_values[i])) { | 759 | latest_vibration_values[npad_index][device_index] = vibration_values[i]; |
| 752 | switch (connected_controllers[npad_index].type) { | ||
| 753 | case NPadControllerType::None: | ||
| 754 | UNREACHABLE(); | ||
| 755 | break; | ||
| 756 | case NPadControllerType::ProController: | ||
| 757 | case NPadControllerType::Handheld: | ||
| 758 | case NPadControllerType::JoyDual: | ||
| 759 | // Since we can't vibrate motors independently yet, we can reduce state changes by | ||
| 760 | // assigning all 3 device indices the current vibration value. | ||
| 761 | latest_vibration_values[npad_index][0] = vibration_values[i]; | ||
| 762 | latest_vibration_values[npad_index][1] = vibration_values[i]; | ||
| 763 | latest_vibration_values[npad_index][2] = vibration_values[i]; | ||
| 764 | break; | ||
| 765 | case NPadControllerType::JoyLeft: | ||
| 766 | case NPadControllerType::JoyRight: | ||
| 767 | case NPadControllerType::Pokeball: | ||
| 768 | default: | ||
| 769 | latest_vibration_values[npad_index][device_index] = vibration_values[i]; | ||
| 770 | break; | ||
| 771 | } | ||
| 772 | } | 760 | } |
| 773 | } | 761 | } |
| 774 | } | 762 | } |
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 576ef1558..3ae9fb8e6 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h | |||
| @@ -148,7 +148,8 @@ public: | |||
| 148 | 148 | ||
| 149 | void SetNpadMode(u32 npad_id, NpadAssignments assignment_mode); | 149 | void SetNpadMode(u32 npad_id, NpadAssignments assignment_mode); |
| 150 | 150 | ||
| 151 | bool VibrateControllerAtIndex(std::size_t npad_index, const VibrationValue& vibration_value); | 151 | bool VibrateControllerAtIndex(std::size_t npad_index, std::size_t device_index, |
| 152 | const VibrationValue& vibration_value = {}); | ||
| 152 | 153 | ||
| 153 | void VibrateControllers(const std::vector<DeviceHandle>& vibration_device_handles, | 154 | void VibrateControllers(const std::vector<DeviceHandle>& vibration_device_handles, |
| 154 | const std::vector<VibrationValue>& vibration_values); | 155 | const std::vector<VibrationValue>& vibration_values); |
| @@ -399,18 +400,22 @@ private: | |||
| 399 | using StickArray = std::array< | 400 | using StickArray = std::array< |
| 400 | std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>, | 401 | std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>, |
| 401 | 10>; | 402 | 10>; |
| 403 | using VibrationArray = std::array<std::array<std::unique_ptr<Input::VibrationDevice>, | ||
| 404 | Settings::NativeVibration::NUM_VIBRATIONS_HID>, | ||
| 405 | 10>; | ||
| 402 | using MotionArray = std::array< | 406 | using MotionArray = std::array< |
| 403 | std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTION_HID>, | 407 | std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTIONS_HID>, |
| 404 | 10>; | 408 | 10>; |
| 405 | ButtonArray buttons; | 409 | ButtonArray buttons; |
| 406 | StickArray sticks; | 410 | StickArray sticks; |
| 411 | VibrationArray vibrations; | ||
| 407 | MotionArray motions; | 412 | MotionArray motions; |
| 408 | std::vector<u32> supported_npad_id_types{}; | 413 | std::vector<u32> supported_npad_id_types{}; |
| 409 | NpadHoldType hold_type{NpadHoldType::Vertical}; | 414 | NpadHoldType hold_type{NpadHoldType::Vertical}; |
| 410 | NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual}; | 415 | NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual}; |
| 411 | // Each controller should have their own styleset changed event | 416 | // Each controller should have their own styleset changed event |
| 412 | std::array<Kernel::EventPair, 10> styleset_changed_events; | 417 | std::array<Kernel::EventPair, 10> styleset_changed_events; |
| 413 | std::array<std::array<VibrationValue, 3>, 10> latest_vibration_values; | 418 | std::array<std::array<VibrationValue, 2>, 10> latest_vibration_values{}; |
| 414 | std::array<ControllerHolder, 10> connected_controllers{}; | 419 | std::array<ControllerHolder, 10> connected_controllers{}; |
| 415 | std::array<bool, 10> unintended_home_button_input_protection{}; | 420 | std::array<bool, 10> unintended_home_button_input_protection{}; |
| 416 | GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard}; | 421 | GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard}; |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index e88f30d6a..1d882a977 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -998,6 +998,7 @@ void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { | |||
| 998 | break; | 998 | break; |
| 999 | case Controller_NPad::DeviceIndex::None: | 999 | case Controller_NPad::DeviceIndex::None: |
| 1000 | default: | 1000 | default: |
| 1001 | UNREACHABLE_MSG("DeviceIndex should never be None!"); | ||
| 1001 | vibration_device_info.position = VibrationDevicePosition::None; | 1002 | vibration_device_info.position = VibrationDevicePosition::None; |
| 1002 | break; | 1003 | break; |
| 1003 | } | 1004 | } |
diff --git a/src/input_common/gcadapter/gc_adapter.cpp b/src/input_common/gcadapter/gc_adapter.cpp index b912188b6..d80195c82 100644 --- a/src/input_common/gcadapter/gc_adapter.cpp +++ b/src/input_common/gcadapter/gc_adapter.cpp | |||
| @@ -230,10 +230,8 @@ void Adapter::SendVibrations() { | |||
| 230 | vibration_changed = false; | 230 | vibration_changed = false; |
| 231 | } | 231 | } |
| 232 | 232 | ||
| 233 | bool Adapter::RumblePlay(std::size_t port, f32 amplitude) { | 233 | bool Adapter::RumblePlay(std::size_t port, u8 amplitude) { |
| 234 | amplitude = std::clamp(amplitude, 0.0f, 1.0f); | 234 | pads[port].rumble_amplitude = amplitude; |
| 235 | const auto raw_amp = static_cast<u8>(amplitude * 0x8); | ||
| 236 | pads[port].rumble_amplitude = raw_amp; | ||
| 237 | 235 | ||
| 238 | return rumble_enabled; | 236 | return rumble_enabled; |
| 239 | } | 237 | } |
diff --git a/src/input_common/gcadapter/gc_adapter.h b/src/input_common/gcadapter/gc_adapter.h index d28dcfad3..f1256c9da 100644 --- a/src/input_common/gcadapter/gc_adapter.h +++ b/src/input_common/gcadapter/gc_adapter.h | |||
| @@ -77,8 +77,8 @@ public: | |||
| 77 | Adapter(); | 77 | Adapter(); |
| 78 | ~Adapter(); | 78 | ~Adapter(); |
| 79 | 79 | ||
| 80 | /// Request a vibration for a controlelr | 80 | /// Request a vibration for a controller |
| 81 | bool RumblePlay(std::size_t port, f32 amplitude); | 81 | bool RumblePlay(std::size_t port, u8 amplitude); |
| 82 | 82 | ||
| 83 | /// Used for polling | 83 | /// Used for polling |
| 84 | void BeginConfiguration(); | 84 | void BeginConfiguration(); |
diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp index 6bd6f57fc..fe57c13a5 100644 --- a/src/input_common/gcadapter/gc_poller.cpp +++ b/src/input_common/gcadapter/gc_poller.cpp | |||
| @@ -15,7 +15,7 @@ namespace InputCommon { | |||
| 15 | 15 | ||
| 16 | class GCButton final : public Input::ButtonDevice { | 16 | class GCButton final : public Input::ButtonDevice { |
| 17 | public: | 17 | public: |
| 18 | explicit GCButton(u32 port_, s32 button_, GCAdapter::Adapter* adapter) | 18 | explicit GCButton(u32 port_, s32 button_, const GCAdapter::Adapter* adapter) |
| 19 | : port(port_), button(button_), gcadapter(adapter) {} | 19 | : port(port_), button(button_), gcadapter(adapter) {} |
| 20 | 20 | ||
| 21 | ~GCButton() override; | 21 | ~GCButton() override; |
| @@ -27,18 +27,10 @@ public: | |||
| 27 | return false; | 27 | return false; |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | bool SetRumblePlay(f32 amp_high, f32 amp_low, f32 freq_high, f32 freq_low) const override { | ||
| 31 | const float amplitude = amp_high + amp_low > 2.0f ? 1.0f : (amp_high + amp_low) * 0.5f; | ||
| 32 | const auto new_amp = | ||
| 33 | static_cast<f32>(pow(amplitude, 0.5f) * (3.0f - 2.0f * pow(amplitude, 0.15f))); | ||
| 34 | |||
| 35 | return gcadapter->RumblePlay(port, new_amp); | ||
| 36 | } | ||
| 37 | |||
| 38 | private: | 30 | private: |
| 39 | const u32 port; | 31 | const u32 port; |
| 40 | const s32 button; | 32 | const s32 button; |
| 41 | GCAdapter::Adapter* gcadapter; | 33 | const GCAdapter::Adapter* gcadapter; |
| 42 | }; | 34 | }; |
| 43 | 35 | ||
| 44 | class GCAxisButton final : public Input::ButtonDevice { | 36 | class GCAxisButton final : public Input::ButtonDevice { |
| @@ -299,4 +291,42 @@ Common::ParamPackage GCAnalogFactory::GetNextInput() { | |||
| 299 | return params; | 291 | return params; |
| 300 | } | 292 | } |
| 301 | 293 | ||
| 294 | class GCVibration final : public Input::VibrationDevice { | ||
| 295 | public: | ||
| 296 | explicit GCVibration(u32 port_, GCAdapter::Adapter* adapter) | ||
| 297 | : port(port_), gcadapter(adapter) {} | ||
| 298 | |||
| 299 | u8 GetStatus() const override { | ||
| 300 | return gcadapter->RumblePlay(port, 0); | ||
| 301 | } | ||
| 302 | |||
| 303 | bool SetRumblePlay(f32 amp_low, f32 freq_low, f32 amp_high, f32 freq_high) const override { | ||
| 304 | const auto mean_amplitude = (amp_low + amp_high) * 0.5f; | ||
| 305 | const auto processed_amplitude = static_cast<u8>( | ||
| 306 | pow(mean_amplitude, 0.5f) * (3.0f - 2.0f * pow(mean_amplitude, 0.15f)) * 0x8); | ||
| 307 | |||
| 308 | return gcadapter->RumblePlay(port, processed_amplitude); | ||
| 309 | } | ||
| 310 | |||
| 311 | private: | ||
| 312 | const u32 port; | ||
| 313 | GCAdapter::Adapter* gcadapter; | ||
| 314 | }; | ||
| 315 | |||
| 316 | /// An vibration device factory that creates vibration devices from GC Adapter | ||
| 317 | GCVibrationFactory::GCVibrationFactory(std::shared_ptr<GCAdapter::Adapter> adapter_) | ||
| 318 | : adapter(std::move(adapter_)) {} | ||
| 319 | |||
| 320 | /** | ||
| 321 | * Creates a vibration device from a joystick | ||
| 322 | * @param params contains parameters for creating the device: | ||
| 323 | * - "port": the nth gcpad on the adapter | ||
| 324 | */ | ||
| 325 | std::unique_ptr<Input::VibrationDevice> GCVibrationFactory::Create( | ||
| 326 | const Common::ParamPackage& params) { | ||
| 327 | const auto port = static_cast<u32>(params.Get("port", 0)); | ||
| 328 | |||
| 329 | return std::make_unique<GCVibration>(port, adapter.get()); | ||
| 330 | } | ||
| 331 | |||
| 302 | } // namespace InputCommon | 332 | } // namespace InputCommon |
diff --git a/src/input_common/gcadapter/gc_poller.h b/src/input_common/gcadapter/gc_poller.h index 0527f328f..d1271e3ea 100644 --- a/src/input_common/gcadapter/gc_poller.h +++ b/src/input_common/gcadapter/gc_poller.h | |||
| @@ -64,4 +64,15 @@ private: | |||
| 64 | bool polling = false; | 64 | bool polling = false; |
| 65 | }; | 65 | }; |
| 66 | 66 | ||
| 67 | /// A vibration device factory creates vibration devices from GC Adapter | ||
| 68 | class GCVibrationFactory final : public Input::Factory<Input::VibrationDevice> { | ||
| 69 | public: | ||
| 70 | explicit GCVibrationFactory(std::shared_ptr<GCAdapter::Adapter> adapter_); | ||
| 71 | |||
| 72 | std::unique_ptr<Input::VibrationDevice> Create(const Common::ParamPackage& params) override; | ||
| 73 | |||
| 74 | private: | ||
| 75 | std::shared_ptr<GCAdapter::Adapter> adapter; | ||
| 76 | }; | ||
| 77 | |||
| 67 | } // namespace InputCommon | 78 | } // namespace InputCommon |
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index b438482cc..e59ad4ff5 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp | |||
| @@ -28,6 +28,8 @@ struct InputSubsystem::Impl { | |||
| 28 | Input::RegisterFactory<Input::ButtonDevice>("gcpad", gcbuttons); | 28 | Input::RegisterFactory<Input::ButtonDevice>("gcpad", gcbuttons); |
| 29 | gcanalog = std::make_shared<GCAnalogFactory>(gcadapter); | 29 | gcanalog = std::make_shared<GCAnalogFactory>(gcadapter); |
| 30 | Input::RegisterFactory<Input::AnalogDevice>("gcpad", gcanalog); | 30 | Input::RegisterFactory<Input::AnalogDevice>("gcpad", gcanalog); |
| 31 | gcvibration = std::make_shared<GCVibrationFactory>(gcadapter); | ||
| 32 | Input::RegisterFactory<Input::VibrationDevice>("gcpad", gcvibration); | ||
| 31 | 33 | ||
| 32 | keyboard = std::make_shared<Keyboard>(); | 34 | keyboard = std::make_shared<Keyboard>(); |
| 33 | Input::RegisterFactory<Input::ButtonDevice>("keyboard", keyboard); | 35 | Input::RegisterFactory<Input::ButtonDevice>("keyboard", keyboard); |
| @@ -64,9 +66,11 @@ struct InputSubsystem::Impl { | |||
| 64 | #endif | 66 | #endif |
| 65 | Input::UnregisterFactory<Input::ButtonDevice>("gcpad"); | 67 | Input::UnregisterFactory<Input::ButtonDevice>("gcpad"); |
| 66 | Input::UnregisterFactory<Input::AnalogDevice>("gcpad"); | 68 | Input::UnregisterFactory<Input::AnalogDevice>("gcpad"); |
| 69 | Input::UnregisterFactory<Input::VibrationDevice>("gcpad"); | ||
| 67 | 70 | ||
| 68 | gcbuttons.reset(); | 71 | gcbuttons.reset(); |
| 69 | gcanalog.reset(); | 72 | gcanalog.reset(); |
| 73 | gcvibration.reset(); | ||
| 70 | 74 | ||
| 71 | Input::UnregisterFactory<Input::MotionDevice>("cemuhookudp"); | 75 | Input::UnregisterFactory<Input::MotionDevice>("cemuhookudp"); |
| 72 | Input::UnregisterFactory<Input::TouchDevice>("cemuhookudp"); | 76 | Input::UnregisterFactory<Input::TouchDevice>("cemuhookudp"); |
| @@ -142,6 +146,7 @@ struct InputSubsystem::Impl { | |||
| 142 | #endif | 146 | #endif |
| 143 | std::shared_ptr<GCButtonFactory> gcbuttons; | 147 | std::shared_ptr<GCButtonFactory> gcbuttons; |
| 144 | std::shared_ptr<GCAnalogFactory> gcanalog; | 148 | std::shared_ptr<GCAnalogFactory> gcanalog; |
| 149 | std::shared_ptr<GCVibrationFactory> gcvibration; | ||
| 145 | std::shared_ptr<UDPMotionFactory> udpmotion; | 150 | std::shared_ptr<UDPMotionFactory> udpmotion; |
| 146 | std::shared_ptr<UDPTouchFactory> udptouch; | 151 | std::shared_ptr<UDPTouchFactory> udptouch; |
| 147 | std::shared_ptr<CemuhookUDP::Client> udp; | 152 | std::shared_ptr<CemuhookUDP::Client> udp; |
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp index 18fb2ac5e..a2a83cdc9 100644 --- a/src/input_common/sdl/sdl_impl.cpp +++ b/src/input_common/sdl/sdl_impl.cpp | |||
| @@ -85,16 +85,17 @@ public: | |||
| 85 | using std::chrono::milliseconds; | 85 | using std::chrono::milliseconds; |
| 86 | using std::chrono::steady_clock; | 86 | using std::chrono::steady_clock; |
| 87 | 87 | ||
| 88 | // Prevent vibrations less than 10ms apart from each other. | 88 | // Block non-zero vibrations less than 10ms apart from each other. |
| 89 | if (duration_cast<milliseconds>(steady_clock::now() - last_vibration) < milliseconds(10)) { | 89 | if ((amp_low != 0 || amp_high != 0) && |
| 90 | duration_cast<milliseconds>(steady_clock::now() - last_vibration) < milliseconds(10)) { | ||
| 90 | return false; | 91 | return false; |
| 91 | }; | 92 | } |
| 92 | 93 | ||
| 93 | last_vibration = steady_clock::now(); | 94 | last_vibration = steady_clock::now(); |
| 94 | 95 | ||
| 95 | if (sdl_controller != nullptr) { | 96 | if (sdl_controller) { |
| 96 | return SDL_GameControllerRumble(sdl_controller.get(), amp_low, amp_high, 0) == 0; | 97 | return SDL_GameControllerRumble(sdl_controller.get(), amp_low, amp_high, 0) == 0; |
| 97 | } else if (sdl_joystick != nullptr) { | 98 | } else if (sdl_joystick) { |
| 98 | return SDL_JoystickRumble(sdl_joystick.get(), amp_low, amp_high, 0) == 0; | 99 | return SDL_JoystickRumble(sdl_joystick.get(), amp_low, amp_high, 0) == 0; |
| 99 | } | 100 | } |
| 100 | 101 | ||
| @@ -321,14 +322,6 @@ public: | |||
| 321 | return joystick->GetButton(button); | 322 | return joystick->GetButton(button); |
| 322 | } | 323 | } |
| 323 | 324 | ||
| 324 | bool SetRumblePlay(f32 amp_low, f32 freq_low, f32 amp_high, f32 freq_high) const override { | ||
| 325 | const u16 processed_amp_low = | ||
| 326 | static_cast<u16>(pow(amp_low, 0.5f) * (3.0f - 2.0f * pow(amp_low, 0.15f)) * 0xFFFF); | ||
| 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); | ||
| 330 | } | ||
| 331 | |||
| 332 | private: | 325 | private: |
| 333 | std::shared_ptr<SDLJoystick> joystick; | 326 | std::shared_ptr<SDLJoystick> joystick; |
| 334 | int button; | 327 | int button; |
| @@ -412,6 +405,32 @@ private: | |||
| 412 | const float range; | 405 | const float range; |
| 413 | }; | 406 | }; |
| 414 | 407 | ||
| 408 | class SDLVibration final : public Input::VibrationDevice { | ||
| 409 | public: | ||
| 410 | explicit SDLVibration(std::shared_ptr<SDLJoystick> joystick_) | ||
| 411 | : joystick(std::move(joystick_)) {} | ||
| 412 | |||
| 413 | u8 GetStatus() const override { | ||
| 414 | joystick->RumblePlay(1, 1); | ||
| 415 | return joystick->RumblePlay(0, 0); | ||
| 416 | } | ||
| 417 | |||
| 418 | bool SetRumblePlay(f32 amp_low, f32 freq_low, f32 amp_high, f32 freq_high) const override { | ||
| 419 | const auto process_amplitude = [](f32 amplitude) { | ||
| 420 | return static_cast<u16>(std::pow(amplitude, 0.5f) * | ||
| 421 | (3.0f - 2.0f * std::pow(amplitude, 0.15f)) * 0xFFFF); | ||
| 422 | }; | ||
| 423 | |||
| 424 | const auto processed_amp_low = process_amplitude(amp_low); | ||
| 425 | const auto processed_amp_high = process_amplitude(amp_high); | ||
| 426 | |||
| 427 | return joystick->RumblePlay(processed_amp_low, processed_amp_high); | ||
| 428 | } | ||
| 429 | |||
| 430 | private: | ||
| 431 | std::shared_ptr<SDLJoystick> joystick; | ||
| 432 | }; | ||
| 433 | |||
| 415 | class SDLDirectionMotion final : public Input::MotionDevice { | 434 | class SDLDirectionMotion final : public Input::MotionDevice { |
| 416 | public: | 435 | public: |
| 417 | explicit SDLDirectionMotion(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_) | 436 | explicit SDLDirectionMotion(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_) |
| @@ -554,7 +573,7 @@ class SDLAnalogFactory final : public Input::Factory<Input::AnalogDevice> { | |||
| 554 | public: | 573 | public: |
| 555 | explicit SDLAnalogFactory(SDLState& state_) : state(state_) {} | 574 | explicit SDLAnalogFactory(SDLState& state_) : state(state_) {} |
| 556 | /** | 575 | /** |
| 557 | * Creates analog device from joystick axes | 576 | * Creates an analog device from joystick axes |
| 558 | * @param params contains parameters for creating the device: | 577 | * @param params contains parameters for creating the device: |
| 559 | * - "guid": the guid of the joystick to bind | 578 | * - "guid": the guid of the joystick to bind |
| 560 | * - "port": the nth joystick of the same type | 579 | * - "port": the nth joystick of the same type |
| @@ -580,6 +599,26 @@ private: | |||
| 580 | SDLState& state; | 599 | SDLState& state; |
| 581 | }; | 600 | }; |
| 582 | 601 | ||
| 602 | /// An vibration device factory that creates vibration devices from SDL joystick | ||
| 603 | class SDLVibrationFactory final : public Input::Factory<Input::VibrationDevice> { | ||
| 604 | public: | ||
| 605 | explicit SDLVibrationFactory(SDLState& state_) : state(state_) {} | ||
| 606 | /** | ||
| 607 | * Creates a vibration device from a joystick | ||
| 608 | * @param params contains parameters for creating the device: | ||
| 609 | * - "guid": the guid of the joystick to bind | ||
| 610 | * - "port": the nth joystick of the same type | ||
| 611 | */ | ||
| 612 | std::unique_ptr<Input::VibrationDevice> Create(const Common::ParamPackage& params) override { | ||
| 613 | const std::string guid = params.Get("guid", "0"); | ||
| 614 | const int port = params.Get("port", 0); | ||
| 615 | return std::make_unique<SDLVibration>(state.GetSDLJoystickByGUID(guid, port)); | ||
| 616 | } | ||
| 617 | |||
| 618 | private: | ||
| 619 | SDLState& state; | ||
| 620 | }; | ||
| 621 | |||
| 583 | /// A motion device factory that creates motion devices from SDL joystick | 622 | /// A motion device factory that creates motion devices from SDL joystick |
| 584 | class SDLMotionFactory final : public Input::Factory<Input::MotionDevice> { | 623 | class SDLMotionFactory final : public Input::Factory<Input::MotionDevice> { |
| 585 | public: | 624 | public: |
| @@ -646,11 +685,13 @@ private: | |||
| 646 | 685 | ||
| 647 | SDLState::SDLState() { | 686 | SDLState::SDLState() { |
| 648 | using namespace Input; | 687 | using namespace Input; |
| 649 | analog_factory = std::make_shared<SDLAnalogFactory>(*this); | ||
| 650 | button_factory = std::make_shared<SDLButtonFactory>(*this); | 688 | button_factory = std::make_shared<SDLButtonFactory>(*this); |
| 689 | analog_factory = std::make_shared<SDLAnalogFactory>(*this); | ||
| 690 | vibration_factory = std::make_shared<SDLVibrationFactory>(*this); | ||
| 651 | motion_factory = std::make_shared<SDLMotionFactory>(*this); | 691 | motion_factory = std::make_shared<SDLMotionFactory>(*this); |
| 652 | RegisterFactory<AnalogDevice>("sdl", analog_factory); | ||
| 653 | RegisterFactory<ButtonDevice>("sdl", button_factory); | 692 | RegisterFactory<ButtonDevice>("sdl", button_factory); |
| 693 | RegisterFactory<AnalogDevice>("sdl", analog_factory); | ||
| 694 | RegisterFactory<VibrationDevice>("sdl", vibration_factory); | ||
| 654 | RegisterFactory<MotionDevice>("sdl", motion_factory); | 695 | RegisterFactory<MotionDevice>("sdl", motion_factory); |
| 655 | 696 | ||
| 656 | // If the frontend is going to manage the event loop, then we don't start one here | 697 | // If the frontend is going to manage the event loop, then we don't start one here |
| @@ -687,6 +728,7 @@ SDLState::~SDLState() { | |||
| 687 | using namespace Input; | 728 | using namespace Input; |
| 688 | UnregisterFactory<ButtonDevice>("sdl"); | 729 | UnregisterFactory<ButtonDevice>("sdl"); |
| 689 | UnregisterFactory<AnalogDevice>("sdl"); | 730 | UnregisterFactory<AnalogDevice>("sdl"); |
| 731 | UnregisterFactory<VibrationDevice>("sdl"); | ||
| 690 | UnregisterFactory<MotionDevice>("sdl"); | 732 | UnregisterFactory<MotionDevice>("sdl"); |
| 691 | 733 | ||
| 692 | CloseJoysticks(); | 734 | CloseJoysticks(); |
diff --git a/src/input_common/sdl/sdl_impl.h b/src/input_common/sdl/sdl_impl.h index b9bb4dc56..08044b00d 100644 --- a/src/input_common/sdl/sdl_impl.h +++ b/src/input_common/sdl/sdl_impl.h | |||
| @@ -22,6 +22,7 @@ namespace InputCommon::SDL { | |||
| 22 | class SDLAnalogFactory; | 22 | class SDLAnalogFactory; |
| 23 | class SDLButtonFactory; | 23 | class SDLButtonFactory; |
| 24 | class SDLMotionFactory; | 24 | class SDLMotionFactory; |
| 25 | class SDLVibrationFactory; | ||
| 25 | class SDLJoystick; | 26 | class SDLJoystick; |
| 26 | 27 | ||
| 27 | class SDLState : public State { | 28 | class SDLState : public State { |
| @@ -72,6 +73,7 @@ private: | |||
| 72 | 73 | ||
| 73 | std::shared_ptr<SDLButtonFactory> button_factory; | 74 | std::shared_ptr<SDLButtonFactory> button_factory; |
| 74 | std::shared_ptr<SDLAnalogFactory> analog_factory; | 75 | std::shared_ptr<SDLAnalogFactory> analog_factory; |
| 76 | std::shared_ptr<SDLVibrationFactory> vibration_factory; | ||
| 75 | std::shared_ptr<SDLMotionFactory> motion_factory; | 77 | std::shared_ptr<SDLMotionFactory> motion_factory; |
| 76 | 78 | ||
| 77 | bool start_thread = false; | 79 | bool start_thread = false; |
diff --git a/src/input_common/settings.cpp b/src/input_common/settings.cpp index b66c05856..557e7a9a0 100644 --- a/src/input_common/settings.cpp +++ b/src/input_common/settings.cpp | |||
| @@ -14,13 +14,6 @@ const std::array<const char*, NumButtons> mapping = {{ | |||
| 14 | }}; | 14 | }}; |
| 15 | } | 15 | } |
| 16 | 16 | ||
| 17 | namespace NativeMotion { | ||
| 18 | const std::array<const char*, NumMotions> mapping = {{ | ||
| 19 | "motionleft", | ||
| 20 | "motionright", | ||
| 21 | }}; | ||
| 22 | } | ||
| 23 | |||
| 24 | namespace NativeAnalog { | 17 | namespace NativeAnalog { |
| 25 | const std::array<const char*, NumAnalogs> mapping = {{ | 18 | const std::array<const char*, NumAnalogs> mapping = {{ |
| 26 | "lstick", | 19 | "lstick", |
| @@ -28,6 +21,20 @@ const std::array<const char*, NumAnalogs> mapping = {{ | |||
| 28 | }}; | 21 | }}; |
| 29 | } | 22 | } |
| 30 | 23 | ||
| 24 | namespace NativeVibration { | ||
| 25 | const std::array<const char*, NumVibrations> mapping = {{ | ||
| 26 | "left_vibration_device", | ||
| 27 | "right_vibration_device", | ||
| 28 | }}; | ||
| 29 | } | ||
| 30 | |||
| 31 | namespace NativeMotion { | ||
| 32 | const std::array<const char*, NumMotions> mapping = {{ | ||
| 33 | "motionleft", | ||
| 34 | "motionright", | ||
| 35 | }}; | ||
| 36 | } | ||
| 37 | |||
| 31 | namespace NativeMouseButton { | 38 | namespace NativeMouseButton { |
| 32 | const std::array<const char*, NumMouseButtons> mapping = {{ | 39 | const std::array<const char*, NumMouseButtons> mapping = {{ |
| 33 | "left", | 40 | "left", |
diff --git a/src/input_common/settings.h b/src/input_common/settings.h index 2763ed991..75486554b 100644 --- a/src/input_common/settings.h +++ b/src/input_common/settings.h | |||
| @@ -66,17 +66,32 @@ constexpr int NUM_STICKS_HID = NumAnalogs; | |||
| 66 | extern const std::array<const char*, NumAnalogs> mapping; | 66 | extern const std::array<const char*, NumAnalogs> mapping; |
| 67 | } // namespace NativeAnalog | 67 | } // namespace NativeAnalog |
| 68 | 68 | ||
| 69 | namespace NativeVibration { | ||
| 70 | enum Values : int { | ||
| 71 | LeftVibrationDevice, | ||
| 72 | RightVibrationDevice, | ||
| 73 | |||
| 74 | NumVibrations, | ||
| 75 | }; | ||
| 76 | |||
| 77 | constexpr int VIBRATION_HID_BEGIN = LeftVibrationDevice; | ||
| 78 | constexpr int VIBRATION_HID_END = NumVibrations; | ||
| 79 | constexpr int NUM_VIBRATIONS_HID = NumVibrations; | ||
| 80 | |||
| 81 | extern const std::array<const char*, NumVibrations> mapping; | ||
| 82 | }; // namespace NativeVibration | ||
| 83 | |||
| 69 | namespace NativeMotion { | 84 | namespace NativeMotion { |
| 70 | enum Values : int { | 85 | enum Values : int { |
| 71 | MOTIONLEFT, | 86 | MotionLeft, |
| 72 | MOTIONRIGHT, | 87 | MotionRight, |
| 73 | 88 | ||
| 74 | NumMotions, | 89 | NumMotions, |
| 75 | }; | 90 | }; |
| 76 | 91 | ||
| 77 | constexpr int MOTION_HID_BEGIN = MOTIONLEFT; | 92 | constexpr int MOTION_HID_BEGIN = MotionLeft; |
| 78 | constexpr int MOTION_HID_END = NumMotions; | 93 | constexpr int MOTION_HID_END = NumMotions; |
| 79 | constexpr int NUM_MOTION_HID = NumMotions; | 94 | constexpr int NUM_MOTIONS_HID = NumMotions; |
| 80 | 95 | ||
| 81 | extern const std::array<const char*, NumMotions> mapping; | 96 | extern const std::array<const char*, NumMotions> mapping; |
| 82 | } // namespace NativeMotion | 97 | } // namespace NativeMotion |
| @@ -305,9 +320,11 @@ constexpr int NUM_KEYBOARD_MODS_HID = NumKeyboardMods; | |||
| 305 | 320 | ||
| 306 | } // namespace NativeKeyboard | 321 | } // namespace NativeKeyboard |
| 307 | 322 | ||
| 308 | using ButtonsRaw = std::array<std::string, NativeButton::NumButtons>; | ||
| 309 | using AnalogsRaw = std::array<std::string, NativeAnalog::NumAnalogs>; | 323 | using AnalogsRaw = std::array<std::string, NativeAnalog::NumAnalogs>; |
| 310 | using MotionRaw = std::array<std::string, NativeMotion::NumMotions>; | 324 | using ButtonsRaw = std::array<std::string, NativeButton::NumButtons>; |
| 325 | using MotionsRaw = std::array<std::string, NativeMotion::NumMotions>; | ||
| 326 | using VibrationsRaw = std::array<std::string, NativeVibration::NumVibrations>; | ||
| 327 | |||
| 311 | using MouseButtonsRaw = std::array<std::string, NativeMouseButton::NumMouseButtons>; | 328 | using MouseButtonsRaw = std::array<std::string, NativeMouseButton::NumMouseButtons>; |
| 312 | using KeyboardKeysRaw = std::array<std::string, NativeKeyboard::NumKeyboardKeys>; | 329 | using KeyboardKeysRaw = std::array<std::string, NativeKeyboard::NumKeyboardKeys>; |
| 313 | using KeyboardModsRaw = std::array<std::string, NativeKeyboard::NumKeyboardMods>; | 330 | using KeyboardModsRaw = std::array<std::string, NativeKeyboard::NumKeyboardMods>; |
| @@ -330,7 +347,8 @@ struct PlayerInput { | |||
| 330 | ControllerType controller_type; | 347 | ControllerType controller_type; |
| 331 | ButtonsRaw buttons; | 348 | ButtonsRaw buttons; |
| 332 | AnalogsRaw analogs; | 349 | AnalogsRaw analogs; |
| 333 | MotionRaw motions; | 350 | VibrationsRaw vibrations; |
| 351 | MotionsRaw motions; | ||
| 334 | 352 | ||
| 335 | bool vibration_enabled; | 353 | bool vibration_enabled; |
| 336 | int vibration_strength; | 354 | int vibration_strength; |
diff --git a/src/yuzu/applets/controller.cpp b/src/yuzu/applets/controller.cpp index c5e671309..cdcd3d28d 100644 --- a/src/yuzu/applets/controller.cpp +++ b/src/yuzu/applets/controller.cpp | |||
| @@ -478,6 +478,8 @@ void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) | |||
| 478 | return; | 478 | return; |
| 479 | } | 479 | } |
| 480 | 480 | ||
| 481 | ConfigureVibration::SetVibrationDevices(player_index); | ||
| 482 | |||
| 481 | // Player 1 and Handheld | 483 | // Player 1 and Handheld |
| 482 | auto& handheld = Settings::values.players.GetValue()[8]; | 484 | auto& handheld = Settings::values.players.GetValue()[8]; |
| 483 | // If Handheld is selected, copy all the settings from Player 1 to Handheld. | 485 | // If Handheld is selected, copy all the settings from Player 1 to Handheld. |
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 7f66f29aa..6fa842cd5 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -344,21 +344,6 @@ void Config::ReadPlayerValue(std::size_t player_index) { | |||
| 344 | } | 344 | } |
| 345 | } | 345 | } |
| 346 | 346 | ||
| 347 | for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { | ||
| 348 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); | ||
| 349 | auto& player_motions = player.motions[i]; | ||
| 350 | |||
| 351 | player_motions = qt_config | ||
| 352 | ->value(QStringLiteral("%1").arg(player_prefix) + | ||
| 353 | QString::fromUtf8(Settings::NativeMotion::mapping[i]), | ||
| 354 | QString::fromStdString(default_param)) | ||
| 355 | .toString() | ||
| 356 | .toStdString(); | ||
| 357 | if (player_motions.empty()) { | ||
| 358 | player_motions = default_param; | ||
| 359 | } | ||
| 360 | } | ||
| 361 | |||
| 362 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | 347 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { |
| 363 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | 348 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( |
| 364 | default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], | 349 | default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], |
| @@ -375,6 +360,33 @@ void Config::ReadPlayerValue(std::size_t player_index) { | |||
| 375 | player_analogs = default_param; | 360 | player_analogs = default_param; |
| 376 | } | 361 | } |
| 377 | } | 362 | } |
| 363 | |||
| 364 | for (int i = 0; i < Settings::NativeVibration::NumVibrations; ++i) { | ||
| 365 | auto& player_vibrations = player.vibrations[i]; | ||
| 366 | |||
| 367 | player_vibrations = | ||
| 368 | qt_config | ||
| 369 | ->value(QStringLiteral("%1").arg(player_prefix) + | ||
| 370 | QString::fromUtf8(Settings::NativeVibration::mapping[i]), | ||
| 371 | QString{}) | ||
| 372 | .toString() | ||
| 373 | .toStdString(); | ||
| 374 | } | ||
| 375 | |||
| 376 | for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { | ||
| 377 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); | ||
| 378 | auto& player_motions = player.motions[i]; | ||
| 379 | |||
| 380 | player_motions = qt_config | ||
| 381 | ->value(QStringLiteral("%1").arg(player_prefix) + | ||
| 382 | QString::fromUtf8(Settings::NativeMotion::mapping[i]), | ||
| 383 | QString::fromStdString(default_param)) | ||
| 384 | .toString() | ||
| 385 | .toStdString(); | ||
| 386 | if (player_motions.empty()) { | ||
| 387 | player_motions = default_param; | ||
| 388 | } | ||
| 389 | } | ||
| 378 | } | 390 | } |
| 379 | 391 | ||
| 380 | void Config::ReadDebugValues() { | 392 | void Config::ReadDebugValues() { |
| @@ -1014,13 +1026,6 @@ void Config::SavePlayerValue(std::size_t player_index) { | |||
| 1014 | QString::fromStdString(player.buttons[i]), | 1026 | QString::fromStdString(player.buttons[i]), |
| 1015 | QString::fromStdString(default_param)); | 1027 | QString::fromStdString(default_param)); |
| 1016 | } | 1028 | } |
| 1017 | for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { | ||
| 1018 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); | ||
| 1019 | WriteSetting(QStringLiteral("%1").arg(player_prefix) + | ||
| 1020 | QString::fromStdString(Settings::NativeMotion::mapping[i]), | ||
| 1021 | QString::fromStdString(player.motions[i]), | ||
| 1022 | QString::fromStdString(default_param)); | ||
| 1023 | } | ||
| 1024 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | 1029 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { |
| 1025 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | 1030 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( |
| 1026 | default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], | 1031 | default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], |
| @@ -1030,6 +1035,18 @@ void Config::SavePlayerValue(std::size_t player_index) { | |||
| 1030 | QString::fromStdString(player.analogs[i]), | 1035 | QString::fromStdString(player.analogs[i]), |
| 1031 | QString::fromStdString(default_param)); | 1036 | QString::fromStdString(default_param)); |
| 1032 | } | 1037 | } |
| 1038 | for (int i = 0; i < Settings::NativeVibration::NumVibrations; ++i) { | ||
| 1039 | WriteSetting(QStringLiteral("%1").arg(player_prefix) + | ||
| 1040 | QString::fromStdString(Settings::NativeVibration::mapping[i]), | ||
| 1041 | QString::fromStdString(player.vibrations[i]), QString{}); | ||
| 1042 | } | ||
| 1043 | for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { | ||
| 1044 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); | ||
| 1045 | WriteSetting(QStringLiteral("%1").arg(player_prefix) + | ||
| 1046 | QString::fromStdString(Settings::NativeMotion::mapping[i]), | ||
| 1047 | QString::fromStdString(player.motions[i]), | ||
| 1048 | QString::fromStdString(default_param)); | ||
| 1049 | } | ||
| 1033 | } | 1050 | } |
| 1034 | 1051 | ||
| 1035 | void Config::SaveDebugValues() { | 1052 | void Config::SaveDebugValues() { |
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 460ff08a4..3e785c224 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include "ui_configure_input_player.h" | 22 | #include "ui_configure_input_player.h" |
| 23 | #include "yuzu/configuration/config.h" | 23 | #include "yuzu/configuration/config.h" |
| 24 | #include "yuzu/configuration/configure_input_player.h" | 24 | #include "yuzu/configuration/configure_input_player.h" |
| 25 | #include "yuzu/configuration/configure_vibration.h" | ||
| 25 | #include "yuzu/configuration/input_profiles.h" | 26 | #include "yuzu/configuration/input_profiles.h" |
| 26 | #include "yuzu/util/limitable_input_dialog.h" | 27 | #include "yuzu/util/limitable_input_dialog.h" |
| 27 | 28 | ||
| @@ -39,6 +40,10 @@ namespace { | |||
| 39 | 40 | ||
| 40 | void UpdateController(Settings::ControllerType controller_type, std::size_t npad_index, | 41 | void UpdateController(Settings::ControllerType controller_type, std::size_t npad_index, |
| 41 | bool connected) { | 42 | bool connected) { |
| 43 | auto& player = Settings::values.players.GetValue()[npad_index]; | ||
| 44 | player.controller_type = controller_type; | ||
| 45 | player.connected = connected; | ||
| 46 | |||
| 42 | Core::System& system{Core::System::GetInstance()}; | 47 | Core::System& system{Core::System::GetInstance()}; |
| 43 | if (!system.IsPoweredOn()) { | 48 | if (!system.IsPoweredOn()) { |
| 44 | return; | 49 | return; |
| @@ -565,6 +570,8 @@ void ConfigureInputPlayer::ApplyConfiguration() { | |||
| 565 | static_cast<Settings::ControllerType>(ui->comboControllerType->currentIndex()); | 570 | static_cast<Settings::ControllerType>(ui->comboControllerType->currentIndex()); |
| 566 | player.connected = ui->groupConnectedController->isChecked(); | 571 | player.connected = ui->groupConnectedController->isChecked(); |
| 567 | 572 | ||
| 573 | ConfigureVibration::SetVibrationDevices(player_index); | ||
| 574 | |||
| 568 | // Player 2-8 | 575 | // Player 2-8 |
| 569 | if (player_index != 0) { | 576 | if (player_index != 0) { |
| 570 | UpdateController(player.controller_type, player_index, player.connected); | 577 | UpdateController(player.controller_type, player_index, player.connected); |
diff --git a/src/yuzu/configuration/configure_vibration.cpp b/src/yuzu/configuration/configure_vibration.cpp index 1c68f28f3..714db5b80 100644 --- a/src/yuzu/configuration/configure_vibration.cpp +++ b/src/yuzu/configuration/configure_vibration.cpp | |||
| @@ -2,6 +2,12 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | ||
| 6 | #include <unordered_map> | ||
| 7 | |||
| 8 | #include <fmt/format.h> | ||
| 9 | |||
| 10 | #include "common/param_package.h" | ||
| 5 | #include "core/settings.h" | 11 | #include "core/settings.h" |
| 6 | #include "ui_configure_vibration.h" | 12 | #include "ui_configure_vibration.h" |
| 7 | #include "yuzu/configuration/configure_vibration.h" | 13 | #include "yuzu/configuration/configure_vibration.h" |
| @@ -53,6 +59,80 @@ void ConfigureVibration::ApplyConfiguration() { | |||
| 53 | ui->checkBoxAccurateVibration->isChecked()); | 59 | ui->checkBoxAccurateVibration->isChecked()); |
| 54 | } | 60 | } |
| 55 | 61 | ||
| 62 | void ConfigureVibration::SetVibrationDevices(std::size_t player_index) { | ||
| 63 | using namespace Settings::NativeButton; | ||
| 64 | static constexpr std::array<std::array<Settings::NativeButton::Values, 6>, 2> buttons{{ | ||
| 65 | {DLeft, DUp, DRight, DDown, L, ZL}, // Left Buttons | ||
| 66 | {A, B, X, Y, R, ZR}, // Right Buttons | ||
| 67 | }}; | ||
| 68 | |||
| 69 | auto& player = Settings::values.players.GetValue()[player_index]; | ||
| 70 | |||
| 71 | for (std::size_t device_idx = 0; device_idx < buttons.size(); ++device_idx) { | ||
| 72 | std::unordered_map<std::string, int> params_count; | ||
| 73 | |||
| 74 | for (const auto button_index : buttons[device_idx]) { | ||
| 75 | const auto& player_button = player.buttons[button_index]; | ||
| 76 | |||
| 77 | if (params_count.find(player_button) != params_count.end()) { | ||
| 78 | ++params_count[player_button]; | ||
| 79 | continue; | ||
| 80 | } | ||
| 81 | |||
| 82 | params_count.insert_or_assign(player_button, 1); | ||
| 83 | } | ||
| 84 | |||
| 85 | const auto it = std::max_element( | ||
| 86 | params_count.begin(), params_count.end(), | ||
| 87 | [](const auto& lhs, const auto& rhs) { return lhs.second < rhs.second; }); | ||
| 88 | |||
| 89 | auto& vibration_param_str = player.vibrations[device_idx]; | ||
| 90 | vibration_param_str.clear(); | ||
| 91 | |||
| 92 | if (it->first.empty()) { | ||
| 93 | continue; | ||
| 94 | } | ||
| 95 | |||
| 96 | const auto param = Common::ParamPackage(it->first); | ||
| 97 | |||
| 98 | const auto engine = param.Get("engine", ""); | ||
| 99 | const auto guid = param.Get("guid", ""); | ||
| 100 | const auto port = param.Get("port", ""); | ||
| 101 | |||
| 102 | if (engine.empty() || engine == "keyboard") { | ||
| 103 | continue; | ||
| 104 | } | ||
| 105 | |||
| 106 | vibration_param_str += fmt::format("engine:{}", engine); | ||
| 107 | |||
| 108 | if (!port.empty()) { | ||
| 109 | vibration_param_str += fmt::format(",port:{}", port); | ||
| 110 | } | ||
| 111 | if (!guid.empty()) { | ||
| 112 | vibration_param_str += fmt::format(",guid:{}", guid); | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | if (player.vibrations[0] != player.vibrations[1]) { | ||
| 117 | return; | ||
| 118 | } | ||
| 119 | |||
| 120 | if (!player.vibrations[0].empty() && | ||
| 121 | player.controller_type != Settings::ControllerType::RightJoycon) { | ||
| 122 | player.vibrations[1].clear(); | ||
| 123 | } else if (!player.vibrations[1].empty() && | ||
| 124 | player.controller_type == Settings::ControllerType::RightJoycon) { | ||
| 125 | player.vibrations[0].clear(); | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | void ConfigureVibration::SetAllVibrationDevices() { | ||
| 130 | // Set vibration devices for all player indices including handheld | ||
| 131 | for (std::size_t player_idx = 0; player_idx < NUM_PLAYERS + 1; ++player_idx) { | ||
| 132 | SetVibrationDevices(player_idx); | ||
| 133 | } | ||
| 134 | } | ||
| 135 | |||
| 56 | void ConfigureVibration::changeEvent(QEvent* event) { | 136 | void ConfigureVibration::changeEvent(QEvent* event) { |
| 57 | if (event->type() == QEvent::LanguageChange) { | 137 | if (event->type() == QEvent::LanguageChange) { |
| 58 | RetranslateUI(); | 138 | RetranslateUI(); |
diff --git a/src/yuzu/configuration/configure_vibration.h b/src/yuzu/configuration/configure_vibration.h index 37bbc2653..07411a86f 100644 --- a/src/yuzu/configuration/configure_vibration.h +++ b/src/yuzu/configuration/configure_vibration.h | |||
| @@ -24,6 +24,9 @@ public: | |||
| 24 | 24 | ||
| 25 | void ApplyConfiguration(); | 25 | void ApplyConfiguration(); |
| 26 | 26 | ||
| 27 | static void SetVibrationDevices(std::size_t player_index); | ||
| 28 | static void SetAllVibrationDevices(); | ||
| 29 | |||
| 27 | private: | 30 | private: |
| 28 | void changeEvent(QEvent* event) override; | 31 | void changeEvent(QEvent* event) override; |
| 29 | void RetranslateUI(); | 32 | void RetranslateUI(); |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 54a46827f..76a5c32f4 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include "applets/web_browser.h" | 18 | #include "applets/web_browser.h" |
| 19 | #include "configuration/configure_input.h" | 19 | #include "configuration/configure_input.h" |
| 20 | #include "configuration/configure_per_game.h" | 20 | #include "configuration/configure_per_game.h" |
| 21 | #include "configuration/configure_vibration.h" | ||
| 21 | #include "core/file_sys/vfs.h" | 22 | #include "core/file_sys/vfs.h" |
| 22 | #include "core/file_sys/vfs_real.h" | 23 | #include "core/file_sys/vfs_real.h" |
| 23 | #include "core/frontend/applets/controller.h" | 24 | #include "core/frontend/applets/controller.h" |
| @@ -1096,6 +1097,8 @@ void GMainWindow::BootGame(const QString& filename) { | |||
| 1096 | Config per_game_config(fmt::format("{:016X}", title_id), Config::ConfigType::PerGameConfig); | 1097 | Config per_game_config(fmt::format("{:016X}", title_id), Config::ConfigType::PerGameConfig); |
| 1097 | } | 1098 | } |
| 1098 | 1099 | ||
| 1100 | ConfigureVibration::SetAllVibrationDevices(); | ||
| 1101 | |||
| 1099 | Settings::LogSettings(); | 1102 | Settings::LogSettings(); |
| 1100 | 1103 | ||
| 1101 | if (UISettings::values.select_user_on_boot) { | 1104 | if (UISettings::values.select_user_on_boot) { |