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