Merge branch 'feature/developer-mode'
[supertux.git] / src / control / game_controller_manager.cpp
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
24 GameControllerManager::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
33 GameControllerManager::~GameControllerManager()
34 {
35   for(auto con : m_game_controllers)
36   {
37     SDL_GameControllerClose(con);
38   }
39 }
40
41 void
42 GameControllerManager::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   auto controller = m_parent->get_controller();
46   auto set_control = [this, &controller](Controller::Control control, bool value)
47   {
48     m_button_state[control] = value;
49     controller->set_control(control, m_button_state[control] || m_stick_state[control]);
50   };
51   switch(ev.button)
52   {
53     case SDL_CONTROLLER_BUTTON_A:
54       set_control(Controller::JUMP, ev.state);
55       set_control(Controller::MENU_SELECT, ev.state);
56       break;
57
58     case SDL_CONTROLLER_BUTTON_B:
59       set_control(Controller::MENU_BACK, ev.state);
60       break;
61
62     case SDL_CONTROLLER_BUTTON_X:
63       set_control(Controller::ACTION, ev.state);
64       break;
65
66     case SDL_CONTROLLER_BUTTON_Y:
67       break;
68
69     case SDL_CONTROLLER_BUTTON_BACK:
70       set_control(Controller::CONSOLE, ev.state);
71       break;
72
73     case SDL_CONTROLLER_BUTTON_GUIDE:
74       set_control(Controller::CHEAT_MENU, ev.state);
75       break;
76
77     case SDL_CONTROLLER_BUTTON_START:
78       set_control(Controller::PAUSE_MENU, 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(Controller::PEEK_LEFT, ev.state);
89       break;
90
91     case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
92       set_control(Controller::PEEK_RIGHT, ev.state);
93       break;
94
95     case SDL_CONTROLLER_BUTTON_DPAD_UP:
96       set_control(Controller::UP, ev.state);
97       break;
98
99     case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
100       set_control(Controller::DOWN, ev.state);
101       break;
102
103     case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
104       set_control(Controller::LEFT, ev.state);
105       break;
106
107     case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
108       set_control(Controller::RIGHT, ev.state);
109       break;
110
111     default:
112       break;
113   }
114 }
115
116 void
117 GameControllerManager::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   auto controller = m_parent->get_controller();
124   auto set_control = [this, &controller](Controller::Control control, bool value)
125   {
126     m_stick_state[control] = value;
127     controller->set_control(control, m_button_state[control] || m_stick_state[control]);
128   };
129
130   auto axis2button = [this, &set_control](int value,
131                                          Controller::Control control_left, Controller::Control control_right)
132     {
133       if (value < -m_deadzone)
134       {
135         set_control(control_left, true);
136         set_control(control_right, false);
137       }
138       else if (value > m_deadzone)
139       {
140         set_control(control_left, false);
141         set_control(control_right, true);
142       }
143       else
144       {
145         set_control(control_left, false);
146         set_control(control_right, false);
147       }
148     };
149
150   switch(ev.axis)
151   {
152     case SDL_CONTROLLER_AXIS_LEFTX:
153       axis2button(ev.value, Controller::LEFT, Controller::RIGHT);
154       break;
155
156     case SDL_CONTROLLER_AXIS_LEFTY:
157       axis2button(ev.value, Controller::UP, Controller::DOWN);
158       break;
159
160     case SDL_CONTROLLER_AXIS_RIGHTX:
161       axis2button(ev.value, Controller::PEEK_LEFT, Controller::PEEK_RIGHT);
162       break;
163
164     case SDL_CONTROLLER_AXIS_RIGHTY:
165       axis2button(ev.value, Controller::PEEK_UP, Controller::PEEK_DOWN);
166       break;
167
168     case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
169       break;
170
171     case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
172       break;
173
174     default:
175       break;
176   }
177 }
178
179 void
180 GameControllerManager::on_controller_added(int joystick_index)
181 {
182   if (!SDL_IsGameController(joystick_index))
183   {
184     log_warning << "joystick is not a game controller, ignoring: " << joystick_index << std::endl;
185   }
186   else
187   {
188     SDL_GameController* game_controller = SDL_GameControllerOpen(joystick_index);
189     if (!game_controller)
190     {
191       log_warning << "failed to open game_controller: " << joystick_index
192                   << ": " << SDL_GetError() << std::endl;
193     }
194     else
195     {
196       m_game_controllers.push_back(game_controller);
197     }
198   }
199 }
200
201 void
202 GameControllerManager::on_controller_removed(int instance_id)
203 {
204   for(auto& controller : m_game_controllers)
205   {
206     SDL_Joystick* joy = SDL_GameControllerGetJoystick(controller);
207     SDL_JoystickID id = SDL_JoystickInstanceID(joy);
208     if (id == instance_id)
209     {
210       SDL_GameControllerClose(controller);
211       controller = nullptr;
212     }
213   }
214
215   m_game_controllers.erase(std::remove(m_game_controllers.begin(), m_game_controllers.end(), nullptr),
216                            m_game_controllers.end());
217 }
218
219 /* EOF */