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