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