Added MENU_BACK button (i.e. B on Xbox360 controller)
[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       controller->set_control(Controller::MENU_BACK, ev.state);
53       break;
54
55     case SDL_CONTROLLER_BUTTON_X:
56       controller->set_control(Controller::ACTION, ev.state);
57       break;
58
59     case SDL_CONTROLLER_BUTTON_Y:
60       break;
61
62     case SDL_CONTROLLER_BUTTON_BACK:
63       break;
64
65     case SDL_CONTROLLER_BUTTON_GUIDE:
66       controller->set_control(Controller::CONSOLE, ev.state);
67       break;
68
69     case SDL_CONTROLLER_BUTTON_START:
70       controller->set_control(Controller::PAUSE_MENU, ev.state);
71       break;
72
73     case SDL_CONTROLLER_BUTTON_LEFTSTICK:
74       break;
75
76     case SDL_CONTROLLER_BUTTON_RIGHTSTICK:
77       break;
78
79     case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
80       controller->set_control(Controller::PEEK_LEFT, ev.state);
81       break;
82
83     case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
84       controller->set_control(Controller::PEEK_RIGHT, ev.state);
85       break;
86
87     case SDL_CONTROLLER_BUTTON_DPAD_UP:
88       controller->set_control(Controller::UP, ev.state);
89       break;
90
91     case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
92       controller->set_control(Controller::DOWN, ev.state);
93       break;
94
95     case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
96       controller->set_control(Controller::LEFT, ev.state);
97       break;
98
99     case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
100       controller->set_control(Controller::RIGHT, ev.state);
101       break;
102
103     default:
104       break;
105   }
106 }
107
108 void
109 GameControllerManager::process_axis_event(const SDL_ControllerAxisEvent& ev)
110 {
111   // FIXME: buttons and axis are fighting for control ownership, need
112   // to OR the values together
113
114   //log_info << "axis event: " << static_cast<int>(ev.axis) << " " << ev.value << std::endl;
115   auto controller = m_parent->get_main_controller();
116   auto axis2button = [this, &controller](int value,
117                                          Controller::Control control_left, Controller::Control control_right)
118     {
119       if (value < -m_deadzone)
120       {
121         controller->set_control(control_left, true);
122         controller->set_control(control_right, false);
123       }
124       else if (value > m_deadzone)
125       {
126         controller->set_control(control_left, false);
127         controller->set_control(control_right, true);
128       }
129       else
130       {
131         controller->set_control(control_left, false);
132         controller->set_control(control_right, false);
133       }
134     };
135
136   switch(ev.axis)
137   {
138     case SDL_CONTROLLER_AXIS_LEFTX:
139       axis2button(ev.value, Controller::LEFT, Controller::RIGHT);
140       break;
141
142     case SDL_CONTROLLER_AXIS_LEFTY:
143       axis2button(ev.value, Controller::UP, Controller::DOWN);
144       break;
145
146     case SDL_CONTROLLER_AXIS_RIGHTX:
147       axis2button(ev.value, Controller::PEEK_LEFT, Controller::PEEK_RIGHT);
148       break;
149
150     case SDL_CONTROLLER_AXIS_RIGHTY:
151       axis2button(ev.value, Controller::PEEK_UP, Controller::PEEK_DOWN);
152       break;
153
154     case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
155       break;
156
157     case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
158       break;
159
160     default:
161       break;
162   }
163 }
164
165 void
166 GameControllerManager::on_controller_added(int joystick_index)
167 {
168   if (!SDL_IsGameController(joystick_index))
169   {
170     log_warning << "joystick is not a game controller, ignoring: " << joystick_index << std::endl;
171   }
172   else
173   {
174     SDL_GameController* game_controller = SDL_GameControllerOpen(joystick_index);
175     if (!game_controller)
176     {
177       log_warning << "failed to open game_controller: " << joystick_index
178                   << ": " << SDL_GetError() << std::endl;
179     }
180     else
181     {
182       m_game_controllers.push_back(game_controller);
183     }
184   }
185 }
186
187 void
188 GameControllerManager::on_controller_removed(int instance_id)
189 {
190   for(auto& controller : m_game_controllers)
191   {
192     SDL_Joystick* joy = SDL_GameControllerGetJoystick(controller);
193     SDL_JoystickID id = SDL_JoystickInstanceID(joy);
194     if (id == instance_id)
195     {
196       SDL_GameControllerClose(controller);
197       controller = nullptr;
198     }
199   }
200
201   m_game_controllers.erase(std::remove(m_game_controllers.begin(), m_game_controllers.end(), nullptr),
202                            m_game_controllers.end());
203 }
204
205 /* EOF */