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