diff options
| author | 2020-11-17 20:02:27 -0800 | |
|---|---|---|
| committer | 2020-11-17 20:02:27 -0800 | |
| commit | abda36636245c416a75774165d2a5b49610952fc (patch) | |
| tree | 0bf3bab90e2155a3a16ffa21eabbc2a4c8f9d39d /src/input_common/sdl/sdl_impl.cpp | |
| parent | Merge pull request #4933 from lioncash/nodisc-gpu (diff) | |
| parent | sdl_impl: Pump SDL Events at 1000 Hz (diff) | |
| download | yuzu-abda36636245c416a75774165d2a5b49610952fc.tar.gz yuzu-abda36636245c416a75774165d2a5b49610952fc.tar.xz yuzu-abda36636245c416a75774165d2a5b49610952fc.zip | |
Merge pull request #4866 from Morph1984/mjolnir-p3-prod
Project Mjölnir: Part 3 - Controller Profiles and Vibration Rework
Diffstat (limited to 'src/input_common/sdl/sdl_impl.cpp')
| -rw-r--r-- | src/input_common/sdl/sdl_impl.cpp | 138 |
1 files changed, 71 insertions, 67 deletions
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp index 10883e2d9..8c48bb861 100644 --- a/src/input_common/sdl/sdl_impl.cpp +++ b/src/input_common/sdl/sdl_impl.cpp | |||
| @@ -80,30 +80,13 @@ 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 | if (sdl_controller) { |
| 85 | const u16 raw_amp_high = static_cast<u16>(amp_high * 0xFFFF); | 85 | return SDL_GameControllerRumble(sdl_controller.get(), amp_low, amp_high, 0) == 0; |
| 86 | // Lower drastically the number of state changes | 86 | } else if (sdl_joystick) { |
| 87 | if (raw_amp_low >> 11 == last_state_rumble_low >> 11 && | 87 | return SDL_JoystickRumble(sdl_joystick.get(), amp_low, amp_high, 0) == 0; |
| 88 | raw_amp_high >> 11 == last_state_rumble_high >> 11) { | ||
| 89 | if (raw_amp_low + raw_amp_high != 0 || | ||
| 90 | last_state_rumble_low + last_state_rumble_high == 0) { | ||
| 91 | return false; | ||
| 92 | } | ||
| 93 | } | ||
| 94 | // Don't change state if last vibration was < 20ms | ||
| 95 | const auto now = std::chrono::system_clock::now(); | ||
| 96 | if (std::chrono::duration_cast<std::chrono::milliseconds>(now - last_vibration) < | ||
| 97 | std::chrono::milliseconds(20)) { | ||
| 98 | return raw_amp_low + raw_amp_high == 0; | ||
| 99 | } | 88 | } |
| 100 | 89 | ||
| 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; | 90 | return false; |
| 108 | } | 91 | } |
| 109 | 92 | ||
| @@ -172,9 +155,6 @@ private: | |||
| 172 | } state; | 155 | } state; |
| 173 | std::string guid; | 156 | std::string guid; |
| 174 | int port; | 157 | 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; | 158 | std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick; |
| 179 | std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller; | 159 | std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller; |
| 180 | mutable std::mutex mutex; | 160 | mutable std::mutex mutex; |
| @@ -327,12 +307,6 @@ public: | |||
| 327 | return joystick->GetButton(button); | 307 | return joystick->GetButton(button); |
| 328 | } | 308 | } |
| 329 | 309 | ||
| 330 | bool SetRumblePlay(f32 amp_high, f32 amp_low, f32 freq_high, f32 freq_low) const override { | ||
| 331 | const f32 new_amp_low = pow(amp_low, 0.5f) * (3.0f - 2.0f * pow(amp_low, 0.15f)); | ||
| 332 | const f32 new_amp_high = pow(amp_high, 0.5f) * (3.0f - 2.0f * pow(amp_high, 0.15f)); | ||
| 333 | return joystick->RumblePlay(new_amp_low, new_amp_high, 250); | ||
| 334 | } | ||
| 335 | |||
| 336 | private: | 310 | private: |
| 337 | std::shared_ptr<SDLJoystick> joystick; | 311 | std::shared_ptr<SDLJoystick> joystick; |
| 338 | int button; | 312 | int button; |
| @@ -416,6 +390,32 @@ private: | |||
| 416 | const float range; | 390 | const float range; |
| 417 | }; | 391 | }; |
| 418 | 392 | ||
| 393 | class SDLVibration final : public Input::VibrationDevice { | ||
| 394 | public: | ||
| 395 | explicit SDLVibration(std::shared_ptr<SDLJoystick> joystick_) | ||
| 396 | : joystick(std::move(joystick_)) {} | ||
| 397 | |||
| 398 | u8 GetStatus() const override { | ||
| 399 | joystick->RumblePlay(1, 1); | ||
| 400 | return joystick->RumblePlay(0, 0); | ||
| 401 | } | ||
| 402 | |||
| 403 | bool SetRumblePlay(f32 amp_low, f32 freq_low, f32 amp_high, f32 freq_high) const override { | ||
| 404 | const auto process_amplitude = [](f32 amplitude) { | ||
| 405 | return static_cast<u16>(std::pow(amplitude, 0.5f) * | ||
| 406 | (3.0f - 2.0f * std::pow(amplitude, 0.15f)) * 0xFFFF); | ||
| 407 | }; | ||
| 408 | |||
| 409 | const auto processed_amp_low = process_amplitude(amp_low); | ||
| 410 | const auto processed_amp_high = process_amplitude(amp_high); | ||
| 411 | |||
| 412 | return joystick->RumblePlay(processed_amp_low, processed_amp_high); | ||
| 413 | } | ||
| 414 | |||
| 415 | private: | ||
| 416 | std::shared_ptr<SDLJoystick> joystick; | ||
| 417 | }; | ||
| 418 | |||
| 419 | class SDLDirectionMotion final : public Input::MotionDevice { | 419 | class SDLDirectionMotion final : public Input::MotionDevice { |
| 420 | public: | 420 | public: |
| 421 | explicit SDLDirectionMotion(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_) | 421 | explicit SDLDirectionMotion(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_) |
| @@ -558,7 +558,7 @@ class SDLAnalogFactory final : public Input::Factory<Input::AnalogDevice> { | |||
| 558 | public: | 558 | public: |
| 559 | explicit SDLAnalogFactory(SDLState& state_) : state(state_) {} | 559 | explicit SDLAnalogFactory(SDLState& state_) : state(state_) {} |
| 560 | /** | 560 | /** |
| 561 | * Creates analog device from joystick axes | 561 | * Creates an analog device from joystick axes |
| 562 | * @param params contains parameters for creating the device: | 562 | * @param params contains parameters for creating the device: |
| 563 | * - "guid": the guid of the joystick to bind | 563 | * - "guid": the guid of the joystick to bind |
| 564 | * - "port": the nth joystick of the same type | 564 | * - "port": the nth joystick of the same type |
| @@ -584,6 +584,26 @@ private: | |||
| 584 | SDLState& state; | 584 | SDLState& state; |
| 585 | }; | 585 | }; |
| 586 | 586 | ||
| 587 | /// An vibration device factory that creates vibration devices from SDL joystick | ||
| 588 | class SDLVibrationFactory final : public Input::Factory<Input::VibrationDevice> { | ||
| 589 | public: | ||
| 590 | explicit SDLVibrationFactory(SDLState& state_) : state(state_) {} | ||
| 591 | /** | ||
| 592 | * Creates a vibration device from a joystick | ||
| 593 | * @param params contains parameters for creating the device: | ||
| 594 | * - "guid": the guid of the joystick to bind | ||
| 595 | * - "port": the nth joystick of the same type | ||
| 596 | */ | ||
| 597 | std::unique_ptr<Input::VibrationDevice> Create(const Common::ParamPackage& params) override { | ||
| 598 | const std::string guid = params.Get("guid", "0"); | ||
| 599 | const int port = params.Get("port", 0); | ||
| 600 | return std::make_unique<SDLVibration>(state.GetSDLJoystickByGUID(guid, port)); | ||
| 601 | } | ||
| 602 | |||
| 603 | private: | ||
| 604 | SDLState& state; | ||
| 605 | }; | ||
| 606 | |||
| 587 | /// A motion device factory that creates motion devices from SDL joystick | 607 | /// A motion device factory that creates motion devices from SDL joystick |
| 588 | class SDLMotionFactory final : public Input::Factory<Input::MotionDevice> { | 608 | class SDLMotionFactory final : public Input::Factory<Input::MotionDevice> { |
| 589 | public: | 609 | public: |
| @@ -650,11 +670,13 @@ private: | |||
| 650 | 670 | ||
| 651 | SDLState::SDLState() { | 671 | SDLState::SDLState() { |
| 652 | using namespace Input; | 672 | using namespace Input; |
| 653 | analog_factory = std::make_shared<SDLAnalogFactory>(*this); | ||
| 654 | button_factory = std::make_shared<SDLButtonFactory>(*this); | 673 | button_factory = std::make_shared<SDLButtonFactory>(*this); |
| 674 | analog_factory = std::make_shared<SDLAnalogFactory>(*this); | ||
| 675 | vibration_factory = std::make_shared<SDLVibrationFactory>(*this); | ||
| 655 | motion_factory = std::make_shared<SDLMotionFactory>(*this); | 676 | motion_factory = std::make_shared<SDLMotionFactory>(*this); |
| 656 | RegisterFactory<AnalogDevice>("sdl", analog_factory); | ||
| 657 | RegisterFactory<ButtonDevice>("sdl", button_factory); | 677 | RegisterFactory<ButtonDevice>("sdl", button_factory); |
| 678 | RegisterFactory<AnalogDevice>("sdl", analog_factory); | ||
| 679 | RegisterFactory<VibrationDevice>("sdl", vibration_factory); | ||
| 658 | RegisterFactory<MotionDevice>("sdl", motion_factory); | 680 | RegisterFactory<MotionDevice>("sdl", motion_factory); |
| 659 | 681 | ||
| 660 | // If the frontend is going to manage the event loop, then we don't start one here | 682 | // If the frontend is going to manage the event loop, then we don't start one here |
| @@ -676,7 +698,7 @@ SDLState::SDLState() { | |||
| 676 | using namespace std::chrono_literals; | 698 | using namespace std::chrono_literals; |
| 677 | while (initialized) { | 699 | while (initialized) { |
| 678 | SDL_PumpEvents(); | 700 | SDL_PumpEvents(); |
| 679 | std::this_thread::sleep_for(5ms); | 701 | std::this_thread::sleep_for(1ms); |
| 680 | } | 702 | } |
| 681 | }); | 703 | }); |
| 682 | } | 704 | } |
| @@ -691,6 +713,7 @@ SDLState::~SDLState() { | |||
| 691 | using namespace Input; | 713 | using namespace Input; |
| 692 | UnregisterFactory<ButtonDevice>("sdl"); | 714 | UnregisterFactory<ButtonDevice>("sdl"); |
| 693 | UnregisterFactory<AnalogDevice>("sdl"); | 715 | UnregisterFactory<AnalogDevice>("sdl"); |
| 716 | UnregisterFactory<VibrationDevice>("sdl"); | ||
| 694 | UnregisterFactory<MotionDevice>("sdl"); | 717 | UnregisterFactory<MotionDevice>("sdl"); |
| 695 | 718 | ||
| 696 | CloseJoysticks(); | 719 | CloseJoysticks(); |
| @@ -1045,7 +1068,6 @@ public: | |||
| 1045 | 1068 | ||
| 1046 | void Start(const std::string& device_id) override { | 1069 | void Start(const std::string& device_id) override { |
| 1047 | SDLPoller::Start(device_id); | 1070 | SDLPoller::Start(device_id); |
| 1048 | // Load the game controller | ||
| 1049 | // Reset stored axes | 1071 | // Reset stored axes |
| 1050 | analog_x_axis = -1; | 1072 | analog_x_axis = -1; |
| 1051 | analog_y_axis = -1; | 1073 | analog_y_axis = -1; |
| @@ -1058,40 +1080,21 @@ public: | |||
| 1058 | if (event.type == SDL_JOYAXISMOTION && std::abs(event.jaxis.value / 32767.0) < 0.5) { | 1080 | if (event.type == SDL_JOYAXISMOTION && std::abs(event.jaxis.value / 32767.0) < 0.5) { |
| 1059 | continue; | 1081 | continue; |
| 1060 | } | 1082 | } |
| 1061 | // Simplify controller config by testing if game controller support is enabled. | ||
| 1062 | if (event.type == SDL_JOYAXISMOTION) { | 1083 | if (event.type == SDL_JOYAXISMOTION) { |
| 1063 | const auto axis = event.jaxis.axis; | 1084 | const auto axis = event.jaxis.axis; |
| 1064 | if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); | 1085 | // In order to return a complete analog param, we need inputs for both axes. |
| 1065 | auto* const controller = joystick->GetSDLGameController()) { | 1086 | // First we take the x-axis (horizontal) input, then the y-axis (vertical) input. |
| 1066 | const auto axis_left_x = | 1087 | if (analog_x_axis == -1) { |
| 1067 | SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX) | 1088 | analog_x_axis = axis; |
| 1068 | .value.axis; | 1089 | } else if (analog_y_axis == -1 && analog_x_axis != axis) { |
| 1069 | const auto axis_left_y = | 1090 | analog_y_axis = axis; |
| 1070 | SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY) | 1091 | } |
| 1071 | .value.axis; | 1092 | } else { |
| 1072 | const auto axis_right_x = | 1093 | // If the press wasn't accepted as a joy axis, check for a button press |
| 1073 | SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX) | 1094 | auto button_press = button_poller.FromEvent(event); |
| 1074 | .value.axis; | 1095 | if (button_press) { |
| 1075 | const auto axis_right_y = | 1096 | return *button_press; |
| 1076 | SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY) | ||
| 1077 | .value.axis; | ||
| 1078 | |||
| 1079 | if (axis == axis_left_x || axis == axis_left_y) { | ||
| 1080 | analog_x_axis = axis_left_x; | ||
| 1081 | analog_y_axis = axis_left_y; | ||
| 1082 | break; | ||
| 1083 | } else if (axis == axis_right_x || axis == axis_right_y) { | ||
| 1084 | analog_x_axis = axis_right_x; | ||
| 1085 | analog_y_axis = axis_right_y; | ||
| 1086 | break; | ||
| 1087 | } | ||
| 1088 | } | 1097 | } |
| 1089 | } | ||
| 1090 | |||
| 1091 | // If the press wasn't accepted as a joy axis, check for a button press | ||
| 1092 | auto button_press = button_poller.FromEvent(event); | ||
| 1093 | if (button_press) { | ||
| 1094 | return *button_press; | ||
| 1095 | } | 1098 | } |
| 1096 | } | 1099 | } |
| 1097 | 1100 | ||
| @@ -1104,6 +1107,7 @@ public: | |||
| 1104 | return params; | 1107 | return params; |
| 1105 | } | 1108 | } |
| 1106 | } | 1109 | } |
| 1110 | |||
| 1107 | return {}; | 1111 | return {}; |
| 1108 | } | 1112 | } |
| 1109 | 1113 | ||