Removed obsolete keycode range check
[supertux.git] / src / control / joystickkeyboardcontroller.cpp
1 //  SuperTux
2 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>,
3 //                2007 Ingo Ruhnke <grumbel@gmx.de>
4 //
5 //  This program is free software: you can redistribute it and/or modify
6 //  it under the terms of the GNU General Public License as published by
7 //  the Free Software Foundation, either version 3 of the License, or
8 //  (at your option) any later version.
9 //
10 //  This program is distributed in the hope that it will be useful,
11 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //  GNU General Public License for more details.
14 //
15 //  You should have received a copy of the GNU General Public License
16 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18 #include "control/joystickkeyboardcontroller.hpp"
19
20 #include <iostream>
21
22 #include "control/joystick_manager.hpp"
23 #include "control/game_controller_manager.hpp"
24 #include "gui/menu_manager.hpp"
25 #include "lisp/list_iterator.hpp"
26 #include "supertux/console.hpp"
27 #include "supertux/gameconfig.hpp"
28 #include "supertux/menu/joystick_menu.hpp"
29 #include "supertux/menu/keyboard_menu.hpp"
30 #include "supertux/menu/menu_storage.hpp"
31 #include "util/gettext.hpp"
32 #include "util/writer.hpp"
33
34 JoystickKeyboardController::JoystickKeyboardController() :
35   controller(new Controller),
36   m_use_game_controller(true),
37   joystick_manager(new JoystickManager(this)),
38   game_controller_manager(new GameControllerManager(this)),
39   keymap(),
40   jump_with_up_kbd(),
41   wait_for_key(-1)
42 {
43   // initialize default keyboard map
44   keymap[SDLK_LEFT]     = Controller::LEFT;
45   keymap[SDLK_RIGHT]    = Controller::RIGHT;
46   keymap[SDLK_UP]       = Controller::UP;
47   keymap[SDLK_DOWN]     = Controller::DOWN;
48   keymap[SDLK_SPACE]    = Controller::JUMP;
49   keymap[SDLK_LCTRL]    = Controller::ACTION;
50   keymap[SDLK_LALT]     = Controller::ACTION;
51   keymap[SDLK_ESCAPE]   = Controller::PAUSE_MENU;
52   keymap[SDLK_p]        = Controller::PAUSE_MENU;
53   keymap[SDLK_PAUSE]    = Controller::PAUSE_MENU;
54   keymap[SDLK_RETURN]   = Controller::MENU_SELECT;
55   keymap[SDLK_KP_ENTER] = Controller::MENU_SELECT;
56   keymap[SDLK_CARET]    = Controller::CONSOLE;
57   keymap[SDLK_DELETE]   = Controller::PEEK_LEFT;
58   keymap[SDLK_PAGEDOWN] = Controller::PEEK_RIGHT;
59   keymap[SDLK_HOME]     = Controller::PEEK_UP;
60   keymap[SDLK_END]      = Controller::PEEK_DOWN;
61
62   jump_with_up_kbd = false;
63 }
64
65 JoystickKeyboardController::~JoystickKeyboardController()
66 {
67 }
68
69 Controller*
70 JoystickKeyboardController::get_main_controller()
71 {
72   return controller.get();
73 }
74
75 void
76 JoystickKeyboardController::read(const Reader& lisp)
77 {
78   const lisp::Lisp* keymap_lisp = lisp.get_lisp("keymap");
79   if (keymap_lisp) {
80     keymap.clear();
81     keymap_lisp->get("jump-with-up", jump_with_up_kbd);
82     lisp::ListIterator iter(keymap_lisp);
83     while(iter.next()) {
84       if (iter.item() == "map") {
85         int key = -1;
86         std::string control;
87         const lisp::Lisp* map = iter.lisp();
88         map->get("key", key);
89         map->get("control", control);
90
91         int i = 0;
92         for(i = 0; Controller::controlNames[i] != 0; ++i) {
93           if (control == Controller::controlNames[i])
94             break;
95         }
96         if (Controller::controlNames[i] == 0) {
97           log_info << "Invalid control '" << control << "' in keymap" << std::endl;
98           continue;
99         }
100         keymap[SDL_Keycode(key)] = Control(i);
101       }
102     }
103   }
104
105   const lisp::Lisp* joystick_lisp = lisp.get_lisp(_("joystick"));
106   if (joystick_lisp) 
107   {
108     joystick_manager->read(joystick_lisp);
109   }
110 }
111
112 void
113 JoystickKeyboardController::write(Writer& writer)
114 {
115   writer.start_list("keymap");
116   writer.write("jump-with-up", jump_with_up_kbd);
117   for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
118     writer.start_list("map");
119     writer.write("key", (int) i->first);
120     writer.write("control", Controller::controlNames[i->second]);
121     writer.end_list("map");
122   }
123   writer.end_list("keymap");
124
125   writer.start_list("joystick");
126   joystick_manager->write(writer);
127   writer.end_list("joystick");
128 }
129
130 void
131 JoystickKeyboardController::update()
132 {
133   controller->update();
134 }
135
136 void
137 JoystickKeyboardController::reset()
138 {
139   controller->reset();
140 }
141
142 void
143 JoystickKeyboardController::process_event(const SDL_Event& event)
144 {
145   switch(event.type) {
146     case SDL_TEXTINPUT:
147       process_text_input_event(event.text);
148       break;
149
150     case SDL_KEYUP:
151     case SDL_KEYDOWN:
152       process_key_event(event.key);
153       break;
154
155     case SDL_JOYAXISMOTION:
156       if (!m_use_game_controller) joystick_manager->process_axis_event(event.jaxis);
157       break;
158
159     case SDL_JOYHATMOTION:
160       if (!m_use_game_controller) joystick_manager->process_hat_event(event.jhat);
161       break;
162
163     case SDL_JOYBUTTONDOWN:
164     case SDL_JOYBUTTONUP:
165       if (!m_use_game_controller) joystick_manager->process_button_event(event.jbutton);
166       break;
167
168     case SDL_JOYDEVICEADDED:
169       if (!m_use_game_controller) joystick_manager->on_joystick_added(event.jdevice.which);
170       break;
171
172     case SDL_JOYDEVICEREMOVED:
173       if (!m_use_game_controller) joystick_manager->on_joystick_removed(event.jdevice.which);
174       break;
175
176     case SDL_CONTROLLERAXISMOTION:
177       if (m_use_game_controller) game_controller_manager->process_axis_event(event.caxis);
178       break;
179
180     case SDL_CONTROLLERBUTTONDOWN:
181       if (m_use_game_controller) game_controller_manager->process_button_event(event.cbutton);
182       break;
183
184     case SDL_CONTROLLERBUTTONUP:
185       if (m_use_game_controller) game_controller_manager->process_button_event(event.cbutton);
186       break;
187
188     case SDL_CONTROLLERDEVICEADDED:
189       std::cout << "SDL_CONTROLLERDEVICEADDED" << std::endl;
190       if (m_use_game_controller) game_controller_manager->on_controller_added(event.cdevice.which);
191       break;
192
193     case SDL_CONTROLLERDEVICEREMOVED:
194       std::cout << "SDL_CONTROLLERDEVICEREMOVED" << std::endl;
195       if (m_use_game_controller) game_controller_manager->on_controller_removed(event.cdevice.which);
196       break;
197
198     case SDL_CONTROLLERDEVICEREMAPPED:
199       std::cout << "SDL_CONTROLLERDEVICEREMAPPED" << std::endl;
200       break;
201
202     default:
203       break;
204   }
205 }
206
207 void
208 JoystickKeyboardController::process_text_input_event(const SDL_TextInputEvent& event)
209 {
210   if (Console::instance->hasFocus()) {
211     for(int i = 0; event.text[i] != '\0'; ++i)
212     {
213       Console::instance->input(event.text[i]);
214     }
215   }
216 }
217
218 void
219 JoystickKeyboardController::process_key_event(const SDL_KeyboardEvent& event)
220 {
221   KeyMap::iterator key_mapping = keymap.find(event.keysym.sym);
222
223   // if console key was pressed: toggle console
224   if ((key_mapping != keymap.end()) && (key_mapping->second == Controller::CONSOLE)) {
225     if (event.type == SDL_KEYDOWN) 
226       Console::instance->toggle();
227   } else {
228     if (Console::instance->hasFocus()) {
229       // if console is open: send key there
230       process_console_key_event(event);
231     } else if (MenuManager::current()) {
232       // if menu mode: send key there
233       process_menu_key_event(event);
234     } else if (key_mapping == keymap.end()) {
235       // default action: update controls
236       //log_debug << "Key " << event.key.SDL_Keycode.sym << " is unbound" << std::endl;
237     } else {
238       Control control = key_mapping->second;
239       bool value = (event.type == SDL_KEYDOWN);
240       controller->set_control(control, value);
241       if (jump_with_up_kbd && control == Controller::UP){
242         controller->set_control(Controller::JUMP, value);
243       }
244     }
245   }
246 }
247
248 void
249 JoystickKeyboardController::process_console_key_event(const SDL_KeyboardEvent& event)
250 {
251   if (event.type != SDL_KEYDOWN) return;
252
253   switch (event.keysym.sym) {
254     case SDLK_RETURN:
255       Console::instance->enter();
256       break;
257     case SDLK_BACKSPACE:
258       Console::instance->backspace();
259       break;
260     case SDLK_TAB:
261       Console::instance->autocomplete();
262       break;
263     case SDLK_PAGEUP:
264       Console::instance->scroll(-1);
265       break;
266     case SDLK_PAGEDOWN:
267       Console::instance->scroll(+1);
268       break;
269     case SDLK_HOME:
270       Console::instance->move_cursor(-65535);
271       break;
272     case SDLK_END:
273       Console::instance->move_cursor(+65535);
274       break;
275     case SDLK_UP:
276       Console::instance->show_history(-1);
277       break;
278     case SDLK_DOWN:
279       Console::instance->show_history(+1);
280       break;
281     case SDLK_LEFT:
282       Console::instance->move_cursor(-1);
283       break;
284     case SDLK_RIGHT:
285       Console::instance->move_cursor(+1);
286       break;
287     default:
288       break;
289   }
290 }
291
292 void
293 JoystickKeyboardController::process_menu_key_event(const SDL_KeyboardEvent& event)
294 {
295   // wait for key mode?
296   if (wait_for_key >= 0) {
297     if (event.type == SDL_KEYUP)
298       return;
299
300     if (event.keysym.sym != SDLK_ESCAPE
301        && event.keysym.sym != SDLK_PAUSE) {
302       bind_key(event.keysym.sym, Control(wait_for_key));
303     }
304     reset();
305     MenuStorage::get_key_options_menu()->update();
306     wait_for_key = -1;
307     return;
308   }
309   if (joystick_manager->wait_for_joystick >= 0) {
310     if (event.keysym.sym == SDLK_ESCAPE) {
311       reset();
312       MenuStorage::get_joystick_options_menu()->update();
313       joystick_manager->wait_for_joystick = -1;
314     }
315     return;
316   }
317
318   Control control;
319   /* we use default keys when the menu is open (to avoid problems when
320    * redefining keys to invalid settings
321    */
322   switch(event.keysym.sym) {
323     case SDLK_UP:
324       control = Controller::UP;
325       break;
326     case SDLK_DOWN:
327       control = Controller::DOWN;
328       break;
329     case SDLK_LEFT:
330       control = Controller::LEFT;
331       break;
332     case SDLK_RIGHT:
333       control = Controller::RIGHT;
334       break;
335     case SDLK_SPACE:
336     case SDLK_RETURN:
337     case SDLK_KP_ENTER:
338       control = Controller::MENU_SELECT;
339       break;
340     case SDLK_ESCAPE:
341     case SDLK_PAUSE:
342       control = Controller::PAUSE_MENU;
343       break;
344     default:
345       return;
346       break;
347   }
348
349   controller->set_control(control, (event.type == SDL_KEYDOWN));
350 }
351
352 void
353 JoystickKeyboardController::bind_key(SDL_Keycode key, Control control)
354 {
355   // remove all previous mappings for that control and for that key
356   for(KeyMap::iterator i = keymap.begin();
357       i != keymap.end(); /* no ++i */) {
358     if (i->second == control) {
359       KeyMap::iterator e = i;
360       ++i;
361       keymap.erase(e);
362     } else {
363       ++i;
364     }
365   }
366
367   KeyMap::iterator i = keymap.find(key);
368   if (i != keymap.end())
369     keymap.erase(i);
370
371   // add new mapping
372   keymap[key] = control;
373 }
374
375 SDL_Keycode
376 JoystickKeyboardController::reversemap_key(Control c)
377 {
378   for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
379     if (i->second == c)
380       return i->first;
381   }
382
383   return SDLK_UNKNOWN;
384 }
385
386 /* EOF */