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