1// SuperTux
2// Copyright (C) 2014 Ingo Ruhnke <grumbel@gmail.com>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17#include "control/game_controller_manager.hpp"
18
19#include <algorithm>
20
21#include "control/input_manager.hpp"
22#include "util/log.hpp"
23
24GameControllerManager::GameControllerManager(InputManager* parent) :
25 m_parent(parent),
26 m_deadzone(8000),
27 m_game_controllers(),
28 m_stick_state(),
29 m_button_state()
30{
31}
32
33GameControllerManager::~GameControllerManager()
34{
35 for (const auto& con : m_game_controllers)
36 {
37 SDL_GameControllerClose(con);
38 }
39}
40
41void
42GameControllerManager::process_button_event(const SDL_ControllerButtonEvent& ev)
43{
44 //log_info << "button event: " << static_cast<int>(ev.button) << " " << static_cast<int>(ev.state) << std::endl;
45 Controller& controller = m_parent->get_controller();
46 auto set_control = [this, &controller](Control control, Uint8 value)
47 {
48 m_button_state[static_cast<int>(control)] = (value != 0);
49 controller.set_control(control, m_button_state[static_cast<int>(control)] == SDL_PRESSED || m_stick_state[static_cast<int>(control)] == SDL_PRESSED);
50 };
51 switch (ev.button)
52 {
53 case SDL_CONTROLLER_BUTTON_A:
54 set_control(Control::JUMP, ev.state);
55 set_control(Control::MENU_SELECT, ev.state);
56 break;
57
58 case SDL_CONTROLLER_BUTTON_B:
59 set_control(Control::MENU_BACK, ev.state);
60 break;
61
62 case SDL_CONTROLLER_BUTTON_X:
63 set_control(Control::ACTION, ev.state);
64 break;
65
66 case SDL_CONTROLLER_BUTTON_Y:
67 break;
68
69 case SDL_CONTROLLER_BUTTON_BACK:
70 set_control(Control::CONSOLE, ev.state);
71 break;
72
73 case SDL_CONTROLLER_BUTTON_GUIDE:
74 set_control(Control::CHEAT_MENU, ev.state);
75 break;
76
77 case SDL_CONTROLLER_BUTTON_START:
78 set_control(Control::START, ev.state);
79 break;
80
81 case SDL_CONTROLLER_BUTTON_LEFTSTICK:
82 break;
83
84 case SDL_CONTROLLER_BUTTON_RIGHTSTICK:
85 break;
86
87 case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
88 set_control(Control::PEEK_LEFT, ev.state);
89 break;
90
91 case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
92 set_control(Control::PEEK_RIGHT, ev.state);
93 break;
94
95 case SDL_CONTROLLER_BUTTON_DPAD_UP:
96 set_control(Control::UP, ev.state);
97 break;
98
99 case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
100 set_control(Control::DOWN, ev.state);
101 break;
102
103 case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
104 set_control(Control::LEFT, ev.state);
105 break;
106
107 case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
108 set_control(Control::RIGHT, ev.state);
109 break;
110
111 default:
112 break;
113 }
114}
115
116void
117GameControllerManager::process_axis_event(const SDL_ControllerAxisEvent& ev)
118{
119 // FIXME: buttons and axis are fighting for control ownership, need
120 // to OR the values together
121
122 //log_info << "axis event: " << static_cast<int>(ev.axis) << " " << ev.value << std::endl;
123 Controller& controller = m_parent->get_controller();
124 auto set_control = [this, &controller](Control control, bool value)
125 {
126 m_stick_state[static_cast<int>(control)] = value;
127 controller.set_control(control, m_button_state[static_cast<int>(control)] || m_stick_state[static_cast<int>(control)]);
128 };
129
130 auto axis2button = [this, &set_control](int value, Control control_left, Control control_right)
131 {
132 if (value < -m_deadzone)
133 {
134 set_control(control_left, true);
135 set_control(control_right, false);
136 }
137 else if (value > m_deadzone)
138 {
139 set_control(control_left, false);
140 set_control(control_right, true);
141 }
142 else
143 {
144 set_control(control_left, false);
145 set_control(control_right, false);
146 }
147 };
148
149 switch (ev.axis)
150 {
151 case SDL_CONTROLLER_AXIS_LEFTX:
152 axis2button(ev.value, Control::LEFT, Control::RIGHT);
153 break;
154
155 case SDL_CONTROLLER_AXIS_LEFTY:
156 axis2button(ev.value, Control::UP, Control::DOWN);
157 break;
158
159 case SDL_CONTROLLER_AXIS_RIGHTX:
160 axis2button(ev.value, Control::PEEK_LEFT, Control::PEEK_RIGHT);
161 break;
162
163 case SDL_CONTROLLER_AXIS_RIGHTY:
164 axis2button(ev.value, Control::PEEK_UP, Control::PEEK_DOWN);
165 break;
166
167 case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
168 break;
169
170 case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
171 break;
172
173 default:
174 break;
175 }
176}
177
178void
179GameControllerManager::on_controller_added(int joystick_index)
180{
181 if (!SDL_IsGameController(joystick_index))
182 {
183 log_warning << "joystick is not a game controller, ignoring: " << joystick_index << std::endl;
184 }
185 else
186 {
187 SDL_GameController* game_controller = SDL_GameControllerOpen(joystick_index);
188 if (!game_controller)
189 {
190 log_warning << "failed to open game_controller: " << joystick_index
191 << ": " << SDL_GetError() << std::endl;
192 }
193 else
194 {
195 m_game_controllers.push_back(game_controller);
196 }
197 }
198}
199
200void
201GameControllerManager::on_controller_removed(int instance_id)
202{
203 for (auto& controller : m_game_controllers)
204 {
205 auto joy = SDL_GameControllerGetJoystick(controller);
206 SDL_JoystickID id = SDL_JoystickInstanceID(joy);
207 if (id == instance_id)
208 {
209 SDL_GameControllerClose(controller);
210 controller = nullptr;
211 }
212 }
213
214 m_game_controllers.erase(std::remove(m_game_controllers.begin(), m_game_controllers.end(), nullptr),
215 m_game_controllers.end());
216}
217
218/* EOF */
219