Cheating handled by Console
[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.hpp"
24 #include "msg.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   
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       msg_warning("Joystick " << i << " has less than 2 buttons");
82       good = false;
83     }
84     if(SDL_JoystickNumAxes(joystick) < 2
85        && SDL_JoystickNumHats(joystick) == 0) {
86       msg_warning("Joystick " << i << " has less than 2 axes and no hat");
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           msg_warning("Invalid key '" << key << "' in keymap");
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           msg_warning("Invalid control '" << control << "' in keymap");
166           continue;
167         }
168         keymap.insert(std::make_pair((SDLKey) key, (Control) i));
169       } else {
170         msg_warning("Invalid lisp element '" << iter.item() << "' in keymap");
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           msg_warning("Invalid button '" << button << "' in buttonmap");
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           msg_warning("Invalid control '" << control << "' in buttonmap");
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 }
242
243 void
244 JoystickKeyboardController::process_event(const SDL_Event& event)
245 {
246   switch(event.type) {
247     case SDL_KEYUP:
248     case SDL_KEYDOWN:
249       if(event.type == SDL_KEYDOWN && (event.key.keysym.unicode & 0xFF80) == 0) {
250         if (Console::hasFocus()) {
251           // if the Console is open, send keys there
252           char c = event.key.keysym.unicode;
253           if ((c >= 32) && (c <= 126)) {
254             Console::input << c;
255           }
256           if ((c == '\n') || (c == '\r')) {
257             Console::input << std::endl;
258           }
259           if (c == '\t') {
260             Console::hide();
261           }
262         } else {
263           char c = event.key.keysym.unicode;
264           if (c == '\t') {
265             Console::show();
266           }
267         }
268       }
269
270       if(Console::hasFocus()) {
271         // console is open - ignore key
272       } 
273       else if(Menu::current()) { 
274         // menu mode
275         process_menu_key_event(event);
276         return;
277       } else {
278         // normal mode, find key in keymap
279         KeyMap::iterator i = keymap.find(event.key.keysym.sym);
280         if(i == keymap.end()) {
281           msg_debug("Pressed key without mapping");
282           return;
283         }
284         Control control = i->second;
285         controls[control] = event.type == SDL_KEYDOWN ? true : false;
286       }
287       break;
288
289     case SDL_JOYAXISMOTION:
290       if(event.jaxis.axis == joyaxis_x) {
291         if(event.jaxis.value < -dead_zone_x) {
292           controls[LEFT] = true;
293           controls[RIGHT] = false;
294         } else if(event.jaxis.value > dead_zone_x) {
295           controls[LEFT] = false;
296           controls[RIGHT] = true;
297         } else {
298           controls[LEFT] = false;
299           controls[RIGHT] = false;
300         }
301       } else if(event.jaxis.axis == joyaxis_y) {
302         if(event.jaxis.value < -dead_zone_y) {
303           controls[UP] = true;
304           controls[DOWN] = false;
305         } else if(event.jaxis.value > dead_zone_y) {
306           controls[UP] = false;
307           controls[DOWN] = true;
308         } else {
309           controls[UP] = false;
310           controls[DOWN] = false;
311         }
312       }
313       break;
314
315     case SDL_JOYHATMOTION:
316       if(!use_hat)
317         break;
318       
319       if(event.jhat.value & SDL_HAT_UP) {
320         controls[UP] = true;
321         controls[DOWN] = false;
322       }
323       if(event.jhat.value & SDL_HAT_DOWN) {
324         controls[UP] = false;
325         controls[DOWN] = true;
326       }
327       if(event.jhat.value & SDL_HAT_LEFT) {
328         controls[LEFT] = true;
329         controls[RIGHT] = false;
330       }
331       if(event.jhat.value & SDL_HAT_RIGHT) {
332         controls[LEFT] = false;
333         controls[RIGHT] = true;
334       }
335       if(event.jhat.value == SDL_HAT_CENTERED) {
336         controls[UP] = false;
337         controls[DOWN] = false;
338         controls[LEFT] = false;
339         controls[RIGHT] = false;
340       }
341       break;
342
343     case SDL_JOYBUTTONDOWN:
344     case SDL_JOYBUTTONUP:
345     {
346       if(wait_for_joybutton >= 0) {
347         if(event.type == SDL_JOYBUTTONUP)
348           return;
349
350         Control c = (Control) wait_for_joybutton;
351         reset_joybutton(event.jbutton.button, c);
352         reset();
353         joystick_options_menu->update();
354         wait_for_joybutton = -1;
355         return;
356       }
357
358       ButtonMap::iterator i = joy_button_map.find(event.jbutton.button);
359       if(i == joy_button_map.end()) {
360         msg_debug("Unmapped joybutton " << (int) event.jbutton.button
361           << " pressed");
362         return;
363       }
364       
365       controls[i->second] =
366         event.type == SDL_JOYBUTTONDOWN ? true : false;
367       break;
368     }
369
370     default:
371       break;
372   }
373 }
374
375 void
376 JoystickKeyboardController::process_menu_key_event(const SDL_Event& event)
377 {
378   // wait for key mode?
379   if(wait_for_key >= 0) {
380     if(event.type == SDL_KEYUP)
381       return;
382
383     if(event.key.keysym.sym != SDLK_ESCAPE                      
384         && event.key.keysym.sym != SDLK_PAUSE) {
385       reset_key(event.key.keysym.sym, (Control) wait_for_key);
386     }
387     reset();
388     key_options_menu->update();
389     wait_for_key = -1;
390     return;
391   } 
392   if(wait_for_joybutton >= 0) {
393     if(event.key.keysym.sym == SDLK_ESCAPE) {
394       reset();
395       joystick_options_menu->update();
396       wait_for_joybutton = -1;
397     }
398     return;
399   }
400  
401   Control control;
402   /* we use default keys when the menu is open (to avoid problems when
403    * redefining keys to invalid settings
404    */
405   switch(event.key.keysym.sym) {
406     case SDLK_UP:
407       control = UP;
408       break;
409     case SDLK_DOWN:
410       control = DOWN;
411       break;
412     case SDLK_LEFT:
413       control = LEFT;
414       break;
415     case SDLK_RIGHT:
416       control = RIGHT;
417       break;
418     case SDLK_SPACE:
419     case SDLK_RETURN:
420     case SDLK_KP_ENTER:
421       control = MENU_SELECT;
422       break;
423     case SDLK_ESCAPE:
424     case SDLK_PAUSE:
425       control = PAUSE_MENU;
426       break;
427     default:
428       return;
429       break;
430   }
431
432   controls[control] = event.type == SDL_KEYDOWN ? true : false;
433 }
434
435 void
436 JoystickKeyboardController::reset_joybutton(int button, Control control)
437 {
438   // remove all previous mappings for that control and for that key
439   for(ButtonMap::iterator i = joy_button_map.begin();
440       i != joy_button_map.end(); /* no ++i */) {
441     if(i->second == control) {
442       ButtonMap::iterator e = i;
443       ++i;
444       joy_button_map.erase(e);
445     } else {
446       ++i;
447     }
448   }
449   ButtonMap::iterator i = joy_button_map.find(button);
450   if(i != joy_button_map.end())
451     joy_button_map.erase(i);
452
453   // add new mapping
454   joy_button_map.insert(std::make_pair(button, control));
455
456   // map all unused buttons to MENU_SELECT
457   for(int b = 0; b < max_joybuttons; ++b) {
458     ButtonMap::iterator i = joy_button_map.find(b);
459     if(i != joy_button_map.end())
460       continue;
461
462     joy_button_map.insert(std::make_pair(b, MENU_SELECT));
463   }
464 }
465
466 void
467 JoystickKeyboardController::reset_key(SDLKey key, Control control)
468 {
469   // remove all previous mappings for that control and for that key
470   for(KeyMap::iterator i = keymap.begin();
471       i != keymap.end(); /* no ++i */) {
472     if(i->second == control) {
473       KeyMap::iterator e = i;
474       ++i;
475       keymap.erase(e);
476     } else {
477       ++i;
478     }
479   }
480   KeyMap::iterator i = keymap.find(key);
481   if(i != keymap.end())
482     keymap.erase(i);
483
484   // add new mapping
485   keymap.insert(std::make_pair(key, control));
486 }
487
488 SDLKey
489 JoystickKeyboardController::reversemap_key(Control c)
490 {
491   for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
492     if(i->second == c)
493       return i->first;
494   }
495
496   return SDLK_UNKNOWN;
497 }
498
499 int
500 JoystickKeyboardController::reversemap_joybutton(Control c)
501 {
502   for(ButtonMap::iterator i = joy_button_map.begin();
503       i != joy_button_map.end(); ++i) {
504     if(i->second == c)
505       return i->first;
506   }
507
508   return -1;
509 }
510
511 Menu*
512 JoystickKeyboardController::get_key_options_menu()
513 {
514   if(key_options_menu == 0) {
515     key_options_menu = new KeyboardMenu(this);
516   }
517
518   return key_options_menu;
519 }
520
521 Menu*
522 JoystickKeyboardController::get_joystick_options_menu()
523 {
524   if(joystick_options_menu == 0) {
525     joystick_options_menu = new JoystickMenu(this);
526   }
527
528   return joystick_options_menu;
529 }
530
531 //----------------------------------------------------------------------------
532
533 JoystickKeyboardController::KeyboardMenu::KeyboardMenu(
534     JoystickKeyboardController* _controller)
535   : controller(_controller)
536 {
537     add_label(_("Keyboard Setup"));
538     add_hl();
539     add_controlfield(Controller::UP, _("Up"));
540     add_controlfield(Controller::DOWN, _("Down"));
541     add_controlfield(Controller::LEFT, _("Left"));
542     add_controlfield(Controller::RIGHT, _("Right"));
543     add_controlfield(Controller::JUMP, _("Jump"));
544     add_controlfield(Controller::ACTION, _("Shoot/Run"));
545     add_hl();
546     add_back(_("Back"));
547     update();
548 }
549
550 JoystickKeyboardController::KeyboardMenu::~KeyboardMenu()
551 {}
552
553 std::string
554 JoystickKeyboardController::KeyboardMenu::get_key_name(SDLKey key)
555 {
556   switch(key) {
557     case SDLK_UNKNOWN:
558       return _("None");
559     case SDLK_UP:
560       return _("Up cursor");
561     case SDLK_DOWN:
562       return _("Down cursor");
563     case SDLK_LEFT:
564       return _("Left cursor");
565     case SDLK_RIGHT:
566       return _("Right cursor");
567     case SDLK_RETURN:
568       return _("Return");
569     case SDLK_SPACE:
570       return _("Space");
571     case SDLK_RSHIFT:
572       return _("Right Shift");
573     case SDLK_LSHIFT:
574       return _("Left Shift");
575     case SDLK_RCTRL:
576       return _("Right Control");
577     case SDLK_LCTRL:
578       return _("Left Control");
579     case SDLK_RALT:
580       return _("Right Alt");
581     case SDLK_LALT:
582       return _("Left Alt");
583     default:
584       return SDL_GetKeyName((SDLKey) key);
585   }
586 }
587
588 void
589 JoystickKeyboardController::KeyboardMenu::menu_action(MenuItem* item)
590 {
591   assert(item->id >= 0 && item->id < Controller::CONTROLCOUNT);
592   item->change_input(_("Press Key"));
593   controller->wait_for_key = item->id;
594 }
595
596 void
597 JoystickKeyboardController::KeyboardMenu::update()
598 {
599   // update menu
600   get_item_by_id((int) Controller::UP).change_input(get_key_name(
601     controller->reversemap_key(Controller::UP)));
602   get_item_by_id((int) Controller::DOWN).change_input(get_key_name(
603     controller->reversemap_key(Controller::DOWN)));
604   get_item_by_id((int) Controller::LEFT).change_input(get_key_name(
605     controller->reversemap_key(Controller::LEFT)));
606   get_item_by_id((int) Controller::RIGHT).change_input(get_key_name(
607     controller->reversemap_key(Controller::RIGHT)));
608   get_item_by_id((int) Controller::JUMP).change_input(get_key_name(
609     controller->reversemap_key(Controller::JUMP)));
610   get_item_by_id((int) Controller::ACTION).change_input(get_key_name(
611     controller->reversemap_key(Controller::ACTION)));
612 }
613
614 //---------------------------------------------------------------------------
615
616 JoystickKeyboardController::JoystickMenu::JoystickMenu(
617   JoystickKeyboardController* _controller)
618   : controller(_controller)
619 {
620   add_label(_("Joystick Setup"));
621   add_hl();
622   if(controller->joysticks.size() > 0) {
623     add_controlfield(Controller::JUMP, _("Jump"));
624     add_controlfield(Controller::ACTION, _("Shoot/Run"));
625     add_controlfield(Controller::PAUSE_MENU, _("Pause/Menu"));
626   } else {
627     add_deactive(-1, _("No Joysticks found"));
628   }
629   add_hl();
630   add_back(_("Back"));
631   update();
632 }
633
634 JoystickKeyboardController::JoystickMenu::~JoystickMenu()
635 {}
636
637 std::string
638 JoystickKeyboardController::JoystickMenu::get_button_name(int button)
639 {
640   if(button < 0)
641     return _("None");
642     
643   std::ostringstream name;
644   name << "Button " << button;
645   return name.str();
646 }
647
648 void
649 JoystickKeyboardController::JoystickMenu::menu_action(MenuItem* item)
650 {
651   assert(item->id >= 0 && item->id < Controller::CONTROLCOUNT);
652   item->change_input(_("Press Button"));
653   controller->wait_for_joybutton = item->id;
654 }
655
656 void
657 JoystickKeyboardController::JoystickMenu::update()
658 {
659   if(controller->joysticks.size() == 0)
660     return;
661
662   // update menu
663   get_item_by_id((int) Controller::JUMP).change_input(get_button_name(
664     controller->reversemap_joybutton(Controller::JUMP)));
665   get_item_by_id((int) Controller::ACTION).change_input(get_button_name(
666     controller->reversemap_joybutton(Controller::ACTION)));
667   get_item_by_id((int) Controller::PAUSE_MENU).change_input(get_button_name(
668     controller->reversemap_joybutton(Controller::PAUSE_MENU)));
669 }
670