1// SuperTux
2// Copyright (C) 2014 Ingo Ruhnke <grumbel@gmail.com>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17#include "control/keyboard_config.hpp"
18
19#include <boost/optional.hpp>
20
21#include "util/log.hpp"
22#include "util/reader_mapping.hpp"
23#include "util/writer.hpp"
24
25KeyboardConfig::KeyboardConfig() :
26 m_keymap(),
27 m_jump_with_up_kbd(false)
28{
29 // initialize default keyboard map
30 m_keymap[SDLK_LEFT] = Control::LEFT;
31 m_keymap[SDLK_RIGHT] = Control::RIGHT;
32 m_keymap[SDLK_UP] = Control::UP;
33 m_keymap[SDLK_DOWN] = Control::DOWN;
34 m_keymap[SDLK_SPACE] = Control::JUMP;
35 m_keymap[SDLK_LCTRL] = Control::ACTION;
36 m_keymap[SDLK_LALT] = Control::ACTION;
37 m_keymap[SDLK_ESCAPE] = Control::ESCAPE;
38 m_keymap[SDLK_p] = Control::START;
39 m_keymap[SDLK_PAUSE] = Control::START;
40 m_keymap[SDLK_RETURN] = Control::MENU_SELECT;
41 m_keymap[SDLK_KP_ENTER] = Control::MENU_SELECT;
42 m_keymap[SDLK_CARET] = Control::CONSOLE;
43 m_keymap[SDLK_DELETE] = Control::PEEK_LEFT;
44 m_keymap[SDLK_PAGEDOWN] = Control::PEEK_RIGHT;
45 m_keymap[SDLK_HOME] = Control::PEEK_UP;
46 m_keymap[SDLK_END] = Control::PEEK_DOWN;
47 m_keymap[SDLK_F1] = Control::CHEAT_MENU;
48 m_keymap[SDLK_F2] = Control::DEBUG_MENU;
49 m_keymap[SDLK_BACKSPACE]= Control::REMOVE;
50}
51
52void
53KeyboardConfig::read(const ReaderMapping& keymap_mapping)
54{
55 // keycode values changed between SDL1 and SDL2, so we skip old SDL1
56 // based values and use the defaults instead on the first read of
57 // the config file
58 bool config_is_sdl2 = false;
59 keymap_mapping.get("sdl2", config_is_sdl2);
60 if (config_is_sdl2)
61 {
62 keymap_mapping.get("jump-with-up", m_jump_with_up_kbd);
63
64 auto iter = keymap_mapping.get_iter();
65 while (iter.next())
66 {
67 if (iter.get_key() == "map")
68 {
69 int key = -1;
70 auto map = iter.as_mapping();
71 map.get("key", key);
72
73 std::string control_text;
74 map.get("control", control_text);
75
76 const boost::optional<Control> maybe_control = Control_from_string(control_text);
77 if (!maybe_control) {
78 log_info << "Invalid control '" << control_text << "' in keymap" << std::endl;
79 } else {
80 const Control control = *maybe_control;
81 m_keymap[static_cast<SDL_Keycode>(key)] = control;
82 }
83 }
84 }
85 }
86}
87
88void
89KeyboardConfig::bind_key(SDL_Keycode key, Control control)
90{
91 // remove all previous mappings for that control and for that key
92 for (auto i = m_keymap.begin(); i != m_keymap.end(); /* no ++i */)
93 {
94 if (i->second == control)
95 {
96 auto e = i;
97 ++i;
98 m_keymap.erase(e);
99 }
100 else
101 {
102 ++i;
103 }
104 }
105
106 auto i = m_keymap.find(key);
107 if (i != m_keymap.end())
108 m_keymap.erase(i);
109
110 // add new mapping
111 m_keymap[key] = control;
112}
113
114SDL_Keycode
115KeyboardConfig::reversemap_key(Control c) const
116{
117 for (const auto& i : m_keymap)
118 {
119 if (i.second == c)
120 {
121 return i.first;
122 }
123 }
124
125 return SDLK_UNKNOWN;
126}
127
128void
129KeyboardConfig::write(Writer& writer)
130{
131 // this flag handles the transition from SDL1 to SDL2, as keycodes
132 // are incompatible between the two, if it's not set an old SDL1
133 // config file is assumed and controls are reset to default
134 writer.write("sdl2", true);
135
136 writer.write("jump-with-up", m_jump_with_up_kbd);
137
138 for (const auto& i : m_keymap)
139 {
140 writer.start_list("map");
141 writer.write("key", static_cast<int>(i.first));
142 writer.write("control", Control_to_string(i.second));
143 writer.end_list("map");
144 }
145}
146
147/* EOF */
148