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