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