Implemented basic support for SDL GameController
[supertux.git] / src / control / game_controller_manager.cpp
1 //  SuperTux
2 //  Copyright (C) 2014 Ingo Ruhnke <grumbel@gmx.de>
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/joystickkeyboardcontroller.hpp"
22 #include "util/log.hpp"
23
24 GameControllerManager::GameControllerManager(JoystickKeyboardController* parent) :
25   m_parent(parent),
26   m_deadzone(8000),
27   m_game_controllers()
28 {
29 }
30
31 GameControllerManager::~GameControllerManager()
32 {
33   for(auto con : m_game_controllers)
34   {
35     SDL_GameControllerClose(con);
36   }
37 }
38
39 void
40 GameControllerManager::process_button_event(const SDL_ControllerButtonEvent& ev)
41 {
42   //log_info << "button event: " << static_cast<int>(ev.button) << " " << static_cast<int>(ev.state) << std::endl;
43   auto controller = m_parent->get_main_controller();
44   switch(ev.button)
45   {
46     case SDL_CONTROLLER_BUTTON_A:
47       controller->set_control(Controller::JUMP, ev.state);
48       controller->set_control(Controller::MENU_SELECT, ev.state);
49       break;
50
51     case SDL_CONTROLLER_BUTTON_B:
52       break;
53
54     case SDL_CONTROLLER_BUTTON_X:
55       controller->set_control(Controller::ACTION, ev.state);
56       break;
57
58     case SDL_CONTROLLER_BUTTON_Y:
59       break;
60
61     case SDL_CONTROLLER_BUTTON_BACK:
62       break;
63
64     case SDL_CONTROLLER_BUTTON_GUIDE:
65       controller->set_control(Controller::CONSOLE, ev.state);
66       break;
67
68     case SDL_CONTROLLER_BUTTON_START:
69       controller->set_control(Controller::PAUSE_MENU, ev.state);
70       break;
71
72     case SDL_CONTROLLER_BUTTON_LEFTSTICK:
73       break;
74
75     case SDL_CONTROLLER_BUTTON_RIGHTSTICK:
76       break;
77
78     case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
79       controller->set_control(Controller::PEEK_LEFT, ev.state);
80       break;
81
82     case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
83       controller->set_control(Controller::PEEK_RIGHT, ev.state);
84       break;
85
86     case SDL_CONTROLLER_BUTTON_DPAD_UP:
87       controller->set_control(Controller::UP, ev.state);
88       break;
89
90     case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
91       controller->set_control(Controller::DOWN, ev.state);
92       break;
93
94     case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
95       controller->set_control(Controller::LEFT, ev.state);
96       break;
97
98     case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
99       controller->set_control(Controller::RIGHT, ev.state);
100       break;
101
102     default:
103       break;
104   }
105 }
106
107 void
108 GameControllerManager::process_axis_event(const SDL_ControllerAxisEvent& ev)
109 {
110   // FIXME: buttons and axis are fighting for control ownership, need
111   // to OR the values together
112
113   //log_info << "axis event: " << static_cast<int>(ev.axis) << " " << ev.value << std::endl;
114   auto controller = m_parent->get_main_controller();
115   auto axis2button = [this, &controller](int value,
116                                          Controller::Control control_left, Controller::Control control_right)
117     {
118       if (value < -m_deadzone)
119       {
120         controller->set_control(control_left, true);
121         controller->set_control(control_right, false);
122       }
123       else if (value > m_deadzone)
124       {
125         controller->set_control(control_left, false);
126         controller->set_control(control_right, true);
127       }
128       else
129       {
130         controller->set_control(control_left, false);
131         controller->set_control(control_right, false);
132       }
133     };
134
135   switch(ev.axis)
136   {
137     case SDL_CONTROLLER_AXIS_LEFTX:
138       axis2button(ev.value, Controller::LEFT, Controller::RIGHT);
139       break;
140
141     case SDL_CONTROLLER_AXIS_LEFTY:
142       axis2button(ev.value, Controller::UP, Controller::DOWN);
143       break;
144
145     case SDL_CONTROLLER_AXIS_RIGHTX:
146       axis2button(ev.value, Controller::PEEK_LEFT, Controller::PEEK_RIGHT);
147       break;
148
149     case SDL_CONTROLLER_AXIS_RIGHTY:
150       axis2button(ev.value, Controller::PEEK_UP, Controller::PEEK_DOWN);
151       break;
152
153     case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
154       break;
155
156     case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
157       break;
158
159     default:
160       break;
161   }
162 }
163
164 void
165 GameControllerManager::on_controller_added(int joystick_index)
166 {
167   if (!SDL_IsGameController(joystick_index))
168   {
169     log_warning << "joystick is not a game controller, ignoring: " << joystick_index << std::endl;
170   }
171   else
172   {
173     SDL_GameController* game_controller = SDL_GameControllerOpen(joystick_index);
174     if (!game_controller)
175     {
176       log_warning << "failed to open game_controller: " << joystick_index
177                   << ": " << SDL_GetError() << std::endl;
178     }
179     else
180     {
181       m_game_controllers.push_back(game_controller);
182     }
183   }
184 }
185
186 void
187 GameControllerManager::on_controller_removed(int instance_id)
188 {
189   for(auto& controller : m_game_controllers)
190   {
191     SDL_Joystick* joy = SDL_GameControllerGetJoystick(controller);
192     SDL_JoystickID id = SDL_JoystickInstanceID(joy);
193     if (id == instance_id)
194     {
195       SDL_GameControllerClose(controller);
196       controller = nullptr;
197     }
198   }
199
200   m_game_controllers.erase(std::remove(m_game_controllers.begin(), m_game_controllers.end(), nullptr),
201                            m_game_controllers.end());
202 }
203
204 /* EOF */