summaryrefslogtreecommitdiff
path: root/src/input_common/sdl/sdl_impl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/input_common/sdl/sdl_impl.cpp')
-rw-r--r--src/input_common/sdl/sdl_impl.cpp138
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
336private: 310private:
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
393class SDLVibration final : public Input::VibrationDevice {
394public:
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
415private:
416 std::shared_ptr<SDLJoystick> joystick;
417};
418
419class SDLDirectionMotion final : public Input::MotionDevice { 419class SDLDirectionMotion final : public Input::MotionDevice {
420public: 420public:
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> {
558public: 558public:
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
588class SDLVibrationFactory final : public Input::Factory<Input::VibrationDevice> {
589public:
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
603private:
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
588class SDLMotionFactory final : public Input::Factory<Input::MotionDevice> { 608class SDLMotionFactory final : public Input::Factory<Input::MotionDevice> {
589public: 609public:
@@ -650,11 +670,13 @@ private:
650 670
651SDLState::SDLState() { 671SDLState::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