- configurable joystick hat support
[supertux.git] / src / control / joystickkeyboardcontroller.cpp
1 //  $Id$
2 //
3 //  SuperTux
4 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>,
5 //                2007 Ingo Ruhnke <grumbel@gmx.de>
6 //
7 //  This program is free software; you can redistribute it and/or
8 //  modify it under the terms of the GNU General Public License
9 //  as published by the Free Software Foundation; either version 2
10 //  of the License, or (at your option) any later version.
11 //
12 //  This program is distributed in the hope that it will be useful,
13 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 //  GNU General Public License for more details.
16 //
17 //  You should have received a copy of the GNU General Public License
18 //  along with this program; if not, write to the Free Software
19 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20
21 #include <config.h>
22
23 #include <sstream>
24 #include "joystickkeyboardcontroller.hpp"
25 #include "log.hpp"
26 #include "gui/menu.hpp"
27 #include "gettext.hpp"
28 #include "lisp/lisp.hpp"
29 #include "lisp/list_iterator.hpp"
30 #include "game_session.hpp"
31 #include "console.hpp"
32 #include "gameconfig.hpp"
33
34 class JoystickKeyboardController::JoystickMenu : public Menu
35 {
36 public:
37   JoystickMenu(JoystickKeyboardController* controller);
38   virtual ~JoystickMenu();
39
40   void update();
41   std::string get_button_name(int button);
42   void update_menu_item(Control id);
43   virtual void menu_action(MenuItem* item);
44   JoystickKeyboardController* controller;
45 };
46
47 class JoystickKeyboardController::KeyboardMenu : public Menu
48 {
49 public:
50   KeyboardMenu(JoystickKeyboardController* controller);
51   ~KeyboardMenu();
52
53   void update();
54   std::string get_key_name(SDLKey key);
55   virtual void menu_action(MenuItem* item);
56   JoystickKeyboardController* controller;
57 };
58
59 JoystickKeyboardController::JoystickKeyboardController()
60   : hat_state(0),
61     wait_for_key(-1), wait_for_joystick(-1),
62     key_options_menu(0), joystick_options_menu(0)
63 {
64   // initialize default keyboard map
65   keymap.insert(std::make_pair(SDLK_LEFT,     LEFT));
66   keymap.insert(std::make_pair(SDLK_RIGHT,    RIGHT));
67   keymap.insert(std::make_pair(SDLK_UP,       UP));
68   keymap.insert(std::make_pair(SDLK_DOWN,     DOWN));
69   keymap.insert(std::make_pair(SDLK_SPACE,    JUMP));
70   keymap.insert(std::make_pair(SDLK_LCTRL,    ACTION));
71   keymap.insert(std::make_pair(SDLK_LALT,     ACTION));
72   keymap.insert(std::make_pair(SDLK_ESCAPE,   PAUSE_MENU));
73   keymap.insert(std::make_pair(SDLK_p,        PAUSE_MENU));
74   keymap.insert(std::make_pair(SDLK_PAUSE,    PAUSE_MENU));
75   keymap.insert(std::make_pair(SDLK_RETURN,   MENU_SELECT));
76   keymap.insert(std::make_pair(SDLK_KP_ENTER, MENU_SELECT));
77   keymap.insert(std::make_pair(SDLK_CARET,    CONSOLE));
78   keymap.insert(std::make_pair(SDLK_DELETE,   PEEK_LEFT));
79   keymap.insert(std::make_pair(SDLK_END,      PEEK_RIGHT));
80
81   int joystick_count = SDL_NumJoysticks();
82   min_joybuttons = -1;
83   max_joybuttons = -1;
84   max_joyaxis    = -1;
85   max_joyhats    = -1;
86
87   for(int i = 0; i < joystick_count; ++i) {
88     SDL_Joystick* joystick = SDL_JoystickOpen(i);
89     bool good = true;
90     if(SDL_JoystickNumButtons(joystick) < 2) {
91       log_info << "Joystick " << i << " has less than 2 buttons" << std::endl;
92       good = false;
93     }
94     if(SDL_JoystickNumAxes(joystick) < 2
95        && SDL_JoystickNumHats(joystick) == 0) {
96       log_info << "Joystick " << i << " has less than 2 axes and no hat" << std::endl;
97       good = false;
98     }
99     if(!good) {
100       SDL_JoystickClose(joystick);
101       continue;
102     }
103
104     if(min_joybuttons < 0 || SDL_JoystickNumButtons(joystick) < min_joybuttons)
105       min_joybuttons = SDL_JoystickNumButtons(joystick);
106
107     if(SDL_JoystickNumButtons(joystick) > max_joybuttons)
108       max_joybuttons = SDL_JoystickNumButtons(joystick);
109
110     if(SDL_JoystickNumAxes(joystick) > max_joyaxis)
111       max_joyaxis = SDL_JoystickNumAxes(joystick);
112
113     if(SDL_JoystickNumHats(joystick) > max_joyhats)
114       max_joyhats = SDL_JoystickNumHats(joystick);
115
116     joysticks.push_back(joystick);
117   }
118
119   dead_zone = 1000;
120
121   // Default joystick button configuration
122   joy_button_map.insert(std::make_pair(0, JUMP));
123   joy_button_map.insert(std::make_pair(1, ACTION));
124   // 6 or more Buttons
125   if( min_joybuttons > 5 ){
126     joy_button_map.insert(std::make_pair( 4, PEEK_LEFT));
127     joy_button_map.insert(std::make_pair( 5, PEEK_RIGHT));
128     // 8 or more
129     if(min_joybuttons > 7)
130       joy_button_map.insert(std::make_pair(min_joybuttons-1, PAUSE_MENU));
131     // map all remaining joystick buttons to MENU_SELECT
132     for(int i = 2; i < max_joybuttons; ++i) {
133       if( i != min_joybuttons-1 && i !=4  && i!= 5 )
134         joy_button_map.insert(std::make_pair(i, MENU_SELECT));
135     }
136
137   } else {
138     // map the last 2 buttons to menu and pause
139     if(min_joybuttons > 2)
140       joy_button_map.insert(std::make_pair(min_joybuttons-1, PAUSE_MENU));
141     // map all remaining joystick buttons to MENU_SELECT
142     for(int i = 2; i < max_joybuttons; ++i) {
143       if(i != min_joybuttons-1)
144         joy_button_map.insert(std::make_pair(i, MENU_SELECT));
145     }
146   }
147
148   // Default joystick axis configuration
149   joy_axis_map.insert(std::make_pair(-1, LEFT));
150   joy_axis_map.insert(std::make_pair( 1, RIGHT));
151   joy_axis_map.insert(std::make_pair(-2, UP));
152   joy_axis_map.insert(std::make_pair( 2, DOWN));
153
154   // some joysticks or SDL seem to produce some bogus events after being opened
155   Uint32 ticks = SDL_GetTicks();
156   while(SDL_GetTicks() - ticks < 200) {
157     SDL_Event event;
158     SDL_PollEvent(&event);
159   }
160 }
161
162 JoystickKeyboardController::~JoystickKeyboardController()
163 {
164   for(std::vector<SDL_Joystick*>::iterator i = joysticks.begin();
165       i != joysticks.end(); ++i) {
166     if(*i != 0)
167       SDL_JoystickClose(*i);
168   }
169
170   delete key_options_menu;
171   delete joystick_options_menu;
172 }
173
174 void
175 JoystickKeyboardController::read(const lisp::Lisp& lisp)
176 {
177   const lisp::Lisp* keymap_lisp = lisp.get_lisp("keymap");
178   if(keymap_lisp) {
179     keymap.clear();
180     lisp::ListIterator iter(keymap_lisp);
181     while(iter.next()) {
182       if(iter.item() == "map") {
183         int key = -1;
184         std::string control;
185         const lisp::Lisp* map = iter.lisp();
186         map->get("key", key);
187         map->get("control", control);
188         if(key < SDLK_FIRST || key >= SDLK_LAST) {
189           log_info << "Invalid key '" << key << "' in keymap" << std::endl;
190           continue;
191         }
192
193         int i = 0;
194         for(i = 0; controlNames[i] != 0; ++i) {
195           if(control == controlNames[i])
196             break;
197         }
198         if(controlNames[i] == 0) {
199           log_info << "Invalid control '" << control << "' in keymap" << std::endl;
200           continue;
201         }
202         keymap.insert(std::make_pair((SDLKey) key, (Control) i));
203       } else {
204         log_info << "Invalid lisp element '" << iter.item() << "' in keymap" << std::endl;
205       }
206     }
207   }
208
209   const lisp::Lisp* joystick_lisp = lisp.get_lisp("joystick");
210   if(joystick_lisp) {
211     joystick_lisp->get("dead_zone", dead_zone);
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           reset_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           reset_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             reset_joyhat(hat, (Control) i);
257           }
258         }
259       }
260     }
261   }
262 }
263
264 void
265 JoystickKeyboardController::write(lisp::Writer& writer)
266 {
267   writer.start_list("keymap");
268   for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
269     writer.start_list("map");
270     writer.write_int("key", (int) i->first);
271     writer.write_string("control", controlNames[i->second]);
272     writer.end_list("map");
273   }
274   writer.end_list("keymap");
275
276   writer.start_list("joystick");
277   writer.write_int("dead_zone", dead_zone);
278
279   for(ButtonMap::iterator i = joy_button_map.begin(); i != joy_button_map.end();
280       ++i) {
281     writer.start_list("map");
282     writer.write_int("button", i->first);
283     writer.write_string("control", controlNames[i->second]);
284     writer.end_list("map");
285   }
286
287   for(HatMap::iterator i = joy_hat_map.begin(); i != joy_hat_map.end(); ++i) {
288     writer.start_list("map");
289     writer.write_int("hat", i->first);
290     writer.write_string("control", controlNames[i->second]);
291     writer.end_list("map");
292   }
293
294   for(AxisMap::iterator i = joy_axis_map.begin(); i != joy_axis_map.end(); ++i) {
295     writer.start_list("map");
296     writer.write_int("axis", i->first);
297     writer.write_string("control", controlNames[i->second]);
298     writer.end_list("map");
299   }
300
301   writer.end_list("joystick");
302 }
303
304 void
305 JoystickKeyboardController::reset()
306 {
307   Controller::reset();
308 }
309
310 void
311 JoystickKeyboardController::process_event(const SDL_Event& event)
312 {
313   switch(event.type) {
314     case SDL_KEYUP:
315     case SDL_KEYDOWN:
316       process_key_event(event);
317       break;
318
319     case SDL_JOYAXISMOTION:
320       process_axis_event(event.jaxis);
321       break;
322
323     case SDL_JOYHATMOTION:
324       process_hat_event(event.jhat);
325       break;
326
327     case SDL_JOYBUTTONDOWN:
328     case SDL_JOYBUTTONUP:
329       {
330         if(wait_for_joystick >= 0) {
331           if(event.type == SDL_JOYBUTTONUP)
332             return;
333
334           Control c = (Control) wait_for_joystick;
335           reset_joybutton(event.jbutton.button, c);
336           reset();
337           joystick_options_menu->update();
338           wait_for_joystick = -1;
339           return;
340         }
341
342         ButtonMap::iterator i = joy_button_map.find(event.jbutton.button);
343         if(i == joy_button_map.end()) {
344           log_debug << "Unmapped joybutton " << (int)event.jbutton.button << " pressed" << std::endl;
345           return;
346         }
347
348         controls[i->second] = (event.type == SDL_JOYBUTTONDOWN);
349         break;
350       }
351
352     default:
353       break;
354   }
355 }
356
357 void
358 JoystickKeyboardController::process_axis_event(const SDL_JoyAxisEvent& jaxis)
359 {
360   if (wait_for_joystick >= 0)
361     {
362       if (abs(jaxis.value) > dead_zone)
363         {
364           if (jaxis.value < 0)
365             reset_joyaxis(-(jaxis.axis + 1), Control(wait_for_joystick));
366           else
367             reset_joyaxis(jaxis.axis + 1, Control(wait_for_joystick));
368
369           joystick_options_menu->update();
370           wait_for_joystick = -1;
371         }
372     }
373   else
374     {
375       // Split the axis into left and right, so that both can be
376       // mapped seperatly (needed for jump/down vs up/down)
377       int axis = jaxis.axis + 1;
378           
379       AxisMap::iterator left  = joy_axis_map.find(-axis);
380       AxisMap::iterator right = joy_axis_map.find(axis);
381
382       if(left == joy_axis_map.end()) {
383         std::cout << "Unmapped joyaxis " << (int)jaxis.axis << " moved" << std::endl;
384       } else {         
385         if (jaxis.value < -dead_zone)
386           controls[left->second]  = true;
387         else if (jaxis.value > dead_zone)
388           controls[left->second]  = false;
389         else
390           controls[left->second]  = false;
391       }
392
393       if(right == joy_axis_map.end()) {
394         std::cout << "Unmapped joyaxis " << (int)jaxis.axis << " moved" << std::endl;
395       } else {
396         if (jaxis.value < -dead_zone)
397           controls[right->second] = false;            
398         else if (jaxis.value > dead_zone)
399           controls[right->second] = true;              
400         else
401           controls[right->second] = false;
402       }
403     }
404 }
405
406 void
407 JoystickKeyboardController::process_hat_event(const SDL_JoyHatEvent& jhat)
408 {
409   Uint8 changed = hat_state ^ jhat.value;
410   
411   if (wait_for_joystick >= 0)
412     {
413       if (changed & SDL_HAT_UP && jhat.value & SDL_HAT_UP)
414         reset_joyhat(SDL_HAT_UP, (Control)wait_for_joystick);
415
416       if (changed & SDL_HAT_DOWN && jhat.value & SDL_HAT_DOWN)
417         reset_joyhat(SDL_HAT_DOWN, (Control)wait_for_joystick);
418
419       if (changed & SDL_HAT_LEFT && jhat.value & SDL_HAT_LEFT)
420         reset_joyhat(SDL_HAT_LEFT, (Control)wait_for_joystick);
421
422       if (changed & SDL_HAT_RIGHT && jhat.value & SDL_HAT_RIGHT)
423         reset_joyhat(SDL_HAT_RIGHT, (Control)wait_for_joystick);
424
425       joystick_options_menu->update();
426       wait_for_joystick = -1;
427     }
428   else
429     {
430       if (changed & SDL_HAT_UP)
431         {
432           HatMap::iterator it = joy_hat_map.find(SDL_HAT_UP);
433           if (it != joy_hat_map.end())
434             controls[it->second] = jhat.value & SDL_HAT_UP;
435         }
436         
437       if (changed & SDL_HAT_DOWN)
438         {
439           HatMap::iterator it = joy_hat_map.find(SDL_HAT_DOWN);
440           if (it != joy_hat_map.end())
441             controls[it->second] = jhat.value & SDL_HAT_DOWN;          
442         }
443         
444       if (changed & SDL_HAT_LEFT)
445         {
446           HatMap::iterator it = joy_hat_map.find(SDL_HAT_LEFT);
447           if (it != joy_hat_map.end())
448             controls[it->second] = jhat.value & SDL_HAT_LEFT;
449         }
450         
451       if (changed & SDL_HAT_RIGHT)
452         {
453           HatMap::iterator it = joy_hat_map.find(SDL_HAT_RIGHT);
454           if (it != joy_hat_map.end())
455             controls[it->second] = jhat.value & SDL_HAT_RIGHT;          
456         }
457     }
458
459   hat_state = jhat.value;
460 }
461
462 void
463 JoystickKeyboardController::process_key_event(const SDL_Event& event)
464 {
465   KeyMap::iterator key_mapping = keymap.find(event.key.keysym.sym);
466
467   // if console key was pressed: toggle console
468   if ((key_mapping != keymap.end()) && (key_mapping->second == CONSOLE)) {
469     if (event.type != SDL_KEYDOWN) return;
470     Console::instance->toggle();
471     return;
472   }
473
474   // if console is open: send key there
475   if (Console::instance->hasFocus()) {
476     process_console_key_event(event);
477     return;
478   }
479
480   // if menu mode: send key there
481   if (Menu::current()) {
482     process_menu_key_event(event);
483     return;
484   }
485
486   // default action: update controls
487   if(key_mapping == keymap.end()) {
488     log_debug << "Key " << event.key.keysym.sym << " is unbound" << std::endl;
489     return;
490   }
491   Control control = key_mapping->second;
492   controls[control] = (event.type == SDL_KEYDOWN);
493 }
494
495 void
496 JoystickKeyboardController::process_console_key_event(const SDL_Event& event)
497 {
498   if (event.type != SDL_KEYDOWN) return;
499
500   switch (event.key.keysym.sym) {
501     case SDLK_RETURN:
502       Console::instance->enter();
503       break;
504     case SDLK_BACKSPACE:
505       Console::instance->backspace();
506       break;
507     case SDLK_TAB:
508       Console::instance->autocomplete();
509       break;
510     case SDLK_PAGEUP:
511       Console::instance->scroll(-1);
512       break;
513     case SDLK_PAGEDOWN:
514       Console::instance->scroll(+1);
515       break;
516     case SDLK_HOME:
517       Console::instance->move_cursor(-65535);
518       break;
519     case SDLK_END:
520       Console::instance->move_cursor(+65535);
521       break;
522     case SDLK_UP:
523       Console::instance->show_history(-1);
524       break;
525     case SDLK_DOWN:
526       Console::instance->show_history(+1);
527       break;
528     case SDLK_LEFT:
529       Console::instance->move_cursor(-1);
530       break;
531     case SDLK_RIGHT:
532       Console::instance->move_cursor(+1);
533       break;
534     default:
535       int c = event.key.keysym.unicode;
536       if ((c >= 32) && (c <= 126)) {
537         Console::instance->input((char)c);
538       }
539       break;
540   }
541 }
542
543 void
544 JoystickKeyboardController::process_menu_key_event(const SDL_Event& event)
545 {
546   // wait for key mode?
547   if(wait_for_key >= 0) {
548     if(event.type == SDL_KEYUP)
549       return;
550
551     if(event.key.keysym.sym != SDLK_ESCAPE
552         && event.key.keysym.sym != SDLK_PAUSE) {
553       reset_key(event.key.keysym.sym, (Control) wait_for_key);
554     }
555     reset();
556     key_options_menu->update();
557     wait_for_key = -1;
558     return;
559   }
560   if(wait_for_joystick >= 0) {
561     if(event.key.keysym.sym == SDLK_ESCAPE) {
562       reset();
563       joystick_options_menu->update();
564       wait_for_joystick = -1;
565     }
566     return;
567   }
568
569   Control control;
570   /* we use default keys when the menu is open (to avoid problems when
571    * redefining keys to invalid settings
572    */
573   switch(event.key.keysym.sym) {
574     case SDLK_UP:
575       control = UP;
576       break;
577     case SDLK_DOWN:
578       control = DOWN;
579       break;
580     case SDLK_LEFT:
581       control = LEFT;
582       break;
583     case SDLK_RIGHT:
584       control = RIGHT;
585       break;
586     case SDLK_SPACE:
587     case SDLK_RETURN:
588     case SDLK_KP_ENTER:
589       control = MENU_SELECT;
590       break;
591     case SDLK_ESCAPE:
592     case SDLK_PAUSE:
593       control = PAUSE_MENU;
594       break;
595     default:
596       return;
597       break;
598   }
599
600   controls[control] = (event.type == SDL_KEYDOWN);
601 }
602
603 void 
604 JoystickKeyboardController::unbind_control(Control control)
605 {
606   // remove all previous mappings for that control
607   for(AxisMap::iterator i = joy_axis_map.begin(); 
608       i != joy_axis_map.end(); /* no ++i */) {
609     if(i->second == control) {
610       AxisMap::iterator e = i;
611       ++i;
612       joy_axis_map.erase(e);
613     } else {
614       ++i;
615     }
616   }
617
618   for(ButtonMap::iterator i = joy_button_map.begin();
619       i != joy_button_map.end(); /* no ++i */) {
620     if(i->second == control) {
621       ButtonMap::iterator e = i;
622       ++i;
623       joy_button_map.erase(e);
624     } else {
625       ++i;
626     }
627   }
628
629   for(HatMap::iterator i = joy_hat_map.begin();
630       i != joy_hat_map.end(); /* no ++i */) {
631     if(i->second == control) {
632       HatMap::iterator e = i;
633       ++i;
634       joy_hat_map.erase(e);
635     } else {
636       ++i;
637     }
638   }
639 }
640
641 void
642 JoystickKeyboardController::reset_joyaxis(int axis, Control control)
643 {
644   // axis isn't the SDL axis number, but axisnumber + 1 with sign
645   // changed depending on if the positive or negative end is to be
646   // used (negative axis 0 becomes -1, positive axis 2 becomes +3,
647   // etc.)
648
649   unbind_control(control);
650
651   // remove all previous and for that axis
652   AxisMap::iterator i = joy_axis_map.find(axis);
653   if(i != joy_axis_map.end())
654     joy_axis_map.erase(i);
655
656   // add new mapping
657   joy_axis_map.insert(std::make_pair(axis, control));
658 }
659
660 void
661 JoystickKeyboardController::reset_joyhat(int dir, Control c)
662 {
663   unbind_control(c);
664   joy_hat_map.insert(std::make_pair(dir, c));
665 }
666
667 void
668 JoystickKeyboardController::reset_joybutton(int button, Control control)
669 {
670   unbind_control(control);
671
672   // add new mapping
673   joy_button_map.insert(std::make_pair(button, control));
674
675   // map all unused buttons to MENU_SELECT
676   for(int b = 0; b < max_joybuttons; ++b) {
677     ButtonMap::iterator i = joy_button_map.find(b);
678     if(i != joy_button_map.end())
679       continue;
680
681     joy_button_map.insert(std::make_pair(b, MENU_SELECT));
682   }
683 }
684
685 void
686 JoystickKeyboardController::reset_key(SDLKey key, Control control)
687 {
688   // remove all previous mappings for that control and for that key
689   for(KeyMap::iterator i = keymap.begin();
690       i != keymap.end(); /* no ++i */) {
691     if(i->second == control) {
692       KeyMap::iterator e = i;
693       ++i;
694       keymap.erase(e);
695     } else {
696       ++i;
697     }
698   }
699   KeyMap::iterator i = keymap.find(key);
700   if(i != keymap.end())
701     keymap.erase(i);
702
703   // add new mapping
704   keymap.insert(std::make_pair(key, control));
705 }
706
707 SDLKey
708 JoystickKeyboardController::reversemap_key(Control c)
709 {
710   for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
711     if(i->second == c)
712       return i->first;
713   }
714
715   return SDLK_UNKNOWN;
716 }
717
718 int
719 JoystickKeyboardController::reversemap_joyaxis(Control c)
720 {
721   for(AxisMap::iterator i = joy_axis_map.begin(); i != joy_axis_map.end(); ++i) {
722     if(i->second == c)
723       return i->first;
724   }
725   
726   return 0;
727 }
728
729 int
730 JoystickKeyboardController::reversemap_joybutton(Control c)
731 {
732   for(ButtonMap::iterator i = joy_button_map.begin();
733       i != joy_button_map.end(); ++i) {
734     if(i->second == c)
735       return i->first;
736   }
737
738   return -1;
739 }
740
741 int
742 JoystickKeyboardController::reversemap_joyhat(Control c)
743 {
744   for(HatMap::iterator i = joy_hat_map.begin();
745       i != joy_hat_map.end(); ++i) {
746     if(i->second == c)
747       return i->first;
748   }
749
750   return -1; 
751 }
752
753 Menu*
754 JoystickKeyboardController::get_key_options_menu()
755 {
756   if(key_options_menu == 0) {
757     key_options_menu = new KeyboardMenu(this);
758   }
759
760   return key_options_menu;
761 }
762
763 Menu*
764 JoystickKeyboardController::get_joystick_options_menu()
765 {
766   if(joystick_options_menu == 0) {
767     joystick_options_menu = new JoystickMenu(this);
768   }
769
770   return joystick_options_menu;
771 }
772
773 //----------------------------------------------------------------------------
774
775 JoystickKeyboardController::KeyboardMenu::KeyboardMenu(
776     JoystickKeyboardController* _controller)
777   : controller(_controller)
778 {
779     add_label(_("Setup Keyboard"));
780     add_hl();
781     add_controlfield(Controller::UP,         _("Up"));
782     add_controlfield(Controller::DOWN,       _("Down"));
783     add_controlfield(Controller::LEFT,       _("Left"));
784     add_controlfield(Controller::RIGHT,      _("Right"));
785     add_controlfield(Controller::JUMP,       _("Jump"));
786     add_controlfield(Controller::ACTION,     _("Action"));
787     add_controlfield(Controller::PEEK_LEFT,  _("Peek Left"));
788     add_controlfield(Controller::PEEK_RIGHT, _("Peek Right"));
789     if (config->console_enabled) {
790       add_controlfield(Controller::CONSOLE, _("Console"));
791     }
792     add_hl();
793     add_back(_("Back"));
794     update();
795 }
796
797 JoystickKeyboardController::KeyboardMenu::~KeyboardMenu()
798 {}
799
800 std::string
801 JoystickKeyboardController::KeyboardMenu::get_key_name(SDLKey key)
802 {
803   switch(key) {
804     case SDLK_UNKNOWN:
805       return _("None");
806     case SDLK_UP:
807       return _("Up cursor");
808     case SDLK_DOWN:
809       return _("Down cursor");
810     case SDLK_LEFT:
811       return _("Left cursor");
812     case SDLK_RIGHT:
813       return _("Right cursor");
814     case SDLK_RETURN:
815       return _("Return");
816     case SDLK_SPACE:
817       return _("Space");
818     case SDLK_RSHIFT:
819       return _("Right Shift");
820     case SDLK_LSHIFT:
821       return _("Left Shift");
822     case SDLK_RCTRL:
823       return _("Right Control");
824     case SDLK_LCTRL:
825       return _("Left Control");
826     case SDLK_RALT:
827       return _("Right Alt");
828     case SDLK_LALT:
829       return _("Left Alt");
830     default:
831       return SDL_GetKeyName((SDLKey) key);
832   }
833 }
834
835 void
836 JoystickKeyboardController::KeyboardMenu::menu_action(MenuItem* item)
837 {
838   assert(item->id >= 0 && item->id < Controller::CONTROLCOUNT);
839   item->change_input(_("Press Key"));
840   controller->wait_for_key = item->id;
841 }
842
843 void
844 JoystickKeyboardController::KeyboardMenu::update()
845 {
846   // update menu
847   get_item_by_id((int) Controller::UP).change_input(get_key_name(
848     controller->reversemap_key(Controller::UP)));
849   get_item_by_id((int) Controller::DOWN).change_input(get_key_name(
850     controller->reversemap_key(Controller::DOWN)));
851   get_item_by_id((int) Controller::LEFT).change_input(get_key_name(
852     controller->reversemap_key(Controller::LEFT)));
853   get_item_by_id((int) Controller::RIGHT).change_input(get_key_name(
854     controller->reversemap_key(Controller::RIGHT)));
855   get_item_by_id((int) Controller::JUMP).change_input(get_key_name(
856     controller->reversemap_key(Controller::JUMP)));
857   get_item_by_id((int) Controller::ACTION).change_input(get_key_name(
858     controller->reversemap_key(Controller::ACTION)));
859   get_item_by_id((int) Controller::PEEK_LEFT).change_input(get_key_name(
860     controller->reversemap_key(Controller::PEEK_LEFT)));
861   get_item_by_id((int) Controller::PEEK_RIGHT).change_input(get_key_name(
862     controller->reversemap_key(Controller::PEEK_RIGHT)));
863   if (config->console_enabled) {
864     get_item_by_id((int) Controller::CONSOLE).change_input(get_key_name(
865       controller->reversemap_key(Controller::CONSOLE)));
866   }
867 }
868
869 //---------------------------------------------------------------------------
870
871 JoystickKeyboardController::JoystickMenu::JoystickMenu(
872   JoystickKeyboardController* _controller)
873   : controller(_controller)
874 {
875   add_label(_("Setup Joystick"));
876   add_hl();
877   if(controller->joysticks.size() > 0) {
878     add_controlfield(Controller::UP,          _("Up"));
879     add_controlfield(Controller::DOWN,        _("Down"));
880     add_controlfield(Controller::LEFT,        _("Left"));
881     add_controlfield(Controller::RIGHT,       _("Right"));
882     add_controlfield(Controller::JUMP,        _("Jump"));
883     add_controlfield(Controller::ACTION,      _("Action"));
884     add_controlfield(Controller::PAUSE_MENU,  _("Pause/Menu"));
885     add_controlfield(Controller::PEEK_LEFT,   _("Peek Left"));
886     add_controlfield(Controller::PEEK_RIGHT,  _("Peek Right"));
887   } else {
888     add_deactive(-1, _("No Joysticks found"));
889   }
890   add_hl();
891   add_back(_("Back"));
892   update();
893 }
894
895 JoystickKeyboardController::JoystickMenu::~JoystickMenu()
896 {}
897
898 std::string
899 JoystickKeyboardController::JoystickMenu::get_button_name(int button)
900 {
901   if(button < 0)
902     return _("None");
903
904   std::ostringstream name;
905   name << "Button " << button;
906   return name.str();
907 }
908
909 void
910 JoystickKeyboardController::JoystickMenu::menu_action(MenuItem* item)
911 {
912   assert(item->id >= 0 && item->id < Controller::CONTROLCOUNT);
913   item->change_input(_("Press Button"));
914   controller->wait_for_joystick = item->id;
915 }
916
917 void
918 JoystickKeyboardController::JoystickMenu::update_menu_item(Control id)
919 {
920   int button  = controller->reversemap_joybutton(id);
921   int axis    = controller->reversemap_joyaxis(id);
922   int hat_dir = controller->reversemap_joyhat(id);
923
924   if (button != -1) {
925     get_item_by_id((int)id).change_input(get_button_name(button));
926   } else if (axis != 0) {
927     std::ostringstream name;
928
929     name << "Axis ";
930
931     if (axis < 0)
932       name << "-";
933     else
934       name << "+";
935
936     if (abs(axis) == 1)
937       name << "X";
938     else if (abs(axis) == 2)
939       name << "Y";
940     else if (abs(axis) == 2)
941       name << "X2";
942     else if (abs(axis) == 3)
943       name << "Y2";
944     else 
945       name << abs(axis);
946
947     get_item_by_id((int)id).change_input(name.str());
948   } else if (hat_dir != -1) {
949     std::string name;
950     
951     switch (hat_dir)
952       {
953         case SDL_HAT_UP:
954           name = "Hat Up";
955           break;
956
957         case SDL_HAT_DOWN:
958           name = "Hat Down";
959           break;
960
961         case SDL_HAT_LEFT:
962           name = "Hat Left";
963           break;
964
965         case SDL_HAT_RIGHT:
966           name = "Hat Right";
967           break;
968
969         default:
970           name = "Unknown hat_dir";
971           break;
972       }
973
974     get_item_by_id((int)id).change_input(name);
975   } else {
976     get_item_by_id((int)id).change_input("None");
977   }
978 }
979
980 void
981 JoystickKeyboardController::JoystickMenu::update()
982 {
983   if(controller->joysticks.size() == 0)
984     return;
985
986   update_menu_item(Controller::UP);
987   update_menu_item(Controller::DOWN);
988   update_menu_item(Controller::LEFT);
989   update_menu_item(Controller::RIGHT);
990
991   update_menu_item(Controller::JUMP);
992   update_menu_item(Controller::ACTION);
993   update_menu_item(Controller::PAUSE_MENU);
994   update_menu_item(Controller::PEEK_LEFT);
995   update_menu_item(Controller::PEEK_RIGHT);
996 }