2 // Copyright (C) 2006 Matthias Braun <matze@braunis.de>,
3 // 2007-2014 Ingo Ruhnke <grumbel@gmx.de>
5 // This program is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "control/keyboard_manager.hpp"
20 #include "control/controller.hpp"
21 #include "control/joystick_manager.hpp"
22 #include "gui/menu_manager.hpp"
23 #include "lisp/list_iterator.hpp"
24 #include "supertux/console.hpp"
25 #include "supertux/menu/joystick_menu.hpp"
26 #include "supertux/menu/keyboard_menu.hpp"
27 #include "supertux/menu/menu_storage.hpp"
28 #include "util/writer.hpp"
30 KeyboardManager::KeyboardManager(InputManager* parent) :
33 jump_with_up_kbd(false),
36 // initialize default keyboard map
37 keymap[SDLK_LEFT] = Controller::LEFT;
38 keymap[SDLK_RIGHT] = Controller::RIGHT;
39 keymap[SDLK_UP] = Controller::UP;
40 keymap[SDLK_DOWN] = Controller::DOWN;
41 keymap[SDLK_SPACE] = Controller::JUMP;
42 keymap[SDLK_LCTRL] = Controller::ACTION;
43 keymap[SDLK_LALT] = Controller::ACTION;
44 keymap[SDLK_ESCAPE] = Controller::PAUSE_MENU;
45 keymap[SDLK_p] = Controller::PAUSE_MENU;
46 keymap[SDLK_PAUSE] = Controller::PAUSE_MENU;
47 keymap[SDLK_RETURN] = Controller::MENU_SELECT;
48 keymap[SDLK_KP_ENTER] = Controller::MENU_SELECT;
49 keymap[SDLK_CARET] = Controller::CONSOLE;
50 keymap[SDLK_DELETE] = Controller::PEEK_LEFT;
51 keymap[SDLK_PAGEDOWN] = Controller::PEEK_RIGHT;
52 keymap[SDLK_HOME] = Controller::PEEK_UP;
53 keymap[SDLK_END] = Controller::PEEK_DOWN;
56 KeyboardManager::~KeyboardManager()
61 KeyboardManager::process_key_event(const SDL_KeyboardEvent& event)
63 KeyMap::iterator key_mapping = keymap.find(event.keysym.sym);
65 // if console key was pressed: toggle console
66 if (key_mapping != keymap.end() &&
67 key_mapping->second == Controller::CONSOLE)
69 if (event.type == SDL_KEYDOWN)
71 Console::instance->toggle();
74 else if (Console::instance->hasFocus())
76 // if console is open: send key there
77 process_console_key_event(event);
79 else if (MenuManager::instance().current())
81 // if menu mode: send key there
82 process_menu_key_event(event);
84 else if (key_mapping == keymap.end())
86 // default action: update controls
87 //log_debug << "Key " << event.key.SDL_Keycode.sym << " is unbound" << std::endl;
91 auto control = key_mapping->second;
92 bool value = (event.type == SDL_KEYDOWN);
93 m_parent->get_controller()->set_control(control, value);
94 if (jump_with_up_kbd && control == Controller::UP)
96 m_parent->get_controller()->set_control(Controller::JUMP, value);
102 KeyboardManager::process_text_input_event(const SDL_TextInputEvent& event)
104 if (Console::instance->hasFocus()) {
105 for(int i = 0; event.text[i] != '\0'; ++i)
107 Console::instance->input(event.text[i]);
113 KeyboardManager::process_console_key_event(const SDL_KeyboardEvent& event)
115 if (event.type != SDL_KEYDOWN) return;
117 switch (event.keysym.sym) {
119 Console::instance->enter();
122 Console::instance->backspace();
125 Console::instance->autocomplete();
128 Console::instance->scroll(-1);
131 Console::instance->scroll(+1);
134 Console::instance->move_cursor(-65535);
137 Console::instance->move_cursor(+65535);
140 Console::instance->show_history(-1);
143 Console::instance->show_history(+1);
146 Console::instance->move_cursor(-1);
149 Console::instance->move_cursor(+1);
157 KeyboardManager::process_menu_key_event(const SDL_KeyboardEvent& event)
159 // wait for key mode?
160 if (wait_for_key >= 0)
162 if (event.type == SDL_KEYUP)
165 if (event.keysym.sym != SDLK_ESCAPE &&
166 event.keysym.sym != SDLK_PAUSE)
168 bind_key(event.keysym.sym, static_cast<Controller::Control>(wait_for_key));
171 MenuStorage::instance().get_key_options_menu()->update();
176 if (m_parent->joystick_manager->wait_for_joystick >= 0)
178 if (event.keysym.sym == SDLK_ESCAPE)
181 MenuStorage::instance().get_joystick_options_menu()->update();
182 m_parent->joystick_manager->wait_for_joystick = -1;
187 Controller::Control control;
188 /* we use default keys when the menu is open (to avoid problems when
189 * redefining keys to invalid settings
191 switch(event.keysym.sym) {
193 control = Controller::UP;
196 control = Controller::DOWN;
199 control = Controller::LEFT;
202 control = Controller::RIGHT;
207 control = Controller::MENU_SELECT;
211 control = Controller::PAUSE_MENU;
218 m_parent->get_controller()->set_control(control, (event.type == SDL_KEYDOWN));
222 KeyboardManager::bind_key(SDL_Keycode key, Controller::Control control)
224 // remove all previous mappings for that control and for that key
225 for(KeyMap::iterator i = keymap.begin();
226 i != keymap.end(); /* no ++i */) {
227 if (i->second == control) {
228 KeyMap::iterator e = i;
236 KeyMap::iterator i = keymap.find(key);
237 if (i != keymap.end())
241 keymap[key] = control;
245 KeyboardManager::reversemap_key(Controller::Control c)
247 for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i)
259 KeyboardManager::read(const lisp::Lisp* keymap_lisp)
261 // keycode values changed between SDL1 and SDL2, so we skip old SDL1
262 // based values and use the defaults instead on the first read of
264 bool config_is_sdl2 = false;
265 keymap_lisp->get("sdl2", config_is_sdl2);
269 keymap_lisp->get("jump-with-up", jump_with_up_kbd);
270 lisp::ListIterator iter(keymap_lisp);
272 if (iter.item() == "map") {
275 const lisp::Lisp* map = iter.lisp();
276 map->get("key", key);
278 map->get("control", control);
281 for(i = 0; Controller::controlNames[i] != 0; ++i) {
282 if (control == Controller::controlNames[i])
285 if (Controller::controlNames[i] == 0) {
286 log_info << "Invalid control '" << control << "' in keymap" << std::endl;
289 keymap[static_cast<SDL_Keycode>(key)] = static_cast<Controller::Control>(i);
296 KeyboardManager::write(Writer& writer)
298 writer.write("sdl2", true);
299 writer.write("jump-with-up", jump_with_up_kbd);
300 for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
301 writer.start_list("map");
302 writer.write("key", (int) i->first);
303 writer.write("control", Controller::controlNames[i->second]);
304 writer.end_list("map");