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