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"
24 #include "gui/menu.hpp"
25 #include "gettext.hpp"
26 #include "lisp/lisp.hpp"
27 #include "lisp/list_iterator.hpp"
28 #include "game_session.hpp"
30 class JoystickKeyboardController::JoystickMenu : public Menu
33 JoystickMenu(JoystickKeyboardController* controller);
34 virtual ~JoystickMenu();
37 std::string get_button_name(int button);
38 virtual void menu_action(MenuItem* item);
39 JoystickKeyboardController* controller;
42 class JoystickKeyboardController::KeyboardMenu : public Menu
45 KeyboardMenu(JoystickKeyboardController* controller);
49 std::string get_key_name(SDLKey key);
50 virtual void menu_action(MenuItem* item);
51 JoystickKeyboardController* controller;
54 JoystickKeyboardController::JoystickKeyboardController()
55 : wait_for_key(-1), wait_for_joybutton(-1), key_options_menu(0),
56 joystick_options_menu(0)
58 memset(last_keys, 0, sizeof(last_keys));
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));
74 int joystick_count = SDL_NumJoysticks();
77 for(int i = 0; i < joystick_count; ++i) {
78 SDL_Joystick* joystick = SDL_JoystickOpen(i);
80 if(SDL_JoystickNumButtons(joystick) < 2) {
81 std::cerr << "Joystick " << i << " has less than 2 buttons.\n";
84 if(SDL_JoystickNumAxes(joystick) < 2
85 && SDL_JoystickNumHats(joystick) == 0) {
86 std::cerr << "Joystick " << i << " has less than 2 axes and no hat.\n";
90 SDL_JoystickClose(joystick);
94 if(min_joybuttons < 0 || SDL_JoystickNumButtons(joystick) < min_joybuttons)
95 min_joybuttons = SDL_JoystickNumButtons(joystick);
96 if(SDL_JoystickNumButtons(joystick) > max_joybuttons) {
97 max_joybuttons = SDL_JoystickNumButtons(joystick);
100 joysticks.push_back(joystick);
109 joy_button_map.insert(std::make_pair(0, JUMP));
110 joy_button_map.insert(std::make_pair(1, ACTION));
111 // map the last 2 buttons to menu and pause
112 if(min_joybuttons > 2)
113 joy_button_map.insert(std::make_pair(min_joybuttons-1, PAUSE_MENU));
114 // map all remaining joystick buttons to MENU_SELECT
115 for(int i = 2; i < max_joybuttons; ++i) {
116 if(i != min_joybuttons-1)
117 joy_button_map.insert(std::make_pair(i, MENU_SELECT));
120 // some joysticks or SDL seem to produce some bogus events after being opened
121 Uint32 ticks = SDL_GetTicks();
122 while(SDL_GetTicks() - ticks < 200) {
124 SDL_PollEvent(&event);
128 JoystickKeyboardController::~JoystickKeyboardController()
130 for(std::vector<SDL_Joystick*>::iterator i = joysticks.begin();
131 i != joysticks.end(); ++i) {
133 SDL_JoystickClose(*i);
136 delete key_options_menu;
137 delete joystick_options_menu;
141 JoystickKeyboardController::read(const lisp::Lisp& lisp)
143 const lisp::Lisp* keymap_lisp = lisp.get_lisp("keymap");
146 lisp::ListIterator iter(keymap_lisp);
148 if(iter.item() == "map") {
151 const lisp::Lisp* map = iter.lisp();
152 map->get("key", key);
153 map->get("control", control);
154 if(key < SDLK_FIRST || key >= SDLK_LAST) {
155 std::cerr << "Invalid key '" << key << "' in keymap.\n";
160 for(i = 0; controlNames[i] != 0; ++i) {
161 if(control == controlNames[i])
164 if(controlNames[i] == 0) {
165 std::cerr << "Invalid control '" << control << "' in keymap.\n";
168 keymap.insert(std::make_pair((SDLKey) key, (Control) i));
170 std::cerr << "Invalid lisp element '" << iter.item() << "' in keymap.\n";
175 const lisp::Lisp* joystick_lisp = lisp.get_lisp("joystick");
177 joystick_lisp->get("use_hat", use_hat);
178 joystick_lisp->get("axis_x", joyaxis_x);
179 joystick_lisp->get("axis_y", joyaxis_y);
180 joystick_lisp->get("dead_zone_x", dead_zone_x);
181 joystick_lisp->get("dead_zone_y", dead_zone_y);
182 lisp::ListIterator iter(joystick_lisp);
184 if(iter.item() == "map") {
187 const lisp::Lisp* map = iter.lisp();
188 map->get("button", button);
189 map->get("control", control);
190 if(button < 0 || button >= max_joybuttons) {
191 std::cerr << "Invalid button '" << button << "' in buttonmap.\n";
196 for(i = 0; controlNames[i] != 0; ++i) {
197 if(control == controlNames[i])
200 if(controlNames[i] == 0) {
201 std::cerr << "Invalid control '" << control << "' in buttonmap.\n";
204 reset_joybutton(button, (Control) i);
211 JoystickKeyboardController::write(lisp::Writer& writer)
213 writer.start_list("keymap");
214 for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
215 writer.start_list("map");
216 writer.write_int("key", (int) i->first);
217 writer.write_string("control", controlNames[i->second]);
218 writer.end_list("map");
220 writer.end_list("keymap");
221 writer.start_list("joystick");
222 writer.write_bool("use_hat", use_hat);
223 writer.write_int("axis_x", joyaxis_x);
224 writer.write_int("axis_y", joyaxis_y);
225 writer.write_int("dead_zone_x", dead_zone_x);
226 writer.write_int("dead_zone_y", dead_zone_y);
227 for(ButtonMap::iterator i = joy_button_map.begin(); i != joy_button_map.end();
229 writer.start_list("map");
230 writer.write_int("button", i->first);
231 writer.write_string("control", controlNames[i->second]);
232 writer.end_list("map");
234 writer.end_list("joystick");
238 JoystickKeyboardController::reset()
241 for(size_t i = 0; i < sizeof(last_keys); ++i)
246 JoystickKeyboardController::process_event(const SDL_Event& event)
251 // remember ascii keys for cheat codes...
252 if(event.type == SDL_KEYDOWN &&
253 (event.key.keysym.unicode & 0xFF80) == 0) {
254 memmove(last_keys, last_keys+1, sizeof(last_keys)-1);
255 last_keys[sizeof(last_keys)-1] = event.key.keysym.unicode;
256 if(GameSession::current() != NULL)
257 GameSession::current()->try_cheats();
261 if(Menu::current()) { // menu mode
262 process_menu_key_event(event);
265 // normal mode, find key in keymap
266 KeyMap::iterator i = keymap.find(event.key.keysym.sym);
267 if(i == keymap.end()) {
269 std::cerr << "Pressed key without mapping.\n";
273 Control control = i->second;
274 controls[control] = event.type == SDL_KEYDOWN ? true : false;
278 case SDL_JOYAXISMOTION:
279 if(event.jaxis.axis == joyaxis_x) {
280 if(event.jaxis.value < -dead_zone_x) {
281 controls[LEFT] = true;
282 controls[RIGHT] = false;
283 } else if(event.jaxis.value > dead_zone_x) {
284 controls[LEFT] = false;
285 controls[RIGHT] = true;
287 controls[LEFT] = false;
288 controls[RIGHT] = false;
290 } else if(event.jaxis.axis == joyaxis_y) {
291 if(event.jaxis.value < -dead_zone_y) {
293 controls[DOWN] = false;
294 } else if(event.jaxis.value > dead_zone_y) {
295 controls[UP] = false;
296 controls[DOWN] = true;
298 controls[UP] = false;
299 controls[DOWN] = false;
304 case SDL_JOYHATMOTION:
308 if(event.jhat.value & SDL_HAT_UP) {
310 controls[DOWN] = false;
312 if(event.jhat.value & SDL_HAT_DOWN) {
313 controls[UP] = false;
314 controls[DOWN] = true;
316 if(event.jhat.value & SDL_HAT_LEFT) {
317 controls[LEFT] = true;
318 controls[RIGHT] = false;
320 if(event.jhat.value & SDL_HAT_RIGHT) {
321 controls[LEFT] = false;
322 controls[RIGHT] = true;
324 if(event.jhat.value == SDL_HAT_CENTERED) {
325 controls[UP] = false;
326 controls[DOWN] = false;
327 controls[LEFT] = false;
328 controls[RIGHT] = false;
332 case SDL_JOYBUTTONDOWN:
333 case SDL_JOYBUTTONUP:
335 if(wait_for_joybutton >= 0) {
336 if(event.type == SDL_JOYBUTTONUP)
339 Control c = (Control) wait_for_joybutton;
340 reset_joybutton(event.jbutton.button, c);
342 joystick_options_menu->update();
343 wait_for_joybutton = -1;
347 ButtonMap::iterator i = joy_button_map.find(event.jbutton.button);
348 if(i == joy_button_map.end()) {
350 std::cerr << "Unmapped joybutton " << (int) event.jbutton.button
356 controls[i->second] =
357 event.type == SDL_JOYBUTTONDOWN ? true : false;
367 JoystickKeyboardController::process_menu_key_event(const SDL_Event& event)
369 // wait for key mode?
370 if(wait_for_key >= 0) {
371 if(event.type == SDL_KEYUP)
374 if(event.key.keysym.sym != SDLK_ESCAPE
375 && event.key.keysym.sym != SDLK_PAUSE) {
376 reset_key(event.key.keysym.sym, (Control) wait_for_key);
379 key_options_menu->update();
383 if(wait_for_joybutton >= 0) {
384 if(event.key.keysym.sym == SDLK_ESCAPE) {
386 joystick_options_menu->update();
387 wait_for_joybutton = -1;
393 /* we use default keys when the menu is open (to avoid problems when
394 * redefining keys to invalid settings
396 switch(event.key.keysym.sym) {
412 control = MENU_SELECT;
416 control = PAUSE_MENU;
423 controls[control] = event.type == SDL_KEYDOWN ? true : false;
427 JoystickKeyboardController::reset_joybutton(int button, Control control)
429 // remove all previous mappings for that control and for that key
430 for(ButtonMap::iterator i = joy_button_map.begin();
431 i != joy_button_map.end(); /* no ++i */) {
432 if(i->second == control) {
433 ButtonMap::iterator e = i;
435 joy_button_map.erase(e);
440 ButtonMap::iterator i = joy_button_map.find(button);
441 if(i != joy_button_map.end())
442 joy_button_map.erase(i);
445 joy_button_map.insert(std::make_pair(button, control));
447 // map all unused buttons to MENU_SELECT
448 for(int b = 0; b < max_joybuttons; ++b) {
449 ButtonMap::iterator i = joy_button_map.find(b);
450 if(i != joy_button_map.end())
453 joy_button_map.insert(std::make_pair(b, MENU_SELECT));
458 JoystickKeyboardController::reset_key(SDLKey key, Control control)
460 // remove all previous mappings for that control and for that key
461 for(KeyMap::iterator i = keymap.begin();
462 i != keymap.end(); /* no ++i */) {
463 if(i->second == control) {
464 KeyMap::iterator e = i;
471 KeyMap::iterator i = keymap.find(key);
472 if(i != keymap.end())
476 keymap.insert(std::make_pair(key, control));
480 JoystickKeyboardController::reversemap_key(Control c)
482 for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
491 JoystickKeyboardController::reversemap_joybutton(Control c)
493 for(ButtonMap::iterator i = joy_button_map.begin();
494 i != joy_button_map.end(); ++i) {
503 JoystickKeyboardController::get_key_options_menu()
505 if(key_options_menu == 0) {
506 key_options_menu = new KeyboardMenu(this);
509 return key_options_menu;
513 JoystickKeyboardController::get_joystick_options_menu()
515 if(joystick_options_menu == 0) {
516 joystick_options_menu = new JoystickMenu(this);
519 return joystick_options_menu;
523 JoystickKeyboardController::check_cheatcode(const std::string& cheatcode)
525 if(cheatcode.size() > sizeof(last_keys)) {
527 std::cerr << "Cheat Code too long.\n";
532 for(size_t i = 0; i < cheatcode.size(); ++i) {
533 if(last_keys[sizeof(last_keys)-1 - i] != cheatcode[cheatcode.size()-1-i])
539 //----------------------------------------------------------------------------
541 JoystickKeyboardController::KeyboardMenu::KeyboardMenu(
542 JoystickKeyboardController* _controller)
543 : controller(_controller)
545 add_label(_("Keyboard Setup"));
547 add_controlfield(Controller::UP, _("Up"));
548 add_controlfield(Controller::DOWN, _("Down"));
549 add_controlfield(Controller::LEFT, _("Left"));
550 add_controlfield(Controller::RIGHT, _("Right"));
551 add_controlfield(Controller::JUMP, _("Jump"));
552 add_controlfield(Controller::ACTION, _("Shoot/Run"));
558 JoystickKeyboardController::KeyboardMenu::~KeyboardMenu()
562 JoystickKeyboardController::KeyboardMenu::get_key_name(SDLKey key)
568 return _("Up cursor");
570 return _("Down cursor");
572 return _("Left cursor");
574 return _("Right cursor");
580 return _("Right Shift");
582 return _("Left Shift");
584 return _("Right Control");
586 return _("Left Control");
588 return _("Right Alt");
590 return _("Left Alt");
592 return SDL_GetKeyName((SDLKey) key);
597 JoystickKeyboardController::KeyboardMenu::menu_action(MenuItem* item)
599 assert(item->id >= 0 && item->id < Controller::CONTROLCOUNT);
600 item->change_input(_("Press Key"));
601 controller->wait_for_key = item->id;
605 JoystickKeyboardController::KeyboardMenu::update()
608 get_item_by_id((int) Controller::UP).change_input(get_key_name(
609 controller->reversemap_key(Controller::UP)));
610 get_item_by_id((int) Controller::DOWN).change_input(get_key_name(
611 controller->reversemap_key(Controller::DOWN)));
612 get_item_by_id((int) Controller::LEFT).change_input(get_key_name(
613 controller->reversemap_key(Controller::LEFT)));
614 get_item_by_id((int) Controller::RIGHT).change_input(get_key_name(
615 controller->reversemap_key(Controller::RIGHT)));
616 get_item_by_id((int) Controller::JUMP).change_input(get_key_name(
617 controller->reversemap_key(Controller::JUMP)));
618 get_item_by_id((int) Controller::ACTION).change_input(get_key_name(
619 controller->reversemap_key(Controller::ACTION)));
622 //---------------------------------------------------------------------------
624 JoystickKeyboardController::JoystickMenu::JoystickMenu(
625 JoystickKeyboardController* _controller)
626 : controller(_controller)
628 add_label(_("Joystick Setup"));
630 if(controller->joysticks.size() > 0) {
631 add_controlfield(Controller::JUMP, _("Jump"));
632 add_controlfield(Controller::ACTION, _("Shoot/Run"));
633 add_controlfield(Controller::PAUSE_MENU, _("Pause/Menu"));
635 add_deactive(-1, _("No Joysticks found"));
642 JoystickKeyboardController::JoystickMenu::~JoystickMenu()
646 JoystickKeyboardController::JoystickMenu::get_button_name(int button)
651 std::ostringstream name;
652 name << "Button " << button;
657 JoystickKeyboardController::JoystickMenu::menu_action(MenuItem* item)
659 assert(item->id >= 0 && item->id < Controller::CONTROLCOUNT);
660 item->change_input(_("Press Button"));
661 controller->wait_for_joybutton = item->id;
665 JoystickKeyboardController::JoystickMenu::update()
667 if(controller->joysticks.size() == 0)
671 get_item_by_id((int) Controller::JUMP).change_input(get_button_name(
672 controller->reversemap_joybutton(Controller::JUMP)));
673 get_item_by_id((int) Controller::ACTION).change_input(get_button_name(
674 controller->reversemap_joybutton(Controller::ACTION)));
675 get_item_by_id((int) Controller::PAUSE_MENU).change_input(get_button_name(
676 controller->reversemap_joybutton(Controller::PAUSE_MENU)));