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