Adjusted sources wrt localization
[supertux.git] / src / control / joystickkeyboardcontroller.cpp
1 //  $Id$
2 //
3 //  SuperTux
4 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
5 //
6 //  This program is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU General Public License
8 //  as published by the Free Software Foundation; either version 2
9 //  of the License, or (at your option) any later version.
10 //
11 //  This program is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 //
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19
20 #include <config.h>
21
22 #include <sstream>
23 #include "joystickkeyboardcontroller.hpp"
24 #include "log.hpp"
25 #include "gui/menu.hpp"
26 #include "gettext.hpp"
27 #include "lisp/lisp.hpp"
28 #include "lisp/list_iterator.hpp"
29 #include "game_session.hpp"
30 #include "console.hpp"
31
32 class JoystickKeyboardController::JoystickMenu : public Menu
33 {
34 public:
35   JoystickMenu(JoystickKeyboardController* controller);
36   virtual ~JoystickMenu();
37
38   void update();
39   std::string get_button_name(int button);
40   virtual void menu_action(MenuItem* item);
41   JoystickKeyboardController* controller;
42 };
43
44 class JoystickKeyboardController::KeyboardMenu : public Menu
45 {
46 public:
47   KeyboardMenu(JoystickKeyboardController* controller);
48   ~KeyboardMenu();
49
50   void update();
51   std::string get_key_name(SDLKey key);
52   virtual void menu_action(MenuItem* item);
53   JoystickKeyboardController* controller;
54 };
55   
56 JoystickKeyboardController::JoystickKeyboardController()
57   : wait_for_key(-1), wait_for_joybutton(-1), key_options_menu(0),
58     joystick_options_menu(0)
59 {
60   // initialize default keyboard map
61   keymap.insert(std::make_pair(SDLK_LEFT, LEFT));
62   keymap.insert(std::make_pair(SDLK_RIGHT, RIGHT));
63   keymap.insert(std::make_pair(SDLK_UP, UP));
64   keymap.insert(std::make_pair(SDLK_DOWN, DOWN));
65   keymap.insert(std::make_pair(SDLK_SPACE, JUMP));
66   keymap.insert(std::make_pair(SDLK_LCTRL, ACTION));
67   keymap.insert(std::make_pair(SDLK_LALT, ACTION));
68   keymap.insert(std::make_pair(SDLK_ESCAPE, PAUSE_MENU));
69   keymap.insert(std::make_pair(SDLK_p, PAUSE_MENU));
70   keymap.insert(std::make_pair(SDLK_PAUSE, PAUSE_MENU));  
71   keymap.insert(std::make_pair(SDLK_RETURN, MENU_SELECT));
72   keymap.insert(std::make_pair(SDLK_KP_ENTER, MENU_SELECT));
73   keymap.insert(std::make_pair(SDLK_CARET, CONSOLE));
74   
75   int joystick_count = SDL_NumJoysticks();
76   min_joybuttons = -1;
77   max_joybuttons = -1;
78   for(int i = 0; i < joystick_count; ++i) {
79     SDL_Joystick* joystick = SDL_JoystickOpen(i);
80     bool good = true;
81     if(SDL_JoystickNumButtons(joystick) < 2) {
82       log_warning << "Joystick " << i << " has less than 2 buttons" << std::endl;
83       good = false;
84     }
85     if(SDL_JoystickNumAxes(joystick) < 2
86        && SDL_JoystickNumHats(joystick) == 0) {
87       log_warning << "Joystick " << i << " has less than 2 axes and no hat" << std::endl;
88       good = false;
89     }
90     if(!good) {
91       SDL_JoystickClose(joystick);
92       continue;
93     }
94     
95     if(min_joybuttons < 0 || SDL_JoystickNumButtons(joystick) < min_joybuttons)
96       min_joybuttons = SDL_JoystickNumButtons(joystick);
97     if(SDL_JoystickNumButtons(joystick) > max_joybuttons) {
98       max_joybuttons = SDL_JoystickNumButtons(joystick);
99     }
100
101     joysticks.push_back(joystick);
102   }
103
104   use_hat = true;
105   joyaxis_x = 0;
106   joyaxis_y = 1;
107   dead_zone_x = 1000;
108   dead_zone_y = 1000;
109   
110   joy_button_map.insert(std::make_pair(0, JUMP));
111   joy_button_map.insert(std::make_pair(1, ACTION));
112   // map the last 2 buttons to menu and pause
113   if(min_joybuttons > 2)
114     joy_button_map.insert(std::make_pair(min_joybuttons-1, PAUSE_MENU));
115   // map all remaining joystick buttons to MENU_SELECT
116   for(int i = 2; i < max_joybuttons; ++i) {
117     if(i != min_joybuttons-1)
118       joy_button_map.insert(std::make_pair(i, MENU_SELECT));
119   }
120
121   // some joysticks or SDL seem to produce some bogus events after being opened
122   Uint32 ticks = SDL_GetTicks();
123   while(SDL_GetTicks() - ticks < 200) {
124     SDL_Event event;
125     SDL_PollEvent(&event);
126   }
127 }
128
129 JoystickKeyboardController::~JoystickKeyboardController()
130 {
131   for(std::vector<SDL_Joystick*>::iterator i = joysticks.begin();
132       i != joysticks.end(); ++i) {
133     if(*i != 0)
134       SDL_JoystickClose(*i);
135   }
136
137   delete key_options_menu;
138   delete joystick_options_menu;
139 }
140
141 void
142 JoystickKeyboardController::read(const lisp::Lisp& lisp)
143 {
144   const lisp::Lisp* keymap_lisp = lisp.get_lisp("keymap");
145   if(keymap_lisp) {
146     keymap.clear();
147     lisp::ListIterator iter(keymap_lisp);
148     while(iter.next()) {
149       if(iter.item() == "map") {
150         int key = -1;
151         std::string control;
152         const lisp::Lisp* map = iter.lisp();
153         map->get("key", key);
154         map->get("control", control);
155         if(key < SDLK_FIRST || key >= SDLK_LAST) {
156           log_warning << "Invalid key '" << key << "' in keymap" << std::endl;
157           continue;
158         }
159
160         int i = 0;
161         for(i = 0; controlNames[i] != 0; ++i) {
162           if(control == controlNames[i])
163             break;
164         }
165         if(controlNames[i] == 0) {
166           log_warning << "Invalid control '" << control << "' in keymap" << std::endl;
167           continue;
168         }
169         keymap.insert(std::make_pair((SDLKey) key, (Control) i));
170       } else {
171         log_warning << "Invalid lisp element '" << iter.item() << "' in keymap" << std::endl;
172       }
173     }
174   }
175
176   const lisp::Lisp* joystick_lisp = lisp.get_lisp("joystick");
177   if(joystick_lisp) {
178     joystick_lisp->get("use_hat", use_hat);
179     joystick_lisp->get("axis_x", joyaxis_x);
180     joystick_lisp->get("axis_y", joyaxis_y);
181     joystick_lisp->get("dead_zone_x", dead_zone_x);
182     joystick_lisp->get("dead_zone_y", dead_zone_y);
183     lisp::ListIterator iter(joystick_lisp);
184     while(iter.next()) {
185       if(iter.item() == "map") {
186         int button = -1;
187         std::string control;
188         const lisp::Lisp* map = iter.lisp();
189         map->get("button", button);
190         map->get("control", control);
191         if(button < 0 || button >= max_joybuttons) {
192           log_warning << "Invalid button '" << button << "' in buttonmap" << std::endl;
193           continue;
194         }
195         
196         int i = 0;
197         for(i = 0; controlNames[i] != 0; ++i) {
198           if(control == controlNames[i])
199             break;
200         }                                                                           
201         if(controlNames[i] == 0) {
202           log_warning << "Invalid control '" << control << "' in buttonmap" << std::endl;
203           continue;
204         }
205         reset_joybutton(button, (Control) i);
206       }
207     }
208   }
209 }
210
211 void
212 JoystickKeyboardController::write(lisp::Writer& writer)
213 {
214   writer.start_list("keymap");
215   for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
216     writer.start_list("map");
217     writer.write_int("key", (int) i->first);
218     writer.write_string("control", controlNames[i->second]);
219     writer.end_list("map");
220   }
221   writer.end_list("keymap");
222   writer.start_list("joystick");
223   writer.write_bool("use_hat", use_hat);
224   writer.write_int("axis_x", joyaxis_x);
225   writer.write_int("axis_y", joyaxis_y);
226   writer.write_int("dead_zone_x", dead_zone_x);
227   writer.write_int("dead_zone_y", dead_zone_y);
228   for(ButtonMap::iterator i = joy_button_map.begin(); i != joy_button_map.end();
229       ++i) {
230     writer.start_list("map");
231     writer.write_int("button", i->first);
232     writer.write_string("control", controlNames[i->second]);
233     writer.end_list("map");
234   }
235   writer.end_list("joystick");  
236 }
237
238 void
239 JoystickKeyboardController::reset()
240 {
241   Controller::reset();
242 }
243
244 void
245 JoystickKeyboardController::process_event(const SDL_Event& event)
246 {
247   switch(event.type) {
248     case SDL_KEYUP:
249     case SDL_KEYDOWN:
250       process_key_event(event);
251       break;
252
253     case SDL_JOYAXISMOTION:
254       if(event.jaxis.axis == joyaxis_x) {
255         if(event.jaxis.value < -dead_zone_x) {
256           controls[LEFT] = true;
257           controls[RIGHT] = false;
258         } else if(event.jaxis.value > dead_zone_x) {
259           controls[LEFT] = false;
260           controls[RIGHT] = true;
261         } else {
262           controls[LEFT] = false;
263           controls[RIGHT] = false;
264         }
265       } else if(event.jaxis.axis == joyaxis_y) {
266         if(event.jaxis.value < -dead_zone_y) {
267           controls[UP] = true;
268           controls[DOWN] = false;
269         } else if(event.jaxis.value > dead_zone_y) {
270           controls[UP] = false;
271           controls[DOWN] = true;
272         } else {
273           controls[UP] = false;
274           controls[DOWN] = false;
275         }
276       }
277       break;
278
279     case SDL_JOYHATMOTION:
280       if(!use_hat)
281         break;
282       
283       if(event.jhat.value & SDL_HAT_UP) {
284         controls[UP] = true;
285         controls[DOWN] = false;
286       }
287       if(event.jhat.value & SDL_HAT_DOWN) {
288         controls[UP] = false;
289         controls[DOWN] = true;
290       }
291       if(event.jhat.value & SDL_HAT_LEFT) {
292         controls[LEFT] = true;
293         controls[RIGHT] = false;
294       }
295       if(event.jhat.value & SDL_HAT_RIGHT) {
296         controls[LEFT] = false;
297         controls[RIGHT] = true;
298       }
299       if(event.jhat.value == SDL_HAT_CENTERED) {
300         controls[UP] = false;
301         controls[DOWN] = false;
302         controls[LEFT] = false;
303         controls[RIGHT] = false;
304       }
305       break;
306
307     case SDL_JOYBUTTONDOWN:
308     case SDL_JOYBUTTONUP:
309     {
310       if(wait_for_joybutton >= 0) {
311         if(event.type == SDL_JOYBUTTONUP)
312           return;
313
314         Control c = (Control) wait_for_joybutton;
315         reset_joybutton(event.jbutton.button, c);
316         reset();
317         joystick_options_menu->update();
318         wait_for_joybutton = -1;
319         return;
320       }
321
322       ButtonMap::iterator i = joy_button_map.find(event.jbutton.button);
323       if(i == joy_button_map.end()) {
324         log_debug << "Unmapped joybutton " << (int)event.jbutton.button << " pressed" << std::endl;
325         return;
326       }
327       
328       controls[i->second] =
329         event.type == SDL_JOYBUTTONDOWN ? true : false;
330       break;
331     }
332
333     default:
334       break;
335   }
336 }
337
338 void
339 JoystickKeyboardController::process_key_event(const SDL_Event& event)
340 {
341   KeyMap::iterator key_mapping = keymap.find(event.key.keysym.sym);
342
343   // if console key was pressed: toggle console
344   if ((key_mapping != keymap.end()) && (key_mapping->second == CONSOLE)) {
345     if (event.type != SDL_KEYDOWN) return;
346     Console::instance->toggle();
347     return;
348   }
349
350   // if console is open: send key there
351   if (Console::instance->hasFocus()) {
352     process_console_key_event(event);
353     return;
354   } 
355
356   // if menu mode: send key there
357   if (Menu::current()) { 
358     process_menu_key_event(event);
359     return;
360   }
361
362   // default action: update controls
363   if(key_mapping == keymap.end()) {
364     log_debug << "Key " << event.key.keysym.sym << " is unbound" << std::endl;
365     return;
366   }
367   Control control = key_mapping->second;
368   controls[control] = event.type == SDL_KEYDOWN ? true : false;
369 }
370
371 void
372 JoystickKeyboardController::process_console_key_event(const SDL_Event& event)
373 {
374   if (event.type != SDL_KEYDOWN) return;
375
376   switch (event.key.keysym.sym) {
377     case SDLK_RETURN:
378       Console::instance->input << std::endl;
379       break;
380     case SDLK_BACKSPACE:
381       Console::instance->backspace();
382       break;
383     case SDLK_TAB:
384       Console::instance->autocomplete();
385       break;
386     case SDLK_PAGEUP:
387       Console::instance->scroll(-1);
388       break;
389     case SDLK_PAGEDOWN:
390       Console::instance->scroll(+1);
391       break;
392     case SDLK_END:
393       Console::instance->scroll(+65535);
394       break;
395     case SDLK_UP:
396       Console::instance->show_history(-1);
397       break;
398     case SDLK_DOWN:
399       Console::instance->show_history(+1);
400       break;
401     default:
402       int c = event.key.keysym.unicode;
403       if ((c >= 32) && (c <= 126)) {
404         Console::instance->input << (char)c;
405       }
406       break;
407   }
408 }
409
410 void
411 JoystickKeyboardController::process_menu_key_event(const SDL_Event& event)
412 {
413   // wait for key mode?
414   if(wait_for_key >= 0) {
415     if(event.type == SDL_KEYUP)
416       return;
417
418     if(event.key.keysym.sym != SDLK_ESCAPE                      
419         && event.key.keysym.sym != SDLK_PAUSE) {
420       reset_key(event.key.keysym.sym, (Control) wait_for_key);
421     }
422     reset();
423     key_options_menu->update();
424     wait_for_key = -1;
425     return;
426   } 
427   if(wait_for_joybutton >= 0) {
428     if(event.key.keysym.sym == SDLK_ESCAPE) {
429       reset();
430       joystick_options_menu->update();
431       wait_for_joybutton = -1;
432     }
433     return;
434   }
435  
436   Control control;
437   /* we use default keys when the menu is open (to avoid problems when
438    * redefining keys to invalid settings
439    */
440   switch(event.key.keysym.sym) {
441     case SDLK_UP:
442       control = UP;
443       break;
444     case SDLK_DOWN:
445       control = DOWN;
446       break;
447     case SDLK_LEFT:
448       control = LEFT;
449       break;
450     case SDLK_RIGHT:
451       control = RIGHT;
452       break;
453     case SDLK_SPACE:
454     case SDLK_RETURN:
455     case SDLK_KP_ENTER:
456       control = MENU_SELECT;
457       break;
458     case SDLK_ESCAPE:
459     case SDLK_PAUSE:
460       control = PAUSE_MENU;
461       break;
462     default:
463       return;
464       break;
465   }
466
467   controls[control] = event.type == SDL_KEYDOWN ? true : false;
468 }
469
470 void
471 JoystickKeyboardController::reset_joybutton(int button, Control control)
472 {
473   // remove all previous mappings for that control and for that key
474   for(ButtonMap::iterator i = joy_button_map.begin();
475       i != joy_button_map.end(); /* no ++i */) {
476     if(i->second == control) {
477       ButtonMap::iterator e = i;
478       ++i;
479       joy_button_map.erase(e);
480     } else {
481       ++i;
482     }
483   }
484   ButtonMap::iterator i = joy_button_map.find(button);
485   if(i != joy_button_map.end())
486     joy_button_map.erase(i);
487
488   // add new mapping
489   joy_button_map.insert(std::make_pair(button, control));
490
491   // map all unused buttons to MENU_SELECT
492   for(int b = 0; b < max_joybuttons; ++b) {
493     ButtonMap::iterator i = joy_button_map.find(b);
494     if(i != joy_button_map.end())
495       continue;
496
497     joy_button_map.insert(std::make_pair(b, MENU_SELECT));
498   }
499 }
500
501 void
502 JoystickKeyboardController::reset_key(SDLKey key, Control control)
503 {
504   // remove all previous mappings for that control and for that key
505   for(KeyMap::iterator i = keymap.begin();
506       i != keymap.end(); /* no ++i */) {
507     if(i->second == control) {
508       KeyMap::iterator e = i;
509       ++i;
510       keymap.erase(e);
511     } else {
512       ++i;
513     }
514   }
515   KeyMap::iterator i = keymap.find(key);
516   if(i != keymap.end())
517     keymap.erase(i);
518
519   // add new mapping
520   keymap.insert(std::make_pair(key, control));
521 }
522
523 SDLKey
524 JoystickKeyboardController::reversemap_key(Control c)
525 {
526   for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
527     if(i->second == c)
528       return i->first;
529   }
530
531   return SDLK_UNKNOWN;
532 }
533
534 int
535 JoystickKeyboardController::reversemap_joybutton(Control c)
536 {
537   for(ButtonMap::iterator i = joy_button_map.begin();
538       i != joy_button_map.end(); ++i) {
539     if(i->second == c)
540       return i->first;
541   }
542
543   return -1;
544 }
545
546 Menu*
547 JoystickKeyboardController::get_key_options_menu()
548 {
549   if(key_options_menu == 0) {
550     key_options_menu = new KeyboardMenu(this);
551   }
552
553   return key_options_menu;
554 }
555
556 Menu*
557 JoystickKeyboardController::get_joystick_options_menu()
558 {
559   if(joystick_options_menu == 0) {
560     joystick_options_menu = new JoystickMenu(this);
561   }
562
563   return joystick_options_menu;
564 }
565
566 //----------------------------------------------------------------------------
567
568 JoystickKeyboardController::KeyboardMenu::KeyboardMenu(
569     JoystickKeyboardController* _controller)
570   : controller(_controller)
571 {
572     add_label(_("Setup Keyboard"));
573     add_hl();
574     add_controlfield(Controller::UP, _("Up"));
575     add_controlfield(Controller::DOWN, _("Down"));
576     add_controlfield(Controller::LEFT, _("Left"));
577     add_controlfield(Controller::RIGHT, _("Right"));
578     add_controlfield(Controller::JUMP, _("Jump"));
579     add_controlfield(Controller::ACTION, _("Action"));
580     add_hl();
581     add_back(_("Back"));
582     update();
583 }
584
585 JoystickKeyboardController::KeyboardMenu::~KeyboardMenu()
586 {}
587
588 std::string
589 JoystickKeyboardController::KeyboardMenu::get_key_name(SDLKey key)
590 {
591   switch(key) {
592     case SDLK_UNKNOWN:
593       return _("None");
594     case SDLK_UP:
595       return _("Up cursor");
596     case SDLK_DOWN:
597       return _("Down cursor");
598     case SDLK_LEFT:
599       return _("Left cursor");
600     case SDLK_RIGHT:
601       return _("Right cursor");
602     case SDLK_RETURN:
603       return _("Return");
604     case SDLK_SPACE:
605       return _("Space");
606     case SDLK_RSHIFT:
607       return _("Right Shift");
608     case SDLK_LSHIFT:
609       return _("Left Shift");
610     case SDLK_RCTRL:
611       return _("Right Control");
612     case SDLK_LCTRL:
613       return _("Left Control");
614     case SDLK_RALT:
615       return _("Right Alt");
616     case SDLK_LALT:
617       return _("Left Alt");
618     default:
619       return SDL_GetKeyName((SDLKey) key);
620   }
621 }
622
623 void
624 JoystickKeyboardController::KeyboardMenu::menu_action(MenuItem* item)
625 {
626   assert(item->id >= 0 && item->id < Controller::CONTROLCOUNT);
627   item->change_input(_("Press Key"));
628   controller->wait_for_key = item->id;
629 }
630
631 void
632 JoystickKeyboardController::KeyboardMenu::update()
633 {
634   // update menu
635   get_item_by_id((int) Controller::UP).change_input(get_key_name(
636     controller->reversemap_key(Controller::UP)));
637   get_item_by_id((int) Controller::DOWN).change_input(get_key_name(
638     controller->reversemap_key(Controller::DOWN)));
639   get_item_by_id((int) Controller::LEFT).change_input(get_key_name(
640     controller->reversemap_key(Controller::LEFT)));
641   get_item_by_id((int) Controller::RIGHT).change_input(get_key_name(
642     controller->reversemap_key(Controller::RIGHT)));
643   get_item_by_id((int) Controller::JUMP).change_input(get_key_name(
644     controller->reversemap_key(Controller::JUMP)));
645   get_item_by_id((int) Controller::ACTION).change_input(get_key_name(
646     controller->reversemap_key(Controller::ACTION)));
647 }
648
649 //---------------------------------------------------------------------------
650
651 JoystickKeyboardController::JoystickMenu::JoystickMenu(
652   JoystickKeyboardController* _controller)
653   : controller(_controller)
654 {
655   add_label(_("Setup Joystick"));
656   add_hl();
657   if(controller->joysticks.size() > 0) {
658     add_controlfield(Controller::JUMP, _("Jump"));
659     add_controlfield(Controller::ACTION, _("Action"));
660     add_controlfield(Controller::PAUSE_MENU, _("Pause/Menu"));
661   } else {
662     add_deactive(-1, _("No Joysticks found"));
663   }
664   add_hl();
665   add_back(_("Back"));
666   update();
667 }
668
669 JoystickKeyboardController::JoystickMenu::~JoystickMenu()
670 {}
671
672 std::string
673 JoystickKeyboardController::JoystickMenu::get_button_name(int button)
674 {
675   if(button < 0)
676     return _("None");
677     
678   std::ostringstream name;
679   name << "Button " << button;
680   return name.str();
681 }
682
683 void
684 JoystickKeyboardController::JoystickMenu::menu_action(MenuItem* item)
685 {
686   assert(item->id >= 0 && item->id < Controller::CONTROLCOUNT);
687   item->change_input(_("Press Button"));
688   controller->wait_for_joybutton = item->id;
689 }
690
691 void
692 JoystickKeyboardController::JoystickMenu::update()
693 {
694   if(controller->joysticks.size() == 0)
695     return;
696
697   // update menu
698   get_item_by_id((int) Controller::JUMP).change_input(get_button_name(
699     controller->reversemap_joybutton(Controller::JUMP)));
700   get_item_by_id((int) Controller::ACTION).change_input(get_button_name(
701     controller->reversemap_joybutton(Controller::ACTION)));
702   get_item_by_id((int) Controller::PAUSE_MENU).change_input(get_button_name(
703     controller->reversemap_joybutton(Controller::PAUSE_MENU)));
704 }
705