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