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