2 // Copyright (C) 2006 Matthias Braun <matze@braunis.de>,
3 // 2007 Ingo Ruhnke <grumbel@gmx.de>
5 // This program is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "control/joystickkeyboardcontroller.hpp"
22 #include "lisp/list_iterator.hpp"
23 #include "gui/menu_manager.hpp"
24 #include "supertux/console.hpp"
25 #include "supertux/gameconfig.hpp"
26 #include "supertux/menu/menu_storage.hpp"
27 #include "supertux/menu/joystick_menu.hpp"
28 #include "supertux/menu/keyboard_menu.hpp"
29 #include "util/gettext.hpp"
30 #include "util/writer.hpp"
31 //#include <SDL_keycode.h> // add by giby
33 JoystickKeyboardController::JoystickKeyboardController() :
52 controller = new Controller;
54 // initialize default keyboard map
55 keymap[SDLK_LEFT] = Controller::LEFT;
56 keymap[SDLK_RIGHT] = Controller::RIGHT;
57 keymap[SDLK_UP] = Controller::UP;
58 keymap[SDLK_DOWN] = Controller::DOWN;
59 keymap[SDLK_SPACE] = Controller::JUMP;
60 keymap[SDLK_LCTRL] = Controller::ACTION;
61 keymap[SDLK_LALT] = Controller::ACTION;
62 keymap[SDLK_ESCAPE] = Controller::PAUSE_MENU;
63 keymap[SDLK_p] = Controller::PAUSE_MENU;
64 keymap[SDLK_PAUSE] = Controller::PAUSE_MENU;
65 keymap[SDLK_RETURN] = Controller::MENU_SELECT;
66 keymap[SDLK_KP_ENTER] = Controller::MENU_SELECT;
67 keymap[SDLK_CARET] = Controller::CONSOLE;
68 keymap[SDLK_DELETE] = Controller::PEEK_LEFT;
69 keymap[SDLK_PAGEDOWN] = Controller::PEEK_RIGHT;
70 keymap[SDLK_HOME] = Controller::PEEK_UP;
71 keymap[SDLK_END] = Controller::PEEK_DOWN;
73 jump_with_up_joy = false;
74 jump_with_up_kbd = false;
76 updateAvailableJoysticks();
80 // Default joystick button configuration
81 bind_joybutton(0, 0, Controller::JUMP);
82 bind_joybutton(0, 1, Controller::ACTION);
84 if( min_joybuttons > 5 ){
85 bind_joybutton(0, 4, Controller::PEEK_LEFT);
86 bind_joybutton(0, 5, Controller::PEEK_RIGHT);
88 if(min_joybuttons > 7)
89 bind_joybutton(0, min_joybuttons-1, Controller::PAUSE_MENU);
91 // map the last 2 buttons to menu and pause
92 if(min_joybuttons > 2)
93 bind_joybutton(0, min_joybuttons-1, Controller::PAUSE_MENU);
94 // map all remaining joystick buttons to MENU_SELECT
95 for(int i = 2; i < max_joybuttons; ++i) {
96 if(i != min_joybuttons-1)
97 bind_joybutton(0, i, Controller::MENU_SELECT);
101 // Default joystick axis configuration
102 bind_joyaxis(0, -1, Controller::LEFT);
103 bind_joyaxis(0, 1, Controller::RIGHT);
104 bind_joyaxis(0, -2, Controller::UP);
105 bind_joyaxis(0, 2, Controller::DOWN);
108 JoystickKeyboardController::~JoystickKeyboardController()
110 for(std::vector<SDL_Joystick*>::iterator i = joysticks.begin();
111 i != joysticks.end(); ++i) {
113 SDL_JoystickClose(*i);
119 JoystickKeyboardController::updateAvailableJoysticks()
121 for(std::vector<SDL_Joystick*>::iterator i = joysticks.begin();
122 i != joysticks.end(); ++i) {
124 SDL_JoystickClose(*i);
128 SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
129 SDL_InitSubSystem(SDL_INIT_JOYSTICK);
131 int joystick_count = SDL_NumJoysticks();
137 if( joystick_count > 0 ){
138 for(int i = 0; i < joystick_count; ++i) {
139 SDL_Joystick* joystick = SDL_JoystickOpen(i);
141 if(SDL_JoystickNumButtons(joystick) < 2) {
142 log_info << _("Joystick ") << i << ": " << SDL_JoystickID(i) << _(" has less than 2 buttons") << std::endl;
145 if(SDL_JoystickNumAxes(joystick) < 2
146 && SDL_JoystickNumHats(joystick) == 0) {
147 log_info << _("Joystick ") << i << ": " << SDL_JoystickID(i) << _(" has less than 2 axes and no hat") << std::endl;
151 SDL_JoystickClose(joystick);
155 if(min_joybuttons < 0 || SDL_JoystickNumButtons(joystick) < min_joybuttons)
156 min_joybuttons = SDL_JoystickNumButtons(joystick);
158 if(SDL_JoystickNumButtons(joystick) > max_joybuttons)
159 max_joybuttons = SDL_JoystickNumButtons(joystick);
161 if(SDL_JoystickNumAxes(joystick) > max_joyaxis)
162 max_joyaxis = SDL_JoystickNumAxes(joystick);
164 if(SDL_JoystickNumHats(joystick) > max_joyhats)
165 max_joyhats = SDL_JoystickNumHats(joystick);
167 joysticks.push_back(joystick);
171 // some joysticks or SDL seem to produce some bogus events after being opened
172 Uint32 ticks = SDL_GetTicks();
173 while(SDL_GetTicks() - ticks < 200) {
175 SDL_PollEvent(&event);
180 JoystickKeyboardController::get_main_controller()
186 JoystickKeyboardController::read(const Reader& lisp)
188 const lisp::Lisp* keymap_lisp = lisp.get_lisp("keymap");
191 keymap_lisp->get("jump-with-up", jump_with_up_kbd);
192 lisp::ListIterator iter(keymap_lisp);
194 if(iter.item() == "map") {
197 const lisp::Lisp* map = iter.lisp();
198 map->get("key", key);
199 map->get("control", control);
200 // if(key < SDLK_FIRST || key >= SDLK_LAST) {
201 // log_info << "Invalid key '" << key << "' in keymap" << std::endl;
206 for(i = 0; Controller::controlNames[i] != 0; ++i) {
207 if(control == Controller::controlNames[i])
210 if(Controller::controlNames[i] == 0) {
211 log_info << "Invalid control '" << control << "' in keymap" << std::endl;
214 keymap[SDL_Keycode(key)] = Control(i);
219 const lisp::Lisp* joystick_lisp = lisp.get_lisp(_("joystick"));
221 joystick_lisp->get("dead-zone", dead_zone);
222 joystick_lisp->get("jump-with-up", jump_with_up_joy);
223 lisp::ListIterator iter(joystick_lisp);
225 if(iter.item() == _("map")) {
230 const lisp::Lisp* map = iter.lisp();
232 map->get("control", control);
234 for(i = 0; Controller::controlNames[i] != 0; ++i) {
235 if(control == Controller::controlNames[i])
238 if(Controller::controlNames[i] == 0) {
239 log_info << "Invalid control '" << control << "' in buttonmap" << std::endl;
243 bool js_available = joysticks.size() > 0;
245 if (map->get("button", button)) {
246 if(js_available && (button < 0 || button >= max_joybuttons)) {
247 log_info << "Invalid button '" << button << "' in buttonmap" << std::endl;
250 bind_joybutton(0, button, Control(i));
253 if (map->get("axis", axis)) {
254 if (js_available && (axis == 0 || abs(axis) > max_joyaxis)) {
255 log_info << "Invalid axis '" << axis << "' in axismap" << std::endl;
258 bind_joyaxis(0, axis, Control(i));
261 if (map->get("hat", hat)) {
264 hat != SDL_HAT_DOWN &&
265 hat != SDL_HAT_LEFT &&
266 hat != SDL_HAT_RIGHT) {
267 log_info << "Invalid axis '" << axis << "' in axismap" << std::endl;
270 bind_joyhat(0, hat, Control(i));
279 JoystickKeyboardController::write(Writer& writer)
281 writer.start_list("keymap");
282 writer.write("jump-with-up", jump_with_up_kbd);
283 for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
284 writer.start_list("map");
285 writer.write("key", (int) i->first);
286 writer.write("control", Controller::controlNames[i->second]);
287 writer.end_list("map");
289 writer.end_list("keymap");
291 writer.start_list("joystick");
292 writer.write("dead-zone", dead_zone);
293 writer.write("jump-with-up", jump_with_up_joy);
295 for(ButtonMap::iterator i = joy_button_map.begin(); i != joy_button_map.end();
297 writer.start_list("map");
298 writer.write("button", i->first.second);
299 writer.write("control", Controller::controlNames[i->second]);
300 writer.end_list("map");
303 for(HatMap::iterator i = joy_hat_map.begin(); i != joy_hat_map.end(); ++i) {
304 writer.start_list("map");
305 writer.write("hat", i->first.second);
306 writer.write("control", Controller::controlNames[i->second]);
307 writer.end_list("map");
310 for(AxisMap::iterator i = joy_axis_map.begin(); i != joy_axis_map.end(); ++i) {
311 writer.start_list("map");
312 writer.write("axis", i->first.second);
313 writer.write("control", Controller::controlNames[i->second]);
314 writer.end_list("map");
317 writer.end_list("joystick");
321 JoystickKeyboardController::update()
323 controller->update();
327 JoystickKeyboardController::reset()
333 JoystickKeyboardController::set_joy_controls(Control id, bool value)
335 if (jump_with_up_joy && id == Controller::UP)
336 controller->set_control(Controller::JUMP, value);
338 controller->set_control(id, value);
342 JoystickKeyboardController::process_event(const SDL_Event& event)
346 process_text_input_event(event.text);
351 process_key_event(event.key);
354 case SDL_JOYAXISMOTION:
355 process_axis_event(event.jaxis);
358 case SDL_JOYHATMOTION:
359 process_hat_event(event.jhat);
362 case SDL_JOYBUTTONDOWN:
363 case SDL_JOYBUTTONUP:
364 process_button_event(event.jbutton);
373 JoystickKeyboardController::process_button_event(const SDL_JoyButtonEvent& jbutton)
375 if(wait_for_joystick >= 0)
377 if(jbutton.state == SDL_PRESSED)
379 bind_joybutton(jbutton.which, jbutton.button, (Control)wait_for_joystick);
380 MenuStorage::get_joystick_options_menu()->update();
382 wait_for_joystick = -1;
387 ButtonMap::iterator i = joy_button_map.find(std::make_pair(jbutton.which, jbutton.button));
388 if(i == joy_button_map.end()) {
389 log_debug << "Unmapped joybutton " << (int)jbutton.button << " pressed" << std::endl;
391 set_joy_controls(i->second, (jbutton.state == SDL_PRESSED));
397 JoystickKeyboardController::process_axis_event(const SDL_JoyAxisEvent& jaxis)
399 if (wait_for_joystick >= 0)
401 if (abs(jaxis.value) > dead_zone) {
403 bind_joyaxis(jaxis.which, -(jaxis.axis + 1), Control(wait_for_joystick));
405 bind_joyaxis(jaxis.which, jaxis.axis + 1, Control(wait_for_joystick));
407 MenuStorage::get_joystick_options_menu()->update();
408 wait_for_joystick = -1;
413 // Split the axis into left and right, so that both can be
414 // mapped separately (needed for jump/down vs up/down)
415 int axis = jaxis.axis + 1;
417 AxisMap::iterator left = joy_axis_map.find(std::make_pair(jaxis.which, -axis));
418 AxisMap::iterator right = joy_axis_map.find(std::make_pair(jaxis.which, axis));
420 if(left == joy_axis_map.end()) {
421 // std::cout << "Unmapped joyaxis " << (int)jaxis.axis << " moved" << std::endl;
423 if (jaxis.value < -dead_zone)
424 set_joy_controls(left->second, true);
426 set_joy_controls(left->second, false);
429 if(right == joy_axis_map.end()) {
430 // std::cout << "Unmapped joyaxis " << (int)jaxis.axis << " moved" << std::endl;
432 if (jaxis.value > dead_zone)
433 set_joy_controls(right->second, true);
435 set_joy_controls(right->second, false);
441 JoystickKeyboardController::process_hat_event(const SDL_JoyHatEvent& jhat)
443 Uint8 changed = hat_state ^ jhat.value;
445 if (wait_for_joystick >= 0)
447 if (changed & SDL_HAT_UP && jhat.value & SDL_HAT_UP)
448 bind_joyhat(jhat.which, SDL_HAT_UP, Control(wait_for_joystick));
450 if (changed & SDL_HAT_DOWN && jhat.value & SDL_HAT_DOWN)
451 bind_joyhat(jhat.which, SDL_HAT_DOWN, Control(wait_for_joystick));
453 if (changed & SDL_HAT_LEFT && jhat.value & SDL_HAT_LEFT)
454 bind_joyhat(jhat.which, SDL_HAT_LEFT, Control(wait_for_joystick));
456 if (changed & SDL_HAT_RIGHT && jhat.value & SDL_HAT_RIGHT)
457 bind_joyhat(jhat.which, SDL_HAT_RIGHT, Control(wait_for_joystick));
459 MenuStorage::get_joystick_options_menu()->update();
460 wait_for_joystick = -1;
464 if (changed & SDL_HAT_UP)
466 HatMap::iterator it = joy_hat_map.find(std::make_pair(jhat.which, SDL_HAT_UP));
467 if (it != joy_hat_map.end())
468 set_joy_controls(it->second, jhat.value & SDL_HAT_UP);
471 if (changed & SDL_HAT_DOWN)
473 HatMap::iterator it = joy_hat_map.find(std::make_pair(jhat.which, SDL_HAT_DOWN));
474 if (it != joy_hat_map.end())
475 set_joy_controls(it->second, jhat.value & SDL_HAT_DOWN);
478 if (changed & SDL_HAT_LEFT)
480 HatMap::iterator it = joy_hat_map.find(std::make_pair(jhat.which, SDL_HAT_LEFT));
481 if (it != joy_hat_map.end())
482 set_joy_controls(it->second, jhat.value & SDL_HAT_LEFT);
485 if (changed & SDL_HAT_RIGHT)
487 HatMap::iterator it = joy_hat_map.find(std::make_pair(jhat.which, SDL_HAT_RIGHT));
488 if (it != joy_hat_map.end())
489 set_joy_controls(it->second, jhat.value & SDL_HAT_RIGHT);
493 hat_state = jhat.value;
497 JoystickKeyboardController::process_text_input_event(const SDL_TextInputEvent& event)
499 if (Console::instance->hasFocus()) {
500 for(int i = 0; event.text[i] != '\0'; ++i)
502 Console::instance->input(event.text[i]);
508 JoystickKeyboardController::process_key_event(const SDL_KeyboardEvent& event)
510 KeyMap::iterator key_mapping = keymap.find(event.keysym.sym);
512 // if console key was pressed: toggle console
513 if ((key_mapping != keymap.end()) && (key_mapping->second == Controller::CONSOLE)) {
514 if (event.type == SDL_KEYDOWN)
515 Console::instance->toggle();
517 if (Console::instance->hasFocus()) {
518 // if console is open: send key there
519 process_console_key_event(event);
520 } else if (MenuManager::current()) {
521 // if menu mode: send key there
522 process_menu_key_event(event);
523 } else if(key_mapping == keymap.end()) {
524 // default action: update controls
525 //log_debug << "Key " << event.key.SDL_Keycode.sym << " is unbound" << std::endl;
527 Control control = key_mapping->second;
528 bool value = (event.type == SDL_KEYDOWN);
529 controller->set_control(control, value);
530 if (jump_with_up_kbd && control == Controller::UP){
531 controller->set_control(Controller::JUMP, value);
538 JoystickKeyboardController::process_console_key_event(const SDL_KeyboardEvent& event)
540 if (event.type != SDL_KEYDOWN) return;
542 switch (event.keysym.sym) {
544 Console::instance->enter();
547 Console::instance->backspace();
550 Console::instance->autocomplete();
553 Console::instance->scroll(-1);
556 Console::instance->scroll(+1);
559 Console::instance->move_cursor(-65535);
562 Console::instance->move_cursor(+65535);
565 Console::instance->show_history(-1);
568 Console::instance->show_history(+1);
571 Console::instance->move_cursor(-1);
574 Console::instance->move_cursor(+1);
582 JoystickKeyboardController::process_menu_key_event(const SDL_KeyboardEvent& event)
584 // wait for key mode?
585 if(wait_for_key >= 0) {
586 if(event.type == SDL_KEYUP)
589 if(event.keysym.sym != SDLK_ESCAPE
590 && event.keysym.sym != SDLK_PAUSE) {
591 bind_key(event.keysym.sym, Control(wait_for_key));
594 MenuStorage::get_key_options_menu()->update();
598 if(wait_for_joystick >= 0) {
599 if(event.keysym.sym == SDLK_ESCAPE) {
601 MenuStorage::get_joystick_options_menu()->update();
602 wait_for_joystick = -1;
608 /* we use default keys when the menu is open (to avoid problems when
609 * redefining keys to invalid settings
611 switch(event.keysym.sym) {
613 control = Controller::UP;
616 control = Controller::DOWN;
619 control = Controller::LEFT;
622 control = Controller::RIGHT;
627 control = Controller::MENU_SELECT;
631 control = Controller::PAUSE_MENU;
638 controller->set_control(control, (event.type == SDL_KEYDOWN));
642 JoystickKeyboardController::unbind_joystick_control(Control control)
644 // remove all previous mappings for that control
645 for(AxisMap::iterator i = joy_axis_map.begin(); i != joy_axis_map.end(); /* no ++i */) {
646 if(i->second == control)
647 joy_axis_map.erase(i++);
652 for(ButtonMap::iterator i = joy_button_map.begin(); i != joy_button_map.end(); /* no ++i */) {
653 if(i->second == control)
654 joy_button_map.erase(i++);
659 for(HatMap::iterator i = joy_hat_map.begin(); i != joy_hat_map.end(); /* no ++i */) {
660 if(i->second == control)
661 joy_hat_map.erase(i++);
668 JoystickKeyboardController::bind_joyaxis(JoyId joy_id, int axis, Control control)
670 // axis isn't the SDL axis number, but axisnumber + 1 with sign
671 // changed depending on if the positive or negative end is to be
672 // used (negative axis 0 becomes -1, positive axis 2 becomes +3,
675 unbind_joystick_control(control);
678 joy_axis_map[std::make_pair(joy_id, axis)] = control;
682 JoystickKeyboardController::bind_joyhat(JoyId joy_id, int dir, Control c)
684 unbind_joystick_control(c);
687 joy_hat_map[std::make_pair(joy_id, dir)] = c;
691 JoystickKeyboardController::bind_joybutton(JoyId joy_id, int button, Control control)
693 unbind_joystick_control(control);
696 joy_button_map[std::make_pair(joy_id, button)] = control;
700 JoystickKeyboardController::bind_key(SDL_Keycode key, Control control)
702 // remove all previous mappings for that control and for that key
703 for(KeyMap::iterator i = keymap.begin();
704 i != keymap.end(); /* no ++i */) {
705 if(i->second == control) {
706 KeyMap::iterator e = i;
714 KeyMap::iterator i = keymap.find(key);
715 if(i != keymap.end())
719 keymap[key] = control;
723 JoystickKeyboardController::print_joystick_mappings()
725 std::cout << _("Joystick Mappings") << std::endl;
726 std::cout << "-----------------" << std::endl;
727 for(AxisMap::iterator i = joy_axis_map.begin(); i != joy_axis_map.end(); ++i) {
728 std::cout << "Axis: " << i->first.second << " -> " << i->second << std::endl;
731 for(ButtonMap::iterator i = joy_button_map.begin(); i != joy_button_map.end(); ++i) {
732 std::cout << "Button: " << i->first.second << " -> " << i->second << std::endl;
735 for(HatMap::iterator i = joy_hat_map.begin(); i != joy_hat_map.end(); ++i) {
736 std::cout << "Hat: " << i->first.second << " -> " << i->second << std::endl;
738 std::cout << std::endl;
742 JoystickKeyboardController::reversemap_key(Control c)
744 for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
753 JoystickKeyboardController::reversemap_joyaxis(Control c)
755 for(AxisMap::iterator i = joy_axis_map.begin(); i != joy_axis_map.end(); ++i) {
757 return i->first.second;
764 JoystickKeyboardController::reversemap_joybutton(Control c)
766 for(ButtonMap::iterator i = joy_button_map.begin(); i != joy_button_map.end(); ++i) {
768 return i->first.second;
775 JoystickKeyboardController::reversemap_joyhat(Control c)
777 for(HatMap::iterator i = joy_hat_map.begin(); i != joy_hat_map.end(); ++i) {
779 return i->first.second;