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