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();
83 for(int i = 0; i < joystick_count; ++i) {
84 SDL_Joystick* joystick = SDL_JoystickOpen(i);
86 if(SDL_JoystickNumButtons(joystick) < 2) {
87 log_info << "Joystick " << i << " has less than 2 buttons" << std::endl;
90 if(SDL_JoystickNumAxes(joystick) < 2
91 && SDL_JoystickNumHats(joystick) == 0) {
92 log_info << "Joystick " << i << " has less than 2 axes and no hat" << std::endl;
96 SDL_JoystickClose(joystick);
100 if(min_joybuttons < 0 || SDL_JoystickNumButtons(joystick) < min_joybuttons)
101 min_joybuttons = SDL_JoystickNumButtons(joystick);
102 if(SDL_JoystickNumButtons(joystick) > max_joybuttons) {
103 max_joybuttons = SDL_JoystickNumButtons(joystick);
106 joysticks.push_back(joystick);
114 // Default joystick button configuration
115 joy_button_map.insert(std::make_pair(0, JUMP));
116 joy_button_map.insert(std::make_pair(1, ACTION));
118 if( min_joybuttons > 5 ){
119 joy_button_map.insert(std::make_pair( 4, PEEK_LEFT));
120 joy_button_map.insert(std::make_pair( 5, PEEK_RIGHT));
122 if(min_joybuttons > 7)
123 joy_button_map.insert(std::make_pair(min_joybuttons-1, PAUSE_MENU));
124 // map all remaining joystick buttons to MENU_SELECT
125 for(int i = 2; i < max_joybuttons; ++i) {
126 if( i != min_joybuttons-1 && i !=4 && i!= 5 )
127 joy_button_map.insert(std::make_pair(i, MENU_SELECT));
131 // map the last 2 buttons to menu and pause
132 if(min_joybuttons > 2)
133 joy_button_map.insert(std::make_pair(min_joybuttons-1, PAUSE_MENU));
134 // map all remaining joystick buttons to MENU_SELECT
135 for(int i = 2; i < max_joybuttons; ++i) {
136 if(i != min_joybuttons-1)
137 joy_button_map.insert(std::make_pair(i, MENU_SELECT));
141 // Default joystick axis configuration
142 joy_axis_map.insert(std::make_pair(-1, LEFT));
143 joy_axis_map.insert(std::make_pair( 1, RIGHT));
144 joy_axis_map.insert(std::make_pair(-2, JUMP));
145 joy_axis_map.insert(std::make_pair( 2, DOWN));
147 // some joysticks or SDL seem to produce some bogus events after being opened
148 Uint32 ticks = SDL_GetTicks();
149 while(SDL_GetTicks() - ticks < 200) {
151 SDL_PollEvent(&event);
155 JoystickKeyboardController::~JoystickKeyboardController()
157 for(std::vector<SDL_Joystick*>::iterator i = joysticks.begin();
158 i != joysticks.end(); ++i) {
160 SDL_JoystickClose(*i);
163 delete key_options_menu;
164 delete joystick_options_menu;
168 JoystickKeyboardController::read(const lisp::Lisp& lisp)
170 const lisp::Lisp* keymap_lisp = lisp.get_lisp("keymap");
173 lisp::ListIterator iter(keymap_lisp);
175 if(iter.item() == "map") {
178 const lisp::Lisp* map = iter.lisp();
179 map->get("key", key);
180 map->get("control", control);
181 if(key < SDLK_FIRST || key >= SDLK_LAST) {
182 log_info << "Invalid key '" << key << "' in keymap" << std::endl;
187 for(i = 0; controlNames[i] != 0; ++i) {
188 if(control == controlNames[i])
191 if(controlNames[i] == 0) {
192 log_info << "Invalid control '" << control << "' in keymap" << std::endl;
195 keymap.insert(std::make_pair((SDLKey) key, (Control) i));
197 log_info << "Invalid lisp element '" << iter.item() << "' in keymap" << std::endl;
202 const lisp::Lisp* joystick_lisp = lisp.get_lisp("joystick");
204 joystick_lisp->get("use_hat", use_hat);
205 joystick_lisp->get("axis_x", joyaxis_x);
206 joystick_lisp->get("axis_y", joyaxis_y);
207 joystick_lisp->get("dead_zone", dead_zone);
208 lisp::ListIterator iter(joystick_lisp);
210 if(iter.item() == "map") {
213 const lisp::Lisp* map = iter.lisp();
214 map->get("button", button);
215 map->get("control", control);
216 if(button < 0 || button >= max_joybuttons) {
217 log_info << "Invalid button '" << button << "' in buttonmap" << std::endl;
222 for(i = 0; controlNames[i] != 0; ++i) {
223 if(control == controlNames[i])
226 if(controlNames[i] == 0) {
227 log_info << "Invalid control '" << control << "' in buttonmap" << std::endl;
230 reset_joybutton(button, (Control) i);
237 JoystickKeyboardController::write(lisp::Writer& writer)
239 writer.start_list("keymap");
240 for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
241 writer.start_list("map");
242 writer.write_int("key", (int) i->first);
243 writer.write_string("control", controlNames[i->second]);
244 writer.end_list("map");
246 writer.end_list("keymap");
247 writer.start_list("joystick");
248 writer.write_bool("use_hat", use_hat);
249 writer.write_int("axis_x", joyaxis_x);
250 writer.write_int("axis_y", joyaxis_y);
251 writer.write_int("dead_zone", dead_zone);
253 for(ButtonMap::iterator i = joy_button_map.begin(); i != joy_button_map.end();
255 writer.start_list("map");
256 writer.write_int("button", i->first);
257 writer.write_string("control", controlNames[i->second]);
258 writer.end_list("map");
260 writer.end_list("joystick");
264 JoystickKeyboardController::reset()
270 JoystickKeyboardController::process_event(const SDL_Event& event)
275 process_key_event(event);
278 case SDL_JOYAXISMOTION:
279 if (wait_for_joystick >= 0)
281 if (abs(event.jaxis.value) > dead_zone)
283 if (event.jaxis.value < 0)
284 reset_joyaxis(-(event.jaxis.axis + 1), Control(wait_for_joystick));
286 reset_joyaxis(event.jaxis.axis + 1, Control(wait_for_joystick));
288 joystick_options_menu->update();
289 wait_for_joystick = -1;
294 // Split the axis into left and right, so that both can be
295 // mapped seperatly (needed for jump/down vs up/down)
296 int axis = event.jaxis.axis + 1;
298 AxisMap::iterator left = joy_axis_map.find(-axis);
299 AxisMap::iterator right = joy_axis_map.find(axis);
301 if(left == joy_axis_map.end()) {
302 std::cout << "Unmapped joyaxis " << (int)event.jaxis.axis << " moved" << std::endl;
304 if (event.jaxis.value < -dead_zone)
305 controls[left->second] = true;
306 else if (event.jaxis.value > dead_zone)
307 controls[left->second] = false;
309 controls[left->second] = false;
312 if(right == joy_axis_map.end()) {
313 std::cout << "Unmapped joyaxis " << (int)event.jaxis.axis << " moved" << std::endl;
315 if (event.jaxis.value < -dead_zone)
316 controls[right->second] = false;
317 else if (event.jaxis.value > dead_zone)
318 controls[right->second] = true;
320 controls[right->second] = false;
325 case SDL_JOYHATMOTION:
329 if(event.jhat.value & SDL_HAT_UP) {
331 controls[DOWN] = false;
333 if(event.jhat.value & SDL_HAT_DOWN) {
334 controls[UP] = false;
335 controls[DOWN] = true;
337 if(event.jhat.value & SDL_HAT_LEFT) {
338 controls[LEFT] = true;
339 controls[RIGHT] = false;
341 if(event.jhat.value & SDL_HAT_RIGHT) {
342 controls[LEFT] = false;
343 controls[RIGHT] = true;
345 if(event.jhat.value == SDL_HAT_CENTERED) {
346 controls[UP] = false;
347 controls[DOWN] = false;
348 controls[LEFT] = false;
349 controls[RIGHT] = false;
353 case SDL_JOYBUTTONDOWN:
354 case SDL_JOYBUTTONUP:
356 if(wait_for_joystick >= 0) {
357 if(event.type == SDL_JOYBUTTONUP)
360 Control c = (Control) wait_for_joystick;
361 reset_joybutton(event.jbutton.button, c);
363 joystick_options_menu->update();
364 wait_for_joystick = -1;
368 ButtonMap::iterator i = joy_button_map.find(event.jbutton.button);
369 if(i == joy_button_map.end()) {
370 log_debug << "Unmapped joybutton " << (int)event.jbutton.button << " pressed" << std::endl;
374 controls[i->second] = (event.type == SDL_JOYBUTTONDOWN);
384 JoystickKeyboardController::process_key_event(const SDL_Event& event)
386 KeyMap::iterator key_mapping = keymap.find(event.key.keysym.sym);
388 // if console key was pressed: toggle console
389 if ((key_mapping != keymap.end()) && (key_mapping->second == CONSOLE)) {
390 if (event.type != SDL_KEYDOWN) return;
391 Console::instance->toggle();
395 // if console is open: send key there
396 if (Console::instance->hasFocus()) {
397 process_console_key_event(event);
401 // if menu mode: send key there
402 if (Menu::current()) {
403 process_menu_key_event(event);
407 // default action: update controls
408 if(key_mapping == keymap.end()) {
409 log_debug << "Key " << event.key.keysym.sym << " is unbound" << std::endl;
412 Control control = key_mapping->second;
413 controls[control] = (event.type == SDL_KEYDOWN);
417 JoystickKeyboardController::process_console_key_event(const SDL_Event& event)
419 if (event.type != SDL_KEYDOWN) return;
421 switch (event.key.keysym.sym) {
423 Console::instance->enter();
426 Console::instance->backspace();
429 Console::instance->autocomplete();
432 Console::instance->scroll(-1);
435 Console::instance->scroll(+1);
438 Console::instance->move_cursor(-65535);
441 Console::instance->move_cursor(+65535);
444 Console::instance->show_history(-1);
447 Console::instance->show_history(+1);
450 Console::instance->move_cursor(-1);
453 Console::instance->move_cursor(+1);
456 int c = event.key.keysym.unicode;
457 if ((c >= 32) && (c <= 126)) {
458 Console::instance->input((char)c);
465 JoystickKeyboardController::process_menu_key_event(const SDL_Event& event)
467 // wait for key mode?
468 if(wait_for_key >= 0) {
469 if(event.type == SDL_KEYUP)
472 if(event.key.keysym.sym != SDLK_ESCAPE
473 && event.key.keysym.sym != SDLK_PAUSE) {
474 reset_key(event.key.keysym.sym, (Control) wait_for_key);
477 key_options_menu->update();
481 if(wait_for_joystick >= 0) {
482 if(event.key.keysym.sym == SDLK_ESCAPE) {
484 joystick_options_menu->update();
485 wait_for_joystick = -1;
491 /* we use default keys when the menu is open (to avoid problems when
492 * redefining keys to invalid settings
494 switch(event.key.keysym.sym) {
510 control = MENU_SELECT;
514 control = PAUSE_MENU;
521 controls[control] = (event.type == SDL_KEYDOWN);
525 JoystickKeyboardController::reset_joyaxis(int axis, Control control)
527 // axis isn't the SDL axis number, but axisnumber + 1 with sign
528 // changed depending on if the positive or negative end is to be
529 // used (negative axis 0 becomes -1, positive axis 2 becomes +3,
532 // remove all previous mappings for that control
533 for(AxisMap::iterator i = joy_axis_map.begin();
534 i != joy_axis_map.end(); /* no ++i */) {
535 if(i->second == control) {
536 AxisMap::iterator e = i;
538 joy_axis_map.erase(e);
544 // remove all previous mappings for that control
545 for(ButtonMap::iterator i = joy_button_map.begin();
546 i != joy_button_map.end(); /* no ++i */) {
547 if(i->second == control) {
548 ButtonMap::iterator e = i;
550 joy_button_map.erase(e);
556 // remove all previous and for that axis
557 AxisMap::iterator i = joy_axis_map.find(axis);
558 if(i != joy_axis_map.end())
559 joy_axis_map.erase(i);
562 joy_axis_map.insert(std::make_pair(axis, control));
566 JoystickKeyboardController::reset_joybutton(int button, Control control)
568 // remove all previous mappings for that control
569 for(AxisMap::iterator i = joy_axis_map.begin();
570 i != joy_axis_map.end(); /* no ++i */) {
571 if(i->second == control) {
572 AxisMap::iterator e = i;
574 joy_axis_map.erase(e);
580 // remove all previous mappings for that control and for that key
581 for(ButtonMap::iterator i = joy_button_map.begin();
582 i != joy_button_map.end(); /* no ++i */) {
583 if(i->second == control) {
584 ButtonMap::iterator e = i;
586 joy_button_map.erase(e);
591 ButtonMap::iterator i = joy_button_map.find(button);
592 if(i != joy_button_map.end())
593 joy_button_map.erase(i);
596 joy_button_map.insert(std::make_pair(button, control));
598 // map all unused buttons to MENU_SELECT
599 for(int b = 0; b < max_joybuttons; ++b) {
600 ButtonMap::iterator i = joy_button_map.find(b);
601 if(i != joy_button_map.end())
604 joy_button_map.insert(std::make_pair(b, MENU_SELECT));
609 JoystickKeyboardController::reset_key(SDLKey key, Control control)
611 // remove all previous mappings for that control and for that key
612 for(KeyMap::iterator i = keymap.begin();
613 i != keymap.end(); /* no ++i */) {
614 if(i->second == control) {
615 KeyMap::iterator e = i;
622 KeyMap::iterator i = keymap.find(key);
623 if(i != keymap.end())
627 keymap.insert(std::make_pair(key, control));
631 JoystickKeyboardController::reversemap_key(Control c)
633 for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
642 JoystickKeyboardController::reversemap_joyaxis(Control c)
644 for(AxisMap::iterator i = joy_axis_map.begin(); i != joy_axis_map.end(); ++i) {
653 JoystickKeyboardController::reversemap_joybutton(Control c)
655 for(ButtonMap::iterator i = joy_button_map.begin();
656 i != joy_button_map.end(); ++i) {
665 JoystickKeyboardController::get_key_options_menu()
667 if(key_options_menu == 0) {
668 key_options_menu = new KeyboardMenu(this);
671 return key_options_menu;
675 JoystickKeyboardController::get_joystick_options_menu()
677 if(joystick_options_menu == 0) {
678 joystick_options_menu = new JoystickMenu(this);
681 return joystick_options_menu;
684 //----------------------------------------------------------------------------
686 JoystickKeyboardController::KeyboardMenu::KeyboardMenu(
687 JoystickKeyboardController* _controller)
688 : controller(_controller)
690 add_label(_("Setup Keyboard"));
692 add_controlfield(Controller::UP, _("Up"));
693 add_controlfield(Controller::DOWN, _("Down"));
694 add_controlfield(Controller::LEFT, _("Left"));
695 add_controlfield(Controller::RIGHT, _("Right"));
696 add_controlfield(Controller::JUMP, _("Jump"));
697 add_controlfield(Controller::ACTION, _("Action"));
698 add_controlfield(Controller::PEEK_LEFT, _("Peek Left"));
699 add_controlfield(Controller::PEEK_RIGHT, _("Peek Right"));
700 if (config->console_enabled) {
701 add_controlfield(Controller::CONSOLE, _("Console"));
708 JoystickKeyboardController::KeyboardMenu::~KeyboardMenu()
712 JoystickKeyboardController::KeyboardMenu::get_key_name(SDLKey key)
718 return _("Up cursor");
720 return _("Down cursor");
722 return _("Left cursor");
724 return _("Right cursor");
730 return _("Right Shift");
732 return _("Left Shift");
734 return _("Right Control");
736 return _("Left Control");
738 return _("Right Alt");
740 return _("Left Alt");
742 return SDL_GetKeyName((SDLKey) key);
747 JoystickKeyboardController::KeyboardMenu::menu_action(MenuItem* item)
749 assert(item->id >= 0 && item->id < Controller::CONTROLCOUNT);
750 item->change_input(_("Press Key"));
751 controller->wait_for_key = item->id;
755 JoystickKeyboardController::KeyboardMenu::update()
758 get_item_by_id((int) Controller::UP).change_input(get_key_name(
759 controller->reversemap_key(Controller::UP)));
760 get_item_by_id((int) Controller::DOWN).change_input(get_key_name(
761 controller->reversemap_key(Controller::DOWN)));
762 get_item_by_id((int) Controller::LEFT).change_input(get_key_name(
763 controller->reversemap_key(Controller::LEFT)));
764 get_item_by_id((int) Controller::RIGHT).change_input(get_key_name(
765 controller->reversemap_key(Controller::RIGHT)));
766 get_item_by_id((int) Controller::JUMP).change_input(get_key_name(
767 controller->reversemap_key(Controller::JUMP)));
768 get_item_by_id((int) Controller::ACTION).change_input(get_key_name(
769 controller->reversemap_key(Controller::ACTION)));
770 get_item_by_id((int) Controller::PEEK_LEFT).change_input(get_key_name(
771 controller->reversemap_key(Controller::PEEK_LEFT)));
772 get_item_by_id((int) Controller::PEEK_RIGHT).change_input(get_key_name(
773 controller->reversemap_key(Controller::PEEK_RIGHT)));
774 if (config->console_enabled) {
775 get_item_by_id((int) Controller::CONSOLE).change_input(get_key_name(
776 controller->reversemap_key(Controller::CONSOLE)));
780 //---------------------------------------------------------------------------
782 JoystickKeyboardController::JoystickMenu::JoystickMenu(
783 JoystickKeyboardController* _controller)
784 : controller(_controller)
786 add_label(_("Setup Joystick"));
788 if(controller->joysticks.size() > 0) {
789 add_controlfield(Controller::UP, _("Up"));
790 add_controlfield(Controller::DOWN, _("Down"));
791 add_controlfield(Controller::LEFT, _("Left"));
792 add_controlfield(Controller::RIGHT, _("Right"));
793 add_controlfield(Controller::JUMP, _("Jump"));
794 add_controlfield(Controller::ACTION, _("Action"));
795 add_controlfield(Controller::PAUSE_MENU, _("Pause/Menu"));
796 add_controlfield(Controller::PEEK_LEFT, _("Peek Left"));
797 add_controlfield(Controller::PEEK_RIGHT, _("Peek Right"));
799 add_deactive(-1, _("No Joysticks found"));
806 JoystickKeyboardController::JoystickMenu::~JoystickMenu()
810 JoystickKeyboardController::JoystickMenu::get_button_name(int button)
815 std::ostringstream name;
816 name << "Button " << button;
821 JoystickKeyboardController::JoystickMenu::menu_action(MenuItem* item)
823 assert(item->id >= 0 && item->id < Controller::CONTROLCOUNT);
824 item->change_input(_("Press Button"));
825 controller->wait_for_joystick = item->id;
829 JoystickKeyboardController::JoystickMenu::update_menu_item(Control id)
831 int button = controller->reversemap_joybutton(id);
832 int axis = controller->reversemap_joyaxis(id);
835 get_item_by_id((int)id).change_input(get_button_name(button));
836 } else if (axis != 0) {
837 std::ostringstream name;
848 else if (abs(axis) == 2)
850 else if (abs(axis) == 2)
852 else if (abs(axis) == 3)
857 get_item_by_id((int)id).change_input(name.str());
859 get_item_by_id((int)id).change_input("None");
864 JoystickKeyboardController::JoystickMenu::update()
866 if(controller->joysticks.size() == 0)
869 update_menu_item(Controller::UP);
870 update_menu_item(Controller::DOWN);
871 update_menu_item(Controller::LEFT);
872 update_menu_item(Controller::RIGHT);
874 update_menu_item(Controller::JUMP);
875 update_menu_item(Controller::ACTION);
876 update_menu_item(Controller::PAUSE_MENU);
877 update_menu_item(Controller::PEEK_LEFT);
878 update_menu_item(Controller::PEEK_RIGHT);