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"
32 class JoystickKeyboardController::JoystickMenu : public Menu
35 JoystickMenu(JoystickKeyboardController* controller);
36 virtual ~JoystickMenu();
39 std::string get_button_name(int button);
40 virtual void menu_action(MenuItem* item);
41 JoystickKeyboardController* controller;
44 class JoystickKeyboardController::KeyboardMenu : public Menu
47 KeyboardMenu(JoystickKeyboardController* controller);
51 std::string get_key_name(SDLKey key);
52 virtual void menu_action(MenuItem* item);
53 JoystickKeyboardController* controller;
56 JoystickKeyboardController::JoystickKeyboardController()
57 : wait_for_key(-1), wait_for_joybutton(-1), key_options_menu(0),
58 joystick_options_menu(0)
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 keymap.insert(std::make_pair(SDLK_CARET, CONSOLE));
75 int joystick_count = SDL_NumJoysticks();
78 for(int i = 0; i < joystick_count; ++i) {
79 SDL_Joystick* joystick = SDL_JoystickOpen(i);
81 if(SDL_JoystickNumButtons(joystick) < 2) {
82 log_warning << "Joystick " << i << " has less than 2 buttons" << std::endl;
85 if(SDL_JoystickNumAxes(joystick) < 2
86 && SDL_JoystickNumHats(joystick) == 0) {
87 log_warning << "Joystick " << i << " has less than 2 axes and no hat" << std::endl;
91 SDL_JoystickClose(joystick);
95 if(min_joybuttons < 0 || SDL_JoystickNumButtons(joystick) < min_joybuttons)
96 min_joybuttons = SDL_JoystickNumButtons(joystick);
97 if(SDL_JoystickNumButtons(joystick) > max_joybuttons) {
98 max_joybuttons = SDL_JoystickNumButtons(joystick);
101 joysticks.push_back(joystick);
110 joy_button_map.insert(std::make_pair(0, JUMP));
111 joy_button_map.insert(std::make_pair(1, ACTION));
112 // map the last 2 buttons to menu and pause
113 if(min_joybuttons > 2)
114 joy_button_map.insert(std::make_pair(min_joybuttons-1, PAUSE_MENU));
115 // map all remaining joystick buttons to MENU_SELECT
116 for(int i = 2; i < max_joybuttons; ++i) {
117 if(i != min_joybuttons-1)
118 joy_button_map.insert(std::make_pair(i, MENU_SELECT));
121 // some joysticks or SDL seem to produce some bogus events after being opened
122 Uint32 ticks = SDL_GetTicks();
123 while(SDL_GetTicks() - ticks < 200) {
125 SDL_PollEvent(&event);
129 JoystickKeyboardController::~JoystickKeyboardController()
131 for(std::vector<SDL_Joystick*>::iterator i = joysticks.begin();
132 i != joysticks.end(); ++i) {
134 SDL_JoystickClose(*i);
137 delete key_options_menu;
138 delete joystick_options_menu;
142 JoystickKeyboardController::read(const lisp::Lisp& lisp)
144 const lisp::Lisp* keymap_lisp = lisp.get_lisp("keymap");
147 lisp::ListIterator iter(keymap_lisp);
149 if(iter.item() == "map") {
152 const lisp::Lisp* map = iter.lisp();
153 map->get("key", key);
154 map->get("control", control);
155 if(key < SDLK_FIRST || key >= SDLK_LAST) {
156 log_warning << "Invalid key '" << key << "' in keymap" << std::endl;
161 for(i = 0; controlNames[i] != 0; ++i) {
162 if(control == controlNames[i])
165 if(controlNames[i] == 0) {
166 log_warning << "Invalid control '" << control << "' in keymap" << std::endl;
169 keymap.insert(std::make_pair((SDLKey) key, (Control) i));
171 log_warning << "Invalid lisp element '" << iter.item() << "' in keymap" << std::endl;
176 const lisp::Lisp* joystick_lisp = lisp.get_lisp("joystick");
178 joystick_lisp->get("use_hat", use_hat);
179 joystick_lisp->get("axis_x", joyaxis_x);
180 joystick_lisp->get("axis_y", joyaxis_y);
181 joystick_lisp->get("dead_zone_x", dead_zone_x);
182 joystick_lisp->get("dead_zone_y", dead_zone_y);
183 lisp::ListIterator iter(joystick_lisp);
185 if(iter.item() == "map") {
188 const lisp::Lisp* map = iter.lisp();
189 map->get("button", button);
190 map->get("control", control);
191 if(button < 0 || button >= max_joybuttons) {
192 log_warning << "Invalid button '" << button << "' in buttonmap" << std::endl;
197 for(i = 0; controlNames[i] != 0; ++i) {
198 if(control == controlNames[i])
201 if(controlNames[i] == 0) {
202 log_warning << "Invalid control '" << control << "' in buttonmap" << std::endl;
205 reset_joybutton(button, (Control) i);
212 JoystickKeyboardController::write(lisp::Writer& writer)
214 writer.start_list("keymap");
215 for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
216 writer.start_list("map");
217 writer.write_int("key", (int) i->first);
218 writer.write_string("control", controlNames[i->second]);
219 writer.end_list("map");
221 writer.end_list("keymap");
222 writer.start_list("joystick");
223 writer.write_bool("use_hat", use_hat);
224 writer.write_int("axis_x", joyaxis_x);
225 writer.write_int("axis_y", joyaxis_y);
226 writer.write_int("dead_zone_x", dead_zone_x);
227 writer.write_int("dead_zone_y", dead_zone_y);
228 for(ButtonMap::iterator i = joy_button_map.begin(); i != joy_button_map.end();
230 writer.start_list("map");
231 writer.write_int("button", i->first);
232 writer.write_string("control", controlNames[i->second]);
233 writer.end_list("map");
235 writer.end_list("joystick");
239 JoystickKeyboardController::reset()
245 JoystickKeyboardController::process_event(const SDL_Event& event)
250 process_key_event(event);
253 case SDL_JOYAXISMOTION:
254 if(event.jaxis.axis == joyaxis_x) {
255 if(event.jaxis.value < -dead_zone_x) {
256 controls[LEFT] = true;
257 controls[RIGHT] = false;
258 } else if(event.jaxis.value > dead_zone_x) {
259 controls[LEFT] = false;
260 controls[RIGHT] = true;
262 controls[LEFT] = false;
263 controls[RIGHT] = false;
265 } else if(event.jaxis.axis == joyaxis_y) {
266 if(event.jaxis.value < -dead_zone_y) {
268 controls[DOWN] = false;
269 } else if(event.jaxis.value > dead_zone_y) {
270 controls[UP] = false;
271 controls[DOWN] = true;
273 controls[UP] = false;
274 controls[DOWN] = false;
279 case SDL_JOYHATMOTION:
283 if(event.jhat.value & SDL_HAT_UP) {
285 controls[DOWN] = false;
287 if(event.jhat.value & SDL_HAT_DOWN) {
288 controls[UP] = false;
289 controls[DOWN] = true;
291 if(event.jhat.value & SDL_HAT_LEFT) {
292 controls[LEFT] = true;
293 controls[RIGHT] = false;
295 if(event.jhat.value & SDL_HAT_RIGHT) {
296 controls[LEFT] = false;
297 controls[RIGHT] = true;
299 if(event.jhat.value == SDL_HAT_CENTERED) {
300 controls[UP] = false;
301 controls[DOWN] = false;
302 controls[LEFT] = false;
303 controls[RIGHT] = false;
307 case SDL_JOYBUTTONDOWN:
308 case SDL_JOYBUTTONUP:
310 if(wait_for_joybutton >= 0) {
311 if(event.type == SDL_JOYBUTTONUP)
314 Control c = (Control) wait_for_joybutton;
315 reset_joybutton(event.jbutton.button, c);
317 joystick_options_menu->update();
318 wait_for_joybutton = -1;
322 ButtonMap::iterator i = joy_button_map.find(event.jbutton.button);
323 if(i == joy_button_map.end()) {
324 log_debug << "Unmapped joybutton " << (int)event.jbutton.button << " pressed" << std::endl;
328 controls[i->second] =
329 event.type == SDL_JOYBUTTONDOWN ? true : false;
339 JoystickKeyboardController::process_key_event(const SDL_Event& event)
341 KeyMap::iterator key_mapping = keymap.find(event.key.keysym.sym);
343 // if console key was pressed: toggle console
344 if ((key_mapping != keymap.end()) && (key_mapping->second == CONSOLE)) {
345 if (event.type != SDL_KEYDOWN) return;
346 Console::instance->toggle();
350 // if console is open: send key there
351 if (Console::instance->hasFocus()) {
352 process_console_key_event(event);
356 // if menu mode: send key there
357 if (Menu::current()) {
358 process_menu_key_event(event);
362 // default action: update controls
363 if(key_mapping == keymap.end()) {
364 log_debug << "Key " << event.key.keysym.sym << " is unbound" << std::endl;
367 Control control = key_mapping->second;
368 controls[control] = event.type == SDL_KEYDOWN ? true : false;
372 JoystickKeyboardController::process_console_key_event(const SDL_Event& event)
374 if (event.type != SDL_KEYDOWN) return;
376 switch (event.key.keysym.sym) {
378 Console::instance->input << std::endl;
381 Console::instance->backspace();
384 Console::instance->autocomplete();
387 Console::instance->scroll(-1);
390 Console::instance->scroll(+1);
393 Console::instance->scroll(+65535);
396 Console::instance->show_history(-1);
399 Console::instance->show_history(+1);
402 int c = event.key.keysym.unicode;
403 if ((c >= 32) && (c <= 126)) {
404 Console::instance->input << (char)c;
411 JoystickKeyboardController::process_menu_key_event(const SDL_Event& event)
413 // wait for key mode?
414 if(wait_for_key >= 0) {
415 if(event.type == SDL_KEYUP)
418 if(event.key.keysym.sym != SDLK_ESCAPE
419 && event.key.keysym.sym != SDLK_PAUSE) {
420 reset_key(event.key.keysym.sym, (Control) wait_for_key);
423 key_options_menu->update();
427 if(wait_for_joybutton >= 0) {
428 if(event.key.keysym.sym == SDLK_ESCAPE) {
430 joystick_options_menu->update();
431 wait_for_joybutton = -1;
437 /* we use default keys when the menu is open (to avoid problems when
438 * redefining keys to invalid settings
440 switch(event.key.keysym.sym) {
456 control = MENU_SELECT;
460 control = PAUSE_MENU;
467 controls[control] = event.type == SDL_KEYDOWN ? true : false;
471 JoystickKeyboardController::reset_joybutton(int button, Control control)
473 // remove all previous mappings for that control and for that key
474 for(ButtonMap::iterator i = joy_button_map.begin();
475 i != joy_button_map.end(); /* no ++i */) {
476 if(i->second == control) {
477 ButtonMap::iterator e = i;
479 joy_button_map.erase(e);
484 ButtonMap::iterator i = joy_button_map.find(button);
485 if(i != joy_button_map.end())
486 joy_button_map.erase(i);
489 joy_button_map.insert(std::make_pair(button, control));
491 // map all unused buttons to MENU_SELECT
492 for(int b = 0; b < max_joybuttons; ++b) {
493 ButtonMap::iterator i = joy_button_map.find(b);
494 if(i != joy_button_map.end())
497 joy_button_map.insert(std::make_pair(b, MENU_SELECT));
502 JoystickKeyboardController::reset_key(SDLKey key, Control control)
504 // remove all previous mappings for that control and for that key
505 for(KeyMap::iterator i = keymap.begin();
506 i != keymap.end(); /* no ++i */) {
507 if(i->second == control) {
508 KeyMap::iterator e = i;
515 KeyMap::iterator i = keymap.find(key);
516 if(i != keymap.end())
520 keymap.insert(std::make_pair(key, control));
524 JoystickKeyboardController::reversemap_key(Control c)
526 for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
535 JoystickKeyboardController::reversemap_joybutton(Control c)
537 for(ButtonMap::iterator i = joy_button_map.begin();
538 i != joy_button_map.end(); ++i) {
547 JoystickKeyboardController::get_key_options_menu()
549 if(key_options_menu == 0) {
550 key_options_menu = new KeyboardMenu(this);
553 return key_options_menu;
557 JoystickKeyboardController::get_joystick_options_menu()
559 if(joystick_options_menu == 0) {
560 joystick_options_menu = new JoystickMenu(this);
563 return joystick_options_menu;
566 //----------------------------------------------------------------------------
568 JoystickKeyboardController::KeyboardMenu::KeyboardMenu(
569 JoystickKeyboardController* _controller)
570 : controller(_controller)
572 add_label(_("Keyboard Setup"));
574 add_controlfield(Controller::UP, _("Up"));
575 add_controlfield(Controller::DOWN, _("Down"));
576 add_controlfield(Controller::LEFT, _("Left"));
577 add_controlfield(Controller::RIGHT, _("Right"));
578 add_controlfield(Controller::JUMP, _("Jump"));
579 add_controlfield(Controller::ACTION, _("Action"));
585 JoystickKeyboardController::KeyboardMenu::~KeyboardMenu()
589 JoystickKeyboardController::KeyboardMenu::get_key_name(SDLKey key)
595 return _("Up cursor");
597 return _("Down cursor");
599 return _("Left cursor");
601 return _("Right cursor");
607 return _("Right Shift");
609 return _("Left Shift");
611 return _("Right Control");
613 return _("Left Control");
615 return _("Right Alt");
617 return _("Left Alt");
619 return SDL_GetKeyName((SDLKey) key);
624 JoystickKeyboardController::KeyboardMenu::menu_action(MenuItem* item)
626 assert(item->id >= 0 && item->id < Controller::CONTROLCOUNT);
627 item->change_input(_("Press Key"));
628 controller->wait_for_key = item->id;
632 JoystickKeyboardController::KeyboardMenu::update()
635 get_item_by_id((int) Controller::UP).change_input(get_key_name(
636 controller->reversemap_key(Controller::UP)));
637 get_item_by_id((int) Controller::DOWN).change_input(get_key_name(
638 controller->reversemap_key(Controller::DOWN)));
639 get_item_by_id((int) Controller::LEFT).change_input(get_key_name(
640 controller->reversemap_key(Controller::LEFT)));
641 get_item_by_id((int) Controller::RIGHT).change_input(get_key_name(
642 controller->reversemap_key(Controller::RIGHT)));
643 get_item_by_id((int) Controller::JUMP).change_input(get_key_name(
644 controller->reversemap_key(Controller::JUMP)));
645 get_item_by_id((int) Controller::ACTION).change_input(get_key_name(
646 controller->reversemap_key(Controller::ACTION)));
649 //---------------------------------------------------------------------------
651 JoystickKeyboardController::JoystickMenu::JoystickMenu(
652 JoystickKeyboardController* _controller)
653 : controller(_controller)
655 add_label(_("Joystick Setup"));
657 if(controller->joysticks.size() > 0) {
658 add_controlfield(Controller::JUMP, _("Jump"));
659 add_controlfield(Controller::ACTION, _("Action"));
660 add_controlfield(Controller::PAUSE_MENU, _("Pause/Menu"));
662 add_deactive(-1, _("No Joysticks found"));
669 JoystickKeyboardController::JoystickMenu::~JoystickMenu()
673 JoystickKeyboardController::JoystickMenu::get_button_name(int button)
678 std::ostringstream name;
679 name << "Button " << button;
684 JoystickKeyboardController::JoystickMenu::menu_action(MenuItem* item)
686 assert(item->id >= 0 && item->id < Controller::CONTROLCOUNT);
687 item->change_input(_("Press Button"));
688 controller->wait_for_joybutton = item->id;
692 JoystickKeyboardController::JoystickMenu::update()
694 if(controller->joysticks.size() == 0)
698 get_item_by_id((int) Controller::JUMP).change_input(get_button_name(
699 controller->reversemap_joybutton(Controller::JUMP)));
700 get_item_by_id((int) Controller::ACTION).change_input(get_button_name(
701 controller->reversemap_joybutton(Controller::ACTION)));
702 get_item_by_id((int) Controller::PAUSE_MENU).change_input(get_button_name(
703 controller->reversemap_joybutton(Controller::PAUSE_MENU)));