summaryrefslogtreecommitdiff
path: root/src/input_common/sdl/sdl.cpp
diff options
context:
space:
mode:
authorGravatar bunnei2017-03-17 14:59:39 -0400
committerGravatar GitHub2017-03-17 14:59:39 -0400
commit423ab5e2bcf5a522e5f412447c05f648df57a14c (patch)
tree1e60eaeffa59229254a47f885d2fe2cbbdc1a5c0 /src/input_common/sdl/sdl.cpp
parentMerge pull request #2618 from wwylele/log-less-filename (diff)
parentqt/config_input: don't connect for null button (diff)
downloadyuzu-423ab5e2bcf5a522e5f412447c05f648df57a14c.tar.gz
yuzu-423ab5e2bcf5a522e5f412447c05f648df57a14c.tar.xz
yuzu-423ab5e2bcf5a522e5f412447c05f648df57a14c.zip
Merge pull request #2497 from wwylele/input-2
Refactor input emulation & add SDL gamepad support
Diffstat (limited to 'src/input_common/sdl/sdl.cpp')
-rw-r--r--src/input_common/sdl/sdl.cpp202
1 files changed, 202 insertions, 0 deletions
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 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <cmath>
6#include <memory>
7#include <string>
8#include <tuple>
9#include <unordered_map>
10#include <SDL.h>
11#include "common/math_util.h"
12#include "input_common/sdl/sdl.h"
13
14namespace InputCommon {
15
16namespace SDL {
17
18class SDLJoystick;
19class SDLButtonFactory;
20class SDLAnalogFactory;
21static std::unordered_map<int, std::weak_ptr<SDLJoystick>> joystick_list;
22static std::shared_ptr<SDLButtonFactory> button_factory;
23static std::shared_ptr<SDLAnalogFactory> analog_factory;
24
25static bool initialized = false;
26
27class SDLJoystick {
28public:
29 explicit SDLJoystick(int joystick_index)
30 : joystick{SDL_JoystickOpen(joystick_index), SDL_JoystickClose} {
31 if (!joystick) {
32 LOG_ERROR(Input, "failed to open joystick %d", joystick_index);
33 }
34 }
35
36 bool GetButton(int button) const {
37 if (!joystick)
38 return {};
39 SDL_JoystickUpdate();
40 return SDL_JoystickGetButton(joystick.get(), button) == 1;
41 }
42
43 std::tuple<float, float> GetAnalog(int axis_x, int axis_y) const {
44 if (!joystick)
45 return {};
46 SDL_JoystickUpdate();
47 float x = SDL_JoystickGetAxis(joystick.get(), axis_x) / 32767.0f;
48 float y = SDL_JoystickGetAxis(joystick.get(), axis_y) / 32767.0f;
49 y = -y; // 3DS uses an y-axis inverse from SDL
50
51 // Make sure the coordinates are in the unit circle,
52 // otherwise normalize it.
53 float r = x * x + y * y;
54 if (r > 1.0f) {
55 r = std::sqrt(r);
56 x /= r;
57 y /= r;
58 }
59
60 return std::make_tuple(x, y);
61 }
62
63 bool GetHatDirection(int hat, Uint8 direction) const {
64 return (SDL_JoystickGetHat(joystick.get(), hat) & direction) != 0;
65 }
66
67private:
68 std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> joystick;
69};
70
71class SDLButton final : public Input::ButtonDevice {
72public:
73 explicit SDLButton(std::shared_ptr<SDLJoystick> joystick_, int button_)
74 : joystick(joystick_), button(button_) {}
75
76 bool GetStatus() const override {
77 return joystick->GetButton(button);
78 }
79
80private:
81 std::shared_ptr<SDLJoystick> joystick;
82 int button;
83};
84
85class SDLDirectionButton final : public Input::ButtonDevice {
86public:
87 explicit SDLDirectionButton(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_)
88 : joystick(joystick_), hat(hat_), direction(direction_) {}
89
90 bool GetStatus() const override {
91 return joystick->GetHatDirection(hat, direction);
92 }
93
94private:
95 std::shared_ptr<SDLJoystick> joystick;
96 int hat;
97 Uint8 direction;
98};
99
100class SDLAnalog final : public Input::AnalogDevice {
101public:
102 SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_)
103 : joystick(joystick_), axis_x(axis_x_), axis_y(axis_y_) {}
104
105 std::tuple<float, float> GetStatus() const override {
106 return joystick->GetAnalog(axis_x, axis_y);
107 }
108
109private:
110 std::shared_ptr<SDLJoystick> joystick;
111 int axis_x;
112 int axis_y;
113};
114
115static std::shared_ptr<SDLJoystick> GetJoystick(int joystick_index) {
116 std::shared_ptr<SDLJoystick> joystick = joystick_list[joystick_index].lock();
117 if (!joystick) {
118 joystick = std::make_shared<SDLJoystick>(joystick_index);
119 joystick_list[joystick_index] = joystick;
120 }
121 return joystick;
122}
123
124/// A button device factory that creates button devices from SDL joystick
125class SDLButtonFactory final : public Input::Factory<Input::ButtonDevice> {
126public:
127 /**
128 * Creates a button device from a joystick button
129 * @param params contains parameters for creating the device:
130 * - "joystick": the index of the joystick to bind
131 * - "button"(optional): the index of the button to bind
132 * - "hat"(optional): the index of the hat to bind as direction buttons
133 * - "direction"(only used for hat): the direction name of the hat to bind. Can be "up",
134 * "down", "left" or "right"
135 */
136 std::unique_ptr<Input::ButtonDevice> Create(const Common::ParamPackage& params) override {
137 const int joystick_index = params.Get("joystick", 0);
138
139 if (params.Has("hat")) {
140 const int hat = params.Get("hat", 0);
141 const std::string direction_name = params.Get("direction", "");
142 Uint8 direction;
143 if (direction_name == "up") {
144 direction = SDL_HAT_UP;
145 } else if (direction_name == "down") {
146 direction = SDL_HAT_DOWN;
147 } else if (direction_name == "left") {
148 direction = SDL_HAT_LEFT;
149 } else if (direction_name == "right") {
150 direction = SDL_HAT_RIGHT;
151 } else {
152 direction = 0;
153 }
154 return std::make_unique<SDLDirectionButton>(GetJoystick(joystick_index), hat,
155 direction);
156 }
157
158 const int button = params.Get("button", 0);
159 return std::make_unique<SDLButton>(GetJoystick(joystick_index), button);
160 }
161};
162
163/// An analog device factory that creates analog devices from SDL joystick
164class SDLAnalogFactory final : public Input::Factory<Input::AnalogDevice> {
165public:
166 /**
167 * Creates analog device from joystick axes
168 * @param params contains parameters for creating the device:
169 * - "joystick": the index of the joystick to bind
170 * - "axis_x": the index of the axis to be bind as x-axis
171 * - "axis_y": the index of the axis to be bind as y-axis
172 */
173 std::unique_ptr<Input::AnalogDevice> Create(const Common::ParamPackage& params) override {
174 const int joystick_index = params.Get("joystick", 0);
175 const int axis_x = params.Get("axis_x", 0);
176 const int axis_y = params.Get("axis_y", 1);
177 return std::make_unique<SDLAnalog>(GetJoystick(joystick_index), axis_x, axis_y);
178 }
179};
180
181void Init() {
182 if (SDL_Init(SDL_INIT_JOYSTICK) < 0) {
183 LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: %s", SDL_GetError());
184 } else {
185 using namespace Input;
186 RegisterFactory<ButtonDevice>("sdl", std::make_shared<SDLButtonFactory>());
187 RegisterFactory<AnalogDevice>("sdl", std::make_shared<SDLAnalogFactory>());
188 initialized = true;
189 }
190}
191
192void Shutdown() {
193 if (initialized) {
194 using namespace Input;
195 UnregisterFactory<ButtonDevice>("sdl");
196 UnregisterFactory<AnalogDevice>("sdl");
197 SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
198 }
199}
200
201} // namespace SDL
202} // namespace InputCommon