make joystick_options_menu and key_options_menu part of joystickkeyboardcontroller...
[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   keymap(),
34   joy_button_map(),
35   joy_axis_map(),
36   joy_hat_map(),
37   joysticks(),
38   name(),
39   dead_zone(),
40   min_joybuttons(),
41   max_joybuttons(),
42   max_joyaxis(),
43   max_joyhats(),
44   hat_state(0),
45   jump_with_up_joy(),
46   jump_with_up_kbd(),
47   wait_for_key(-1), 
48   wait_for_joystick(-1),
49   key_options_menu(0),
50   joystick_options_menu(0)
51 {
52   // initialize default keyboard map
53   keymap[SDLK_LEFT]     = LEFT;
54   keymap[SDLK_RIGHT]    = RIGHT;
55   keymap[SDLK_UP]       = UP;
56   keymap[SDLK_DOWN]     = DOWN;
57   keymap[SDLK_SPACE]    = JUMP;
58   keymap[SDLK_LCTRL]    = ACTION;
59   keymap[SDLK_LALT]     = ACTION;
60   keymap[SDLK_ESCAPE]   = PAUSE_MENU;
61   keymap[SDLK_p]        = PAUSE_MENU;
62   keymap[SDLK_PAUSE]    = PAUSE_MENU;
63   keymap[SDLK_RETURN]   = MENU_SELECT;
64   keymap[SDLK_KP_ENTER] = MENU_SELECT;
65   keymap[SDLK_CARET]    = CONSOLE;
66   keymap[SDLK_DELETE]   = PEEK_LEFT;
67   keymap[SDLK_PAGEDOWN] = PEEK_RIGHT;
68   keymap[SDLK_HOME]     = PEEK_UP;
69   keymap[SDLK_END]      = PEEK_DOWN;
70
71   jump_with_up_joy = false;
72   jump_with_up_kbd = false;
73
74   updateAvailableJoysticks();
75
76   dead_zone = 1000;
77
78   // Default joystick button configuration
79   joy_button_map[0] = JUMP;
80   joy_button_map[1] = ACTION;
81   // 6 or more Buttons
82   if( min_joybuttons > 5 ){
83     joy_button_map[4] = PEEK_LEFT;
84     joy_button_map[5] = PEEK_RIGHT;
85     // 8 or more
86     if(min_joybuttons > 7)
87       joy_button_map[min_joybuttons-1] = PAUSE_MENU;
88   } else {
89     // map the last 2 buttons to menu and pause
90     if(min_joybuttons > 2)
91       joy_button_map[min_joybuttons-1] = PAUSE_MENU;
92     // map all remaining joystick buttons to MENU_SELECT
93     for(int i = 2; i < max_joybuttons; ++i) {
94       if(i != min_joybuttons-1)
95         joy_button_map[i] = MENU_SELECT;
96     }
97   }
98
99   // Default joystick axis configuration
100   joy_axis_map[-1] = LEFT;
101   joy_axis_map[ 1] = RIGHT;
102   joy_axis_map[-2] = UP;
103   joy_axis_map[ 2] = DOWN;
104 }
105
106 JoystickKeyboardController::~JoystickKeyboardController()
107 {
108   for(std::vector<SDL_Joystick*>::iterator i = joysticks.begin();
109       i != joysticks.end(); ++i) {
110     if(*i != 0)
111       SDL_JoystickClose(*i);
112   }
113   delete key_options_menu;
114   delete joystick_options_menu;
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_JoystickName(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_JoystickName(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 KeyboardMenu*
179 JoystickKeyboardController::get_key_options_menu()
180 {
181         if (!key_options_menu)
182                 key_options_menu = new KeyboardMenu(this);
183         return key_options_menu;
184 }
185
186 JoystickMenu*
187 JoystickKeyboardController::get_joystick_options_menu()
188 {
189         if (!joystick_options_menu)
190                 joystick_options_menu = new JoystickMenu(this);
191         return joystick_options_menu;
192 }
193
194 void
195 JoystickKeyboardController::read(const Reader& lisp)
196 {
197   const lisp::Lisp* keymap_lisp = lisp.get_lisp("keymap");
198   if(keymap_lisp) {
199     keymap.clear();
200     keymap_lisp->get("jump-with-up", jump_with_up_kbd);
201     lisp::ListIterator iter(keymap_lisp);
202     while(iter.next()) {
203       if(iter.item() == "map") {
204         int key = -1;
205         std::string control;
206         const lisp::Lisp* map = iter.lisp();
207         map->get("key", key);
208         map->get("control", control);
209         if(key < SDLK_FIRST || key >= SDLK_LAST) {
210           log_info << "Invalid key '" << key << "' in keymap" << std::endl;
211           continue;
212         }
213
214         int i = 0;
215         for(i = 0; controlNames[i] != 0; ++i) {
216           if(control == controlNames[i])
217             break;
218         }
219         if(controlNames[i] == 0) {
220           log_info << "Invalid control '" << control << "' in keymap" << std::endl;
221           continue;
222         }
223         keymap[(SDLKey) key] = (Control)i;
224       }
225     }
226   }
227
228   const lisp::Lisp* joystick_lisp = lisp.get_lisp("joystick");
229   if(joystick_lisp) {
230     joystick_lisp->get("dead-zone", dead_zone);
231     joystick_lisp->get("jump-with-up", jump_with_up_joy);
232     lisp::ListIterator iter(joystick_lisp);
233     while(iter.next()) {
234       if(iter.item() == "map") {
235         int button = -1;
236         int axis   = 0;
237         int hat    = -1;
238         std::string control;
239         const lisp::Lisp* map = iter.lisp();
240
241         map->get("control", control);
242         int i = 0;
243         for(i = 0; controlNames[i] != 0; ++i) {
244           if(control == controlNames[i])
245             break;
246         }
247         if(controlNames[i] == 0) {
248           log_info << "Invalid control '" << control << "' in buttonmap" << std::endl;
249           continue;
250         }
251
252         if (map->get("button", button)) {
253           if(button < 0 || button >= max_joybuttons) {
254             log_info << "Invalid button '" << button << "' in buttonmap" << std::endl;
255             continue;
256           }
257           bind_joybutton(button, (Control) i);
258         }
259
260         if (map->get("axis",   axis)) {
261           if (axis == 0 || abs(axis) > max_joyaxis) {
262             log_info << "Invalid axis '" << axis << "' in axismap" << std::endl;
263             continue;
264           }
265           bind_joyaxis(axis, (Control) i);
266         }
267
268         if (map->get("hat",   hat)) {
269           if (hat != SDL_HAT_UP   &&
270               hat != SDL_HAT_DOWN &&
271               hat != SDL_HAT_LEFT &&
272               hat != SDL_HAT_RIGHT) {
273             log_info << "Invalid axis '" << axis << "' in axismap" << std::endl;
274             continue;
275           } else {
276             bind_joyhat(hat, (Control) i);
277           }
278         }
279       }
280     }
281   }
282 }
283
284 void
285 JoystickKeyboardController::write(Writer& writer)
286 {
287   writer.start_list("keymap");
288   writer.write("jump-with-up", jump_with_up_kbd);
289   for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
290     writer.start_list("map");
291     writer.write("key", (int) i->first);
292     writer.write("control", controlNames[i->second]);
293     writer.end_list("map");
294   }
295   writer.end_list("keymap");
296
297   writer.start_list("joystick");
298   writer.write("dead-zone", dead_zone);
299   writer.write("jump-with-up", jump_with_up_joy);
300
301   for(ButtonMap::iterator i = joy_button_map.begin(); i != joy_button_map.end();
302       ++i) {
303     writer.start_list("map");
304     writer.write("button", i->first);
305     writer.write("control", controlNames[i->second]);
306     writer.end_list("map");
307   }
308
309   for(HatMap::iterator i = joy_hat_map.begin(); i != joy_hat_map.end(); ++i) {
310     writer.start_list("map");
311     writer.write("hat", i->first);
312     writer.write("control", controlNames[i->second]);
313     writer.end_list("map");
314   }
315
316   for(AxisMap::iterator i = joy_axis_map.begin(); i != joy_axis_map.end(); ++i) {
317     writer.start_list("map");
318     writer.write("axis", i->first);
319     writer.write("control", controlNames[i->second]);
320     writer.end_list("map");
321   }
322
323   writer.end_list("joystick");
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     controls[Controller::JUMP] = value;
337
338   controls[(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);
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.button, (Control)wait_for_joystick);
376       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(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.axis + 1), Control(wait_for_joystick));
400       else
401         bind_joyaxis(jaxis.axis + 1, Control(wait_for_joystick));
402
403       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(-axis);
414     AxisMap::iterator right = joy_axis_map.find(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(SDL_HAT_UP, (Control)wait_for_joystick);
449
450     if (changed & SDL_HAT_DOWN && jhat.value & SDL_HAT_DOWN)
451       bind_joyhat(SDL_HAT_DOWN, (Control)wait_for_joystick);
452
453     if (changed & SDL_HAT_LEFT && jhat.value & SDL_HAT_LEFT)
454       bind_joyhat(SDL_HAT_LEFT, (Control)wait_for_joystick);
455
456     if (changed & SDL_HAT_RIGHT && jhat.value & SDL_HAT_RIGHT)
457       bind_joyhat(SDL_HAT_RIGHT, (Control)wait_for_joystick);
458
459     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(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(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(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(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_Event& event)
498 {
499   KeyMap::iterator key_mapping = keymap.find(event.key.keysym.sym);
500
501   // if console key was pressed: toggle console
502   if ((key_mapping != keymap.end()) && (key_mapping->second == 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.keysym.sym << " is unbound" << std::endl;
515     } else {
516       Control control = key_mapping->second;
517       controls[control] = (event.type == SDL_KEYDOWN);
518       if (jump_with_up_kbd && control == UP){
519         controls[JUMP] = (event.type == SDL_KEYDOWN);
520       }
521     }
522   }
523 }
524
525 void
526 JoystickKeyboardController::process_console_key_event(const SDL_Event& event)
527 {
528   if (event.type != SDL_KEYDOWN) return;
529
530   switch (event.key.keysym.sym) {
531     case SDLK_RETURN:
532       Console::instance->enter();
533       break;
534     case SDLK_BACKSPACE:
535       Console::instance->backspace();
536       break;
537     case SDLK_TAB:
538       Console::instance->autocomplete();
539       break;
540     case SDLK_PAGEUP:
541       Console::instance->scroll(-1);
542       break;
543     case SDLK_PAGEDOWN:
544       Console::instance->scroll(+1);
545       break;
546     case SDLK_HOME:
547       Console::instance->move_cursor(-65535);
548       break;
549     case SDLK_END:
550       Console::instance->move_cursor(+65535);
551       break;
552     case SDLK_UP:
553       Console::instance->show_history(-1);
554       break;
555     case SDLK_DOWN:
556       Console::instance->show_history(+1);
557       break;
558     case SDLK_LEFT:
559       Console::instance->move_cursor(-1);
560       break;
561     case SDLK_RIGHT:
562       Console::instance->move_cursor(+1);
563       break;
564     default:
565       int c = event.key.keysym.unicode;
566       if ((c >= 32) && (c <= 126)) {
567         Console::instance->input((char)c);
568       }
569       break;
570   }
571 }
572
573 void
574 JoystickKeyboardController::process_menu_key_event(const SDL_Event& event)
575 {
576   // wait for key mode?
577   if(wait_for_key >= 0) {
578     if(event.type == SDL_KEYUP)
579       return;
580
581     if(event.key.keysym.sym != SDLK_ESCAPE
582        && event.key.keysym.sym != SDLK_PAUSE) {
583       bind_key(event.key.keysym.sym, (Control) wait_for_key);
584     }
585     reset();
586     get_key_options_menu()->update();
587     wait_for_key = -1;
588     return;
589   }
590   if(wait_for_joystick >= 0) {
591     if(event.key.keysym.sym == SDLK_ESCAPE) {
592       reset();
593       get_joystick_options_menu()->update();
594       wait_for_joystick = -1;
595     }
596     return;
597   }
598
599   Control control;
600   /* we use default keys when the menu is open (to avoid problems when
601    * redefining keys to invalid settings
602    */
603   switch(event.key.keysym.sym) {
604     case SDLK_UP:
605       control = UP;
606       break;
607     case SDLK_DOWN:
608       control = DOWN;
609       break;
610     case SDLK_LEFT:
611       control = LEFT;
612       break;
613     case SDLK_RIGHT:
614       control = RIGHT;
615       break;
616     case SDLK_SPACE:
617     case SDLK_RETURN:
618     case SDLK_KP_ENTER:
619       control = MENU_SELECT;
620       break;
621     case SDLK_ESCAPE:
622     case SDLK_PAUSE:
623       control = PAUSE_MENU;
624       break;
625     default:
626       return;
627       break;
628   }
629
630   controls[control] = (event.type == SDL_KEYDOWN);
631 }
632
633 void
634 JoystickKeyboardController::unbind_joystick_control(Control control)
635 {
636   // remove all previous mappings for that control
637   for(AxisMap::iterator i = joy_axis_map.begin(); i != joy_axis_map.end(); /* no ++i */) {
638     if(i->second == control)
639       joy_axis_map.erase(i++);
640     else
641       ++i;
642   }
643
644   for(ButtonMap::iterator i = joy_button_map.begin(); i != joy_button_map.end(); /* no ++i */) {
645     if(i->second == control)
646       joy_button_map.erase(i++);
647     else
648       ++i;
649   }
650
651   for(HatMap::iterator i = joy_hat_map.begin();  i != joy_hat_map.end(); /* no ++i */) {
652     if(i->second == control)
653       joy_hat_map.erase(i++);
654     else
655       ++i;
656   }
657 }
658
659 void
660 JoystickKeyboardController::bind_joyaxis(int axis, Control control)
661 {
662   // axis isn't the SDL axis number, but axisnumber + 1 with sign
663   // changed depending on if the positive or negative end is to be
664   // used (negative axis 0 becomes -1, positive axis 2 becomes +3,
665   // etc.)
666
667   unbind_joystick_control(control);
668
669   // add new mapping
670   joy_axis_map[axis] = control;
671 }
672
673 void
674 JoystickKeyboardController::bind_joyhat(int dir, Control c)
675 {
676   unbind_joystick_control(c);
677
678   // add new mapping
679   joy_hat_map[dir] = c;
680 }
681
682 void
683 JoystickKeyboardController::bind_joybutton(int button, Control control)
684 {
685   unbind_joystick_control(control);
686
687   // add new mapping
688   joy_button_map[button] = control;
689 }
690
691 void
692 JoystickKeyboardController::bind_key(SDLKey key, Control control)
693 {
694   // remove all previous mappings for that control and for that key
695   for(KeyMap::iterator i = keymap.begin();
696       i != keymap.end(); /* no ++i */) {
697     if(i->second == control) {
698       KeyMap::iterator e = i;
699       ++i;
700       keymap.erase(e);
701     } else {
702       ++i;
703     }
704   }
705
706   KeyMap::iterator i = keymap.find(key);
707   if(i != keymap.end())
708     keymap.erase(i);
709
710   // add new mapping
711   keymap[key]= control;
712 }
713
714 void
715 JoystickKeyboardController::print_joystick_mappings()
716 {
717   std::cout << "Joystick Mappings" << std::endl;
718   std::cout << "-----------------" << std::endl;
719   for(AxisMap::iterator i = joy_axis_map.begin(); i != joy_axis_map.end(); ++i) {
720     std::cout << "Axis: " << i->first << " -> " << i->second << std::endl;
721   }
722
723   for(ButtonMap::iterator i = joy_button_map.begin(); i != joy_button_map.end(); ++i) {
724     std::cout << "Button: " << i->first << " -> " << i->second << std::endl;
725   }
726
727   for(HatMap::iterator i = joy_hat_map.begin(); i != joy_hat_map.end(); ++i) {
728     std::cout << "Hat: " << i->first << " -> " << i->second << std::endl;
729   }
730   std::cout << std::endl;
731 }
732
733 SDLKey
734 JoystickKeyboardController::reversemap_key(Control c)
735 {
736   for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
737     if(i->second == c)
738       return i->first;
739   }
740
741   return SDLK_UNKNOWN;
742 }
743
744 int
745 JoystickKeyboardController::reversemap_joyaxis(Control c)
746 {
747   for(AxisMap::iterator i = joy_axis_map.begin(); i != joy_axis_map.end(); ++i) {
748     if(i->second == c)
749       return i->first;
750   }
751
752   return 0;
753 }
754
755 int
756 JoystickKeyboardController::reversemap_joybutton(Control c)
757 {
758   for(ButtonMap::iterator i = joy_button_map.begin(); i != joy_button_map.end(); ++i) {
759     if(i->second == c)
760       return i->first;
761   }
762
763   return -1;
764 }
765
766 int
767 JoystickKeyboardController::reversemap_joyhat(Control c)
768 {
769   for(HatMap::iterator i = joy_hat_map.begin(); i != joy_hat_map.end(); ++i) {
770     if(i->second == c)
771       return i->first;
772   }
773
774   return -1;
775 }
776
777 /* EOF */