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