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