4 // Copyright (C) 2005 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
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 memset(last_keys, 0, sizeof(last_keys));
62 // initialize default keyboard map
63 keymap.insert(std::make_pair(SDLK_LEFT, LEFT));
64 keymap.insert(std::make_pair(SDLK_RIGHT, RIGHT));
65 keymap.insert(std::make_pair(SDLK_UP, UP));
66 keymap.insert(std::make_pair(SDLK_DOWN, DOWN));
67 keymap.insert(std::make_pair(SDLK_SPACE, JUMP));
68 keymap.insert(std::make_pair(SDLK_LCTRL, ACTION));
69 keymap.insert(std::make_pair(SDLK_LALT, ACTION));
70 keymap.insert(std::make_pair(SDLK_ESCAPE, PAUSE_MENU));
71 keymap.insert(std::make_pair(SDLK_p, PAUSE_MENU));
72 keymap.insert(std::make_pair(SDLK_PAUSE, PAUSE_MENU));
73 keymap.insert(std::make_pair(SDLK_RETURN, MENU_SELECT));
74 keymap.insert(std::make_pair(SDLK_KP_ENTER, MENU_SELECT));
76 int joystick_count = SDL_NumJoysticks();
79 for(int i = 0; i < joystick_count; ++i) {
80 SDL_Joystick* joystick = SDL_JoystickOpen(i);
82 if(SDL_JoystickNumButtons(joystick) < 2) {
83 msg_warning("Joystick " << i << " has less than 2 buttons");
86 if(SDL_JoystickNumAxes(joystick) < 2
87 && SDL_JoystickNumHats(joystick) == 0) {
88 msg_warning("Joystick " << i << " has less than 2 axes and no hat");
92 SDL_JoystickClose(joystick);
96 if(min_joybuttons < 0 || SDL_JoystickNumButtons(joystick) < min_joybuttons)
97 min_joybuttons = SDL_JoystickNumButtons(joystick);
98 if(SDL_JoystickNumButtons(joystick) > max_joybuttons) {
99 max_joybuttons = SDL_JoystickNumButtons(joystick);
102 joysticks.push_back(joystick);
111 joy_button_map.insert(std::make_pair(0, JUMP));
112 joy_button_map.insert(std::make_pair(1, ACTION));
113 // map the last 2 buttons to menu and pause
114 if(min_joybuttons > 2)
115 joy_button_map.insert(std::make_pair(min_joybuttons-1, PAUSE_MENU));
116 // map all remaining joystick buttons to MENU_SELECT
117 for(int i = 2; i < max_joybuttons; ++i) {
118 if(i != min_joybuttons-1)
119 joy_button_map.insert(std::make_pair(i, MENU_SELECT));
122 // some joysticks or SDL seem to produce some bogus events after being opened
123 Uint32 ticks = SDL_GetTicks();
124 while(SDL_GetTicks() - ticks < 200) {
126 SDL_PollEvent(&event);
130 JoystickKeyboardController::~JoystickKeyboardController()
132 for(std::vector<SDL_Joystick*>::iterator i = joysticks.begin();
133 i != joysticks.end(); ++i) {
135 SDL_JoystickClose(*i);
138 delete key_options_menu;
139 delete joystick_options_menu;
143 JoystickKeyboardController::read(const lisp::Lisp& lisp)
145 const lisp::Lisp* keymap_lisp = lisp.get_lisp("keymap");
148 lisp::ListIterator iter(keymap_lisp);
150 if(iter.item() == "map") {
153 const lisp::Lisp* map = iter.lisp();
154 map->get("key", key);
155 map->get("control", control);
156 if(key < SDLK_FIRST || key >= SDLK_LAST) {
157 msg_warning("Invalid key '" << key << "' in keymap");
162 for(i = 0; controlNames[i] != 0; ++i) {
163 if(control == controlNames[i])
166 if(controlNames[i] == 0) {
167 msg_warning("Invalid control '" << control << "' in keymap");
170 keymap.insert(std::make_pair((SDLKey) key, (Control) i));
172 msg_warning("Invalid lisp element '" << iter.item() << "' in keymap");
177 const lisp::Lisp* joystick_lisp = lisp.get_lisp("joystick");
179 joystick_lisp->get("use_hat", use_hat);
180 joystick_lisp->get("axis_x", joyaxis_x);
181 joystick_lisp->get("axis_y", joyaxis_y);
182 joystick_lisp->get("dead_zone_x", dead_zone_x);
183 joystick_lisp->get("dead_zone_y", dead_zone_y);
184 lisp::ListIterator iter(joystick_lisp);
186 if(iter.item() == "map") {
189 const lisp::Lisp* map = iter.lisp();
190 map->get("button", button);
191 map->get("control", control);
192 if(button < 0 || button >= max_joybuttons) {
193 msg_warning("Invalid button '" << button << "' in buttonmap");
198 for(i = 0; controlNames[i] != 0; ++i) {
199 if(control == controlNames[i])
202 if(controlNames[i] == 0) {
203 msg_warning("Invalid control '" << control << "' in buttonmap");
206 reset_joybutton(button, (Control) i);
213 JoystickKeyboardController::write(lisp::Writer& writer)
215 writer.start_list("keymap");
216 for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
217 writer.start_list("map");
218 writer.write_int("key", (int) i->first);
219 writer.write_string("control", controlNames[i->second]);
220 writer.end_list("map");
222 writer.end_list("keymap");
223 writer.start_list("joystick");
224 writer.write_bool("use_hat", use_hat);
225 writer.write_int("axis_x", joyaxis_x);
226 writer.write_int("axis_y", joyaxis_y);
227 writer.write_int("dead_zone_x", dead_zone_x);
228 writer.write_int("dead_zone_y", dead_zone_y);
229 for(ButtonMap::iterator i = joy_button_map.begin(); i != joy_button_map.end();
231 writer.start_list("map");
232 writer.write_int("button", i->first);
233 writer.write_string("control", controlNames[i->second]);
234 writer.end_list("map");
236 writer.end_list("joystick");
240 JoystickKeyboardController::reset()
243 for(size_t i = 0; i < sizeof(last_keys); ++i)
248 JoystickKeyboardController::process_event(const SDL_Event& event)
253 // remember ascii keys for cheat codes...
254 if(event.type == SDL_KEYDOWN &&
255 (event.key.keysym.unicode & 0xFF80) == 0) {
256 memmove(last_keys, last_keys+1, sizeof(last_keys)-1);
257 last_keys[sizeof(last_keys)-1] = event.key.keysym.unicode;
259 if (Console::hasFocus()) {
260 // if the Console is open, send keys there
261 char c = event.key.keysym.unicode;
262 if ((c >= 32) && (c <= 126)) {
265 if ((c == '\n') || (c == '\r')) {
266 Console::input << std::endl;
272 char c = event.key.keysym.unicode;
278 if(GameSession::current() != NULL)
279 GameSession::current()->try_cheats();
282 if(Console::hasFocus()) {
283 // console is open - ignore key
285 else if(Menu::current()) {
287 process_menu_key_event(event);
290 // normal mode, find key in keymap
291 KeyMap::iterator i = keymap.find(event.key.keysym.sym);
292 if(i == keymap.end()) {
293 msg_debug("Pressed key without mapping");
296 Control control = i->second;
297 controls[control] = event.type == SDL_KEYDOWN ? true : false;
301 case SDL_JOYAXISMOTION:
302 if(event.jaxis.axis == joyaxis_x) {
303 if(event.jaxis.value < -dead_zone_x) {
304 controls[LEFT] = true;
305 controls[RIGHT] = false;
306 } else if(event.jaxis.value > dead_zone_x) {
307 controls[LEFT] = false;
308 controls[RIGHT] = true;
310 controls[LEFT] = false;
311 controls[RIGHT] = false;
313 } else if(event.jaxis.axis == joyaxis_y) {
314 if(event.jaxis.value < -dead_zone_y) {
316 controls[DOWN] = false;
317 } else if(event.jaxis.value > dead_zone_y) {
318 controls[UP] = false;
319 controls[DOWN] = true;
321 controls[UP] = false;
322 controls[DOWN] = false;
327 case SDL_JOYHATMOTION:
331 if(event.jhat.value & SDL_HAT_UP) {
333 controls[DOWN] = false;
335 if(event.jhat.value & SDL_HAT_DOWN) {
336 controls[UP] = false;
337 controls[DOWN] = true;
339 if(event.jhat.value & SDL_HAT_LEFT) {
340 controls[LEFT] = true;
341 controls[RIGHT] = false;
343 if(event.jhat.value & SDL_HAT_RIGHT) {
344 controls[LEFT] = false;
345 controls[RIGHT] = true;
347 if(event.jhat.value == SDL_HAT_CENTERED) {
348 controls[UP] = false;
349 controls[DOWN] = false;
350 controls[LEFT] = false;
351 controls[RIGHT] = false;
355 case SDL_JOYBUTTONDOWN:
356 case SDL_JOYBUTTONUP:
358 if(wait_for_joybutton >= 0) {
359 if(event.type == SDL_JOYBUTTONUP)
362 Control c = (Control) wait_for_joybutton;
363 reset_joybutton(event.jbutton.button, c);
365 joystick_options_menu->update();
366 wait_for_joybutton = -1;
370 ButtonMap::iterator i = joy_button_map.find(event.jbutton.button);
371 if(i == joy_button_map.end()) {
372 msg_debug("Unmapped joybutton " << (int) event.jbutton.button
377 controls[i->second] =
378 event.type == SDL_JOYBUTTONDOWN ? true : false;
388 JoystickKeyboardController::process_menu_key_event(const SDL_Event& event)
390 // wait for key mode?
391 if(wait_for_key >= 0) {
392 if(event.type == SDL_KEYUP)
395 if(event.key.keysym.sym != SDLK_ESCAPE
396 && event.key.keysym.sym != SDLK_PAUSE) {
397 reset_key(event.key.keysym.sym, (Control) wait_for_key);
400 key_options_menu->update();
404 if(wait_for_joybutton >= 0) {
405 if(event.key.keysym.sym == SDLK_ESCAPE) {
407 joystick_options_menu->update();
408 wait_for_joybutton = -1;
414 /* we use default keys when the menu is open (to avoid problems when
415 * redefining keys to invalid settings
417 switch(event.key.keysym.sym) {
433 control = MENU_SELECT;
437 control = PAUSE_MENU;
444 controls[control] = event.type == SDL_KEYDOWN ? true : false;
448 JoystickKeyboardController::reset_joybutton(int button, Control control)
450 // remove all previous mappings for that control and for that key
451 for(ButtonMap::iterator i = joy_button_map.begin();
452 i != joy_button_map.end(); /* no ++i */) {
453 if(i->second == control) {
454 ButtonMap::iterator e = i;
456 joy_button_map.erase(e);
461 ButtonMap::iterator i = joy_button_map.find(button);
462 if(i != joy_button_map.end())
463 joy_button_map.erase(i);
466 joy_button_map.insert(std::make_pair(button, control));
468 // map all unused buttons to MENU_SELECT
469 for(int b = 0; b < max_joybuttons; ++b) {
470 ButtonMap::iterator i = joy_button_map.find(b);
471 if(i != joy_button_map.end())
474 joy_button_map.insert(std::make_pair(b, MENU_SELECT));
479 JoystickKeyboardController::reset_key(SDLKey key, Control control)
481 // remove all previous mappings for that control and for that key
482 for(KeyMap::iterator i = keymap.begin();
483 i != keymap.end(); /* no ++i */) {
484 if(i->second == control) {
485 KeyMap::iterator e = i;
492 KeyMap::iterator i = keymap.find(key);
493 if(i != keymap.end())
497 keymap.insert(std::make_pair(key, control));
501 JoystickKeyboardController::reversemap_key(Control c)
503 for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
512 JoystickKeyboardController::reversemap_joybutton(Control c)
514 for(ButtonMap::iterator i = joy_button_map.begin();
515 i != joy_button_map.end(); ++i) {
524 JoystickKeyboardController::get_key_options_menu()
526 if(key_options_menu == 0) {
527 key_options_menu = new KeyboardMenu(this);
530 return key_options_menu;
534 JoystickKeyboardController::get_joystick_options_menu()
536 if(joystick_options_menu == 0) {
537 joystick_options_menu = new JoystickMenu(this);
540 return joystick_options_menu;
544 JoystickKeyboardController::check_cheatcode(const std::string& cheatcode)
546 if(cheatcode.size() > sizeof(last_keys)) {
547 msg_debug("Cheat Code too long");
551 for(size_t i = 0; i < cheatcode.size(); ++i) {
552 if(last_keys[sizeof(last_keys)-1 - i] != cheatcode[cheatcode.size()-1-i])
558 //----------------------------------------------------------------------------
560 JoystickKeyboardController::KeyboardMenu::KeyboardMenu(
561 JoystickKeyboardController* _controller)
562 : controller(_controller)
564 add_label(_("Keyboard Setup"));
566 add_controlfield(Controller::UP, _("Up"));
567 add_controlfield(Controller::DOWN, _("Down"));
568 add_controlfield(Controller::LEFT, _("Left"));
569 add_controlfield(Controller::RIGHT, _("Right"));
570 add_controlfield(Controller::JUMP, _("Jump"));
571 add_controlfield(Controller::ACTION, _("Shoot/Run"));
577 JoystickKeyboardController::KeyboardMenu::~KeyboardMenu()
581 JoystickKeyboardController::KeyboardMenu::get_key_name(SDLKey key)
587 return _("Up cursor");
589 return _("Down cursor");
591 return _("Left cursor");
593 return _("Right cursor");
599 return _("Right Shift");
601 return _("Left Shift");
603 return _("Right Control");
605 return _("Left Control");
607 return _("Right Alt");
609 return _("Left Alt");
611 return SDL_GetKeyName((SDLKey) key);
616 JoystickKeyboardController::KeyboardMenu::menu_action(MenuItem* item)
618 assert(item->id >= 0 && item->id < Controller::CONTROLCOUNT);
619 item->change_input(_("Press Key"));
620 controller->wait_for_key = item->id;
624 JoystickKeyboardController::KeyboardMenu::update()
627 get_item_by_id((int) Controller::UP).change_input(get_key_name(
628 controller->reversemap_key(Controller::UP)));
629 get_item_by_id((int) Controller::DOWN).change_input(get_key_name(
630 controller->reversemap_key(Controller::DOWN)));
631 get_item_by_id((int) Controller::LEFT).change_input(get_key_name(
632 controller->reversemap_key(Controller::LEFT)));
633 get_item_by_id((int) Controller::RIGHT).change_input(get_key_name(
634 controller->reversemap_key(Controller::RIGHT)));
635 get_item_by_id((int) Controller::JUMP).change_input(get_key_name(
636 controller->reversemap_key(Controller::JUMP)));
637 get_item_by_id((int) Controller::ACTION).change_input(get_key_name(
638 controller->reversemap_key(Controller::ACTION)));
641 //---------------------------------------------------------------------------
643 JoystickKeyboardController::JoystickMenu::JoystickMenu(
644 JoystickKeyboardController* _controller)
645 : controller(_controller)
647 add_label(_("Joystick Setup"));
649 if(controller->joysticks.size() > 0) {
650 add_controlfield(Controller::JUMP, _("Jump"));
651 add_controlfield(Controller::ACTION, _("Shoot/Run"));
652 add_controlfield(Controller::PAUSE_MENU, _("Pause/Menu"));
654 add_deactive(-1, _("No Joysticks found"));
661 JoystickKeyboardController::JoystickMenu::~JoystickMenu()
665 JoystickKeyboardController::JoystickMenu::get_button_name(int button)
670 std::ostringstream name;
671 name << "Button " << button;
676 JoystickKeyboardController::JoystickMenu::menu_action(MenuItem* item)
678 assert(item->id >= 0 && item->id < Controller::CONTROLCOUNT);
679 item->change_input(_("Press Button"));
680 controller->wait_for_joybutton = item->id;
684 JoystickKeyboardController::JoystickMenu::update()
686 if(controller->joysticks.size() == 0)
690 get_item_by_id((int) Controller::JUMP).change_input(get_button_name(
691 controller->reversemap_joybutton(Controller::JUMP)));
692 get_item_by_id((int) Controller::ACTION).change_input(get_button_name(
693 controller->reversemap_joybutton(Controller::ACTION)));
694 get_item_by_id((int) Controller::PAUSE_MENU).change_input(get_button_name(
695 controller->reversemap_joybutton(Controller::PAUSE_MENU)));