Separate JoystickConfig out into a separate class that can be stored in the global...
[supertux.git] / src / control / joystick_config.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/joystick_config.hpp"
18
19 #include <iostream>
20
21 #include "lisp/list_iterator.hpp"
22 #include "util/gettext.hpp"
23 #include "util/log.hpp"
24
25 JoystickConfig::JoystickConfig() :
26   dead_zone(8000),
27   jump_with_up_joy(false),
28   joy_button_map(),
29   joy_axis_map(),
30   joy_hat_map()
31 {
32   // Default joystick button configuration
33   bind_joybutton(0, 0, Controller::JUMP);
34   bind_joybutton(0, 0, Controller::MENU_SELECT);
35   bind_joybutton(0, 1, Controller::ACTION);
36   bind_joybutton(0, 4, Controller::PEEK_LEFT);
37   bind_joybutton(0, 5, Controller::PEEK_RIGHT);
38   bind_joybutton(0, 6, Controller::PAUSE_MENU);
39
40   // Default joystick axis configuration
41   bind_joyaxis(0, -1, Controller::LEFT);
42   bind_joyaxis(0, 1, Controller::RIGHT);
43   bind_joyaxis(0, -2, Controller::UP);
44   bind_joyaxis(0, 2, Controller::DOWN);
45 }
46
47 int
48 JoystickConfig::reversemap_joyaxis(Controller::Control c)
49 {
50   for(AxisMap::iterator i = joy_axis_map.begin(); i != joy_axis_map.end(); ++i) {
51     if (i->second == c)
52       return i->first.second;
53   }
54
55   return 0;
56 }
57
58 int
59 JoystickConfig::reversemap_joybutton(Controller::Control c)
60 {
61   for(ButtonMap::iterator i = joy_button_map.begin(); i != joy_button_map.end(); ++i) {
62     if (i->second == c)
63       return i->first.second;
64   }
65
66   return -1;
67 }
68
69 int
70 JoystickConfig::reversemap_joyhat(Controller::Control c)
71 {
72   for(HatMap::iterator i = joy_hat_map.begin(); i != joy_hat_map.end(); ++i) {
73     if (i->second == c)
74       return i->first.second;
75   }
76
77   return -1;
78 }
79
80 void
81 JoystickConfig::print_joystick_mappings()
82 {
83   std::cout << _("Joystick Mappings") << std::endl;
84   std::cout << "-----------------" << std::endl;
85   for(AxisMap::iterator i = joy_axis_map.begin(); i != joy_axis_map.end(); ++i) {
86     std::cout << "Axis: " << i->first.second << " -> " << i->second << std::endl;
87   }
88
89   for(ButtonMap::iterator i = joy_button_map.begin(); i != joy_button_map.end(); ++i) {
90     std::cout << "Button: " << i->first.second << " -> " << i->second << std::endl;
91   }
92
93   for(HatMap::iterator i = joy_hat_map.begin(); i != joy_hat_map.end(); ++i) {
94     std::cout << "Hat: " << i->first.second << " -> " << i->second << std::endl;
95   }
96   std::cout << std::endl;
97 }
98
99 void
100 JoystickConfig::unbind_joystick_control(Controller::Control control)
101 {
102   // remove all previous mappings for that control
103   for(AxisMap::iterator i = joy_axis_map.begin(); i != joy_axis_map.end(); /* no ++i */) {
104     if (i->second == control)
105       joy_axis_map.erase(i++);
106     else
107       ++i;
108   }
109
110   for(ButtonMap::iterator i = joy_button_map.begin(); i != joy_button_map.end(); /* no ++i */) {
111     if (i->second == control)
112       joy_button_map.erase(i++);
113     else
114       ++i;
115   }
116
117   for(HatMap::iterator i = joy_hat_map.begin();  i != joy_hat_map.end(); /* no ++i */) {
118     if (i->second == control)
119       joy_hat_map.erase(i++);
120     else
121       ++i;
122   }
123 }
124
125 void
126 JoystickConfig::bind_joyaxis(JoyId joy_id, int axis, Controller::Control control)
127 {
128   // axis isn't the SDL axis number, but axisnumber + 1 with sign
129   // changed depending on if the positive or negative end is to be
130   // used (negative axis 0 becomes -1, positive axis 2 becomes +3,
131   // etc.)
132
133   unbind_joystick_control(control);
134
135   // add new mapping
136   joy_axis_map[std::make_pair(joy_id, axis)] = control;
137 }
138
139 void
140 JoystickConfig::bind_joyhat(JoyId joy_id, int dir, Controller::Control c)
141 {
142   unbind_joystick_control(c);
143
144   // add new mapping
145   joy_hat_map[std::make_pair(joy_id, dir)] = c;
146 }
147
148 void
149 JoystickConfig::bind_joybutton(JoyId joy_id, int button, Controller::Control control)
150 {
151   unbind_joystick_control(control);
152
153   // add new mapping
154   joy_button_map[std::make_pair(joy_id, button)] = control;
155 }
156
157 void
158 JoystickConfig::read(const lisp::Lisp* joystick_lisp)
159 {
160   joystick_lisp->get("dead-zone", dead_zone);
161   joystick_lisp->get("jump-with-up", jump_with_up_joy);
162
163   lisp::ListIterator iter(joystick_lisp);
164   while(iter.next())
165   {
166     if (iter.item() == "map")
167     {
168       int button = -1;
169       int axis   = 0;
170       int hat    = -1;
171       std::string control;
172       const lisp::Lisp* map = iter.lisp();
173
174       map->get("control", control);
175       int i = 0;
176       for(i = 0; Controller::controlNames[i] != 0; ++i)
177       {
178         if (control == Controller::controlNames[i])
179           break;
180       }
181
182       if (Controller::controlNames[i] == 0)
183       {
184         log_info << "Invalid control '" << control << "' in buttonmap" << std::endl;
185       }
186       else
187       {
188         if (map->get("button", button))
189         {
190           bind_joybutton(0, button, Controller::Control(i));
191         }
192         else if (map->get("axis",   axis))
193         {
194           bind_joyaxis(0, axis, Controller::Control(i));
195         }
196         else if (map->get("hat",   hat))
197         {
198           if (hat != SDL_HAT_UP   &&
199               hat != SDL_HAT_DOWN &&
200               hat != SDL_HAT_LEFT &&
201               hat != SDL_HAT_RIGHT) {
202             log_info << "Invalid axis '" << axis << "' in axismap" << std::endl;
203           }
204           else
205           {
206             bind_joyhat(0, hat, Controller::Control(i));
207           }
208         }
209       }
210     }
211   }
212 }
213
214 void
215 JoystickConfig::write(Writer& writer)
216 {
217   writer.write("dead-zone", dead_zone);
218   writer.write("jump-with-up", jump_with_up_joy);
219
220   for(ButtonMap::iterator i = joy_button_map.begin(); i != joy_button_map.end();
221       ++i) {
222     writer.start_list("map");
223     writer.write("button", i->first.second);
224     writer.write("control", Controller::controlNames[i->second]);
225     writer.end_list("map");
226   }
227
228   for(HatMap::iterator i = joy_hat_map.begin(); i != joy_hat_map.end(); ++i) {
229     writer.start_list("map");
230     writer.write("hat", i->first.second);
231     writer.write("control", Controller::controlNames[i->second]);
232     writer.end_list("map");
233   }
234
235   for(AxisMap::iterator i = joy_axis_map.begin(); i != joy_axis_map.end(); ++i) {
236     writer.start_list("map");
237     writer.write("axis", i->first.second);
238     writer.write("control", Controller::controlNames[i->second]);
239     writer.end_list("map");
240   }
241 }
242
243 /* EOF */