2 // Copyright (C) 2014 Ingo Ruhnke <grumbel@gmail.com>
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.
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.
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/>.
17 #include "control/joystick_manager.hpp"
22 #include "control/input_manager.hpp"
23 #include "control/joystick_config.hpp"
24 #include "gui/menu_manager.hpp"
25 #include "lisp/list_iterator.hpp"
26 #include "supertux/menu/joystick_menu.hpp"
27 #include "util/gettext.hpp"
28 #include "util/log.hpp"
29 #include "util/writer.hpp"
31 JoystickManager::JoystickManager(InputManager* parent_,
32 JoystickConfig& joystick_config) :
34 m_joystick_config(joystick_config),
40 wait_for_joystick(-1),
45 JoystickManager::~JoystickManager()
47 for(auto joy : joysticks)
49 SDL_JoystickClose(joy);
54 JoystickManager::on_joystick_added(int joystick_index)
56 log_debug << "on_joystick_added(): " << joystick_index << std::endl;
57 SDL_Joystick* joystick = SDL_JoystickOpen(joystick_index);
60 log_warning << "failed to open joystick: " << joystick_index
61 << ": " << SDL_GetError() << std::endl;
65 joysticks.push_back(joystick);
68 if(min_joybuttons < 0 || SDL_JoystickNumButtons(joystick) < min_joybuttons)
69 min_joybuttons = SDL_JoystickNumButtons(joystick);
71 if(SDL_JoystickNumButtons(joystick) > max_joybuttons)
72 max_joybuttons = SDL_JoystickNumButtons(joystick);
74 if(SDL_JoystickNumAxes(joystick) > max_joyaxis)
75 max_joyaxis = SDL_JoystickNumAxes(joystick);
77 if(SDL_JoystickNumHats(joystick) > max_joyhats)
78 max_joyhats = SDL_JoystickNumHats(joystick);
82 JoystickManager::on_joystick_removed(int instance_id)
84 log_debug << "on_joystick_removed: " << static_cast<int>(instance_id) << std::endl;
85 for(auto& joy : joysticks)
87 SDL_JoystickID id = SDL_JoystickInstanceID(joy);
88 if (id == instance_id)
90 SDL_JoystickClose(joy);
95 joysticks.erase(std::remove(joysticks.begin(), joysticks.end(), nullptr),
100 JoystickManager::process_hat_event(const SDL_JoyHatEvent& jhat)
102 Uint8 changed = hat_state ^ jhat.value;
104 if (wait_for_joystick >= 0)
106 if (changed & SDL_HAT_UP && jhat.value & SDL_HAT_UP)
107 m_joystick_config.bind_joyhat(jhat.which, SDL_HAT_UP, Controller::Control(wait_for_joystick));
109 if (changed & SDL_HAT_DOWN && jhat.value & SDL_HAT_DOWN)
110 m_joystick_config.bind_joyhat(jhat.which, SDL_HAT_DOWN, Controller::Control(wait_for_joystick));
112 if (changed & SDL_HAT_LEFT && jhat.value & SDL_HAT_LEFT)
113 m_joystick_config.bind_joyhat(jhat.which, SDL_HAT_LEFT, Controller::Control(wait_for_joystick));
115 if (changed & SDL_HAT_RIGHT && jhat.value & SDL_HAT_RIGHT)
116 m_joystick_config.bind_joyhat(jhat.which, SDL_HAT_RIGHT, Controller::Control(wait_for_joystick));
118 MenuManager::instance().refresh();
119 wait_for_joystick = -1;
123 if (changed & SDL_HAT_UP)
125 JoystickConfig::HatMap::iterator it = m_joystick_config.joy_hat_map.find(std::make_pair(jhat.which, SDL_HAT_UP));
126 if (it != m_joystick_config.joy_hat_map.end())
127 set_joy_controls(it->second, jhat.value & SDL_HAT_UP);
130 if (changed & SDL_HAT_DOWN)
132 JoystickConfig::HatMap::iterator it = m_joystick_config.joy_hat_map.find(std::make_pair(jhat.which, SDL_HAT_DOWN));
133 if (it != m_joystick_config.joy_hat_map.end())
134 set_joy_controls(it->second, jhat.value & SDL_HAT_DOWN);
137 if (changed & SDL_HAT_LEFT)
139 JoystickConfig::HatMap::iterator it = m_joystick_config.joy_hat_map.find(std::make_pair(jhat.which, SDL_HAT_LEFT));
140 if (it != m_joystick_config.joy_hat_map.end())
141 set_joy_controls(it->second, jhat.value & SDL_HAT_LEFT);
144 if (changed & SDL_HAT_RIGHT)
146 JoystickConfig::HatMap::iterator it = m_joystick_config.joy_hat_map.find(std::make_pair(jhat.which, SDL_HAT_RIGHT));
147 if (it != m_joystick_config.joy_hat_map.end())
148 set_joy_controls(it->second, jhat.value & SDL_HAT_RIGHT);
152 hat_state = jhat.value;
156 JoystickManager::process_axis_event(const SDL_JoyAxisEvent& jaxis)
158 if (wait_for_joystick >= 0)
160 if (abs(jaxis.value) > m_joystick_config.dead_zone) {
162 m_joystick_config.bind_joyaxis(jaxis.which, -(jaxis.axis + 1), Controller::Control(wait_for_joystick));
164 m_joystick_config.bind_joyaxis(jaxis.which, jaxis.axis + 1, Controller::Control(wait_for_joystick));
166 MenuManager::instance().refresh();
167 wait_for_joystick = -1;
172 // Split the axis into left and right, so that both can be
173 // mapped separately (needed for jump/down vs up/down)
174 int axis = jaxis.axis + 1;
176 auto left = m_joystick_config.joy_axis_map.find(std::make_pair(jaxis.which, -axis));
177 auto right = m_joystick_config.joy_axis_map.find(std::make_pair(jaxis.which, axis));
179 if(left == m_joystick_config.joy_axis_map.end()) {
180 // std::cout << "Unmapped joyaxis " << (int)jaxis.axis << " moved" << std::endl;
182 if (jaxis.value < -m_joystick_config.dead_zone)
183 set_joy_controls(left->second, true);
185 set_joy_controls(left->second, false);
188 if(right == m_joystick_config.joy_axis_map.end()) {
189 // std::cout << "Unmapped joyaxis " << (int)jaxis.axis << " moved" << std::endl;
191 if (jaxis.value > m_joystick_config.dead_zone)
192 set_joy_controls(right->second, true);
194 set_joy_controls(right->second, false);
200 JoystickManager::process_button_event(const SDL_JoyButtonEvent& jbutton)
202 if(wait_for_joystick >= 0)
204 if(jbutton.state == SDL_PRESSED)
206 m_joystick_config.bind_joybutton(jbutton.which, jbutton.button, (Controller::Control)wait_for_joystick);
207 MenuManager::instance().refresh();
209 wait_for_joystick = -1;
214 auto i = m_joystick_config.joy_button_map.find(std::make_pair(jbutton.which, jbutton.button));
215 if(i == m_joystick_config.joy_button_map.end()) {
216 log_debug << "Unmapped joybutton " << (int)jbutton.button << " pressed" << std::endl;
218 set_joy_controls(i->second, (jbutton.state == SDL_PRESSED));
224 JoystickManager::bind_next_event_to(Controller::Control id)
226 wait_for_joystick = id;
230 JoystickManager::set_joy_controls(Controller::Control id, bool value)
232 if (m_joystick_config.jump_with_up_joy &&
233 id == Controller::UP)
235 parent->get_controller()->set_control(Controller::JUMP, value);
238 parent->get_controller()->set_control(id, value);