summaryrefslogtreecommitdiff
path: root/src/input_common/sdl/sdl_impl.cpp
diff options
context:
space:
mode:
authorGravatar bunnei2020-10-08 10:18:39 -0700
committerGravatar GitHub2020-10-08 10:18:39 -0700
commit06e65de93cfa923b6fb1f12fa20193515249234d (patch)
tree9771ca19a2686af1185f62ed7488d977d37a1703 /src/input_common/sdl/sdl_impl.cpp
parentMerge pull request #4765 from ReinUsesLisp/fix-sort-devices (diff)
parentAdd random motion input to keyboard (diff)
downloadyuzu-06e65de93cfa923b6fb1f12fa20193515249234d.tar.gz
yuzu-06e65de93cfa923b6fb1f12fa20193515249234d.tar.xz
yuzu-06e65de93cfa923b6fb1f12fa20193515249234d.zip
Merge pull request #4677 from german77/ShakeFromButton
InputCommon: Add random motion input for buttons
Diffstat (limited to 'src/input_common/sdl/sdl_impl.cpp')
-rw-r--r--src/input_common/sdl/sdl_impl.cpp190
1 files changed, 190 insertions, 0 deletions
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index 27a96c18b..bd480570a 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -22,6 +22,7 @@
22#include "common/param_package.h" 22#include "common/param_package.h"
23#include "common/threadsafe_queue.h" 23#include "common/threadsafe_queue.h"
24#include "core/frontend/input.h" 24#include "core/frontend/input.h"
25#include "input_common/motion_input.h"
25#include "input_common/sdl/sdl_impl.h" 26#include "input_common/sdl/sdl_impl.h"
26#include "input_common/settings.h" 27#include "input_common/settings.h"
27 28
@@ -123,6 +124,10 @@ public:
123 return std::make_tuple(x, y); 124 return std::make_tuple(x, y);
124 } 125 }
125 126
127 const InputCommon::MotionInput& GetMotion() const {
128 return motion;
129 }
130
126 void SetHat(int hat, Uint8 direction) { 131 void SetHat(int hat, Uint8 direction) {
127 std::lock_guard lock{mutex}; 132 std::lock_guard lock{mutex};
128 state.hats.insert_or_assign(hat, direction); 133 state.hats.insert_or_assign(hat, direction);
@@ -173,6 +178,9 @@ private:
173 std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick; 178 std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick;
174 std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller; 179 std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller;
175 mutable std::mutex mutex; 180 mutable std::mutex mutex;
181
182 // motion is initalized without PID values as motion input is not aviable for SDL2
183 InputCommon::MotionInput motion{0.0f, 0.0f, 0.0f};
176}; 184};
177 185
178std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) { 186std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) {
@@ -423,6 +431,68 @@ private:
423 const float range; 431 const float range;
424}; 432};
425 433
434class SDLDirectionMotion final : public Input::MotionDevice {
435public:
436 explicit SDLDirectionMotion(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_)
437 : joystick(std::move(joystick_)), hat(hat_), direction(direction_) {}
438
439 Input::MotionStatus GetStatus() const override {
440 if (joystick->GetHatDirection(hat, direction)) {
441 return joystick->GetMotion().GetRandomMotion(2, 6);
442 }
443 return joystick->GetMotion().GetRandomMotion(0, 0);
444 }
445
446private:
447 std::shared_ptr<SDLJoystick> joystick;
448 int hat;
449 Uint8 direction;
450};
451
452class SDLAxisMotion final : public Input::MotionDevice {
453public:
454 explicit SDLAxisMotion(std::shared_ptr<SDLJoystick> joystick_, int axis_, float threshold_,
455 bool trigger_if_greater_)
456 : joystick(std::move(joystick_)), axis(axis_), threshold(threshold_),
457 trigger_if_greater(trigger_if_greater_) {}
458
459 Input::MotionStatus GetStatus() const override {
460 const float axis_value = joystick->GetAxis(axis, 1.0f);
461 bool trigger = axis_value < threshold;
462 if (trigger_if_greater) {
463 trigger = axis_value > threshold;
464 }
465
466 if (trigger) {
467 return joystick->GetMotion().GetRandomMotion(2, 6);
468 }
469 return joystick->GetMotion().GetRandomMotion(0, 0);
470 }
471
472private:
473 std::shared_ptr<SDLJoystick> joystick;
474 int axis;
475 float threshold;
476 bool trigger_if_greater;
477};
478
479class SDLButtonMotion final : public Input::MotionDevice {
480public:
481 explicit SDLButtonMotion(std::shared_ptr<SDLJoystick> joystick_, int button_)
482 : joystick(std::move(joystick_)), button(button_) {}
483
484 Input::MotionStatus GetStatus() const override {
485 if (joystick->GetButton(button)) {
486 return joystick->GetMotion().GetRandomMotion(2, 6);
487 }
488 return joystick->GetMotion().GetRandomMotion(0, 0);
489 }
490
491private:
492 std::shared_ptr<SDLJoystick> joystick;
493 int button;
494};
495
426/// A button device factory that creates button devices from SDL joystick 496/// A button device factory that creates button devices from SDL joystick
427class SDLButtonFactory final : public Input::Factory<Input::ButtonDevice> { 497class SDLButtonFactory final : public Input::Factory<Input::ButtonDevice> {
428public: 498public:
@@ -529,12 +599,78 @@ private:
529 SDLState& state; 599 SDLState& state;
530}; 600};
531 601
602/// A motion device factory that creates motion devices from SDL joystick
603class SDLMotionFactory final : public Input::Factory<Input::MotionDevice> {
604public:
605 explicit SDLMotionFactory(SDLState& state_) : state(state_) {}
606 /**
607 * Creates motion device from joystick axes
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::MotionDevice> Create(const Common::ParamPackage& params) override {
613 const std::string guid = params.Get("guid", "0");
614 const int port = params.Get("port", 0);
615
616 auto joystick = state.GetSDLJoystickByGUID(guid, port);
617
618 if (params.Has("hat")) {
619 const int hat = params.Get("hat", 0);
620 const std::string direction_name = params.Get("direction", "");
621 Uint8 direction;
622 if (direction_name == "up") {
623 direction = SDL_HAT_UP;
624 } else if (direction_name == "down") {
625 direction = SDL_HAT_DOWN;
626 } else if (direction_name == "left") {
627 direction = SDL_HAT_LEFT;
628 } else if (direction_name == "right") {
629 direction = SDL_HAT_RIGHT;
630 } else {
631 direction = 0;
632 }
633 // This is necessary so accessing GetHat with hat won't crash
634 joystick->SetHat(hat, SDL_HAT_CENTERED);
635 return std::make_unique<SDLDirectionMotion>(joystick, hat, direction);
636 }
637
638 if (params.Has("axis")) {
639 const int axis = params.Get("axis", 0);
640 const float threshold = params.Get("threshold", 0.5f);
641 const std::string direction_name = params.Get("direction", "");
642 bool trigger_if_greater;
643 if (direction_name == "+") {
644 trigger_if_greater = true;
645 } else if (direction_name == "-") {
646 trigger_if_greater = false;
647 } else {
648 trigger_if_greater = true;
649 LOG_ERROR(Input, "Unknown direction {}", direction_name);
650 }
651 // This is necessary so accessing GetAxis with axis won't crash
652 joystick->SetAxis(axis, 0);
653 return std::make_unique<SDLAxisMotion>(joystick, axis, threshold, trigger_if_greater);
654 }
655
656 const int button = params.Get("button", 0);
657 // This is necessary so accessing GetButton with button won't crash
658 joystick->SetButton(button, false);
659 return std::make_unique<SDLButtonMotion>(joystick, button);
660 }
661
662private:
663 SDLState& state;
664};
665
532SDLState::SDLState() { 666SDLState::SDLState() {
533 using namespace Input; 667 using namespace Input;
534 analog_factory = std::make_shared<SDLAnalogFactory>(*this); 668 analog_factory = std::make_shared<SDLAnalogFactory>(*this);
535 button_factory = std::make_shared<SDLButtonFactory>(*this); 669 button_factory = std::make_shared<SDLButtonFactory>(*this);
670 motion_factory = std::make_shared<SDLMotionFactory>(*this);
536 RegisterFactory<AnalogDevice>("sdl", analog_factory); 671 RegisterFactory<AnalogDevice>("sdl", analog_factory);
537 RegisterFactory<ButtonDevice>("sdl", button_factory); 672 RegisterFactory<ButtonDevice>("sdl", button_factory);
673 RegisterFactory<MotionDevice>("sdl", motion_factory);
538 674
539 // If the frontend is going to manage the event loop, then we dont start one here 675 // If the frontend is going to manage the event loop, then we dont start one here
540 start_thread = !SDL_WasInit(SDL_INIT_JOYSTICK); 676 start_thread = !SDL_WasInit(SDL_INIT_JOYSTICK);
@@ -570,6 +706,7 @@ SDLState::~SDLState() {
570 using namespace Input; 706 using namespace Input;
571 UnregisterFactory<ButtonDevice>("sdl"); 707 UnregisterFactory<ButtonDevice>("sdl");
572 UnregisterFactory<AnalogDevice>("sdl"); 708 UnregisterFactory<AnalogDevice>("sdl");
709 UnregisterFactory<MotionDevice>("sdl");
573 710
574 CloseJoysticks(); 711 CloseJoysticks();
575 SDL_DelEventWatch(&SDLEventWatcher, this); 712 SDL_DelEventWatch(&SDLEventWatcher, this);
@@ -681,6 +818,27 @@ Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Eve
681 return {}; 818 return {};
682} 819}
683 820
821Common::ParamPackage SDLEventToMotionParamPackage(SDLState& state, const SDL_Event& event) {
822 switch (event.type) {
823 case SDL_JOYAXISMOTION: {
824 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
825 return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
826 event.jaxis.axis, event.jaxis.value);
827 }
828 case SDL_JOYBUTTONUP: {
829 const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which);
830 return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
831 event.jbutton.button);
832 }
833 case SDL_JOYHATMOTION: {
834 const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
835 return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
836 event.jhat.hat, event.jhat.value);
837 }
838 }
839 return {};
840}
841
684Common::ParamPackage BuildParamPackageForBinding(int port, const std::string& guid, 842Common::ParamPackage BuildParamPackageForBinding(int port, const std::string& guid,
685 const SDL_GameControllerButtonBind& binding) { 843 const SDL_GameControllerButtonBind& binding) {
686 switch (binding.bindType) { 844 switch (binding.bindType) {
@@ -846,6 +1004,35 @@ public:
846 } 1004 }
847}; 1005};
848 1006
1007class SDLMotionPoller final : public SDLPoller {
1008public:
1009 explicit SDLMotionPoller(SDLState& state_) : SDLPoller(state_) {}
1010
1011 Common::ParamPackage GetNextInput() override {
1012 SDL_Event event;
1013 while (state.event_queue.Pop(event)) {
1014 const auto package = FromEvent(event);
1015 if (package) {
1016 return *package;
1017 }
1018 }
1019 return {};
1020 }
1021 [[nodiscard]] std::optional<Common::ParamPackage> FromEvent(const SDL_Event& event) const {
1022 switch (event.type) {
1023 case SDL_JOYAXISMOTION:
1024 if (std::abs(event.jaxis.value / 32767.0) < 0.5) {
1025 break;
1026 }
1027 [[fallthrough]];
1028 case SDL_JOYBUTTONUP:
1029 case SDL_JOYHATMOTION:
1030 return {SDLEventToMotionParamPackage(state, event)};
1031 }
1032 return std::nullopt;
1033 }
1034};
1035
849/** 1036/**
850 * Attempts to match the press to a controller joy axis (left/right stick) and if a match 1037 * Attempts to match the press to a controller joy axis (left/right stick) and if a match
851 * isn't found, checks if the event matches anything from SDLButtonPoller and uses that 1038 * isn't found, checks if the event matches anything from SDLButtonPoller and uses that
@@ -937,6 +1124,9 @@ SDLState::Pollers SDLState::GetPollers(InputCommon::Polling::DeviceType type) {
937 case InputCommon::Polling::DeviceType::Button: 1124 case InputCommon::Polling::DeviceType::Button:
938 pollers.emplace_back(std::make_unique<Polling::SDLButtonPoller>(*this)); 1125 pollers.emplace_back(std::make_unique<Polling::SDLButtonPoller>(*this));
939 break; 1126 break;
1127 case InputCommon::Polling::DeviceType::Motion:
1128 pollers.emplace_back(std::make_unique<Polling::SDLMotionPoller>(*this));
1129 break;
940 } 1130 }
941 1131
942 return pollers; 1132 return pollers;