Minor cleanup
[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 "lisp/list_iterator.hpp"
23 #include "gui/menu_manager.hpp"
24 #include "supertux/console.hpp"
25 #include "supertux/gameconfig.hpp"
26 #include "supertux/menu/menu_storage.hpp"
27 #include "supertux/menu/joystick_menu.hpp"
28 #include "supertux/menu/keyboard_menu.hpp"
29 #include "util/gettext.hpp"
30 #include "util/writer.hpp"
31
32 JoystickKeyboardController::JoystickKeyboardController() :
33   controller(),
34   keymap(),
35   joy_button_map(),
36   joy_axis_map(),
37   joy_hat_map(),
38   joysticks(),
39   name(),
40   dead_zone(),
41   min_joybuttons(),
42   max_joybuttons(),
43   max_joyaxis(),
44   max_joyhats(),
45   hat_state(0),
46   jump_with_up_joy(),
47   jump_with_up_kbd(),
48   wait_for_key(-1), 
49   wait_for_joystick(-1)
50 {
51   controller = new Controller;
52
53   // initialize default keyboard map
54   keymap[SDLK_LEFT]     = Controller::LEFT;
55   keymap[SDLK_RIGHT]    = Controller::RIGHT;
56   keymap[SDLK_UP]       = Controller::UP;
57   keymap[SDLK_DOWN]     = Controller::DOWN;
58   keymap[SDLK_SPACE]    = Controller::JUMP;
59   keymap[SDLK_LCTRL]    = Controller::ACTION;
60   keymap[SDLK_LALT]     = Controller::ACTION;
61   keymap[SDLK_ESCAPE]   = Controller::PAUSE_MENU;
62   keymap[SDLK_p]        = Controller::PAUSE_MENU;
63   keymap[SDLK_PAUSE]    = Controller::PAUSE_MENU;
64   keymap[SDLK_RETURN]   = Controller::MENU_SELECT;
65   keymap[SDLK_KP_ENTER] = Controller::MENU_SELECT;
66   keymap[SDLK_CARET]    = Controller::CONSOLE;
67   keymap[SDLK_DELETE]   = Controller::PEEK_LEFT;
68   keymap[SDLK_PAGEDOWN] = Controller::PEEK_RIGHT;
69   keymap[SDLK_HOME]     = Controller::PEEK_UP;
70   keymap[SDLK_END]      = Controller::PEEK_DOWN;
71
72   jump_with_up_joy = false;
73   jump_with_up_kbd = false;
74
75   updateAvailableJoysticks();
76
77   dead_zone = 1000;
78
79   // Default joystick button configuration
80   bind_joybutton(0, 0, Controller::JUMP);
81   bind_joybutton(0, 1, Controller::ACTION);
82   // 6 or more Buttons
83   if( min_joybuttons > 5 ){
84     bind_joybutton(0, 4, Controller::PEEK_LEFT);
85     bind_joybutton(0, 5, Controller::PEEK_RIGHT);
86     // 8 or more
87     if(min_joybuttons > 7)
88       bind_joybutton(0, min_joybuttons-1, Controller::PAUSE_MENU);
89   } else {
90     // map the last 2 buttons to menu and pause
91     if(min_joybuttons > 2)
92       bind_joybutton(0, min_joybuttons-1, Controller::PAUSE_MENU);
93     // map all remaining joystick buttons to MENU_SELECT
94     for(int i = 2; i < max_joybuttons; ++i) {
95       if(i != min_joybuttons-1)
96         bind_joybutton(0, i, Controller::MENU_SELECT);
97     }
98   }
99
100   // Default joystick axis configuration
101   bind_joyaxis(0, -1, Controller::LEFT);
102   bind_joyaxis(0, 1, Controller::RIGHT);
103   bind_joyaxis(0, -2, Controller::UP);
104   bind_joyaxis(0, 2, Controller::DOWN);
105 }
106
107 JoystickKeyboardController::~JoystickKeyboardController()
108 {
109   for(std::vector<SDL_Joystick*>::iterator i = joysticks.begin();
110       i != joysticks.end(); ++i) {
111     if(*i != 0)
112       SDL_JoystickClose(*i);
113   }
114   delete controller;
115 }
116
117 void
118 JoystickKeyboardController::updateAvailableJoysticks()
119 {
120   for(std::vector<SDL_Joystick*>::iterator i = joysticks.begin();
121       i != joysticks.end(); ++i) {
122     if(*i != 0)
123       SDL_JoystickClose(*i);
124   }
125   joysticks.clear();
126   
127   SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
128   SDL_InitSubSystem(SDL_INIT_JOYSTICK);
129
130   int joystick_count = SDL_NumJoysticks();
131   min_joybuttons = -1;
132   max_joybuttons = -1;
133   max_joyaxis    = -1;
134   max_joyhats    = -1;
135
136   if( joystick_count > 0 ){
137     for(int i = 0; i < joystick_count; ++i) {
138       SDL_Joystick* joystick = SDL_JoystickOpen(i);
139       bool good = true;
140       if(SDL_JoystickNumButtons(joystick) < 2) {
141         log_info << _("Joystick ") << i << ": " << SDL_JoystickID(i) << _(" has less than 2 buttons") << std::endl;
142         good = false;
143       }
144       if(SDL_JoystickNumAxes(joystick) < 2
145          && SDL_JoystickNumHats(joystick) == 0) {
146         log_info << _("Joystick ") << i << ": " << SDL_JoystickID(i) << _(" has less than 2 axes and no hat") << std::endl;
147         good = false;
148       }
149       if(!good) {
150         SDL_JoystickClose(joystick);
151         continue;
152       }
153
154       if(min_joybuttons < 0 || SDL_JoystickNumButtons(joystick) < min_joybuttons)
155         min_joybuttons = SDL_JoystickNumButtons(joystick);
156
157       if(SDL_JoystickNumButtons(joystick) > max_joybuttons)
158         max_joybuttons = SDL_JoystickNumButtons(joystick);
159
160       if(SDL_JoystickNumAxes(joystick) > max_joyaxis)
161         max_joyaxis = SDL_JoystickNumAxes(joystick);
162
163       if(SDL_JoystickNumHats(joystick) > max_joyhats)
164         max_joyhats = SDL_JoystickNumHats(joystick);
165
166       joysticks.push_back(joystick);
167     }
168   }
169
170   // some joysticks or SDL seem to produce some bogus events after being opened
171   Uint32 ticks = SDL_GetTicks();
172   while(SDL_GetTicks() - ticks < 200) {
173     SDL_Event event;
174     SDL_PollEvent(&event);
175   }
176 }
177
178 Controller*
179 JoystickKeyboardController::get_main_controller()
180 {
181   return controller;
182 }
183
184 void
185 JoystickKeyboardController::read(const Reader& lisp)
186 {
187   const lisp::Lisp* keymap_lisp = lisp.get_lisp("keymap");
188   if(keymap_lisp) {
189     keymap.clear();
190     keymap_lisp->get("jump-with-up", jump_with_up_kbd);
191     lisp::ListIterator iter(keymap_lisp);
192     while(iter.next()) {
193       if(iter.item() == "map") {
194         int key = -1;
195         std::string control;
196         const lisp::Lisp* map = iter.lisp();
197         map->get("key", key);
198         map->get("control", control);
199 //        if(key < SDLK_FIRST || key >= SDLK_LAST) {
200 //          log_info << "Invalid key '" << key << "' in keymap" << std::endl;
201 //          continue;
202 //        }
203
204         int i = 0;
205         for(i = 0; Controller::controlNames[i] != 0; ++i) {
206           if(control == Controller::controlNames[i])
207             break;
208         }
209         if(Controller::controlNames[i] == 0) {
210           log_info << "Invalid control '" << control << "' in keymap" << std::endl;
211           continue;
212         }
213         keymap[SDL_Keycode(key)] = Control(i);
214       }
215     }
216   }
217
218   const lisp::Lisp* joystick_lisp = lisp.get_lisp(_("joystick"));
219   if(joystick_lisp) {
220     joystick_lisp->get("dead-zone", dead_zone);
221     joystick_lisp->get("jump-with-up", jump_with_up_joy);
222     lisp::ListIterator iter(joystick_lisp);
223     while(iter.next()) {
224       if(iter.item() == _("map")) {
225         int button = -1;
226         int axis   = 0;
227         int hat    = -1;
228         std::string control;
229         const lisp::Lisp* map = iter.lisp();
230
231         map->get("control", control);
232         int i = 0;
233         for(i = 0; Controller::controlNames[i] != 0; ++i) {
234           if(control == Controller::controlNames[i])
235             break;
236         }
237         if(Controller::controlNames[i] == 0) {
238           log_info << "Invalid control '" << control << "' in buttonmap" << std::endl;
239           continue;
240         }
241
242         bool js_available = joysticks.size() > 0;
243
244         if (map->get("button", button)) {
245           if(js_available && (button < 0 || button >= max_joybuttons)) {
246             log_info << "Invalid button '" << button << "' in buttonmap" << std::endl;
247             continue;
248           }
249           bind_joybutton(0, button, Control(i));
250         }
251
252         if (map->get("axis",   axis)) {
253           if (js_available && (axis == 0 || abs(axis) > max_joyaxis)) {
254             log_info << "Invalid axis '" << axis << "' in axismap" << std::endl;
255             continue;
256           }
257           bind_joyaxis(0, axis, Control(i));
258         }
259
260         if (map->get("hat",   hat)) {
261           if (js_available        &&
262               hat != SDL_HAT_UP   &&
263               hat != SDL_HAT_DOWN &&
264               hat != SDL_HAT_LEFT &&
265               hat != SDL_HAT_RIGHT) {
266             log_info << "Invalid axis '" << axis << "' in axismap" << std::endl;
267             continue;
268           } else {
269             bind_joyhat(0, hat, Control(i));
270           }
271         }
272       }
273     }
274   }
275 }
276
277 void
278 JoystickKeyboardController::write(Writer& writer)
279 {
280   writer.start_list("keymap");
281   writer.write("jump-with-up", jump_with_up_kbd);
282   for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
283     writer.start_list("map");
284     writer.write("key", (int) i->first);
285     writer.write("control", Controller::controlNames[i->second]);
286     writer.end_list("map");
287   }
288   writer.end_list("keymap");
289
290   writer.start_list("joystick");
291   writer.write("dead-zone", dead_zone);
292   writer.write("jump-with-up", jump_with_up_joy);
293
294   for(ButtonMap::iterator i = joy_button_map.begin(); i != joy_button_map.end();
295       ++i) {
296     writer.start_list("map");
297     writer.write("button", i->first.second);
298     writer.write("control", Controller::controlNames[i->second]);
299     writer.end_list("map");
300   }
301
302   for(HatMap::iterator i = joy_hat_map.begin(); i != joy_hat_map.end(); ++i) {
303     writer.start_list("map");
304     writer.write("hat", i->first.second);
305     writer.write("control", Controller::controlNames[i->second]);
306     writer.end_list("map");
307   }
308
309   for(AxisMap::iterator i = joy_axis_map.begin(); i != joy_axis_map.end(); ++i) {
310     writer.start_list("map");
311     writer.write("axis", i->first.second);
312     writer.write("control", Controller::controlNames[i->second]);
313     writer.end_list("map");
314   }
315
316   writer.end_list("joystick");
317 }
318
319 void
320 JoystickKeyboardController::update()
321 {
322   controller->update();
323 }
324
325 void
326 JoystickKeyboardController::reset()
327 {
328   controller->reset();
329 }
330
331 void
332 JoystickKeyboardController::set_joy_controls(Control id, bool value)
333 {
334   if (jump_with_up_joy && id == Controller::UP)
335     controller->set_control(Controller::JUMP, value);
336
337   controller->set_control(id, value);
338 }
339
340 void
341 JoystickKeyboardController::process_event(const SDL_Event& event)
342 {
343   switch(event.type) {
344     case SDL_TEXTINPUT:
345       process_text_input_event(event.text);
346       break;
347
348     case SDL_KEYUP:
349     case SDL_KEYDOWN:
350       process_key_event(event.key);
351       break;
352
353     case SDL_JOYAXISMOTION:
354       process_axis_event(event.jaxis);
355       break;
356
357     case SDL_JOYHATMOTION:
358       process_hat_event(event.jhat);
359       break;
360
361     case SDL_JOYBUTTONDOWN:
362     case SDL_JOYBUTTONUP:
363       process_button_event(event.jbutton);
364       break;
365
366     default:
367       break;
368   }
369 }
370
371 void
372 JoystickKeyboardController::process_button_event(const SDL_JoyButtonEvent& jbutton)
373 {
374   if(wait_for_joystick >= 0) 
375   {
376     if(jbutton.state == SDL_PRESSED)
377     {
378       bind_joybutton(jbutton.which, jbutton.button, (Control)wait_for_joystick);
379       MenuStorage::get_joystick_options_menu()->update();
380       reset();
381       wait_for_joystick = -1;
382     }
383   } 
384   else 
385   {
386     ButtonMap::iterator i = joy_button_map.find(std::make_pair(jbutton.which, jbutton.button));
387     if(i == joy_button_map.end()) {
388       log_debug << "Unmapped joybutton " << (int)jbutton.button << " pressed" << std::endl;
389     } else {
390       set_joy_controls(i->second, (jbutton.state == SDL_PRESSED));
391     }
392   }
393 }
394
395 void
396 JoystickKeyboardController::process_axis_event(const SDL_JoyAxisEvent& jaxis)
397 {
398   if (wait_for_joystick >= 0)
399   {
400     if (abs(jaxis.value) > dead_zone) {
401       if (jaxis.value < 0)
402         bind_joyaxis(jaxis.which, -(jaxis.axis + 1), Control(wait_for_joystick));
403       else
404         bind_joyaxis(jaxis.which, jaxis.axis + 1, Control(wait_for_joystick));
405
406       MenuStorage::get_joystick_options_menu()->update();
407       wait_for_joystick = -1;
408     }
409   }
410   else
411   {
412     // Split the axis into left and right, so that both can be
413     // mapped separately (needed for jump/down vs up/down)
414     int axis = jaxis.axis + 1;
415
416     AxisMap::iterator left  = joy_axis_map.find(std::make_pair(jaxis.which, -axis));
417     AxisMap::iterator right = joy_axis_map.find(std::make_pair(jaxis.which, axis));
418
419     if(left == joy_axis_map.end()) {
420       // std::cout << "Unmapped joyaxis " << (int)jaxis.axis << " moved" << std::endl;
421     } else {
422       if (jaxis.value < -dead_zone)
423         set_joy_controls(left->second,  true);
424       else
425         set_joy_controls(left->second, false);
426     }
427
428     if(right == joy_axis_map.end()) {
429       // std::cout << "Unmapped joyaxis " << (int)jaxis.axis << " moved" << std::endl;
430     } else {
431       if (jaxis.value > dead_zone)
432         set_joy_controls(right->second, true);
433       else
434         set_joy_controls(right->second, false);
435     }
436   }
437 }
438
439 void
440 JoystickKeyboardController::process_hat_event(const SDL_JoyHatEvent& jhat)
441 {
442   Uint8 changed = hat_state ^ jhat.value;
443
444   if (wait_for_joystick >= 0)
445   {
446     if (changed & SDL_HAT_UP && jhat.value & SDL_HAT_UP)
447       bind_joyhat(jhat.which, SDL_HAT_UP, Control(wait_for_joystick));
448
449     if (changed & SDL_HAT_DOWN && jhat.value & SDL_HAT_DOWN)
450       bind_joyhat(jhat.which, SDL_HAT_DOWN, Control(wait_for_joystick));
451
452     if (changed & SDL_HAT_LEFT && jhat.value & SDL_HAT_LEFT)
453       bind_joyhat(jhat.which, SDL_HAT_LEFT, Control(wait_for_joystick));
454
455     if (changed & SDL_HAT_RIGHT && jhat.value & SDL_HAT_RIGHT)
456       bind_joyhat(jhat.which, SDL_HAT_RIGHT, Control(wait_for_joystick));
457
458     MenuStorage::get_joystick_options_menu()->update();
459     wait_for_joystick = -1;
460   }
461   else
462   {
463     if (changed & SDL_HAT_UP)
464     {
465       HatMap::iterator it = joy_hat_map.find(std::make_pair(jhat.which, SDL_HAT_UP));
466       if (it != joy_hat_map.end())
467         set_joy_controls(it->second, jhat.value & SDL_HAT_UP);
468     }
469
470     if (changed & SDL_HAT_DOWN)
471     {
472       HatMap::iterator it = joy_hat_map.find(std::make_pair(jhat.which, SDL_HAT_DOWN));
473       if (it != joy_hat_map.end())
474         set_joy_controls(it->second, jhat.value & SDL_HAT_DOWN);
475     }
476
477     if (changed & SDL_HAT_LEFT)
478     {
479       HatMap::iterator it = joy_hat_map.find(std::make_pair(jhat.which, SDL_HAT_LEFT));
480       if (it != joy_hat_map.end())
481         set_joy_controls(it->second, jhat.value & SDL_HAT_LEFT);
482     }
483
484     if (changed & SDL_HAT_RIGHT)
485     {
486       HatMap::iterator it = joy_hat_map.find(std::make_pair(jhat.which, SDL_HAT_RIGHT));
487       if (it != joy_hat_map.end())
488         set_joy_controls(it->second, jhat.value & SDL_HAT_RIGHT);
489     }
490   }
491
492   hat_state = jhat.value;
493 }
494
495 void
496 JoystickKeyboardController::process_text_input_event(const SDL_TextInputEvent& event)
497 {
498   if (Console::instance->hasFocus()) {
499     for(int i = 0; event.text[i] != '\0'; ++i)
500     {
501       Console::instance->input(event.text[i]);
502     }
503   }
504 }
505
506 void
507 JoystickKeyboardController::process_key_event(const SDL_KeyboardEvent& event)
508 {
509   KeyMap::iterator key_mapping = keymap.find(event.keysym.sym);
510
511   // if console key was pressed: toggle console
512   if ((key_mapping != keymap.end()) && (key_mapping->second == Controller::CONSOLE)) {
513     if (event.type == SDL_KEYDOWN) 
514       Console::instance->toggle();
515   } else {
516     if (Console::instance->hasFocus()) {
517       // if console is open: send key there
518       process_console_key_event(event);
519     } else if (MenuManager::current()) {
520       // if menu mode: send key there
521       process_menu_key_event(event);
522     } else if(key_mapping == keymap.end()) {
523       // default action: update controls
524       //log_debug << "Key " << event.key.SDL_Keycode.sym << " is unbound" << std::endl;
525     } else {
526       Control control = key_mapping->second;
527       bool value = (event.type == SDL_KEYDOWN);
528       controller->set_control(control, value);
529       if (jump_with_up_kbd && control == Controller::UP){
530         controller->set_control(Controller::JUMP, value);
531       }
532     }
533   }
534 }
535
536 void
537 JoystickKeyboardController::process_console_key_event(const SDL_KeyboardEvent& event)
538 {
539   if (event.type != SDL_KEYDOWN) return;
540
541   switch (event.keysym.sym) {
542     case SDLK_RETURN:
543       Console::instance->enter();
544       break;
545     case SDLK_BACKSPACE:
546       Console::instance->backspace();
547       break;
548     case SDLK_TAB:
549       Console::instance->autocomplete();
550       break;
551     case SDLK_PAGEUP:
552       Console::instance->scroll(-1);
553       break;
554     case SDLK_PAGEDOWN:
555       Console::instance->scroll(+1);
556       break;
557     case SDLK_HOME:
558       Console::instance->move_cursor(-65535);
559       break;
560     case SDLK_END:
561       Console::instance->move_cursor(+65535);
562       break;
563     case SDLK_UP:
564       Console::instance->show_history(-1);
565       break;
566     case SDLK_DOWN:
567       Console::instance->show_history(+1);
568       break;
569     case SDLK_LEFT:
570       Console::instance->move_cursor(-1);
571       break;
572     case SDLK_RIGHT:
573       Console::instance->move_cursor(+1);
574       break;
575     default:
576       break;
577   }
578 }
579
580 void
581 JoystickKeyboardController::process_menu_key_event(const SDL_KeyboardEvent& event)
582 {
583   // wait for key mode?
584   if(wait_for_key >= 0) {
585     if(event.type == SDL_KEYUP)
586       return;
587
588     if(event.keysym.sym != SDLK_ESCAPE
589        && event.keysym.sym != SDLK_PAUSE) {
590       bind_key(event.keysym.sym, Control(wait_for_key));
591     }
592     reset();
593     MenuStorage::get_key_options_menu()->update();
594     wait_for_key = -1;
595     return;
596   }
597   if(wait_for_joystick >= 0) {
598     if(event.keysym.sym == SDLK_ESCAPE) {
599       reset();
600       MenuStorage::get_joystick_options_menu()->update();
601       wait_for_joystick = -1;
602     }
603     return;
604   }
605
606   Control control;
607   /* we use default keys when the menu is open (to avoid problems when
608    * redefining keys to invalid settings
609    */
610   switch(event.keysym.sym) {
611     case SDLK_UP:
612       control = Controller::UP;
613       break;
614     case SDLK_DOWN:
615       control = Controller::DOWN;
616       break;
617     case SDLK_LEFT:
618       control = Controller::LEFT;
619       break;
620     case SDLK_RIGHT:
621       control = Controller::RIGHT;
622       break;
623     case SDLK_SPACE:
624     case SDLK_RETURN:
625     case SDLK_KP_ENTER:
626       control = Controller::MENU_SELECT;
627       break;
628     case SDLK_ESCAPE:
629     case SDLK_PAUSE:
630       control = Controller::PAUSE_MENU;
631       break;
632     default:
633       return;
634       break;
635   }
636
637   controller->set_control(control, (event.type == SDL_KEYDOWN));
638 }
639
640 void
641 JoystickKeyboardController::unbind_joystick_control(Control control)
642 {
643   // remove all previous mappings for that control
644   for(AxisMap::iterator i = joy_axis_map.begin(); i != joy_axis_map.end(); /* no ++i */) {
645     if(i->second == control)
646       joy_axis_map.erase(i++);
647     else
648       ++i;
649   }
650
651   for(ButtonMap::iterator i = joy_button_map.begin(); i != joy_button_map.end(); /* no ++i */) {
652     if(i->second == control)
653       joy_button_map.erase(i++);
654     else
655       ++i;
656   }
657
658   for(HatMap::iterator i = joy_hat_map.begin();  i != joy_hat_map.end(); /* no ++i */) {
659     if(i->second == control)
660       joy_hat_map.erase(i++);
661     else
662       ++i;
663   }
664 }
665
666 void
667 JoystickKeyboardController::bind_joyaxis(JoyId joy_id, int axis, Control control)
668 {
669   // axis isn't the SDL axis number, but axisnumber + 1 with sign
670   // changed depending on if the positive or negative end is to be
671   // used (negative axis 0 becomes -1, positive axis 2 becomes +3,
672   // etc.)
673
674   unbind_joystick_control(control);
675
676   // add new mapping
677   joy_axis_map[std::make_pair(joy_id, axis)] = control;
678 }
679
680 void
681 JoystickKeyboardController::bind_joyhat(JoyId joy_id, int dir, Control c)
682 {
683   unbind_joystick_control(c);
684
685   // add new mapping
686   joy_hat_map[std::make_pair(joy_id, dir)] = c;
687 }
688
689 void
690 JoystickKeyboardController::bind_joybutton(JoyId joy_id, int button, Control control)
691 {
692   unbind_joystick_control(control);
693
694   // add new mapping
695   joy_button_map[std::make_pair(joy_id, button)] = control;
696 }
697
698 void
699 JoystickKeyboardController::bind_key(SDL_Keycode key, Control control)
700 {
701   // remove all previous mappings for that control and for that key
702   for(KeyMap::iterator i = keymap.begin();
703       i != keymap.end(); /* no ++i */) {
704     if(i->second == control) {
705       KeyMap::iterator e = i;
706       ++i;
707       keymap.erase(e);
708     } else {
709       ++i;
710     }
711   }
712
713   KeyMap::iterator i = keymap.find(key);
714   if(i != keymap.end())
715     keymap.erase(i);
716
717   // add new mapping
718   keymap[key] = control;
719 }
720
721 void
722 JoystickKeyboardController::print_joystick_mappings()
723 {
724   std::cout << _("Joystick Mappings") << std::endl;
725   std::cout << "-----------------" << std::endl;
726   for(AxisMap::iterator i = joy_axis_map.begin(); i != joy_axis_map.end(); ++i) {
727     std::cout << "Axis: " << i->first.second << " -> " << i->second << std::endl;
728   }
729
730   for(ButtonMap::iterator i = joy_button_map.begin(); i != joy_button_map.end(); ++i) {
731     std::cout << "Button: " << i->first.second << " -> " << i->second << std::endl;
732   }
733
734   for(HatMap::iterator i = joy_hat_map.begin(); i != joy_hat_map.end(); ++i) {
735     std::cout << "Hat: " << i->first.second << " -> " << i->second << std::endl;
736   }
737   std::cout << std::endl;
738 }
739
740 SDL_Keycode
741 JoystickKeyboardController::reversemap_key(Control c)
742 {
743   for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
744     if(i->second == c)
745       return i->first;
746   }
747
748   return SDLK_UNKNOWN;
749 }
750
751 int
752 JoystickKeyboardController::reversemap_joyaxis(Control c)
753 {
754   for(AxisMap::iterator i = joy_axis_map.begin(); i != joy_axis_map.end(); ++i) {
755     if(i->second == c)
756       return i->first.second;
757   }
758
759   return 0;
760 }
761
762 int
763 JoystickKeyboardController::reversemap_joybutton(Control c)
764 {
765   for(ButtonMap::iterator i = joy_button_map.begin(); i != joy_button_map.end(); ++i) {
766     if(i->second == c)
767       return i->first.second;
768   }
769
770   return -1;
771 }
772
773 int
774 JoystickKeyboardController::reversemap_joyhat(Control c)
775 {
776   for(HatMap::iterator i = joy_hat_map.begin(); i != joy_hat_map.end(); ++i) {
777     if(i->second == c)
778       return i->first.second;
779   }
780
781   return -1;
782 }
783
784 /* EOF */