changed worldmap format a bit to be more consistent with level format
[supertux.git] / src / control / joystickkeyboardcontroller.cpp
1 //  $Id$
2 // 
3 //  SuperTux
4 //  Copyright (C) 2005 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
19 //  02111-1307, USA.
20 #include <config.h>
21
22 #include <sstream>
23 #include "joystickkeyboardcontroller.h"
24 #include "gui/menu.h"
25 #include "gettext.h"
26 #include "lisp/lisp.h"
27 #include "lisp/list_iterator.h"
28 #include "game_session.h"
29
30 class JoystickKeyboardController::JoystickMenu : public Menu
31 {
32 public:
33   JoystickMenu(JoystickKeyboardController* controller);
34   virtual ~JoystickMenu();
35
36   void update();
37   std::string get_button_name(int button);
38   virtual void menu_action(MenuItem* item);
39   JoystickKeyboardController* controller;
40 };
41
42 class JoystickKeyboardController::KeyboardMenu : public Menu
43 {
44 public:
45   KeyboardMenu(JoystickKeyboardController* controller);
46   ~KeyboardMenu();
47
48   void update();
49   std::string get_key_name(SDLKey key);
50   virtual void menu_action(MenuItem* item);
51   JoystickKeyboardController* controller;
52 };
53   
54 JoystickKeyboardController::JoystickKeyboardController()
55   : wait_for_key(-1), wait_for_joybutton(-1), key_options_menu(0),
56     joystick_options_menu(0)
57 {
58   memset(last_keys, 0, sizeof(last_keys));
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   
74   int joystick_count = SDL_NumJoysticks();
75   min_joybuttons = -1;
76   max_joybuttons = -1;
77   for(int i = 0; i < joystick_count; ++i) {
78     SDL_Joystick* joystick = SDL_JoystickOpen(i);
79     bool good = true;
80     if(SDL_JoystickNumButtons(joystick) < 2) {
81       std::cerr << "Joystick " << i << " has less than 2 buttons.\n";
82       good = false;
83     }
84     if(SDL_JoystickNumAxes(joystick) < 2
85        && SDL_JoystickNumHats(joystick) == 0) {
86       std::cerr << "Joystick " << i << " has less than 2 axes and no hat.\n";
87       good = false;
88     }
89     if(!good) {
90       SDL_JoystickClose(joystick);
91       continue;
92     }
93     
94     if(min_joybuttons < 0 || SDL_JoystickNumButtons(joystick) < min_joybuttons)
95       min_joybuttons = SDL_JoystickNumButtons(joystick);
96     if(SDL_JoystickNumButtons(joystick) > max_joybuttons) {
97       max_joybuttons = SDL_JoystickNumButtons(joystick);
98     }
99
100     joysticks.push_back(joystick);
101   }
102
103   use_hat = true;
104   joyaxis_x = 0;
105   joyaxis_y = 1;
106   dead_zone_x = 1000;
107   dead_zone_y = 1000;
108   
109   joy_button_map.insert(std::make_pair(0, JUMP));
110   joy_button_map.insert(std::make_pair(1, ACTION));
111   // map the last 2 buttons to menu and pause
112   if(min_joybuttons > 2)
113     joy_button_map.insert(std::make_pair(min_joybuttons-1, PAUSE_MENU));
114   // map all remaining joystick buttons to MENU_SELECT
115   for(int i = 2; i < max_joybuttons; ++i) {
116     if(i != min_joybuttons-1)
117       joy_button_map.insert(std::make_pair(i, MENU_SELECT));
118   }
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::read(const lisp::Lisp& lisp)
135 {
136   const lisp::Lisp* keymap_lisp = lisp.get_lisp("keymap");
137   if(keymap_lisp) {
138     keymap.clear();
139     lisp::ListIterator iter(keymap_lisp);
140     while(iter.next()) {
141       if(iter.item() == "map") {
142         int key = -1;
143         std::string control;
144         const lisp::Lisp* map = iter.lisp();
145         map->get("key", key);
146         map->get("control", control);
147         if(key < SDLK_FIRST || key >= SDLK_LAST) {
148           std::cerr << "Invalid key '" << key << "' in keymap.\n";
149           continue;
150         }
151
152         int i = 0;
153         for(i = 0; controlNames[i] != 0; ++i) {
154           if(control == controlNames[i])
155             break;
156         }
157         if(controlNames[i] == 0) {
158           std::cerr << "Invalid control '" << control << "' in keymap.\n";
159           continue;
160         }
161         keymap.insert(std::make_pair((SDLKey) key, (Control) i));
162       } else {
163         std::cerr << "Invalid lisp element '" << iter.item() << "' in keymap.\n";
164       }
165     }
166   }
167
168   const lisp::Lisp* joystick_lisp = lisp.get_lisp("joystick");
169   if(joystick_lisp) {
170     joystick_lisp->get("use_hat", use_hat);
171     joystick_lisp->get("axis_x", joyaxis_x);
172     joystick_lisp->get("axis_y", joyaxis_y);
173     joystick_lisp->get("dead_zone_x", dead_zone_x);
174     joystick_lisp->get("dead_zone_y", dead_zone_y);
175     lisp::ListIterator iter(joystick_lisp);
176     while(iter.next()) {
177       if(iter.item() == "map") {
178         int button = -1;
179         std::string control;
180         const lisp::Lisp* map = iter.lisp();
181         map->get("button", button);
182         map->get("control", control);
183         if(button < 0 || button >= max_joybuttons) {
184           std::cerr << "Invalid button '" << button << "' in buttonmap.\n";
185           continue;
186         }
187         
188         int i = 0;
189         for(i = 0; controlNames[i] != 0; ++i) {
190           if(control == controlNames[i])
191             break;
192         }                                                                           
193         if(controlNames[i] == 0) {
194           std::cerr << "Invalid control '" << control << "' in buttonmap.\n";
195           continue;
196         }
197         reset_joybutton(button, (Control) i);
198       }
199     }
200   }
201 }
202
203 void
204 JoystickKeyboardController::write(lisp::Writer& writer)
205 {
206   writer.start_list("keymap");
207   for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
208     writer.start_list("map");
209     writer.write_int("key", (int) i->first);
210     writer.write_string("control", controlNames[i->second]);
211     writer.end_list("map");
212   }
213   writer.end_list("keymap");
214   writer.start_list("joystick");
215   writer.write_bool("use_hat", use_hat);
216   writer.write_int("axis_x", joyaxis_x);
217   writer.write_int("axis_y", joyaxis_y);
218   writer.write_int("dead_zone_x", dead_zone_x);
219   writer.write_int("dead_zone_y", dead_zone_y);
220   for(ButtonMap::iterator i = joy_button_map.begin(); i != joy_button_map.end();
221       ++i) {
222     writer.start_list("map");
223     writer.write_int("button", i->first);
224     writer.write_string("control", controlNames[i->second]);
225     writer.end_list("map");
226   }
227   writer.end_list("joystick");  
228 }
229
230 void
231 JoystickKeyboardController::process_event(const SDL_Event& event)
232 {
233   switch(event.type) {
234     case SDL_KEYUP:
235     case SDL_KEYDOWN:
236       // remember ascii keys for cheat codes...
237       if(event.type == SDL_KEYDOWN && 
238           (event.key.keysym.unicode & 0xFF80) == 0) {
239         memmove(last_keys, last_keys+1, sizeof(last_keys)-1);
240         last_keys[sizeof(last_keys)-1] = event.key.keysym.unicode;
241         if(GameSession::current())
242           GameSession::current()->try_cheats();
243       }
244                         
245       // menu mode?
246       if(Menu::current()) { // menu mode
247         process_menu_key_event(event);
248         return;
249       } else {
250         // normal mode, find key in keymap
251         KeyMap::iterator i = keymap.find(event.key.keysym.sym);
252         if(i == keymap.end()) {
253 #ifdef DEBUG
254           std::cerr << "Pressed key without mapping.\n";
255 #endif
256           return;
257         }
258         Control control = i->second;
259         controls[control] = event.type == SDL_KEYDOWN ? true : false;
260       }
261       break;
262
263     case SDL_JOYAXISMOTION:
264       if(event.jaxis.axis == joyaxis_x) {
265         if(event.jaxis.value < -dead_zone_x) {
266           controls[LEFT] = true;
267           controls[RIGHT] = false;
268         } else if(event.jaxis.value > dead_zone_x) {
269           controls[LEFT] = false;
270           controls[RIGHT] = true;
271         } else {
272           controls[LEFT] = false;
273           controls[RIGHT] = false;
274         }
275       } else if(event.jaxis.axis == joyaxis_y) {
276         if(event.jaxis.value < -dead_zone_y) {
277           controls[UP] = true;
278           controls[DOWN] = false;
279         } else if(event.jaxis.value > dead_zone_y) {
280           controls[UP] = false;
281           controls[DOWN] = true;
282         } else {
283           controls[UP] = false;
284           controls[DOWN] = false;
285         }
286       }
287       break;
288
289     case SDL_JOYHATMOTION:
290       if(!use_hat)
291         break;
292       
293       if(event.jhat.value & SDL_HAT_UP) {
294         controls[UP] = true;
295         controls[DOWN] = false;
296       }
297       if(event.jhat.value & SDL_HAT_DOWN) {
298         controls[UP] = false;
299         controls[DOWN] = true;
300       }
301       if(event.jhat.value & SDL_HAT_LEFT) {
302         controls[LEFT] = true;
303         controls[RIGHT] = false;
304       }
305       if(event.jhat.value & SDL_HAT_RIGHT) {
306         controls[LEFT] = false;
307         controls[RIGHT] = true;
308       }
309       if(event.jhat.value == SDL_HAT_CENTERED) {
310         controls[UP] = false;
311         controls[DOWN] = false;
312         controls[LEFT] = false;
313         controls[RIGHT] = false;
314       }
315       break;
316
317     case SDL_JOYBUTTONDOWN:
318     case SDL_JOYBUTTONUP:
319     {
320       if(wait_for_joybutton >= 0) {
321         if(event.type == SDL_JOYBUTTONUP)
322           return;
323
324         Control c = (Control) wait_for_joybutton;
325         reset_joybutton(event.jbutton.button, c);
326         reset();
327         joystick_options_menu->update();
328         wait_for_joybutton = -1;
329         return;
330       }
331
332       ButtonMap::iterator i = joy_button_map.find(event.jbutton.button);
333       if(i == joy_button_map.end()) {
334 #ifdef DEBUG
335         std::cerr << "Unmapped joybutton " << (int) event.jbutton.button
336           << " pressed.\n";
337 #endif
338         return;
339       }
340       
341       controls[i->second] =
342         event.type == SDL_JOYBUTTONDOWN ? true : false;
343       break;
344     }
345
346     default:
347       break;
348   }
349 }
350
351 void
352 JoystickKeyboardController::process_menu_key_event(const SDL_Event& event)
353 {
354   // wait for key mode?
355   if(wait_for_key >= 0) {
356     if(event.type == SDL_KEYUP)
357       return;
358
359     if(event.key.keysym.sym != SDLK_ESCAPE                      
360         && event.key.keysym.sym != SDLK_PAUSE) {
361       reset_key(event.key.keysym.sym, (Control) wait_for_key);
362     }
363     reset();
364     key_options_menu->update();
365     wait_for_key = -1;
366     return;
367   } 
368   if(wait_for_joybutton >= 0) {
369     if(event.key.keysym.sym == SDLK_ESCAPE) {
370       reset();
371       joystick_options_menu->update();
372       wait_for_joybutton = -1;
373     }
374     return;
375   }
376  
377   Control control;
378   /* we use default keys when the menu is open (to avoid problems when
379    * redefining keys to invalid settings
380    */
381   switch(event.key.keysym.sym) {
382     case SDLK_UP:
383       control = UP;
384       break;
385     case SDLK_DOWN:
386       control = DOWN;
387       break;
388     case SDLK_LEFT:
389       control = LEFT;
390       break;
391     case SDLK_RIGHT:
392       control = RIGHT;
393       break;
394     case SDLK_SPACE:
395     case SDLK_RETURN:
396     case SDLK_KP_ENTER:
397       control = MENU_SELECT;
398       break;
399     case SDLK_ESCAPE:
400     case SDLK_PAUSE:
401       control = PAUSE_MENU;
402       break;
403     default:
404       return;
405       break;
406   }
407
408   controls[control] = event.type == SDL_KEYDOWN ? true : false;
409 }
410
411 void
412 JoystickKeyboardController::reset_joybutton(int button, Control control)
413 {
414   // remove all previous mappings for that control and for that key
415   for(ButtonMap::iterator i = joy_button_map.begin();
416       i != joy_button_map.end(); /* no ++i */) {
417     if(i->second == control) {
418       ButtonMap::iterator e = i;
419       ++i;
420       joy_button_map.erase(e);
421     } else {
422       ++i;
423     }
424   }
425   ButtonMap::iterator i = joy_button_map.find(button);
426   if(i != joy_button_map.end())
427     joy_button_map.erase(i);
428
429   // add new mapping
430   joy_button_map.insert(std::make_pair(button, control));
431
432   // map all unused buttons to MENU_SELECT
433   for(int b = 0; b < max_joybuttons; ++b) {
434     ButtonMap::iterator i = joy_button_map.find(b);
435     if(i != joy_button_map.end())
436       continue;
437
438     joy_button_map.insert(std::make_pair(b, MENU_SELECT));
439   }
440 }
441
442 void
443 JoystickKeyboardController::reset_key(SDLKey key, Control control)
444 {
445   // remove all previous mappings for that control and for that key
446   for(KeyMap::iterator i = keymap.begin();
447       i != keymap.end(); /* no ++i */) {
448     if(i->second == control) {
449       KeyMap::iterator e = i;
450       ++i;
451       keymap.erase(e);
452     } else {
453       ++i;
454     }
455   }
456   KeyMap::iterator i = keymap.find(key);
457   if(i != keymap.end())
458     keymap.erase(i);
459
460   // add new mapping
461   keymap.insert(std::make_pair(key, control));
462 }
463
464 SDLKey
465 JoystickKeyboardController::reversemap_key(Control c)
466 {
467   for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
468     if(i->second == c)
469       return i->first;
470   }
471
472   return SDLK_UNKNOWN;
473 }
474
475 int
476 JoystickKeyboardController::reversemap_joybutton(Control c)
477 {
478   for(ButtonMap::iterator i = joy_button_map.begin();
479       i != joy_button_map.end(); ++i) {
480     if(i->second == c)
481       return i->first;
482   }
483
484   return -1;
485 }
486
487 Menu*
488 JoystickKeyboardController::get_key_options_menu()
489 {
490   if(key_options_menu == 0) {
491     key_options_menu = new KeyboardMenu(this);
492   }
493
494   return key_options_menu;
495 }
496
497 Menu*
498 JoystickKeyboardController::get_joystick_options_menu()
499 {
500   if(joystick_options_menu == 0) {
501     joystick_options_menu = new JoystickMenu(this);
502   }
503
504   return joystick_options_menu;
505 }
506
507 bool
508 JoystickKeyboardController::check_cheatcode(const std::string& cheatcode)
509 {
510   if(cheatcode.size() > sizeof(last_keys)) {
511 #ifdef DEBUG
512     std::cerr << "Cheat Code too long.\n";
513 #endif
514     return false;
515   }
516
517   for(size_t i = 0; i < cheatcode.size(); ++i) {
518     if(last_keys[sizeof(last_keys)-1 - i] != cheatcode[cheatcode.size()-1-i])
519       return false;
520   }
521   return true;
522 }
523
524 //----------------------------------------------------------------------------
525
526 JoystickKeyboardController::KeyboardMenu::KeyboardMenu(
527     JoystickKeyboardController* _controller)
528   : controller(_controller)
529 {
530     add_label(_("Keyboard Setup"));
531     add_hl();
532     add_controlfield(Controller::UP, _("Up"));
533     add_controlfield(Controller::DOWN, _("Down"));
534     add_controlfield(Controller::LEFT, _("Left"));
535     add_controlfield(Controller::RIGHT, _("Right"));
536     add_controlfield(Controller::JUMP, _("Jump"));
537     add_controlfield(Controller::ACTION, _("Shoot/Run"));
538     add_hl();
539     add_back(_("Back"));
540     update();
541 }
542
543 JoystickKeyboardController::KeyboardMenu::~KeyboardMenu()
544 {}
545
546 std::string
547 JoystickKeyboardController::KeyboardMenu::get_key_name(SDLKey key)
548 {
549   switch(key) {
550     case SDLK_UNKNOWN:
551       return _("None");
552     case SDLK_UP:
553       return _("Up cursor");
554     case SDLK_DOWN:
555       return _("Down cursor");
556     case SDLK_LEFT:
557       return _("Left cursor");
558     case SDLK_RIGHT:
559       return _("Right cursor");
560     case SDLK_RETURN:
561       return _("Return");
562     case SDLK_SPACE:
563       return _("Space");
564     case SDLK_RSHIFT:
565       return _("Right Shift");
566     case SDLK_LSHIFT:
567       return _("Left Shift");
568     case SDLK_RCTRL:
569       return _("Right Control");
570     case SDLK_LCTRL:
571       return _("Left Control");
572     case SDLK_RALT:
573       return _("Right Alt");
574     case SDLK_LALT:
575       return _("Left Alt");
576     default:
577       return SDL_GetKeyName((SDLKey) key);
578   }
579 }
580
581 void
582 JoystickKeyboardController::KeyboardMenu::menu_action(MenuItem* item)
583 {
584   assert(item->id >= 0 && item->id < Controller::CONTROLCOUNT);
585   item->change_input(_("Press Key"));
586   controller->wait_for_key = item->id;
587 }
588
589 void
590 JoystickKeyboardController::KeyboardMenu::update()
591 {
592   // update menu
593   get_item_by_id((int) Controller::UP).change_input(get_key_name(
594     controller->reversemap_key(Controller::UP)));
595   get_item_by_id((int) Controller::DOWN).change_input(get_key_name(
596     controller->reversemap_key(Controller::DOWN)));
597   get_item_by_id((int) Controller::LEFT).change_input(get_key_name(
598     controller->reversemap_key(Controller::LEFT)));
599   get_item_by_id((int) Controller::RIGHT).change_input(get_key_name(
600     controller->reversemap_key(Controller::RIGHT)));
601   get_item_by_id((int) Controller::JUMP).change_input(get_key_name(
602     controller->reversemap_key(Controller::JUMP)));
603   get_item_by_id((int) Controller::ACTION).change_input(get_key_name(
604     controller->reversemap_key(Controller::ACTION)));
605 }
606
607 //---------------------------------------------------------------------------
608
609 JoystickKeyboardController::JoystickMenu::JoystickMenu(
610   JoystickKeyboardController* _controller)
611   : controller(_controller)
612 {
613   add_label(_("Joystick Setup"));
614   add_hl();
615   if(controller->joysticks.size() > 0) {
616     add_controlfield(Controller::JUMP, _("Jump"));
617     add_controlfield(Controller::ACTION, _("Shoot/Run"));
618     add_controlfield(Controller::PAUSE_MENU, _("Pause/Menu"));
619   } else {
620     add_deactive(-1, _("No Joysticks found"));
621   }
622   add_hl();
623   add_back(_("Back"));
624   update();
625 }
626
627 JoystickKeyboardController::JoystickMenu::~JoystickMenu()
628 {}
629
630 std::string
631 JoystickKeyboardController::JoystickMenu::get_button_name(int button)
632 {
633   if(button < 0)
634     return _("None");
635     
636   std::ostringstream name;
637   name << "Button " << button;
638   return name.str();
639 }
640
641 void
642 JoystickKeyboardController::JoystickMenu::menu_action(MenuItem* item)
643 {
644   assert(item->id >= 0 && item->id < Controller::CONTROLCOUNT);
645   item->change_input(_("Press Button"));
646   controller->wait_for_joybutton = item->id;
647 }
648
649 void
650 JoystickKeyboardController::JoystickMenu::update()
651 {
652   if(controller->joysticks.size() == 0)
653     return;
654
655   // update menu
656   get_item_by_id((int) Controller::JUMP).change_input(get_button_name(
657     controller->reversemap_joybutton(Controller::JUMP)));
658   get_item_by_id((int) Controller::ACTION).change_input(get_button_name(
659     controller->reversemap_joybutton(Controller::ACTION)));
660   get_item_by_id((int) Controller::PAUSE_MENU).change_input(get_button_name(
661     controller->reversemap_joybutton(Controller::PAUSE_MENU)));
662 }
663