4 // Copyright (C) 2006 Matthias Braun <matze@braunis.de>
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.
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.
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 02111-1307, USA.
23 #include "joystickkeyboardcontroller.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 #include "gameconfig.hpp"
33 class JoystickKeyboardController::JoystickMenu : public Menu
36 JoystickMenu(JoystickKeyboardController* controller);
37 virtual ~JoystickMenu();
40 std::string get_button_name(int button);
41 virtual void menu_action(MenuItem* item);
42 JoystickKeyboardController* controller;
45 class JoystickKeyboardController::KeyboardMenu : public Menu
48 KeyboardMenu(JoystickKeyboardController* controller);
52 std::string get_key_name(SDLKey key);
53 virtual void menu_action(MenuItem* item);
54 JoystickKeyboardController* controller;
57 JoystickKeyboardController::JoystickKeyboardController()
58 : wait_for_key(-1), wait_for_joybutton(-1), key_options_menu(0),
59 joystick_options_menu(0)
61 // initialize default keyboard map
62 keymap.insert(std::make_pair(SDLK_LEFT, LEFT));
63 keymap.insert(std::make_pair(SDLK_RIGHT, RIGHT));
64 keymap.insert(std::make_pair(SDLK_UP, UP));
65 keymap.insert(std::make_pair(SDLK_DOWN, DOWN));
66 keymap.insert(std::make_pair(SDLK_SPACE, JUMP));
67 keymap.insert(std::make_pair(SDLK_LCTRL, ACTION));
68 keymap.insert(std::make_pair(SDLK_LALT, ACTION));
69 keymap.insert(std::make_pair(SDLK_ESCAPE, PAUSE_MENU));
70 keymap.insert(std::make_pair(SDLK_p, PAUSE_MENU));
71 keymap.insert(std::make_pair(SDLK_PAUSE, PAUSE_MENU));
72 keymap.insert(std::make_pair(SDLK_RETURN, MENU_SELECT));
73 keymap.insert(std::make_pair(SDLK_KP_ENTER, MENU_SELECT));
74 keymap.insert(std::make_pair(SDLK_CARET, CONSOLE));
75 keymap.insert(std::make_pair(SDLK_DELETE, PEEK_LEFT));
76 keymap.insert(std::make_pair(SDLK_END, PEEK_RIGHT));
78 int joystick_count = SDL_NumJoysticks();
81 for(int i = 0; i < joystick_count; ++i) {
82 SDL_Joystick* joystick = SDL_JoystickOpen(i);
84 if(SDL_JoystickNumButtons(joystick) < 2) {
85 log_info << "Joystick " << i << " has less than 2 buttons" << std::endl;
88 if(SDL_JoystickNumAxes(joystick) < 2
89 && SDL_JoystickNumHats(joystick) == 0) {
90 log_info << "Joystick " << i << " has less than 2 axes and no hat" << std::endl;
94 SDL_JoystickClose(joystick);
98 if(min_joybuttons < 0 || SDL_JoystickNumButtons(joystick) < min_joybuttons)
99 min_joybuttons = SDL_JoystickNumButtons(joystick);
100 if(SDL_JoystickNumButtons(joystick) > max_joybuttons) {
101 max_joybuttons = SDL_JoystickNumButtons(joystick);
104 joysticks.push_back(joystick);
113 joy_button_map.insert(std::make_pair(0, JUMP));
114 joy_button_map.insert(std::make_pair(1, ACTION));
116 if( min_joybuttons > 5 ){
117 joy_button_map.insert(std::make_pair( 4, PEEK_LEFT));
118 joy_button_map.insert(std::make_pair( 5, PEEK_RIGHT));
120 if(min_joybuttons > 7)
121 joy_button_map.insert(std::make_pair(min_joybuttons-1, PAUSE_MENU));
122 // map all remaining joystick buttons to MENU_SELECT
123 for(int i = 2; i < max_joybuttons; ++i) {
124 if( i != min_joybuttons-1 && i !=4 && i!= 5 )
125 joy_button_map.insert(std::make_pair(i, MENU_SELECT));
129 // map the last 2 buttons to menu and pause
130 if(min_joybuttons > 2)
131 joy_button_map.insert(std::make_pair(min_joybuttons-1, PAUSE_MENU));
132 // map all remaining joystick buttons to MENU_SELECT
133 for(int i = 2; i < max_joybuttons; ++i) {
134 if(i != min_joybuttons-1)
135 joy_button_map.insert(std::make_pair(i, MENU_SELECT));
139 // some joysticks or SDL seem to produce some bogus events after being opened
140 Uint32 ticks = SDL_GetTicks();
141 while(SDL_GetTicks() - ticks < 200) {
143 SDL_PollEvent(&event);
147 JoystickKeyboardController::~JoystickKeyboardController()
149 for(std::vector<SDL_Joystick*>::iterator i = joysticks.begin();
150 i != joysticks.end(); ++i) {
152 SDL_JoystickClose(*i);
155 delete key_options_menu;
156 delete joystick_options_menu;
160 JoystickKeyboardController::read(const lisp::Lisp& lisp)
162 const lisp::Lisp* keymap_lisp = lisp.get_lisp("keymap");
165 lisp::ListIterator iter(keymap_lisp);
167 if(iter.item() == "map") {
170 const lisp::Lisp* map = iter.lisp();
171 map->get("key", key);
172 map->get("control", control);
173 if(key < SDLK_FIRST || key >= SDLK_LAST) {
174 log_info << "Invalid key '" << key << "' in keymap" << std::endl;
179 for(i = 0; controlNames[i] != 0; ++i) {
180 if(control == controlNames[i])
183 if(controlNames[i] == 0) {
184 log_info << "Invalid control '" << control << "' in keymap" << std::endl;
187 keymap.insert(std::make_pair((SDLKey) key, (Control) i));
189 log_info << "Invalid lisp element '" << iter.item() << "' in keymap" << std::endl;
194 const lisp::Lisp* joystick_lisp = lisp.get_lisp("joystick");
196 joystick_lisp->get("use_hat", use_hat);
197 joystick_lisp->get("axis_x", joyaxis_x);
198 joystick_lisp->get("axis_y", joyaxis_y);
199 joystick_lisp->get("dead_zone_x", dead_zone_x);
200 joystick_lisp->get("dead_zone_y", dead_zone_y);
201 lisp::ListIterator iter(joystick_lisp);
203 if(iter.item() == "map") {
206 const lisp::Lisp* map = iter.lisp();
207 map->get("button", button);
208 map->get("control", control);
209 if(button < 0 || button >= max_joybuttons) {
210 log_info << "Invalid button '" << button << "' in buttonmap" << std::endl;
215 for(i = 0; controlNames[i] != 0; ++i) {
216 if(control == controlNames[i])
219 if(controlNames[i] == 0) {
220 log_info << "Invalid control '" << control << "' in buttonmap" << std::endl;
223 reset_joybutton(button, (Control) i);
230 JoystickKeyboardController::write(lisp::Writer& writer)
232 writer.start_list("keymap");
233 for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
234 writer.start_list("map");
235 writer.write_int("key", (int) i->first);
236 writer.write_string("control", controlNames[i->second]);
237 writer.end_list("map");
239 writer.end_list("keymap");
240 writer.start_list("joystick");
241 writer.write_bool("use_hat", use_hat);
242 writer.write_int("axis_x", joyaxis_x);
243 writer.write_int("axis_y", joyaxis_y);
244 writer.write_int("dead_zone_x", dead_zone_x);
245 writer.write_int("dead_zone_y", dead_zone_y);
246 for(ButtonMap::iterator i = joy_button_map.begin(); i != joy_button_map.end();
248 writer.start_list("map");
249 writer.write_int("button", i->first);
250 writer.write_string("control", controlNames[i->second]);
251 writer.end_list("map");
253 writer.end_list("joystick");
257 JoystickKeyboardController::reset()
263 JoystickKeyboardController::process_event(const SDL_Event& event)
268 process_key_event(event);
271 case SDL_JOYAXISMOTION:
272 if(event.jaxis.axis == joyaxis_x) {
273 if(event.jaxis.value < -dead_zone_x) {
274 controls[LEFT] = true;
275 controls[RIGHT] = false;
276 } else if(event.jaxis.value > dead_zone_x) {
277 controls[LEFT] = false;
278 controls[RIGHT] = true;
280 controls[LEFT] = false;
281 controls[RIGHT] = false;
283 } else if(event.jaxis.axis == joyaxis_y) {
284 if(event.jaxis.value < -dead_zone_y) {
286 controls[DOWN] = false;
287 } else if(event.jaxis.value > dead_zone_y) {
288 controls[UP] = false;
289 controls[DOWN] = true;
291 controls[UP] = false;
292 controls[DOWN] = false;
297 case SDL_JOYHATMOTION:
301 if(event.jhat.value & SDL_HAT_UP) {
303 controls[DOWN] = false;
305 if(event.jhat.value & SDL_HAT_DOWN) {
306 controls[UP] = false;
307 controls[DOWN] = true;
309 if(event.jhat.value & SDL_HAT_LEFT) {
310 controls[LEFT] = true;
311 controls[RIGHT] = false;
313 if(event.jhat.value & SDL_HAT_RIGHT) {
314 controls[LEFT] = false;
315 controls[RIGHT] = true;
317 if(event.jhat.value == SDL_HAT_CENTERED) {
318 controls[UP] = false;
319 controls[DOWN] = false;
320 controls[LEFT] = false;
321 controls[RIGHT] = false;
325 case SDL_JOYBUTTONDOWN:
326 case SDL_JOYBUTTONUP:
328 if(wait_for_joybutton >= 0) {
329 if(event.type == SDL_JOYBUTTONUP)
332 Control c = (Control) wait_for_joybutton;
333 reset_joybutton(event.jbutton.button, c);
335 joystick_options_menu->update();
336 wait_for_joybutton = -1;
340 ButtonMap::iterator i = joy_button_map.find(event.jbutton.button);
341 if(i == joy_button_map.end()) {
342 log_debug << "Unmapped joybutton " << (int)event.jbutton.button << " pressed" << std::endl;
346 controls[i->second] = (event.type == SDL_JOYBUTTONDOWN);
356 JoystickKeyboardController::process_key_event(const SDL_Event& event)
358 KeyMap::iterator key_mapping = keymap.find(event.key.keysym.sym);
360 // if console key was pressed: toggle console
361 if ((key_mapping != keymap.end()) && (key_mapping->second == CONSOLE)) {
362 if (event.type != SDL_KEYDOWN) return;
363 Console::instance->toggle();
367 // if console is open: send key there
368 if (Console::instance->hasFocus()) {
369 process_console_key_event(event);
373 // if menu mode: send key there
374 if (Menu::current()) {
375 process_menu_key_event(event);
379 // default action: update controls
380 if(key_mapping == keymap.end()) {
381 log_debug << "Key " << event.key.keysym.sym << " is unbound" << std::endl;
384 Control control = key_mapping->second;
385 controls[control] = (event.type == SDL_KEYDOWN);
389 JoystickKeyboardController::process_console_key_event(const SDL_Event& event)
391 if (event.type != SDL_KEYDOWN) return;
393 switch (event.key.keysym.sym) {
395 Console::instance->enter();
398 Console::instance->backspace();
401 Console::instance->autocomplete();
404 Console::instance->scroll(-1);
407 Console::instance->scroll(+1);
410 Console::instance->move_cursor(-65535);
413 Console::instance->move_cursor(+65535);
416 Console::instance->show_history(-1);
419 Console::instance->show_history(+1);
422 Console::instance->move_cursor(-1);
425 Console::instance->move_cursor(+1);
428 int c = event.key.keysym.unicode;
429 if ((c >= 32) && (c <= 126)) {
430 Console::instance->input << (char)c;
437 JoystickKeyboardController::process_menu_key_event(const SDL_Event& event)
439 // wait for key mode?
440 if(wait_for_key >= 0) {
441 if(event.type == SDL_KEYUP)
444 if(event.key.keysym.sym != SDLK_ESCAPE
445 && event.key.keysym.sym != SDLK_PAUSE) {
446 reset_key(event.key.keysym.sym, (Control) wait_for_key);
449 key_options_menu->update();
453 if(wait_for_joybutton >= 0) {
454 if(event.key.keysym.sym == SDLK_ESCAPE) {
456 joystick_options_menu->update();
457 wait_for_joybutton = -1;
463 /* we use default keys when the menu is open (to avoid problems when
464 * redefining keys to invalid settings
466 switch(event.key.keysym.sym) {
482 control = MENU_SELECT;
486 control = PAUSE_MENU;
493 controls[control] = (event.type == SDL_KEYDOWN);
497 JoystickKeyboardController::reset_joybutton(int button, Control control)
499 // remove all previous mappings for that control and for that key
500 for(ButtonMap::iterator i = joy_button_map.begin();
501 i != joy_button_map.end(); /* no ++i */) {
502 if(i->second == control) {
503 ButtonMap::iterator e = i;
505 joy_button_map.erase(e);
510 ButtonMap::iterator i = joy_button_map.find(button);
511 if(i != joy_button_map.end())
512 joy_button_map.erase(i);
515 joy_button_map.insert(std::make_pair(button, control));
517 // map all unused buttons to MENU_SELECT
518 for(int b = 0; b < max_joybuttons; ++b) {
519 ButtonMap::iterator i = joy_button_map.find(b);
520 if(i != joy_button_map.end())
523 joy_button_map.insert(std::make_pair(b, MENU_SELECT));
528 JoystickKeyboardController::reset_key(SDLKey key, Control control)
530 // remove all previous mappings for that control and for that key
531 for(KeyMap::iterator i = keymap.begin();
532 i != keymap.end(); /* no ++i */) {
533 if(i->second == control) {
534 KeyMap::iterator e = i;
541 KeyMap::iterator i = keymap.find(key);
542 if(i != keymap.end())
546 keymap.insert(std::make_pair(key, control));
550 JoystickKeyboardController::reversemap_key(Control c)
552 for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
561 JoystickKeyboardController::reversemap_joybutton(Control c)
563 for(ButtonMap::iterator i = joy_button_map.begin();
564 i != joy_button_map.end(); ++i) {
573 JoystickKeyboardController::get_key_options_menu()
575 if(key_options_menu == 0) {
576 key_options_menu = new KeyboardMenu(this);
579 return key_options_menu;
583 JoystickKeyboardController::get_joystick_options_menu()
585 if(joystick_options_menu == 0) {
586 joystick_options_menu = new JoystickMenu(this);
589 return joystick_options_menu;
592 //----------------------------------------------------------------------------
594 JoystickKeyboardController::KeyboardMenu::KeyboardMenu(
595 JoystickKeyboardController* _controller)
596 : controller(_controller)
598 add_label(_("Setup Keyboard"));
600 add_controlfield(Controller::UP, _("Up"));
601 add_controlfield(Controller::DOWN, _("Down"));
602 add_controlfield(Controller::LEFT, _("Left"));
603 add_controlfield(Controller::RIGHT, _("Right"));
604 add_controlfield(Controller::JUMP, _("Jump"));
605 add_controlfield(Controller::ACTION, _("Action"));
606 add_controlfield(Controller::PEEK_LEFT, _("Peek Left"));
607 add_controlfield(Controller::PEEK_RIGHT, _("Peek Right"));
608 if (config->console_enabled) {
609 add_controlfield(Controller::CONSOLE, _("Console"));
616 JoystickKeyboardController::KeyboardMenu::~KeyboardMenu()
620 JoystickKeyboardController::KeyboardMenu::get_key_name(SDLKey key)
626 return _("Up cursor");
628 return _("Down cursor");
630 return _("Left cursor");
632 return _("Right cursor");
638 return _("Right Shift");
640 return _("Left Shift");
642 return _("Right Control");
644 return _("Left Control");
646 return _("Right Alt");
648 return _("Left Alt");
650 return SDL_GetKeyName((SDLKey) key);
655 JoystickKeyboardController::KeyboardMenu::menu_action(MenuItem* item)
657 assert(item->id >= 0 && item->id < Controller::CONTROLCOUNT);
658 item->change_input(_("Press Key"));
659 controller->wait_for_key = item->id;
663 JoystickKeyboardController::KeyboardMenu::update()
666 get_item_by_id((int) Controller::UP).change_input(get_key_name(
667 controller->reversemap_key(Controller::UP)));
668 get_item_by_id((int) Controller::DOWN).change_input(get_key_name(
669 controller->reversemap_key(Controller::DOWN)));
670 get_item_by_id((int) Controller::LEFT).change_input(get_key_name(
671 controller->reversemap_key(Controller::LEFT)));
672 get_item_by_id((int) Controller::RIGHT).change_input(get_key_name(
673 controller->reversemap_key(Controller::RIGHT)));
674 get_item_by_id((int) Controller::JUMP).change_input(get_key_name(
675 controller->reversemap_key(Controller::JUMP)));
676 get_item_by_id((int) Controller::ACTION).change_input(get_key_name(
677 controller->reversemap_key(Controller::ACTION)));
678 get_item_by_id((int) Controller::PEEK_LEFT).change_input(get_key_name(
679 controller->reversemap_key(Controller::PEEK_LEFT)));
680 get_item_by_id((int) Controller::PEEK_RIGHT).change_input(get_key_name(
681 controller->reversemap_key(Controller::PEEK_RIGHT)));
682 if (config->console_enabled) {
683 get_item_by_id((int) Controller::CONSOLE).change_input(get_key_name(
684 controller->reversemap_key(Controller::CONSOLE)));
688 //---------------------------------------------------------------------------
690 JoystickKeyboardController::JoystickMenu::JoystickMenu(
691 JoystickKeyboardController* _controller)
692 : controller(_controller)
694 add_label(_("Setup Joystick"));
696 if(controller->joysticks.size() > 0) {
697 add_controlfield(Controller::JUMP, _("Jump"));
698 add_controlfield(Controller::ACTION, _("Action"));
699 add_controlfield(Controller::PAUSE_MENU, _("Pause/Menu"));
700 add_controlfield(Controller::PEEK_LEFT, _("Peek Left"));
701 add_controlfield(Controller::PEEK_RIGHT, _("Peek Right"));
703 add_deactive(-1, _("No Joysticks found"));
710 JoystickKeyboardController::JoystickMenu::~JoystickMenu()
714 JoystickKeyboardController::JoystickMenu::get_button_name(int button)
719 std::ostringstream name;
720 name << "Button " << button;
725 JoystickKeyboardController::JoystickMenu::menu_action(MenuItem* item)
727 assert(item->id >= 0 && item->id < Controller::CONTROLCOUNT);
728 item->change_input(_("Press Button"));
729 controller->wait_for_joybutton = item->id;
733 JoystickKeyboardController::JoystickMenu::update()
735 if(controller->joysticks.size() == 0)
739 get_item_by_id((int) Controller::JUMP).change_input(get_button_name(
740 controller->reversemap_joybutton(Controller::JUMP)));
741 get_item_by_id((int) Controller::ACTION).change_input(get_button_name(
742 controller->reversemap_joybutton(Controller::ACTION)));
743 get_item_by_id((int) Controller::PAUSE_MENU).change_input(get_button_name(
744 controller->reversemap_joybutton(Controller::PAUSE_MENU)));
745 get_item_by_id((int) Controller::PEEK_LEFT).change_input(get_button_name(
746 controller->reversemap_joybutton(Controller::PEEK_LEFT)));
747 get_item_by_id((int) Controller::PEEK_RIGHT).change_input(get_button_name(
748 controller->reversemap_joybutton(Controller::PEEK_RIGHT)));