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