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