4 // Copyright (C) 2006 Matthias Braun <matze@braunis.de>,
5 // 2007 Ingo Ruhnke <grumbel@gmx.de>
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include "joystickkeyboardcontroller.hpp"
26 #include "gui/menu.hpp"
27 #include "gettext.hpp"
28 #include "lisp/lisp.hpp"
29 #include "lisp/list_iterator.hpp"
30 #include "game_session.hpp"
31 #include "console.hpp"
32 #include "gameconfig.hpp"
34 class JoystickKeyboardController::JoystickMenu : public Menu
37 JoystickMenu(JoystickKeyboardController* controller);
38 virtual ~JoystickMenu();
41 std::string get_button_name(int button);
42 void update_menu_item(Control id);
43 virtual void menu_action(MenuItem* item);
44 JoystickKeyboardController* controller;
47 class JoystickKeyboardController::KeyboardMenu : public Menu
50 KeyboardMenu(JoystickKeyboardController* controller);
54 std::string get_key_name(SDLKey key);
55 virtual void menu_action(MenuItem* item);
56 JoystickKeyboardController* controller;
59 JoystickKeyboardController::JoystickKeyboardController()
60 : wait_for_key(-1), wait_for_joystick(-1),
61 key_options_menu(0), joystick_options_menu(0)
63 // initialize default keyboard map
64 keymap.insert(std::make_pair(SDLK_LEFT, LEFT));
65 keymap.insert(std::make_pair(SDLK_RIGHT, RIGHT));
66 keymap.insert(std::make_pair(SDLK_UP, UP));
67 keymap.insert(std::make_pair(SDLK_DOWN, DOWN));
68 keymap.insert(std::make_pair(SDLK_SPACE, JUMP));
69 keymap.insert(std::make_pair(SDLK_LCTRL, ACTION));
70 keymap.insert(std::make_pair(SDLK_LALT, ACTION));
71 keymap.insert(std::make_pair(SDLK_ESCAPE, PAUSE_MENU));
72 keymap.insert(std::make_pair(SDLK_p, PAUSE_MENU));
73 keymap.insert(std::make_pair(SDLK_PAUSE, PAUSE_MENU));
74 keymap.insert(std::make_pair(SDLK_RETURN, MENU_SELECT));
75 keymap.insert(std::make_pair(SDLK_KP_ENTER, MENU_SELECT));
76 keymap.insert(std::make_pair(SDLK_CARET, CONSOLE));
77 keymap.insert(std::make_pair(SDLK_DELETE, PEEK_LEFT));
78 keymap.insert(std::make_pair(SDLK_END, PEEK_RIGHT));
80 int joystick_count = SDL_NumJoysticks();
84 for(int i = 0; i < joystick_count; ++i) {
85 SDL_Joystick* joystick = SDL_JoystickOpen(i);
87 if(SDL_JoystickNumButtons(joystick) < 2) {
88 log_info << "Joystick " << i << " has less than 2 buttons" << std::endl;
91 if(SDL_JoystickNumAxes(joystick) < 2
92 && SDL_JoystickNumHats(joystick) == 0) {
93 log_info << "Joystick " << i << " has less than 2 axes and no hat" << std::endl;
97 SDL_JoystickClose(joystick);
101 if(min_joybuttons < 0 || SDL_JoystickNumButtons(joystick) < min_joybuttons)
102 min_joybuttons = SDL_JoystickNumButtons(joystick);
104 if(SDL_JoystickNumButtons(joystick) > max_joybuttons)
105 max_joybuttons = SDL_JoystickNumButtons(joystick);
107 if(SDL_JoystickNumAxes(joystick) > max_joyaxis)
108 max_joyaxis = SDL_JoystickNumAxes(joystick);
110 joysticks.push_back(joystick);
116 // Default joystick button configuration
117 joy_button_map.insert(std::make_pair(0, JUMP));
118 joy_button_map.insert(std::make_pair(1, ACTION));
120 if( min_joybuttons > 5 ){
121 joy_button_map.insert(std::make_pair( 4, PEEK_LEFT));
122 joy_button_map.insert(std::make_pair( 5, PEEK_RIGHT));
124 if(min_joybuttons > 7)
125 joy_button_map.insert(std::make_pair(min_joybuttons-1, PAUSE_MENU));
126 // map all remaining joystick buttons to MENU_SELECT
127 for(int i = 2; i < max_joybuttons; ++i) {
128 if( i != min_joybuttons-1 && i !=4 && i!= 5 )
129 joy_button_map.insert(std::make_pair(i, MENU_SELECT));
133 // map the last 2 buttons to menu and pause
134 if(min_joybuttons > 2)
135 joy_button_map.insert(std::make_pair(min_joybuttons-1, PAUSE_MENU));
136 // map all remaining joystick buttons to MENU_SELECT
137 for(int i = 2; i < max_joybuttons; ++i) {
138 if(i != min_joybuttons-1)
139 joy_button_map.insert(std::make_pair(i, MENU_SELECT));
143 // Default joystick axis configuration
144 joy_axis_map.insert(std::make_pair(-1, LEFT));
145 joy_axis_map.insert(std::make_pair( 1, RIGHT));
146 joy_axis_map.insert(std::make_pair(-2, UP));
147 joy_axis_map.insert(std::make_pair( 2, DOWN));
149 // some joysticks or SDL seem to produce some bogus events after being opened
150 Uint32 ticks = SDL_GetTicks();
151 while(SDL_GetTicks() - ticks < 200) {
153 SDL_PollEvent(&event);
157 JoystickKeyboardController::~JoystickKeyboardController()
159 for(std::vector<SDL_Joystick*>::iterator i = joysticks.begin();
160 i != joysticks.end(); ++i) {
162 SDL_JoystickClose(*i);
165 delete key_options_menu;
166 delete joystick_options_menu;
170 JoystickKeyboardController::read(const lisp::Lisp& lisp)
172 const lisp::Lisp* keymap_lisp = lisp.get_lisp("keymap");
175 lisp::ListIterator iter(keymap_lisp);
177 if(iter.item() == "map") {
180 const lisp::Lisp* map = iter.lisp();
181 map->get("key", key);
182 map->get("control", control);
183 if(key < SDLK_FIRST || key >= SDLK_LAST) {
184 log_info << "Invalid key '" << key << "' in keymap" << std::endl;
189 for(i = 0; controlNames[i] != 0; ++i) {
190 if(control == controlNames[i])
193 if(controlNames[i] == 0) {
194 log_info << "Invalid control '" << control << "' in keymap" << std::endl;
197 keymap.insert(std::make_pair((SDLKey) key, (Control) i));
199 log_info << "Invalid lisp element '" << iter.item() << "' in keymap" << std::endl;
204 const lisp::Lisp* joystick_lisp = lisp.get_lisp("joystick");
206 joystick_lisp->get("use_hat", use_hat);
207 joystick_lisp->get("dead_zone", dead_zone);
208 lisp::ListIterator iter(joystick_lisp);
210 if(iter.item() == "map") {
214 const lisp::Lisp* map = iter.lisp();
216 map->get("control", control);
218 for(i = 0; controlNames[i] != 0; ++i) {
219 if(control == controlNames[i])
222 if(controlNames[i] == 0) {
223 log_info << "Invalid control '" << control << "' in buttonmap" << std::endl;
227 if (map->get("button", button)) {
228 if(button < 0 || button >= max_joybuttons) {
229 log_info << "Invalid button '" << button << "' in buttonmap" << std::endl;
232 reset_joybutton(button, (Control) i);
235 if (map->get("axis", axis)) {
236 if (axis == 0 || abs(axis) > max_joyaxis) {
237 log_info << "Invalid axis '" << axis << "' in axismap" << std::endl;
240 reset_joyaxis(axis, (Control) i);
248 JoystickKeyboardController::write(lisp::Writer& writer)
250 writer.start_list("keymap");
251 for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
252 writer.start_list("map");
253 writer.write_int("key", (int) i->first);
254 writer.write_string("control", controlNames[i->second]);
255 writer.end_list("map");
257 writer.end_list("keymap");
259 writer.start_list("joystick");
260 writer.write_bool("use_hat", use_hat);
261 writer.write_int("dead_zone", dead_zone);
263 for(ButtonMap::iterator i = joy_button_map.begin(); i != joy_button_map.end();
265 writer.start_list("map");
266 writer.write_int("button", i->first);
267 writer.write_string("control", controlNames[i->second]);
268 writer.end_list("map");
271 for(AxisMap::iterator i = joy_axis_map.begin(); i != joy_axis_map.end(); ++i) {
272 writer.start_list("map");
273 writer.write_int("axis", i->first);
274 writer.write_string("control", controlNames[i->second]);
275 writer.end_list("map");
278 writer.end_list("joystick");
282 JoystickKeyboardController::reset()
288 JoystickKeyboardController::process_event(const SDL_Event& event)
293 process_key_event(event);
296 case SDL_JOYAXISMOTION:
297 if (wait_for_joystick >= 0)
299 if (abs(event.jaxis.value) > dead_zone)
301 if (event.jaxis.value < 0)
302 reset_joyaxis(-(event.jaxis.axis + 1), Control(wait_for_joystick));
304 reset_joyaxis(event.jaxis.axis + 1, Control(wait_for_joystick));
306 joystick_options_menu->update();
307 wait_for_joystick = -1;
312 // Split the axis into left and right, so that both can be
313 // mapped seperatly (needed for jump/down vs up/down)
314 int axis = event.jaxis.axis + 1;
316 AxisMap::iterator left = joy_axis_map.find(-axis);
317 AxisMap::iterator right = joy_axis_map.find(axis);
319 if(left == joy_axis_map.end()) {
320 std::cout << "Unmapped joyaxis " << (int)event.jaxis.axis << " moved" << std::endl;
322 if (event.jaxis.value < -dead_zone)
323 controls[left->second] = true;
324 else if (event.jaxis.value > dead_zone)
325 controls[left->second] = false;
327 controls[left->second] = false;
330 if(right == joy_axis_map.end()) {
331 std::cout << "Unmapped joyaxis " << (int)event.jaxis.axis << " moved" << std::endl;
333 if (event.jaxis.value < -dead_zone)
334 controls[right->second] = false;
335 else if (event.jaxis.value > dead_zone)
336 controls[right->second] = true;
338 controls[right->second] = false;
343 case SDL_JOYHATMOTION:
347 if(event.jhat.value & SDL_HAT_UP) {
349 controls[DOWN] = false;
351 if(event.jhat.value & SDL_HAT_DOWN) {
352 controls[UP] = false;
353 controls[DOWN] = true;
355 if(event.jhat.value & SDL_HAT_LEFT) {
356 controls[LEFT] = true;
357 controls[RIGHT] = false;
359 if(event.jhat.value & SDL_HAT_RIGHT) {
360 controls[LEFT] = false;
361 controls[RIGHT] = true;
363 if(event.jhat.value == SDL_HAT_CENTERED) {
364 controls[UP] = false;
365 controls[DOWN] = false;
366 controls[LEFT] = false;
367 controls[RIGHT] = false;
371 case SDL_JOYBUTTONDOWN:
372 case SDL_JOYBUTTONUP:
374 if(wait_for_joystick >= 0) {
375 if(event.type == SDL_JOYBUTTONUP)
378 Control c = (Control) wait_for_joystick;
379 reset_joybutton(event.jbutton.button, c);
381 joystick_options_menu->update();
382 wait_for_joystick = -1;
386 ButtonMap::iterator i = joy_button_map.find(event.jbutton.button);
387 if(i == joy_button_map.end()) {
388 log_debug << "Unmapped joybutton " << (int)event.jbutton.button << " pressed" << std::endl;
392 controls[i->second] = (event.type == SDL_JOYBUTTONDOWN);
402 JoystickKeyboardController::process_key_event(const SDL_Event& event)
404 KeyMap::iterator key_mapping = keymap.find(event.key.keysym.sym);
406 // if console key was pressed: toggle console
407 if ((key_mapping != keymap.end()) && (key_mapping->second == CONSOLE)) {
408 if (event.type != SDL_KEYDOWN) return;
409 Console::instance->toggle();
413 // if console is open: send key there
414 if (Console::instance->hasFocus()) {
415 process_console_key_event(event);
419 // if menu mode: send key there
420 if (Menu::current()) {
421 process_menu_key_event(event);
425 // default action: update controls
426 if(key_mapping == keymap.end()) {
427 log_debug << "Key " << event.key.keysym.sym << " is unbound" << std::endl;
430 Control control = key_mapping->second;
431 controls[control] = (event.type == SDL_KEYDOWN);
435 JoystickKeyboardController::process_console_key_event(const SDL_Event& event)
437 if (event.type != SDL_KEYDOWN) return;
439 switch (event.key.keysym.sym) {
441 Console::instance->enter();
444 Console::instance->backspace();
447 Console::instance->autocomplete();
450 Console::instance->scroll(-1);
453 Console::instance->scroll(+1);
456 Console::instance->move_cursor(-65535);
459 Console::instance->move_cursor(+65535);
462 Console::instance->show_history(-1);
465 Console::instance->show_history(+1);
468 Console::instance->move_cursor(-1);
471 Console::instance->move_cursor(+1);
474 int c = event.key.keysym.unicode;
475 if ((c >= 32) && (c <= 126)) {
476 Console::instance->input((char)c);
483 JoystickKeyboardController::process_menu_key_event(const SDL_Event& event)
485 // wait for key mode?
486 if(wait_for_key >= 0) {
487 if(event.type == SDL_KEYUP)
490 if(event.key.keysym.sym != SDLK_ESCAPE
491 && event.key.keysym.sym != SDLK_PAUSE) {
492 reset_key(event.key.keysym.sym, (Control) wait_for_key);
495 key_options_menu->update();
499 if(wait_for_joystick >= 0) {
500 if(event.key.keysym.sym == SDLK_ESCAPE) {
502 joystick_options_menu->update();
503 wait_for_joystick = -1;
509 /* we use default keys when the menu is open (to avoid problems when
510 * redefining keys to invalid settings
512 switch(event.key.keysym.sym) {
528 control = MENU_SELECT;
532 control = PAUSE_MENU;
539 controls[control] = (event.type == SDL_KEYDOWN);
543 JoystickKeyboardController::reset_joyaxis(int axis, Control control)
545 // axis isn't the SDL axis number, but axisnumber + 1 with sign
546 // changed depending on if the positive or negative end is to be
547 // used (negative axis 0 becomes -1, positive axis 2 becomes +3,
550 // remove all previous mappings for that control
551 for(AxisMap::iterator i = joy_axis_map.begin();
552 i != joy_axis_map.end(); /* no ++i */) {
553 if(i->second == control) {
554 AxisMap::iterator e = i;
556 joy_axis_map.erase(e);
562 // remove all previous mappings for that control
563 for(ButtonMap::iterator i = joy_button_map.begin();
564 i != joy_button_map.end(); /* no ++i */) {
565 if(i->second == control) {
566 ButtonMap::iterator e = i;
568 joy_button_map.erase(e);
574 // remove all previous and for that axis
575 AxisMap::iterator i = joy_axis_map.find(axis);
576 if(i != joy_axis_map.end())
577 joy_axis_map.erase(i);
580 joy_axis_map.insert(std::make_pair(axis, control));
584 JoystickKeyboardController::reset_joybutton(int button, Control control)
586 // remove all previous mappings for that control
587 for(AxisMap::iterator i = joy_axis_map.begin();
588 i != joy_axis_map.end(); /* no ++i */) {
589 if(i->second == control) {
590 AxisMap::iterator e = i;
592 joy_axis_map.erase(e);
598 // remove all previous mappings for that control and for that key
599 for(ButtonMap::iterator i = joy_button_map.begin();
600 i != joy_button_map.end(); /* no ++i */) {
601 if(i->second == control) {
602 ButtonMap::iterator e = i;
604 joy_button_map.erase(e);
609 ButtonMap::iterator i = joy_button_map.find(button);
610 if(i != joy_button_map.end())
611 joy_button_map.erase(i);
614 joy_button_map.insert(std::make_pair(button, control));
616 // map all unused buttons to MENU_SELECT
617 for(int b = 0; b < max_joybuttons; ++b) {
618 ButtonMap::iterator i = joy_button_map.find(b);
619 if(i != joy_button_map.end())
622 joy_button_map.insert(std::make_pair(b, MENU_SELECT));
627 JoystickKeyboardController::reset_key(SDLKey key, Control control)
629 // remove all previous mappings for that control and for that key
630 for(KeyMap::iterator i = keymap.begin();
631 i != keymap.end(); /* no ++i */) {
632 if(i->second == control) {
633 KeyMap::iterator e = i;
640 KeyMap::iterator i = keymap.find(key);
641 if(i != keymap.end())
645 keymap.insert(std::make_pair(key, control));
649 JoystickKeyboardController::reversemap_key(Control c)
651 for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
660 JoystickKeyboardController::reversemap_joyaxis(Control c)
662 for(AxisMap::iterator i = joy_axis_map.begin(); i != joy_axis_map.end(); ++i) {
671 JoystickKeyboardController::reversemap_joybutton(Control c)
673 for(ButtonMap::iterator i = joy_button_map.begin();
674 i != joy_button_map.end(); ++i) {
683 JoystickKeyboardController::get_key_options_menu()
685 if(key_options_menu == 0) {
686 key_options_menu = new KeyboardMenu(this);
689 return key_options_menu;
693 JoystickKeyboardController::get_joystick_options_menu()
695 if(joystick_options_menu == 0) {
696 joystick_options_menu = new JoystickMenu(this);
699 return joystick_options_menu;
702 //----------------------------------------------------------------------------
704 JoystickKeyboardController::KeyboardMenu::KeyboardMenu(
705 JoystickKeyboardController* _controller)
706 : controller(_controller)
708 add_label(_("Setup Keyboard"));
710 add_controlfield(Controller::UP, _("Up"));
711 add_controlfield(Controller::DOWN, _("Down"));
712 add_controlfield(Controller::LEFT, _("Left"));
713 add_controlfield(Controller::RIGHT, _("Right"));
714 add_controlfield(Controller::JUMP, _("Jump"));
715 add_controlfield(Controller::ACTION, _("Action"));
716 add_controlfield(Controller::PEEK_LEFT, _("Peek Left"));
717 add_controlfield(Controller::PEEK_RIGHT, _("Peek Right"));
718 if (config->console_enabled) {
719 add_controlfield(Controller::CONSOLE, _("Console"));
726 JoystickKeyboardController::KeyboardMenu::~KeyboardMenu()
730 JoystickKeyboardController::KeyboardMenu::get_key_name(SDLKey key)
736 return _("Up cursor");
738 return _("Down cursor");
740 return _("Left cursor");
742 return _("Right cursor");
748 return _("Right Shift");
750 return _("Left Shift");
752 return _("Right Control");
754 return _("Left Control");
756 return _("Right Alt");
758 return _("Left Alt");
760 return SDL_GetKeyName((SDLKey) key);
765 JoystickKeyboardController::KeyboardMenu::menu_action(MenuItem* item)
767 assert(item->id >= 0 && item->id < Controller::CONTROLCOUNT);
768 item->change_input(_("Press Key"));
769 controller->wait_for_key = item->id;
773 JoystickKeyboardController::KeyboardMenu::update()
776 get_item_by_id((int) Controller::UP).change_input(get_key_name(
777 controller->reversemap_key(Controller::UP)));
778 get_item_by_id((int) Controller::DOWN).change_input(get_key_name(
779 controller->reversemap_key(Controller::DOWN)));
780 get_item_by_id((int) Controller::LEFT).change_input(get_key_name(
781 controller->reversemap_key(Controller::LEFT)));
782 get_item_by_id((int) Controller::RIGHT).change_input(get_key_name(
783 controller->reversemap_key(Controller::RIGHT)));
784 get_item_by_id((int) Controller::JUMP).change_input(get_key_name(
785 controller->reversemap_key(Controller::JUMP)));
786 get_item_by_id((int) Controller::ACTION).change_input(get_key_name(
787 controller->reversemap_key(Controller::ACTION)));
788 get_item_by_id((int) Controller::PEEK_LEFT).change_input(get_key_name(
789 controller->reversemap_key(Controller::PEEK_LEFT)));
790 get_item_by_id((int) Controller::PEEK_RIGHT).change_input(get_key_name(
791 controller->reversemap_key(Controller::PEEK_RIGHT)));
792 if (config->console_enabled) {
793 get_item_by_id((int) Controller::CONSOLE).change_input(get_key_name(
794 controller->reversemap_key(Controller::CONSOLE)));
798 //---------------------------------------------------------------------------
800 JoystickKeyboardController::JoystickMenu::JoystickMenu(
801 JoystickKeyboardController* _controller)
802 : controller(_controller)
804 add_label(_("Setup Joystick"));
806 if(controller->joysticks.size() > 0) {
807 add_controlfield(Controller::UP, _("Up"));
808 add_controlfield(Controller::DOWN, _("Down"));
809 add_controlfield(Controller::LEFT, _("Left"));
810 add_controlfield(Controller::RIGHT, _("Right"));
811 add_controlfield(Controller::JUMP, _("Jump"));
812 add_controlfield(Controller::ACTION, _("Action"));
813 add_controlfield(Controller::PAUSE_MENU, _("Pause/Menu"));
814 add_controlfield(Controller::PEEK_LEFT, _("Peek Left"));
815 add_controlfield(Controller::PEEK_RIGHT, _("Peek Right"));
817 add_deactive(-1, _("No Joysticks found"));
824 JoystickKeyboardController::JoystickMenu::~JoystickMenu()
828 JoystickKeyboardController::JoystickMenu::get_button_name(int button)
833 std::ostringstream name;
834 name << "Button " << button;
839 JoystickKeyboardController::JoystickMenu::menu_action(MenuItem* item)
841 assert(item->id >= 0 && item->id < Controller::CONTROLCOUNT);
842 item->change_input(_("Press Button"));
843 controller->wait_for_joystick = item->id;
847 JoystickKeyboardController::JoystickMenu::update_menu_item(Control id)
849 int button = controller->reversemap_joybutton(id);
850 int axis = controller->reversemap_joyaxis(id);
853 get_item_by_id((int)id).change_input(get_button_name(button));
854 } else if (axis != 0) {
855 std::ostringstream name;
866 else if (abs(axis) == 2)
868 else if (abs(axis) == 2)
870 else if (abs(axis) == 3)
875 get_item_by_id((int)id).change_input(name.str());
877 get_item_by_id((int)id).change_input("None");
882 JoystickKeyboardController::JoystickMenu::update()
884 if(controller->joysticks.size() == 0)
887 update_menu_item(Controller::UP);
888 update_menu_item(Controller::DOWN);
889 update_menu_item(Controller::LEFT);
890 update_menu_item(Controller::RIGHT);
892 update_menu_item(Controller::JUMP);
893 update_menu_item(Controller::ACTION);
894 update_menu_item(Controller::PAUSE_MENU);
895 update_menu_item(Controller::PEEK_LEFT);
896 update_menu_item(Controller::PEEK_RIGHT);