1// SuperTux
2// Copyright (C) 2006 Matthias Braun <matze@braunis.de>,
3// 2007-2014 Ingo Ruhnke <grumbel@gmail.com>
4//
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.
9//
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.
14//
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/>.
17
18#include "control/keyboard_manager.hpp"
19
20#include "control/joystick_manager.hpp"
21#include "control/input_manager.hpp"
22#include "control/keyboard_config.hpp"
23#include "gui/menu_manager.hpp"
24#include "supertux/console.hpp"
25
26KeyboardManager::KeyboardManager(InputManager* parent,
27 KeyboardConfig& keyboard_config) :
28 m_parent(parent),
29 m_keyboard_config(keyboard_config),
30 m_wait_for_key(),
31 m_lock_text_input(false)
32{
33}
34
35void
36KeyboardManager::process_key_event(const SDL_KeyboardEvent& event)
37{
38 auto key_mapping = m_keyboard_config.m_keymap.find(event.keysym.sym);
39
40 // if console key was pressed: toggle console
41 if (key_mapping != m_keyboard_config.m_keymap.end() &&
42 key_mapping->second == Control::CONSOLE)
43 {
44 if (event.type == SDL_KEYDOWN)
45 {
46 // text input gets locked between the console-key being pressed
47 // and released to avoid the console-key getting interpreted as
48 // text input and echoed to the console
49 m_lock_text_input = true;
50
51 Console::current()->toggle();
52 }
53 else if (event.type == SDL_KEYUP)
54 {
55 m_lock_text_input = false;
56 }
57 }
58 else if (Console::current()->hasFocus())
59 {
60 // if console is open: send key there
61 process_console_key_event(event);
62 }
63 else if (MenuManager::instance().is_active())
64 {
65 // if menu mode: send key there
66 process_menu_key_event(event);
67 }
68 else if (key_mapping == m_keyboard_config.m_keymap.end())
69 {
70 // default action: update controls
71 //log_debug << "Key " << event.key.SDL_Keycode.sym << " is unbound" << std::endl;
72 }
73 else
74 {
75 auto control = key_mapping->second;
76 bool value = (event.type == SDL_KEYDOWN);
77
78 m_parent->get_controller().set_control(control, value);
79
80 if (m_keyboard_config.m_jump_with_up_kbd && control == Control::UP) {
81 m_parent->get_controller().set_control(Control::JUMP, value);
82 }
83 }
84}
85
86void
87KeyboardManager::process_text_input_event(const SDL_TextInputEvent& event)
88{
89 if (!m_lock_text_input && Console::current()->hasFocus()) {
90 for (int i = 0; event.text[i] != '\0'; ++i)
91 {
92 Console::current()->input(event.text[i]);
93 }
94 }
95}
96
97void
98KeyboardManager::process_console_key_event(const SDL_KeyboardEvent& event)
99{
100 if (event.type != SDL_KEYDOWN) return;
101 auto console = Console::current();
102
103 switch (event.keysym.sym) {
104 case SDLK_RETURN:
105 console->enter();
106 break;
107 case SDLK_BACKSPACE:
108 console->backspace();
109 break;
110 case SDLK_DELETE:
111 console->eraseChar();
112 break;
113 case SDLK_TAB:
114 console->autocomplete();
115 break;
116 case SDLK_PAGEUP:
117 console->scroll(-1);
118 break;
119 case SDLK_PAGEDOWN:
120 console->scroll(+1);
121 break;
122 case SDLK_HOME:
123 console->move_cursor(-65535);
124 break;
125 case SDLK_END:
126 console->move_cursor(+65535);
127 break;
128 case SDLK_a:
129 if (event.keysym.mod & KMOD_CTRL) {
130 console->move_cursor(-65535);
131 }
132 break;
133 case SDLK_e:
134 if (event.keysym.mod & KMOD_CTRL) {
135 console->move_cursor(+65535);
136 }
137 break;
138 case SDLK_UP:
139 console->show_history(-1);
140 break;
141 case SDLK_DOWN:
142 console->show_history(+1);
143 break;
144 case SDLK_LEFT:
145 console->move_cursor(-1);
146 break;
147 case SDLK_RIGHT:
148 console->move_cursor(+1);
149 break;
150 default:
151 break;
152 }
153}
154
155void
156KeyboardManager::process_menu_key_event(const SDL_KeyboardEvent& event)
157{
158 // wait for key mode?
159 if (m_wait_for_key)
160 {
161 if (event.type == SDL_KEYUP)
162 return;
163
164 if (event.keysym.sym != SDLK_ESCAPE &&
165 event.keysym.sym != SDLK_PAUSE)
166 {
167 m_keyboard_config.bind_key(event.keysym.sym, *m_wait_for_key);
168 }
169 m_parent->reset();
170 MenuManager::instance().refresh();
171 m_wait_for_key = boost::none;
172 return;
173 }
174
175 if (m_parent->joystick_manager->wait_for_joystick >= 0)
176 {
177 if (event.keysym.sym == SDLK_ESCAPE)
178 {
179 m_parent->reset();
180 MenuManager::instance().refresh();
181 m_parent->joystick_manager->wait_for_joystick = -1;
182 }
183 return;
184 }
185
186 Control control;
187 /* we use default keys when the menu is open (to avoid problems when
188 * redefining keys to invalid settings
189 */
190 switch (event.keysym.sym) {
191 case SDLK_UP:
192 control = Control::UP;
193 break;
194 case SDLK_DOWN:
195 control = Control::DOWN;
196 break;
197 case SDLK_LEFT:
198 control = Control::LEFT;
199 break;
200 case SDLK_RIGHT:
201 control = Control::RIGHT;
202 break;
203 case SDLK_SPACE:
204 control = Control::MENU_SELECT_SPACE;
205 break;
206 case SDLK_RETURN:
207 case SDLK_KP_ENTER:
208 control = Control::MENU_SELECT;
209 break;
210 case SDLK_ESCAPE:
211 control = Control::ESCAPE;
212 break;
213 case SDLK_PAUSE:
214 control = Control::START;
215 break;
216 case SDLK_BACKSPACE:
217 control = Control::REMOVE;
218 break;
219 default:
220 if (m_keyboard_config.m_keymap.count(event.keysym.sym) == 0)
221 {
222 return;
223 }
224 control = m_keyboard_config.m_keymap[event.keysym.sym];
225 break;
226 }
227
228 m_parent->get_controller().set_control(control, (event.type == SDL_KEYDOWN));
229}
230
231void
232KeyboardManager::bind_next_event_to(Control id)
233{
234 m_wait_for_key = id;
235}
236
237/* EOF */
238