2 // Copyright (C) 2006 Matthias Braun <matze@braunis.de>,
3 // 2007-2014 Ingo Ruhnke <grumbel@gmail.com>
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;
54 keymap[SDLK_TAB] = Controller::CHEAT_MENU;
57 KeyboardManager::~KeyboardManager()
62 KeyboardManager::process_key_event(const SDL_KeyboardEvent& event)
64 KeyMap::iterator key_mapping = keymap.find(event.keysym.sym);
66 // if console key was pressed: toggle console
67 if (key_mapping != keymap.end() &&
68 key_mapping->second == Controller::CONSOLE)
70 if (event.type == SDL_KEYDOWN)
72 Console::instance->toggle();
75 else if (Console::instance->hasFocus())
77 // if console is open: send key there
78 process_console_key_event(event);
80 else if (MenuManager::instance().is_active())
82 // if menu mode: send key there
83 process_menu_key_event(event);
85 else if (key_mapping == keymap.end())
87 // default action: update controls
88 //log_debug << "Key " << event.key.SDL_Keycode.sym << " is unbound" << std::endl;
92 auto control = key_mapping->second;
93 bool value = (event.type == SDL_KEYDOWN);
94 m_parent->get_controller()->set_control(control, value);
95 if (jump_with_up_kbd && control == Controller::UP)
97 m_parent->get_controller()->set_control(Controller::JUMP, value);
103 KeyboardManager::process_text_input_event(const SDL_TextInputEvent& event)
105 if (Console::instance->hasFocus()) {
106 for(int i = 0; event.text[i] != '\0'; ++i)
108 Console::instance->input(event.text[i]);
114 KeyboardManager::process_console_key_event(const SDL_KeyboardEvent& event)
116 if (event.type != SDL_KEYDOWN) return;
118 switch (event.keysym.sym) {
120 Console::instance->enter();
123 Console::instance->backspace();
126 Console::instance->autocomplete();
129 Console::instance->scroll(-1);
132 Console::instance->scroll(+1);
135 Console::instance->move_cursor(-65535);
138 Console::instance->move_cursor(+65535);
141 Console::instance->show_history(-1);
144 Console::instance->show_history(+1);
147 Console::instance->move_cursor(-1);
150 Console::instance->move_cursor(+1);
158 KeyboardManager::process_menu_key_event(const SDL_KeyboardEvent& event)
160 // wait for key mode?
161 if (wait_for_key >= 0)
163 if (event.type == SDL_KEYUP)
166 if (event.keysym.sym != SDLK_ESCAPE &&
167 event.keysym.sym != SDLK_PAUSE)
169 bind_key(event.keysym.sym, static_cast<Controller::Control>(wait_for_key));
172 MenuManager::instance().refresh();
177 if (m_parent->joystick_manager->wait_for_joystick >= 0)
179 if (event.keysym.sym == SDLK_ESCAPE)
182 MenuManager::instance().refresh();
183 m_parent->joystick_manager->wait_for_joystick = -1;
188 Controller::Control control;
189 /* we use default keys when the menu is open (to avoid problems when
190 * redefining keys to invalid settings
192 switch(event.keysym.sym) {
194 control = Controller::UP;
197 control = Controller::DOWN;
200 control = Controller::LEFT;
203 control = Controller::RIGHT;
208 control = Controller::MENU_SELECT;
212 control = Controller::PAUSE_MENU;
219 m_parent->get_controller()->set_control(control, (event.type == SDL_KEYDOWN));
223 KeyboardManager::bind_key(SDL_Keycode key, Controller::Control control)
225 // remove all previous mappings for that control and for that key
226 for(KeyMap::iterator i = keymap.begin();
227 i != keymap.end(); /* no ++i */) {
228 if (i->second == control) {
229 KeyMap::iterator e = i;
237 KeyMap::iterator i = keymap.find(key);
238 if (i != keymap.end())
242 keymap[key] = control;
246 KeyboardManager::reversemap_key(Controller::Control c)
248 for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i)
260 KeyboardManager::read(const lisp::Lisp* keymap_lisp)
262 // keycode values changed between SDL1 and SDL2, so we skip old SDL1
263 // based values and use the defaults instead on the first read of
265 bool config_is_sdl2 = false;
266 keymap_lisp->get("sdl2", config_is_sdl2);
270 keymap_lisp->get("jump-with-up", jump_with_up_kbd);
271 lisp::ListIterator iter(keymap_lisp);
273 if (iter.item() == "map") {
276 const lisp::Lisp* map = iter.lisp();
277 map->get("key", key);
279 map->get("control", control);
282 for(i = 0; Controller::controlNames[i] != 0; ++i) {
283 if (control == Controller::controlNames[i])
286 if (Controller::controlNames[i] == 0) {
287 log_info << "Invalid control '" << control << "' in keymap" << std::endl;
290 keymap[static_cast<SDL_Keycode>(key)] = static_cast<Controller::Control>(i);
297 KeyboardManager::write(Writer& writer)
299 writer.write("sdl2", true);
300 writer.write("jump-with-up", jump_with_up_kbd);
301 for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
302 writer.start_list("map");
303 writer.write("key", (int) i->first);
304 writer.write("control", Controller::controlNames[i->second]);
305 writer.end_list("map");