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