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