da75d31190dfa0d412a028d7254fae1acb5d94a4
[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   : wait_for_key(-1), wait_for_joystick(-1),
61     key_options_menu(0), joystick_options_menu(0)
62 {
63   // initialize default keyboard map
64   keymap.insert(std::make_pair(SDLK_LEFT,     LEFT));
65   keymap.insert(std::make_pair(SDLK_RIGHT,    RIGHT));
66   keymap.insert(std::make_pair(SDLK_UP,       UP));
67   keymap.insert(std::make_pair(SDLK_DOWN,     DOWN));
68   keymap.insert(std::make_pair(SDLK_SPACE,    JUMP));
69   keymap.insert(std::make_pair(SDLK_LCTRL,    ACTION));
70   keymap.insert(std::make_pair(SDLK_LALT,     ACTION));
71   keymap.insert(std::make_pair(SDLK_ESCAPE,   PAUSE_MENU));
72   keymap.insert(std::make_pair(SDLK_p,        PAUSE_MENU));
73   keymap.insert(std::make_pair(SDLK_PAUSE,    PAUSE_MENU));
74   keymap.insert(std::make_pair(SDLK_RETURN,   MENU_SELECT));
75   keymap.insert(std::make_pair(SDLK_KP_ENTER, MENU_SELECT));
76   keymap.insert(std::make_pair(SDLK_CARET,    CONSOLE));
77   keymap.insert(std::make_pair(SDLK_DELETE,   PEEK_LEFT));
78   keymap.insert(std::make_pair(SDLK_END,      PEEK_RIGHT));
79
80   int joystick_count = SDL_NumJoysticks();
81   min_joybuttons = -1;
82   max_joybuttons = -1;
83   for(int i = 0; i < joystick_count; ++i) {
84     SDL_Joystick* joystick = SDL_JoystickOpen(i);
85     bool good = true;
86     if(SDL_JoystickNumButtons(joystick) < 2) {
87       log_info << "Joystick " << i << " has less than 2 buttons" << std::endl;
88       good = false;
89     }
90     if(SDL_JoystickNumAxes(joystick) < 2
91        && SDL_JoystickNumHats(joystick) == 0) {
92       log_info << "Joystick " << i << " has less than 2 axes and no hat" << std::endl;
93       good = false;
94     }
95     if(!good) {
96       SDL_JoystickClose(joystick);
97       continue;
98     }
99
100     if(min_joybuttons < 0 || SDL_JoystickNumButtons(joystick) < min_joybuttons)
101       min_joybuttons = SDL_JoystickNumButtons(joystick);
102     if(SDL_JoystickNumButtons(joystick) > max_joybuttons) {
103       max_joybuttons = SDL_JoystickNumButtons(joystick);
104     }
105
106     joysticks.push_back(joystick);
107   }
108
109   use_hat = true;
110   joyaxis_x = 0;
111   joyaxis_y = 1;
112   dead_zone = 1000;
113
114   // Default joystick button configuration
115   joy_button_map.insert(std::make_pair(0, JUMP));
116   joy_button_map.insert(std::make_pair(1, ACTION));
117   // 6 or more Buttons
118   if( min_joybuttons > 5 ){
119     joy_button_map.insert(std::make_pair( 4, PEEK_LEFT));
120     joy_button_map.insert(std::make_pair( 5, PEEK_RIGHT));
121     // 8 or more
122     if(min_joybuttons > 7)
123       joy_button_map.insert(std::make_pair(min_joybuttons-1, PAUSE_MENU));
124     // map all remaining joystick buttons to MENU_SELECT
125     for(int i = 2; i < max_joybuttons; ++i) {
126       if( i != min_joybuttons-1 && i !=4  && i!= 5 )
127         joy_button_map.insert(std::make_pair(i, MENU_SELECT));
128     }
129
130   } else {
131     // map the last 2 buttons to menu and pause
132     if(min_joybuttons > 2)
133       joy_button_map.insert(std::make_pair(min_joybuttons-1, PAUSE_MENU));
134     // map all remaining joystick buttons to MENU_SELECT
135     for(int i = 2; i < max_joybuttons; ++i) {
136       if(i != min_joybuttons-1)
137         joy_button_map.insert(std::make_pair(i, MENU_SELECT));
138     }
139   }
140
141   // Default joystick axis configuration
142   joy_axis_map.insert(std::make_pair(-1, LEFT));
143   joy_axis_map.insert(std::make_pair( 1, RIGHT));
144   joy_axis_map.insert(std::make_pair(-2, JUMP));
145   joy_axis_map.insert(std::make_pair( 2, DOWN));
146
147   // some joysticks or SDL seem to produce some bogus events after being opened
148   Uint32 ticks = SDL_GetTicks();
149   while(SDL_GetTicks() - ticks < 200) {
150     SDL_Event event;
151     SDL_PollEvent(&event);
152   }
153 }
154
155 JoystickKeyboardController::~JoystickKeyboardController()
156 {
157   for(std::vector<SDL_Joystick*>::iterator i = joysticks.begin();
158       i != joysticks.end(); ++i) {
159     if(*i != 0)
160       SDL_JoystickClose(*i);
161   }
162
163   delete key_options_menu;
164   delete joystick_options_menu;
165 }
166
167 void
168 JoystickKeyboardController::read(const lisp::Lisp& lisp)
169 {
170   const lisp::Lisp* keymap_lisp = lisp.get_lisp("keymap");
171   if(keymap_lisp) {
172     keymap.clear();
173     lisp::ListIterator iter(keymap_lisp);
174     while(iter.next()) {
175       if(iter.item() == "map") {
176         int key = -1;
177         std::string control;
178         const lisp::Lisp* map = iter.lisp();
179         map->get("key", key);
180         map->get("control", control);
181         if(key < SDLK_FIRST || key >= SDLK_LAST) {
182           log_info << "Invalid key '" << key << "' in keymap" << std::endl;
183           continue;
184         }
185
186         int i = 0;
187         for(i = 0; controlNames[i] != 0; ++i) {
188           if(control == controlNames[i])
189             break;
190         }
191         if(controlNames[i] == 0) {
192           log_info << "Invalid control '" << control << "' in keymap" << std::endl;
193           continue;
194         }
195         keymap.insert(std::make_pair((SDLKey) key, (Control) i));
196       } else {
197         log_info << "Invalid lisp element '" << iter.item() << "' in keymap" << std::endl;
198       }
199     }
200   }
201
202   const lisp::Lisp* joystick_lisp = lisp.get_lisp("joystick");
203   if(joystick_lisp) {
204     joystick_lisp->get("use_hat", use_hat);
205     joystick_lisp->get("axis_x", joyaxis_x);
206     joystick_lisp->get("axis_y", joyaxis_y);
207     joystick_lisp->get("dead_zone", dead_zone);
208     lisp::ListIterator iter(joystick_lisp);
209     while(iter.next()) {
210       if(iter.item() == "map") {
211         int button = -1;
212         std::string control;
213         const lisp::Lisp* map = iter.lisp();
214         map->get("button", button);
215         map->get("control", control);
216         if(button < 0 || button >= max_joybuttons) {
217           log_info << "Invalid button '" << button << "' in buttonmap" << std::endl;
218           continue;
219         }
220
221         int i = 0;
222         for(i = 0; controlNames[i] != 0; ++i) {
223           if(control == controlNames[i])
224             break;
225         }
226         if(controlNames[i] == 0) {
227           log_info << "Invalid control '" << control << "' in buttonmap" << std::endl;
228           continue;
229         }
230         reset_joybutton(button, (Control) i);
231       }
232     }
233   }
234 }
235
236 void
237 JoystickKeyboardController::write(lisp::Writer& writer)
238 {
239   writer.start_list("keymap");
240   for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
241     writer.start_list("map");
242     writer.write_int("key", (int) i->first);
243     writer.write_string("control", controlNames[i->second]);
244     writer.end_list("map");
245   }
246   writer.end_list("keymap");
247   writer.start_list("joystick");
248   writer.write_bool("use_hat", use_hat);
249   writer.write_int("axis_x", joyaxis_x);
250   writer.write_int("axis_y", joyaxis_y);
251   writer.write_int("dead_zone", dead_zone);
252
253   for(ButtonMap::iterator i = joy_button_map.begin(); i != joy_button_map.end();
254       ++i) {
255     writer.start_list("map");
256     writer.write_int("button", i->first);
257     writer.write_string("control", controlNames[i->second]);
258     writer.end_list("map");
259   }
260   writer.end_list("joystick");
261 }
262
263 void
264 JoystickKeyboardController::reset()
265 {
266   Controller::reset();
267 }
268
269 void
270 JoystickKeyboardController::process_event(const SDL_Event& event)
271 {
272   switch(event.type) {
273     case SDL_KEYUP:
274     case SDL_KEYDOWN:
275       process_key_event(event);
276       break;
277
278     case SDL_JOYAXISMOTION:
279       if (wait_for_joystick >= 0)
280         {
281           if (abs(event.jaxis.value) > dead_zone)
282             {
283               if (event.jaxis.value < 0)
284                 reset_joyaxis(-(event.jaxis.axis + 1), Control(wait_for_joystick));
285               else
286                 reset_joyaxis(event.jaxis.axis + 1, Control(wait_for_joystick));
287
288               joystick_options_menu->update();
289               wait_for_joystick = -1;
290             }
291         }
292       else
293         {
294           // Split the axis into left and right, so that both can be
295           // mapped seperatly (needed for jump/down vs up/down)
296           int axis = event.jaxis.axis + 1;
297           
298           AxisMap::iterator left  = joy_axis_map.find(-axis);
299           AxisMap::iterator right = joy_axis_map.find(axis);
300
301           if(left == joy_axis_map.end()) {
302             std::cout << "Unmapped joyaxis " << (int)event.jaxis.axis << " moved" << std::endl;
303           } else {         
304             if (event.jaxis.value < -dead_zone)
305               controls[left->second]  = true;
306             else if (event.jaxis.value > dead_zone)
307               controls[left->second]  = false;
308             else
309               controls[left->second]  = false;
310           }
311
312           if(right == joy_axis_map.end()) {
313             std::cout << "Unmapped joyaxis " << (int)event.jaxis.axis << " moved" << std::endl;
314           } else {
315             if (event.jaxis.value < -dead_zone)
316               controls[right->second] = false;            
317             else if (event.jaxis.value > dead_zone)
318               controls[right->second] = true;              
319             else
320               controls[right->second] = false;
321           }
322         }
323       break;
324
325     case SDL_JOYHATMOTION:
326       if(!use_hat)
327         break;
328
329       if(event.jhat.value & SDL_HAT_UP) {
330         controls[UP]   = true;
331         controls[DOWN] = false;
332       }
333       if(event.jhat.value & SDL_HAT_DOWN) {
334         controls[UP]   = false;
335         controls[DOWN] = true;
336       }
337       if(event.jhat.value & SDL_HAT_LEFT) {
338         controls[LEFT]  = true;
339         controls[RIGHT] = false;
340       }
341       if(event.jhat.value & SDL_HAT_RIGHT) {
342         controls[LEFT]  = false;
343         controls[RIGHT] = true;
344       }
345       if(event.jhat.value == SDL_HAT_CENTERED) {
346         controls[UP]    = false;
347         controls[DOWN]  = false;
348         controls[LEFT]  = false;
349         controls[RIGHT] = false;
350       }
351       break;
352
353     case SDL_JOYBUTTONDOWN:
354     case SDL_JOYBUTTONUP:
355       {
356         if(wait_for_joystick >= 0) {
357           if(event.type == SDL_JOYBUTTONUP)
358             return;
359
360           Control c = (Control) wait_for_joystick;
361           reset_joybutton(event.jbutton.button, c);
362           reset();
363           joystick_options_menu->update();
364           wait_for_joystick = -1;
365           return;
366         }
367
368         ButtonMap::iterator i = joy_button_map.find(event.jbutton.button);
369         if(i == joy_button_map.end()) {
370           log_debug << "Unmapped joybutton " << (int)event.jbutton.button << " pressed" << std::endl;
371           return;
372         }
373
374         controls[i->second] = (event.type == SDL_JOYBUTTONDOWN);
375         break;
376       }
377
378     default:
379       break;
380   }
381 }
382
383 void
384 JoystickKeyboardController::process_key_event(const SDL_Event& event)
385 {
386   KeyMap::iterator key_mapping = keymap.find(event.key.keysym.sym);
387
388   // if console key was pressed: toggle console
389   if ((key_mapping != keymap.end()) && (key_mapping->second == CONSOLE)) {
390     if (event.type != SDL_KEYDOWN) return;
391     Console::instance->toggle();
392     return;
393   }
394
395   // if console is open: send key there
396   if (Console::instance->hasFocus()) {
397     process_console_key_event(event);
398     return;
399   }
400
401   // if menu mode: send key there
402   if (Menu::current()) {
403     process_menu_key_event(event);
404     return;
405   }
406
407   // default action: update controls
408   if(key_mapping == keymap.end()) {
409     log_debug << "Key " << event.key.keysym.sym << " is unbound" << std::endl;
410     return;
411   }
412   Control control = key_mapping->second;
413   controls[control] = (event.type == SDL_KEYDOWN);
414 }
415
416 void
417 JoystickKeyboardController::process_console_key_event(const SDL_Event& event)
418 {
419   if (event.type != SDL_KEYDOWN) return;
420
421   switch (event.key.keysym.sym) {
422     case SDLK_RETURN:
423       Console::instance->enter();
424       break;
425     case SDLK_BACKSPACE:
426       Console::instance->backspace();
427       break;
428     case SDLK_TAB:
429       Console::instance->autocomplete();
430       break;
431     case SDLK_PAGEUP:
432       Console::instance->scroll(-1);
433       break;
434     case SDLK_PAGEDOWN:
435       Console::instance->scroll(+1);
436       break;
437     case SDLK_HOME:
438       Console::instance->move_cursor(-65535);
439       break;
440     case SDLK_END:
441       Console::instance->move_cursor(+65535);
442       break;
443     case SDLK_UP:
444       Console::instance->show_history(-1);
445       break;
446     case SDLK_DOWN:
447       Console::instance->show_history(+1);
448       break;
449     case SDLK_LEFT:
450       Console::instance->move_cursor(-1);
451       break;
452     case SDLK_RIGHT:
453       Console::instance->move_cursor(+1);
454       break;
455     default:
456       int c = event.key.keysym.unicode;
457       if ((c >= 32) && (c <= 126)) {
458         Console::instance->input((char)c);
459       }
460       break;
461   }
462 }
463
464 void
465 JoystickKeyboardController::process_menu_key_event(const SDL_Event& event)
466 {
467   // wait for key mode?
468   if(wait_for_key >= 0) {
469     if(event.type == SDL_KEYUP)
470       return;
471
472     if(event.key.keysym.sym != SDLK_ESCAPE
473         && event.key.keysym.sym != SDLK_PAUSE) {
474       reset_key(event.key.keysym.sym, (Control) wait_for_key);
475     }
476     reset();
477     key_options_menu->update();
478     wait_for_key = -1;
479     return;
480   }
481   if(wait_for_joystick >= 0) {
482     if(event.key.keysym.sym == SDLK_ESCAPE) {
483       reset();
484       joystick_options_menu->update();
485       wait_for_joystick = -1;
486     }
487     return;
488   }
489
490   Control control;
491   /* we use default keys when the menu is open (to avoid problems when
492    * redefining keys to invalid settings
493    */
494   switch(event.key.keysym.sym) {
495     case SDLK_UP:
496       control = UP;
497       break;
498     case SDLK_DOWN:
499       control = DOWN;
500       break;
501     case SDLK_LEFT:
502       control = LEFT;
503       break;
504     case SDLK_RIGHT:
505       control = RIGHT;
506       break;
507     case SDLK_SPACE:
508     case SDLK_RETURN:
509     case SDLK_KP_ENTER:
510       control = MENU_SELECT;
511       break;
512     case SDLK_ESCAPE:
513     case SDLK_PAUSE:
514       control = PAUSE_MENU;
515       break;
516     default:
517       return;
518       break;
519   }
520
521   controls[control] = (event.type == SDL_KEYDOWN);
522 }
523
524 void
525 JoystickKeyboardController::reset_joyaxis(int axis, Control control)
526 {
527   // axis isn't the SDL axis number, but axisnumber + 1 with sign
528   // changed depending on if the positive or negative end is to be
529   // used (negative axis 0 becomes -1, positive axis 2 becomes +3,
530   // etc.)
531   
532   // remove all previous mappings for that control
533   for(AxisMap::iterator i = joy_axis_map.begin(); 
534       i != joy_axis_map.end(); /* no ++i */) {
535     if(i->second == control) {
536       AxisMap::iterator e = i;
537       ++i;
538       joy_axis_map.erase(e);
539     } else {
540       ++i;
541     }
542   }
543
544   // remove all previous mappings for that control
545   for(ButtonMap::iterator i = joy_button_map.begin();
546       i != joy_button_map.end(); /* no ++i */) {
547     if(i->second == control) {
548       ButtonMap::iterator e = i;
549       ++i;
550       joy_button_map.erase(e);
551     } else {
552       ++i;
553     }
554   }
555
556   // remove all previous and for that axis
557   AxisMap::iterator i = joy_axis_map.find(axis);
558   if(i != joy_axis_map.end())
559     joy_axis_map.erase(i);
560
561   // add new mapping
562   joy_axis_map.insert(std::make_pair(axis, control));
563 }
564
565 void
566 JoystickKeyboardController::reset_joybutton(int button, Control control)
567 {
568   // remove all previous mappings for that control
569   for(AxisMap::iterator i = joy_axis_map.begin(); 
570       i != joy_axis_map.end(); /* no ++i */) {
571     if(i->second == control) {
572       AxisMap::iterator e = i;
573       ++i;
574       joy_axis_map.erase(e);
575     } else {
576       ++i;
577     }
578   }
579
580   // remove all previous mappings for that control and for that key
581   for(ButtonMap::iterator i = joy_button_map.begin();
582       i != joy_button_map.end(); /* no ++i */) {
583     if(i->second == control) {
584       ButtonMap::iterator e = i;
585       ++i;
586       joy_button_map.erase(e);
587     } else {
588       ++i;
589     }
590   }
591   ButtonMap::iterator i = joy_button_map.find(button);
592   if(i != joy_button_map.end())
593     joy_button_map.erase(i);
594
595   // add new mapping
596   joy_button_map.insert(std::make_pair(button, control));
597
598   // map all unused buttons to MENU_SELECT
599   for(int b = 0; b < max_joybuttons; ++b) {
600     ButtonMap::iterator i = joy_button_map.find(b);
601     if(i != joy_button_map.end())
602       continue;
603
604     joy_button_map.insert(std::make_pair(b, MENU_SELECT));
605   }
606 }
607
608 void
609 JoystickKeyboardController::reset_key(SDLKey key, Control control)
610 {
611   // remove all previous mappings for that control and for that key
612   for(KeyMap::iterator i = keymap.begin();
613       i != keymap.end(); /* no ++i */) {
614     if(i->second == control) {
615       KeyMap::iterator e = i;
616       ++i;
617       keymap.erase(e);
618     } else {
619       ++i;
620     }
621   }
622   KeyMap::iterator i = keymap.find(key);
623   if(i != keymap.end())
624     keymap.erase(i);
625
626   // add new mapping
627   keymap.insert(std::make_pair(key, control));
628 }
629
630 SDLKey
631 JoystickKeyboardController::reversemap_key(Control c)
632 {
633   for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
634     if(i->second == c)
635       return i->first;
636   }
637
638   return SDLK_UNKNOWN;
639 }
640
641 int
642 JoystickKeyboardController::reversemap_joyaxis(Control c)
643 {
644   for(AxisMap::iterator i = joy_axis_map.begin(); i != joy_axis_map.end(); ++i) {
645     if(i->second == c)
646       return i->first;
647   }
648   
649   return 0;
650 }
651
652 int
653 JoystickKeyboardController::reversemap_joybutton(Control c)
654 {
655   for(ButtonMap::iterator i = joy_button_map.begin();
656       i != joy_button_map.end(); ++i) {
657     if(i->second == c)
658       return i->first;
659   }
660
661   return -1;
662 }
663
664 Menu*
665 JoystickKeyboardController::get_key_options_menu()
666 {
667   if(key_options_menu == 0) {
668     key_options_menu = new KeyboardMenu(this);
669   }
670
671   return key_options_menu;
672 }
673
674 Menu*
675 JoystickKeyboardController::get_joystick_options_menu()
676 {
677   if(joystick_options_menu == 0) {
678     joystick_options_menu = new JoystickMenu(this);
679   }
680
681   return joystick_options_menu;
682 }
683
684 //----------------------------------------------------------------------------
685
686 JoystickKeyboardController::KeyboardMenu::KeyboardMenu(
687     JoystickKeyboardController* _controller)
688   : controller(_controller)
689 {
690     add_label(_("Setup Keyboard"));
691     add_hl();
692     add_controlfield(Controller::UP,         _("Up"));
693     add_controlfield(Controller::DOWN,       _("Down"));
694     add_controlfield(Controller::LEFT,       _("Left"));
695     add_controlfield(Controller::RIGHT,      _("Right"));
696     add_controlfield(Controller::JUMP,       _("Jump"));
697     add_controlfield(Controller::ACTION,     _("Action"));
698     add_controlfield(Controller::PEEK_LEFT,  _("Peek Left"));
699     add_controlfield(Controller::PEEK_RIGHT, _("Peek Right"));
700     if (config->console_enabled) {
701       add_controlfield(Controller::CONSOLE, _("Console"));
702     }
703     add_hl();
704     add_back(_("Back"));
705     update();
706 }
707
708 JoystickKeyboardController::KeyboardMenu::~KeyboardMenu()
709 {}
710
711 std::string
712 JoystickKeyboardController::KeyboardMenu::get_key_name(SDLKey key)
713 {
714   switch(key) {
715     case SDLK_UNKNOWN:
716       return _("None");
717     case SDLK_UP:
718       return _("Up cursor");
719     case SDLK_DOWN:
720       return _("Down cursor");
721     case SDLK_LEFT:
722       return _("Left cursor");
723     case SDLK_RIGHT:
724       return _("Right cursor");
725     case SDLK_RETURN:
726       return _("Return");
727     case SDLK_SPACE:
728       return _("Space");
729     case SDLK_RSHIFT:
730       return _("Right Shift");
731     case SDLK_LSHIFT:
732       return _("Left Shift");
733     case SDLK_RCTRL:
734       return _("Right Control");
735     case SDLK_LCTRL:
736       return _("Left Control");
737     case SDLK_RALT:
738       return _("Right Alt");
739     case SDLK_LALT:
740       return _("Left Alt");
741     default:
742       return SDL_GetKeyName((SDLKey) key);
743   }
744 }
745
746 void
747 JoystickKeyboardController::KeyboardMenu::menu_action(MenuItem* item)
748 {
749   assert(item->id >= 0 && item->id < Controller::CONTROLCOUNT);
750   item->change_input(_("Press Key"));
751   controller->wait_for_key = item->id;
752 }
753
754 void
755 JoystickKeyboardController::KeyboardMenu::update()
756 {
757   // update menu
758   get_item_by_id((int) Controller::UP).change_input(get_key_name(
759     controller->reversemap_key(Controller::UP)));
760   get_item_by_id((int) Controller::DOWN).change_input(get_key_name(
761     controller->reversemap_key(Controller::DOWN)));
762   get_item_by_id((int) Controller::LEFT).change_input(get_key_name(
763     controller->reversemap_key(Controller::LEFT)));
764   get_item_by_id((int) Controller::RIGHT).change_input(get_key_name(
765     controller->reversemap_key(Controller::RIGHT)));
766   get_item_by_id((int) Controller::JUMP).change_input(get_key_name(
767     controller->reversemap_key(Controller::JUMP)));
768   get_item_by_id((int) Controller::ACTION).change_input(get_key_name(
769     controller->reversemap_key(Controller::ACTION)));
770   get_item_by_id((int) Controller::PEEK_LEFT).change_input(get_key_name(
771     controller->reversemap_key(Controller::PEEK_LEFT)));
772   get_item_by_id((int) Controller::PEEK_RIGHT).change_input(get_key_name(
773     controller->reversemap_key(Controller::PEEK_RIGHT)));
774   if (config->console_enabled) {
775     get_item_by_id((int) Controller::CONSOLE).change_input(get_key_name(
776       controller->reversemap_key(Controller::CONSOLE)));
777   }
778 }
779
780 //---------------------------------------------------------------------------
781
782 JoystickKeyboardController::JoystickMenu::JoystickMenu(
783   JoystickKeyboardController* _controller)
784   : controller(_controller)
785 {
786   add_label(_("Setup Joystick"));
787   add_hl();
788   if(controller->joysticks.size() > 0) {
789     add_controlfield(Controller::UP,          _("Up"));
790     add_controlfield(Controller::DOWN,        _("Down"));
791     add_controlfield(Controller::LEFT,        _("Left"));
792     add_controlfield(Controller::RIGHT,       _("Right"));
793     add_controlfield(Controller::JUMP,        _("Jump"));
794     add_controlfield(Controller::ACTION,      _("Action"));
795     add_controlfield(Controller::PAUSE_MENU,  _("Pause/Menu"));
796     add_controlfield(Controller::PEEK_LEFT,   _("Peek Left"));
797     add_controlfield(Controller::PEEK_RIGHT,  _("Peek Right"));
798   } else {
799     add_deactive(-1, _("No Joysticks found"));
800   }
801   add_hl();
802   add_back(_("Back"));
803   update();
804 }
805
806 JoystickKeyboardController::JoystickMenu::~JoystickMenu()
807 {}
808
809 std::string
810 JoystickKeyboardController::JoystickMenu::get_button_name(int button)
811 {
812   if(button < 0)
813     return _("None");
814
815   std::ostringstream name;
816   name << "Button " << button;
817   return name.str();
818 }
819
820 void
821 JoystickKeyboardController::JoystickMenu::menu_action(MenuItem* item)
822 {
823   assert(item->id >= 0 && item->id < Controller::CONTROLCOUNT);
824   item->change_input(_("Press Button"));
825   controller->wait_for_joystick = item->id;
826 }
827
828 void
829 JoystickKeyboardController::JoystickMenu::update_menu_item(Control id)
830 {
831   int button = controller->reversemap_joybutton(id);
832   int axis   = controller->reversemap_joyaxis(id);
833   
834   if (button != -1) {
835     get_item_by_id((int)id).change_input(get_button_name(button));
836   } else if (axis != 0) {
837     std::ostringstream name;
838
839     name << "Axis ";
840
841     if (axis < 0)
842       name << "-";
843     else
844       name << "+";
845
846     if (abs(axis) == 1)
847       name << "X";
848     else if (abs(axis) == 2)
849       name << "Y";
850     else if (abs(axis) == 2)
851       name << "X2";
852     else if (abs(axis) == 3)
853       name << "Y2";
854     else 
855       name << abs(axis);
856
857     get_item_by_id((int)id).change_input(name.str());
858   } else {
859     get_item_by_id((int)id).change_input("None");
860   }
861 }
862
863 void
864 JoystickKeyboardController::JoystickMenu::update()
865 {
866   if(controller->joysticks.size() == 0)
867     return;
868
869   update_menu_item(Controller::UP);
870   update_menu_item(Controller::DOWN);
871   update_menu_item(Controller::LEFT);
872   update_menu_item(Controller::RIGHT);
873
874   update_menu_item(Controller::JUMP);
875   update_menu_item(Controller::ACTION);
876   update_menu_item(Controller::PAUSE_MENU);
877   update_menu_item(Controller::PEEK_LEFT);
878   update_menu_item(Controller::PEEK_RIGHT);
879 }