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