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