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