diff options
author | muemart <muemart@users.noreply.github.com> | 2017-12-06 05:26:29 +0100 |
---|---|---|
committer | noah katz <n-katz@hotmail.com> | 2018-01-16 02:02:30 +0100 |
commit | eaff98dbb3da3c7524a504abb1cdd5daa3480dda (patch) | |
tree | 4e5d28ed590b01d001c065e6ac08f2df6daabf75 /src/input_common/sdl | |
parent | pctl: Clang format. (diff) | |
download | yuzu-eaff98dbb3da3c7524a504abb1cdd5daa3480dda.tar yuzu-eaff98dbb3da3c7524a504abb1cdd5daa3480dda.tar.gz yuzu-eaff98dbb3da3c7524a504abb1cdd5daa3480dda.tar.bz2 yuzu-eaff98dbb3da3c7524a504abb1cdd5daa3480dda.tar.lz yuzu-eaff98dbb3da3c7524a504abb1cdd5daa3480dda.tar.xz yuzu-eaff98dbb3da3c7524a504abb1cdd5daa3480dda.tar.zst yuzu-eaff98dbb3da3c7524a504abb1cdd5daa3480dda.zip |
Diffstat (limited to 'src/input_common/sdl')
-rw-r--r-- | src/input_common/sdl/sdl.cpp | 183 | ||||
-rw-r--r-- | src/input_common/sdl/sdl.h | 23 |
2 files changed, 205 insertions, 1 deletions
diff --git a/src/input_common/sdl/sdl.cpp b/src/input_common/sdl/sdl.cpp index d404afa89..88b557c5d 100644 --- a/src/input_common/sdl/sdl.cpp +++ b/src/input_common/sdl/sdl.cpp @@ -3,13 +3,15 @@ // Refer to the license.txt file included. #include <cmath> -#include <memory> #include <string> #include <tuple> #include <unordered_map> +#include <utility> #include <SDL.h> #include "common/logging/log.h" #include "common/math_util.h" +#include "common/param_package.h" +#include "input_common/main.h" #include "input_common/sdl/sdl.h" namespace InputCommon { @@ -69,6 +71,10 @@ public: return (SDL_JoystickGetHat(joystick.get(), hat) & direction) != 0; } + SDL_JoystickID GetJoystickID() const { + return SDL_JoystickInstanceID(joystick.get()); + } + private: std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> joystick; }; @@ -247,5 +253,180 @@ void Shutdown() { } } +/** + * This function converts a joystick ID used in SDL events to the device index. This is necessary + * because Citra opens joysticks using their indices, not their IDs. + */ +static int JoystickIDToDeviceIndex(SDL_JoystickID id) { + int num_joysticks = SDL_NumJoysticks(); + for (int i = 0; i < num_joysticks; i++) { + auto joystick = GetJoystick(i); + if (joystick->GetJoystickID() == id) { + return i; + } + } + return -1; +} + +Common::ParamPackage SDLEventToButtonParamPackage(const SDL_Event& event) { + Common::ParamPackage params({{"engine", "sdl"}}); + switch (event.type) { + case SDL_JOYAXISMOTION: + params.Set("joystick", JoystickIDToDeviceIndex(event.jaxis.which)); + params.Set("axis", event.jaxis.axis); + if (event.jaxis.value > 0) { + params.Set("direction", "+"); + params.Set("threshold", "0.5"); + } else { + params.Set("direction", "-"); + params.Set("threshold", "-0.5"); + } + break; + case SDL_JOYBUTTONUP: + params.Set("joystick", JoystickIDToDeviceIndex(event.jbutton.which)); + params.Set("button", event.jbutton.button); + break; + case SDL_JOYHATMOTION: + params.Set("joystick", JoystickIDToDeviceIndex(event.jhat.which)); + params.Set("hat", event.jhat.hat); + switch (event.jhat.value) { + case SDL_HAT_UP: + params.Set("direction", "up"); + break; + case SDL_HAT_DOWN: + params.Set("direction", "down"); + break; + case SDL_HAT_LEFT: + params.Set("direction", "left"); + break; + case SDL_HAT_RIGHT: + params.Set("direction", "right"); + break; + default: + return {}; + } + break; + } + return params; +} + +namespace Polling { + +class SDLPoller : public InputCommon::Polling::DevicePoller { +public: + SDLPoller() = default; + + ~SDLPoller() = default; + + void Start() override { + // SDL joysticks must be opened, otherwise they don't generate events + SDL_JoystickUpdate(); + int num_joysticks = SDL_NumJoysticks(); + for (int i = 0; i < num_joysticks; i++) { + joysticks_opened.emplace_back(GetJoystick(i)); + } + // Empty event queue to get rid of old events. citra-qt doesn't use the queue + SDL_Event dummy; + while (SDL_PollEvent(&dummy)) { + } + } + + void Stop() override { + joysticks_opened.clear(); + } + +private: + std::vector<std::shared_ptr<SDLJoystick>> joysticks_opened; +}; + +class SDLButtonPoller final : public SDLPoller { +public: + SDLButtonPoller() = default; + + ~SDLButtonPoller() = default; + + Common::ParamPackage GetNextInput() override { + SDL_Event event; + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_JOYAXISMOTION: + if (std::abs(event.jaxis.value / 32767.0) < 0.5) { + break; + } + case SDL_JOYBUTTONUP: + case SDL_JOYHATMOTION: + return SDLEventToButtonParamPackage(event); + } + } + return {}; + } +}; + +class SDLAnalogPoller final : public SDLPoller { +public: + SDLAnalogPoller() = default; + + ~SDLAnalogPoller() = default; + + void Start() override { + SDLPoller::Start(); + + // Reset stored axes + analog_xaxis = -1; + analog_yaxis = -1; + analog_axes_joystick = -1; + } + + Common::ParamPackage GetNextInput() override { + SDL_Event event; + while (SDL_PollEvent(&event)) { + if (event.type != SDL_JOYAXISMOTION || std::abs(event.jaxis.value / 32767.0) < 0.5) { + continue; + } + // An analog device needs two axes, so we need to store the axis for later and wait for + // a second SDL event. The axes also must be from the same joystick. + int axis = event.jaxis.axis; + if (analog_xaxis == -1) { + analog_xaxis = axis; + analog_axes_joystick = event.jaxis.which; + } else if (analog_yaxis == -1 && analog_xaxis != axis && + analog_axes_joystick == event.jaxis.which) { + analog_yaxis = axis; + } + } + Common::ParamPackage params; + if (analog_xaxis != -1 && analog_yaxis != -1) { + params.Set("engine", "sdl"); + params.Set("joystick", JoystickIDToDeviceIndex(analog_axes_joystick)); + params.Set("axis_x", analog_xaxis); + params.Set("axis_y", analog_yaxis); + analog_xaxis = -1; + analog_yaxis = -1; + analog_axes_joystick = -1; + return params; + } + return params; + } + +private: + int analog_xaxis = -1; + int analog_yaxis = -1; + SDL_JoystickID analog_axes_joystick = -1; +}; + +std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> GetPollers( + InputCommon::Polling::DeviceType type) { + std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> pollers; + switch (type) { + case InputCommon::Polling::DeviceType::Analog: + pollers.push_back(std::make_unique<SDLAnalogPoller>()); + break; + case InputCommon::Polling::DeviceType::Button: + pollers.push_back(std::make_unique<SDLButtonPoller>()); + break; + } + return std::move(pollers); +} +} // namespace Polling } // namespace SDL } // namespace InputCommon diff --git a/src/input_common/sdl/sdl.h b/src/input_common/sdl/sdl.h index 3e72debcc..7934099d4 100644 --- a/src/input_common/sdl/sdl.h +++ b/src/input_common/sdl/sdl.h @@ -4,8 +4,21 @@ #pragma once +#include <memory> +#include <vector> #include "core/frontend/input.h" +union SDL_Event; +namespace Common { +class ParamPackage; +} +namespace InputCommon { +namespace Polling { +class DevicePoller; +enum class DeviceType; +} // namespace Polling +} // namespace InputCommon + namespace InputCommon { namespace SDL { @@ -15,5 +28,15 @@ void Init(); /// Unresisters SDL device factories and shut them down. void Shutdown(); +/// Creates a ParamPackage from an SDL_Event that can directly be used to create a ButtonDevice +Common::ParamPackage SDLEventToButtonParamPackage(const SDL_Event& event); + +namespace Polling { + +/// Get all DevicePoller that use the SDL backend for a specific device type +std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> GetPollers( + InputCommon::Polling::DeviceType type); + +} // namespace Polling } // namespace SDL } // namespace InputCommon |