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
24 #include "joystickkeyboardcontroller.h"
26 #include "app/gettext.h"
27 #include "lisp/lisp.h"
28 #include "lisp/list_iterator.h"
29 #include "game_session.h"
31 class JoystickKeyboardController::JoystickMenu : public Menu
34 JoystickMenu(JoystickKeyboardController* controller);
35 virtual ~JoystickMenu();
38 std::string get_button_name(int button);
39 virtual void menu_action(MenuItem* item);
40 JoystickKeyboardController* controller;
43 class JoystickKeyboardController::KeyboardMenu : public Menu
46 KeyboardMenu(JoystickKeyboardController* controller);
50 std::string get_key_name(SDLKey key);
51 virtual void menu_action(MenuItem* item);
52 JoystickKeyboardController* controller;
55 JoystickKeyboardController::JoystickKeyboardController()
56 : wait_for_key(-1), wait_for_joybutton(-1)
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 joystick_count = SDL_NumJoysticks();
78 std::cout << "Found " << joystick_count << " joysticks.\n";
80 for(int i = 0; i < joystick_count; ++i) {
81 SDL_Joystick* joystick = SDL_JoystickOpen(i);
83 if(SDL_JoystickNumButtons(joystick) < 2) {
84 std::cerr << "Joystick " << i << " has less than 2 buttons.\n";
87 if(SDL_JoystickNumAxes(joystick) < 2
88 && SDL_JoystickNumHats(joystick) == 0) {
89 std::cerr << "Joystick " << i << " has less than 2 axes and no hat.\n";
93 SDL_JoystickClose(joystick);
94 joysticks.push_back(0);
95 joystick_names.push_back("");
99 if(min_joybuttons < 0 || SDL_JoystickNumButtons(joystick) < min_joybuttons)
100 min_joybuttons = SDL_JoystickNumButtons(joystick);
101 if(SDL_JoystickNumButtons(joystick) > max_joybuttons) {
102 max_joybuttons = SDL_JoystickNumButtons(joystick);
105 joystick_names.push_back(SDL_JoystickName(i));
106 joysticks.push_back(joystick);
115 joy_button_map.insert(std::make_pair(0, JUMP));
116 joy_button_map.insert(std::make_pair(1, ACTION));
117 // map the last 2 buttons to menu and pause
118 if(min_joybuttons > 2)
119 joy_button_map.insert(std::make_pair(min_joybuttons-1, PAUSE_MENU));
120 // map all remaining joystick buttons to MENU_SELECT
121 for(int i = 2; i < max_joybuttons; ++i) {
122 if(i != min_joybuttons-1)
123 joy_button_map.insert(std::make_pair(i, MENU_SELECT));
127 JoystickKeyboardController::~JoystickKeyboardController()
129 for(std::vector<SDL_Joystick*>::iterator i = joysticks.begin();
130 i != joysticks.end(); ++i) {
132 SDL_JoystickClose(*i);
135 delete key_options_menu;
136 delete joystick_options_menu;
140 JoystickKeyboardController::read(const lisp::Lisp& lisp)
142 const lisp::Lisp* keymap_lisp = lisp.get_lisp("keymap");
145 lisp::ListIterator iter(keymap_lisp);
147 if(iter.item() == "map") {
150 const lisp::Lisp* map = iter.lisp();
151 map->get("key", key);
152 map->get("control", control);
153 if(key < SDLK_FIRST || key >= SDLK_LAST) {
154 std::cerr << "Invalid key '" << key << "' in keymap.\n";
159 for(i = 0; controlNames[i] != 0; ++i) {
160 if(control == controlNames[i])
163 if(controlNames[i] == 0) {
164 std::cerr << "Invalid control '" << control << "' in keymap.\n";
167 keymap.insert(std::make_pair((SDLKey) key, (Control) i));
169 std::cerr << "Invalid lisp element '" << iter.item() << "' in keymap.\n";
174 const lisp::Lisp* joystick_lisp = lisp.get_lisp("joystick");
176 joystick_lisp->get("use_hat", use_hat);
177 joystick_lisp->get("axis_x", joyaxis_x);
178 joystick_lisp->get("axis_y", joyaxis_y);
179 joystick_lisp->get("dead_zone_x", dead_zone_x);
180 joystick_lisp->get("dead_zone_y", dead_zone_y);
181 lisp::ListIterator iter(joystick_lisp);
183 if(iter.item() == "map") {
186 const lisp::Lisp* map = iter.lisp();
187 map->get("button", button);
188 map->get("control", control);
189 if(button < 0 || button >= max_joybuttons) {
190 std::cerr << "Invalid button '" << button << "' in buttonmap.\n";
195 for(i = 0; controlNames[i] != 0; ++i) {
196 if(control == controlNames[i])
199 if(controlNames[i] == 0) {
200 std::cerr << "Invalid control '" << control << "' in buttonmap.\n";
203 reset_joybutton(button, (Control) i);
210 JoystickKeyboardController::write(lisp::Writer& writer)
212 writer.start_list("keymap");
213 for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
214 writer.start_list("map");
215 writer.write_int("key", (int) i->first);
216 writer.write_string("control", controlNames[i->second]);
217 writer.end_list("map");
219 writer.end_list("keymap");
220 writer.start_list("joystick");
221 writer.write_bool("use_hat", use_hat);
222 writer.write_int("axis_x", joyaxis_x);
223 writer.write_int("axis_y", joyaxis_y);
224 writer.write_int("dead_zone_x", dead_zone_x);
225 writer.write_int("dead_zone_y", dead_zone_y);
226 for(ButtonMap::iterator i = joy_button_map.begin(); i != joy_button_map.end();
228 writer.start_list("map");
229 writer.write_int("button", i->first);
230 writer.write_string("control", controlNames[i->second]);
231 writer.end_list("map");
233 writer.end_list("joystick");
237 JoystickKeyboardController::process_event(const SDL_Event& event)
242 // remember ascii keys for cheat codes...
243 if(event.type == SDL_KEYDOWN &&
244 (event.key.keysym.unicode & 0xFF80) == 0) {
245 memmove(last_keys, last_keys+1, sizeof(last_keys)-1);
246 last_keys[sizeof(last_keys)-1] = event.key.keysym.unicode;
247 if(GameSession::current())
248 GameSession::current()->try_cheats();
252 if(Menu::current()) { // menu mode
253 process_menu_key_event(event);
256 // normal mode, find key in keymap
257 KeyMap::iterator i = keymap.find(event.key.keysym.sym);
258 if(i == keymap.end()) {
260 std::cerr << "Pressed key without mapping.\n";
264 Control control = i->second;
265 controls[control] = event.type == SDL_KEYDOWN ? true : false;
269 case SDL_JOYAXISMOTION:
270 if(event.jaxis.axis == joyaxis_x) {
271 if(event.jaxis.value < -dead_zone_x) {
272 controls[LEFT] = true;
273 controls[RIGHT] = false;
274 } else if(event.jaxis.value > dead_zone_x) {
275 controls[LEFT] = false;
276 controls[RIGHT] = true;
278 controls[LEFT] = false;
279 controls[RIGHT] = false;
281 } else if(event.jaxis.axis == joyaxis_y) {
282 if(event.jaxis.value < -dead_zone_y) {
284 controls[DOWN] = false;
285 } else if(event.jaxis.value > dead_zone_y) {
286 controls[UP] = false;
287 controls[DOWN] = true;
289 controls[UP] = false;
290 controls[DOWN] = false;
295 case SDL_JOYHATMOTION:
299 if(event.jhat.value & SDL_HAT_UP) {
301 controls[DOWN] = false;
303 if(event.jhat.value & SDL_HAT_DOWN) {
304 controls[UP] = false;
305 controls[DOWN] = true;
307 if(event.jhat.value & SDL_HAT_LEFT) {
308 controls[LEFT] = true;
309 controls[RIGHT] = false;
311 if(event.jhat.value & SDL_HAT_RIGHT) {
312 controls[LEFT] = false;
313 controls[RIGHT] = true;
315 if(event.jhat.value == SDL_HAT_CENTERED) {
316 controls[UP] = false;
317 controls[DOWN] = false;
318 controls[LEFT] = false;
319 controls[RIGHT] = false;
323 case SDL_JOYBUTTONDOWN:
324 case SDL_JOYBUTTONUP:
326 if(wait_for_joybutton >= 0) {
327 if(event.type == SDL_JOYBUTTONUP)
330 Control c = (Control) wait_for_joybutton;
331 reset_joybutton(event.jbutton.button, c);
333 joystick_options_menu->update();
334 wait_for_joybutton = -1;
338 ButtonMap::iterator i = joy_button_map.find(event.jbutton.button);
339 if(i == joy_button_map.end()) {
341 std::cerr << "Unmapped joybutton " << (int) event.jbutton.button
347 controls[i->second] =
348 event.type == SDL_JOYBUTTONDOWN ? true : false;
358 JoystickKeyboardController::process_menu_key_event(const SDL_Event& event)
360 // wait for key mode?
361 if(wait_for_key >= 0) {
362 if(event.type == SDL_KEYUP)
365 if(event.key.keysym.sym != SDLK_ESCAPE
366 && event.key.keysym.sym != SDLK_PAUSE) {
367 reset_key(event.key.keysym.sym, (Control) wait_for_key);
370 key_options_menu->update();
374 if(wait_for_joybutton >= 0) {
375 if(event.key.keysym.sym == SDLK_ESCAPE) {
377 joystick_options_menu->update();
378 wait_for_joybutton = -1;
384 /* we use default keys when the menu is open (to avoid problems when
385 * redefining keys to invalid settings
387 switch(event.key.keysym.sym) {
403 control = MENU_SELECT;
407 control = PAUSE_MENU;
414 controls[control] = event.type == SDL_KEYDOWN ? true : false;
418 JoystickKeyboardController::reset_joybutton(int button, Control control)
420 // remove all previous mappings for that control and for that key
421 for(ButtonMap::iterator i = joy_button_map.begin();
422 i != joy_button_map.end(); /* no ++i */) {
423 if(i->second == control) {
424 ButtonMap::iterator e = i;
426 joy_button_map.erase(e);
431 ButtonMap::iterator i = joy_button_map.find(button);
432 if(i != joy_button_map.end())
433 joy_button_map.erase(i);
436 joy_button_map.insert(std::make_pair(button, control));
438 // map all unused buttons to MENU_SELECT
439 for(int b = 0; b < max_joybuttons; ++b) {
440 ButtonMap::iterator i = joy_button_map.find(b);
441 if(i != joy_button_map.end())
444 joy_button_map.insert(std::make_pair(b, MENU_SELECT));
449 JoystickKeyboardController::reset_key(SDLKey key, Control control)
451 // remove all previous mappings for that control and for that key
452 for(KeyMap::iterator i = keymap.begin();
453 i != keymap.end(); /* no ++i */) {
454 if(i->second == control) {
455 KeyMap::iterator e = i;
462 KeyMap::iterator i = keymap.find(key);
463 if(i != keymap.end())
467 keymap.insert(std::make_pair(key, control));
471 JoystickKeyboardController::reversemap_key(Control c)
473 for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
482 JoystickKeyboardController::reversemap_joybutton(Control c)
484 for(ButtonMap::iterator i = joy_button_map.begin();
485 i != joy_button_map.end(); ++i) {
494 JoystickKeyboardController::get_key_options_menu()
496 if(key_options_menu == 0) {
497 key_options_menu = new KeyboardMenu(this);
500 return key_options_menu;
504 JoystickKeyboardController::get_joystick_options_menu()
506 if(joystick_options_menu == 0) {
507 joystick_options_menu = new JoystickMenu(this);
510 return joystick_options_menu;
514 JoystickKeyboardController::check_cheatcode(const std::string& cheatcode)
516 if(cheatcode.size() > sizeof(last_keys)) {
518 std::cerr << "Cheat Code too long.\n";
523 for(size_t i = 0; i < cheatcode.size(); ++i) {
524 if(last_keys[sizeof(last_keys)-1 - i] != cheatcode[cheatcode.size()-1-i])
530 //----------------------------------------------------------------------------
532 JoystickKeyboardController::KeyboardMenu::KeyboardMenu(
533 JoystickKeyboardController* _controller)
534 : controller(_controller)
536 add_label(_("Keyboard Setup"));
538 add_controlfield(Controller::UP, _("Up"));
539 add_controlfield(Controller::DOWN, _("Down"));
540 add_controlfield(Controller::LEFT, _("Left"));
541 add_controlfield(Controller::RIGHT, _("Right"));
542 add_controlfield(Controller::JUMP, _("Jump"));
543 add_controlfield(Controller::ACTION, _("Shoot/Run"));
549 JoystickKeyboardController::KeyboardMenu::~KeyboardMenu()
553 JoystickKeyboardController::KeyboardMenu::get_key_name(SDLKey key)
559 return _("Up cursor");
561 return _("Down cursor");
563 return _("Left cursor");
565 return _("Right cursor");
571 return _("Right Shift");
573 return _("Left Shift");
575 return _("Right Control");
577 return _("Left Control");
579 return _("Right Alt");
581 return _("Left Alt");
583 return SDL_GetKeyName((SDLKey) key);
588 JoystickKeyboardController::KeyboardMenu::menu_action(MenuItem* item)
590 assert(item->id >= 0 && item->id < Controller::CONTROLCOUNT);
591 item->change_input(_("Press Key"));
592 controller->wait_for_key = item->id;
596 JoystickKeyboardController::KeyboardMenu::update()
599 get_item_by_id((int) Controller::UP).change_input(get_key_name(
600 controller->reversemap_key(Controller::UP)));
601 get_item_by_id((int) Controller::DOWN).change_input(get_key_name(
602 controller->reversemap_key(Controller::DOWN)));
603 get_item_by_id((int) Controller::LEFT).change_input(get_key_name(
604 controller->reversemap_key(Controller::LEFT)));
605 get_item_by_id((int) Controller::RIGHT).change_input(get_key_name(
606 controller->reversemap_key(Controller::RIGHT)));
607 get_item_by_id((int) Controller::JUMP).change_input(get_key_name(
608 controller->reversemap_key(Controller::JUMP)));
609 get_item_by_id((int) Controller::ACTION).change_input(get_key_name(
610 controller->reversemap_key(Controller::ACTION)));
613 //---------------------------------------------------------------------------
615 JoystickKeyboardController::JoystickMenu::JoystickMenu(
616 JoystickKeyboardController* _controller)
617 : controller(_controller)
619 add_label(_("Joystick Setup"));
621 add_controlfield(Controller::JUMP, _("Jump"));
622 add_controlfield(Controller::ACTION, _("Shoot/Run"));
623 add_controlfield(Controller::PAUSE_MENU, _("Pause/Menu"));
629 JoystickKeyboardController::JoystickMenu::~JoystickMenu()
633 JoystickKeyboardController::JoystickMenu::get_button_name(int button)
638 std::ostringstream name;
639 name << "Button " << button;
644 JoystickKeyboardController::JoystickMenu::menu_action(MenuItem* item)
646 assert(item->id >= 0 && item->id < Controller::CONTROLCOUNT);
647 item->change_input(_("Press Button"));
648 controller->wait_for_joybutton = item->id;
652 JoystickKeyboardController::JoystickMenu::update()
655 get_item_by_id((int) Controller::JUMP).change_input(get_button_name(
656 controller->reversemap_joybutton(Controller::JUMP)));
657 get_item_by_id((int) Controller::ACTION).change_input(get_button_name(
658 controller->reversemap_joybutton(Controller::ACTION)));
659 get_item_by_id((int) Controller::PAUSE_MENU).change_input(get_button_name(
660 controller->reversemap_joybutton(Controller::PAUSE_MENU)));