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