diff options
author | wwylele <wwylele@gmail.com> | 2017-01-21 16:33:48 +0100 |
---|---|---|
committer | wwylele <wwylele@gmail.com> | 2017-03-01 22:30:57 +0100 |
commit | 51b1c1f211bf8112eba845256bd52cbd36a5932a (patch) | |
tree | ad685410ae7b83df0474b9de206f99b68e5be398 | |
parent | InputCommon: add AnalogFromButton (diff) | |
download | yuzu-51b1c1f211bf8112eba845256bd52cbd36a5932a.tar yuzu-51b1c1f211bf8112eba845256bd52cbd36a5932a.tar.gz yuzu-51b1c1f211bf8112eba845256bd52cbd36a5932a.tar.bz2 yuzu-51b1c1f211bf8112eba845256bd52cbd36a5932a.tar.lz yuzu-51b1c1f211bf8112eba845256bd52cbd36a5932a.tar.xz yuzu-51b1c1f211bf8112eba845256bd52cbd36a5932a.tar.zst yuzu-51b1c1f211bf8112eba845256bd52cbd36a5932a.zip |
-rw-r--r-- | src/input_common/CMakeLists.txt | 10 | ||||
-rw-r--r-- | src/input_common/main.cpp | 10 | ||||
-rw-r--r-- | src/input_common/sdl/sdl.cpp | 202 | ||||
-rw-r--r-- | src/input_common/sdl/sdl.h | 19 |
4 files changed, 241 insertions, 0 deletions
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 9f4422269..cfe5caaa3 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -10,8 +10,18 @@ set(HEADERS main.h ) +if(SDL2_FOUND) + set(SRCS ${SRCS} sdl/sdl.cpp) + set(HEADERS ${HEADERS} sdl/sdl.h) + include_directories(${SDL2_INCLUDE_DIR}) +endif() + create_directory_groups(${SRCS} ${HEADERS}) add_library(input_common STATIC ${SRCS} ${HEADERS}) target_link_libraries(input_common common core) +if(SDL2_FOUND) + target_link_libraries(input_common ${SDL2_LIBRARY}) + set_property(TARGET input_common APPEND PROPERTY COMPILE_DEFINITIONS HAVE_SDL2) +endif() diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 8455fdc17..699f41e6b 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -7,6 +7,9 @@ #include "input_common/analog_from_button.h" #include "input_common/keyboard.h" #include "input_common/main.h" +#ifdef HAVE_SDL2 +#include "input_common/sdl/sdl.h" +#endif namespace InputCommon { @@ -17,12 +20,19 @@ void Init() { Input::RegisterFactory<Input::ButtonDevice>("keyboard", keyboard); Input::RegisterFactory<Input::AnalogDevice>("analog_from_button", std::make_shared<InputCommon::AnalogFromButton>()); +#ifdef HAVE_SDL2 + SDL::Init(); +#endif } void Shutdown() { Input::UnregisterFactory<Input::ButtonDevice>("keyboard"); keyboard.reset(); Input::UnregisterFactory<Input::AnalogDevice>("analog_from_button"); + +#ifdef HAVE_SDL2 + SDL::Shutdown(); +#endif } Keyboard* GetKeyboard() { diff --git a/src/input_common/sdl/sdl.cpp b/src/input_common/sdl/sdl.cpp new file mode 100644 index 000000000..ae0206909 --- /dev/null +++ b/src/input_common/sdl/sdl.cpp @@ -0,0 +1,202 @@ +// Copyright 2017 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <cmath> +#include <memory> +#include <string> +#include <tuple> +#include <unordered_map> +#include <SDL.h> +#include "common/math_util.h" +#include "input_common/sdl/sdl.h" + +namespace InputCommon { + +namespace SDL { + +class SDLJoystick; +class SDLButtonFactory; +class SDLAnalogFactory; +static std::unordered_map<int, std::weak_ptr<SDLJoystick>> joystick_list; +static std::shared_ptr<SDLButtonFactory> button_factory; +static std::shared_ptr<SDLAnalogFactory> analog_factory; + +static bool initialized = false; + +class SDLJoystick { +public: + explicit SDLJoystick(int joystick_index) + : joystick{SDL_JoystickOpen(joystick_index), SDL_JoystickClose} { + if (!joystick) { + LOG_ERROR(Input, "failed to open joystick %d", joystick_index); + } + } + + bool GetButton(int button) const { + if (!joystick) + return {}; + SDL_JoystickUpdate(); + return SDL_JoystickGetButton(joystick.get(), button) == 1; + } + + std::tuple<float, float> GetAnalog(int axis_x, int axis_y) const { + if (!joystick) + return {}; + SDL_JoystickUpdate(); + float x = SDL_JoystickGetAxis(joystick.get(), axis_x) / 32767.0f; + float y = SDL_JoystickGetAxis(joystick.get(), axis_y) / 32767.0f; + y = -y; // 3DS uses an y-axis inverse from SDL + + // Make sure the coordinates are in the unit circle, + // otherwise normalize it. + float r = x * x + y * y; + if (r > 1.0f) { + r = std::sqrt(r); + x /= r; + y /= r; + } + + return std::make_tuple(x, y); + } + + bool GetHatDirection(int hat, Uint8 direction) const { + return (SDL_JoystickGetHat(joystick.get(), hat) & direction) != 0; + } + +private: + std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> joystick; +}; + +class SDLButton final : public Input::ButtonDevice { +public: + explicit SDLButton(std::shared_ptr<SDLJoystick> joystick_, int button_) + : joystick(joystick_), button(button_) {} + + bool GetStatus() const override { + return joystick->GetButton(button); + } + +private: + std::shared_ptr<SDLJoystick> joystick; + int button; +}; + +class SDLDirectionButton final : public Input::ButtonDevice { +public: + explicit SDLDirectionButton(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_) + : joystick(joystick_), hat(hat_), direction(direction_) {} + + bool GetStatus() const override { + return joystick->GetHatDirection(hat, direction); + } + +private: + std::shared_ptr<SDLJoystick> joystick; + int hat; + Uint8 direction; +}; + +class SDLAnalog final : public Input::AnalogDevice { +public: + SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_) + : joystick(joystick_), axis_x(axis_x_), axis_y(axis_y_) {} + + std::tuple<float, float> GetStatus() const override { + return joystick->GetAnalog(axis_x, axis_y); + } + +private: + std::shared_ptr<SDLJoystick> joystick; + int axis_x; + int axis_y; +}; + +static std::shared_ptr<SDLJoystick> GetJoystick(int joystick_index) { + std::shared_ptr<SDLJoystick> joystick = joystick_list[joystick_index].lock(); + if (!joystick) { + joystick = std::make_shared<SDLJoystick>(joystick_index); + joystick_list[joystick_index] = joystick; + } + return joystick; +} + +/// A button device factory that creates button devices from SDL joystick +class SDLButtonFactory final : public Input::Factory<Input::ButtonDevice> { +public: + /** + * Creates a button device from a joystick button + * @param params contains parameters for creating the device: + * - "joystick": the index of the joystick to bind + * - "button"(optional): the index of the button to bind + * - "hat"(optional): the index of the hat to bind as direction buttons + * - "direction"(only used for hat): the direction name of the hat to bind. Can be "up", + * "down", "left" or "right" + */ + std::unique_ptr<Input::ButtonDevice> Create(const Common::ParamPackage& params) override { + const int joystick_index = params.Get("joystick", 0); + + if (params.Has("hat")) { + const int hat = params.Get("hat", 0); + const std::string direction_name = params.Get("direction", ""); + Uint8 direction; + if (direction_name == "up") { + direction = SDL_HAT_UP; + } else if (direction_name == "down") { + direction = SDL_HAT_DOWN; + } else if (direction_name == "left") { + direction = SDL_HAT_LEFT; + } else if (direction_name == "right") { + direction = SDL_HAT_RIGHT; + } else { + direction = 0; + } + return std::make_unique<SDLDirectionButton>(GetJoystick(joystick_index), hat, + direction); + } + + const int button = params.Get("button", 0); + return std::make_unique<SDLButton>(GetJoystick(joystick_index), button); + } +}; + +/// An analog device factory that creates analog devices from SDL joystick +class SDLAnalogFactory final : public Input::Factory<Input::AnalogDevice> { +public: + /** + * Creates analog device from joystick axes + * @param params contains parameters for creating the device: + * - "joystick": the index of the joystick to bind + * - "axis_x": the index of the axis to be bind as x-axis + * - "axis_y": the index of the axis to be bind as y-axis + */ + std::unique_ptr<Input::AnalogDevice> Create(const Common::ParamPackage& params) override { + const int joystick_index = params.Get("joystick", 0); + const int axis_x = params.Get("axis_x", 0); + const int axis_y = params.Get("axis_y", 1); + return std::make_unique<SDLAnalog>(GetJoystick(joystick_index), axis_x, axis_y); + } +}; + +void Init() { + if (SDL_Init(SDL_INIT_JOYSTICK) < 0) { + LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: %s", SDL_GetError()); + } else { + using namespace Input; + RegisterFactory<ButtonDevice>("sdl", std::make_shared<SDLButtonFactory>()); + RegisterFactory<AnalogDevice>("sdl", std::make_shared<SDLAnalogFactory>()); + initialized = true; + } +} + +void Shutdown() { + if (initialized) { + using namespace Input; + UnregisterFactory<ButtonDevice>("sdl"); + UnregisterFactory<AnalogDevice>("sdl"); + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + } +} + +} // namespace SDL +} // namespace InputCommon diff --git a/src/input_common/sdl/sdl.h b/src/input_common/sdl/sdl.h new file mode 100644 index 000000000..3e72debcc --- /dev/null +++ b/src/input_common/sdl/sdl.h @@ -0,0 +1,19 @@ +// Copyright 2017 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/frontend/input.h" + +namespace InputCommon { +namespace SDL { + +/// Initializes and registers SDL device factories +void Init(); + +/// Unresisters SDL device factories and shut them down. +void Shutdown(); + +} // namespace SDL +} // namespace InputCommon |