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