f0740e79e446e77645f90ca97cc9565c93d91b60
[supertux.git] / src / control / joystickkeyboardcontroller.cpp
1 //  SuperTux
2 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>,
3 //                2007 Ingo Ruhnke <grumbel@gmx.de>
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/joystickkeyboardcontroller.hpp"
19
20 #include <iostream>
21
22 #include "control/joystick_manager.hpp"
23 #include "gui/menu_manager.hpp"
24 #include "lisp/list_iterator.hpp"
25 #include "supertux/console.hpp"
26 #include "supertux/gameconfig.hpp"
27 #include "supertux/menu/joystick_menu.hpp"
28 #include "supertux/menu/keyboard_menu.hpp"
29 #include "supertux/menu/menu_storage.hpp"
30 #include "util/gettext.hpp"
31 #include "util/writer.hpp"
32
33 JoystickKeyboardController::JoystickKeyboardController() :
34   controller(new Controller),
35   joystick_manager(new JoystickManager(this)),
36   keymap(),
37   name(),
38   jump_with_up_kbd(),
39   wait_for_key(-1)
40 {
41   // initialize default keyboard map
42   keymap[SDLK_LEFT]     = Controller::LEFT;
43   keymap[SDLK_RIGHT]    = Controller::RIGHT;
44   keymap[SDLK_UP]       = Controller::UP;
45   keymap[SDLK_DOWN]     = Controller::DOWN;
46   keymap[SDLK_SPACE]    = Controller::JUMP;
47   keymap[SDLK_LCTRL]    = Controller::ACTION;
48   keymap[SDLK_LALT]     = Controller::ACTION;
49   keymap[SDLK_ESCAPE]   = Controller::PAUSE_MENU;
50   keymap[SDLK_p]        = Controller::PAUSE_MENU;
51   keymap[SDLK_PAUSE]    = Controller::PAUSE_MENU;
52   keymap[SDLK_RETURN]   = Controller::MENU_SELECT;
53   keymap[SDLK_KP_ENTER] = Controller::MENU_SELECT;
54   keymap[SDLK_CARET]    = Controller::CONSOLE;
55   keymap[SDLK_DELETE]   = Controller::PEEK_LEFT;
56   keymap[SDLK_PAGEDOWN] = Controller::PEEK_RIGHT;
57   keymap[SDLK_HOME]     = Controller::PEEK_UP;
58   keymap[SDLK_END]      = Controller::PEEK_DOWN;
59
60   jump_with_up_kbd = false;
61 }
62
63 JoystickKeyboardController::~JoystickKeyboardController()
64 {
65 }
66
67 Controller*
68 JoystickKeyboardController::get_main_controller()
69 {
70   return controller.get();
71 }
72
73 void
74 JoystickKeyboardController::read(const Reader& lisp)
75 {
76   const lisp::Lisp* keymap_lisp = lisp.get_lisp("keymap");
77   if (keymap_lisp) {
78     keymap.clear();
79     keymap_lisp->get("jump-with-up", jump_with_up_kbd);
80     lisp::ListIterator iter(keymap_lisp);
81     while(iter.next()) {
82       if (iter.item() == "map") {
83         int key = -1;
84         std::string control;
85         const lisp::Lisp* map = iter.lisp();
86         map->get("key", key);
87         map->get("control", control);
88 //        if (key < SDLK_FIRST || key >= SDLK_LAST) {
89 //          log_info << "Invalid key '" << key << "' in keymap" << std::endl;
90 //          continue;
91 //        }
92
93         int i = 0;
94         for(i = 0; Controller::controlNames[i] != 0; ++i) {
95           if (control == Controller::controlNames[i])
96             break;
97         }
98         if (Controller::controlNames[i] == 0) {
99           log_info << "Invalid control '" << control << "' in keymap" << std::endl;
100           continue;
101         }
102         keymap[SDL_Keycode(key)] = Control(i);
103       }
104     }
105   }
106
107   const lisp::Lisp* joystick_lisp = lisp.get_lisp(_("joystick"));
108   if (joystick_lisp) 
109   {
110     joystick_manager->read(joystick_lisp);
111   }
112 }
113
114 void
115 JoystickKeyboardController::write(Writer& writer)
116 {
117   writer.start_list("keymap");
118   writer.write("jump-with-up", jump_with_up_kbd);
119   for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
120     writer.start_list("map");
121     writer.write("key", (int) i->first);
122     writer.write("control", Controller::controlNames[i->second]);
123     writer.end_list("map");
124   }
125   writer.end_list("keymap");
126
127   writer.start_list("joystick");
128   joystick_manager->write(writer);
129   writer.end_list("joystick");
130 }
131
132 void
133 JoystickKeyboardController::update()
134 {
135   controller->update();
136 }
137
138 void
139 JoystickKeyboardController::reset()
140 {
141   controller->reset();
142 }
143
144 void
145 JoystickKeyboardController::process_event(const SDL_Event& event)
146 {
147   switch(event.type) {
148     case SDL_TEXTINPUT:
149       process_text_input_event(event.text);
150       break;
151
152     case SDL_KEYUP:
153     case SDL_KEYDOWN:
154       process_key_event(event.key);
155       break;
156
157     case SDL_JOYAXISMOTION:
158       joystick_manager->process_axis_event(event.jaxis);
159       break;
160
161     case SDL_JOYHATMOTION:
162       joystick_manager->process_hat_event(event.jhat);
163       break;
164
165     case SDL_JOYBUTTONDOWN:
166     case SDL_JOYBUTTONUP:
167       joystick_manager->process_button_event(event.jbutton);
168       break;
169
170     case SDL_JOYDEVICEADDED:
171       joystick_manager->on_joystick_added(event.jdevice.which);
172       break;
173
174     case SDL_JOYDEVICEREMOVED:
175       joystick_manager->on_joystick_removed(event.jdevice.which);
176       break;
177
178     case SDL_CONTROLLERBUTTONDOWN:
179       std::cout << "SDL_CONTROLLERBUTTONDOWN" << std::endl;
180       break;
181
182     case SDL_CONTROLLERBUTTONUP:
183       std::cout << "SDL_CONTROLLERBUTTONUP" << std::endl;
184       break;
185
186     case SDL_CONTROLLERDEVICEADDED:
187       // ignored, handled in SDL_JOYDEVICEADDED
188       std::cout << "SDL_CONTROLLERDEVICEADDED" << std::endl;
189       break;
190
191     case SDL_CONTROLLERDEVICEREMOVED:
192       // ignored, handled in SDL_JOYDEVICEREMOVED
193       std::cout << "SDL_CONTROLLERDEVICEREMOVED" << std::endl;
194       break;
195
196     case SDL_CONTROLLERDEVICEREMAPPED:
197       std::cout << "SDL_CONTROLLERDEVICEREMAPPED" << std::endl;
198       break;
199
200     default:
201       break;
202   }
203 }
204
205 void
206 JoystickKeyboardController::process_text_input_event(const SDL_TextInputEvent& event)
207 {
208   if (Console::instance->hasFocus()) {
209     for(int i = 0; event.text[i] != '\0'; ++i)
210     {
211       Console::instance->input(event.text[i]);
212     }
213   }
214 }
215
216 void
217 JoystickKeyboardController::process_key_event(const SDL_KeyboardEvent& event)
218 {
219   KeyMap::iterator key_mapping = keymap.find(event.keysym.sym);
220
221   // if console key was pressed: toggle console
222   if ((key_mapping != keymap.end()) && (key_mapping->second == Controller::CONSOLE)) {
223     if (event.type == SDL_KEYDOWN) 
224       Console::instance->toggle();
225   } else {
226     if (Console::instance->hasFocus()) {
227       // if console is open: send key there
228       process_console_key_event(event);
229     } else if (MenuManager::current()) {
230       // if menu mode: send key there
231       process_menu_key_event(event);
232     } else if (key_mapping == keymap.end()) {
233       // default action: update controls
234       //log_debug << "Key " << event.key.SDL_Keycode.sym << " is unbound" << std::endl;
235     } else {
236       Control control = key_mapping->second;
237       bool value = (event.type == SDL_KEYDOWN);
238       controller->set_control(control, value);
239       if (jump_with_up_kbd && control == Controller::UP){
240         controller->set_control(Controller::JUMP, value);
241       }
242     }
243   }
244 }
245
246 void
247 JoystickKeyboardController::process_console_key_event(const SDL_KeyboardEvent& event)
248 {
249   if (event.type != SDL_KEYDOWN) return;
250
251   switch (event.keysym.sym) {
252     case SDLK_RETURN:
253       Console::instance->enter();
254       break;
255     case SDLK_BACKSPACE:
256       Console::instance->backspace();
257       break;
258     case SDLK_TAB:
259       Console::instance->autocomplete();
260       break;
261     case SDLK_PAGEUP:
262       Console::instance->scroll(-1);
263       break;
264     case SDLK_PAGEDOWN:
265       Console::instance->scroll(+1);
266       break;
267     case SDLK_HOME:
268       Console::instance->move_cursor(-65535);
269       break;
270     case SDLK_END:
271       Console::instance->move_cursor(+65535);
272       break;
273     case SDLK_UP:
274       Console::instance->show_history(-1);
275       break;
276     case SDLK_DOWN:
277       Console::instance->show_history(+1);
278       break;
279     case SDLK_LEFT:
280       Console::instance->move_cursor(-1);
281       break;
282     case SDLK_RIGHT:
283       Console::instance->move_cursor(+1);
284       break;
285     default:
286       break;
287   }
288 }
289
290 void
291 JoystickKeyboardController::process_menu_key_event(const SDL_KeyboardEvent& event)
292 {
293   // wait for key mode?
294   if (wait_for_key >= 0) {
295     if (event.type == SDL_KEYUP)
296       return;
297
298     if (event.keysym.sym != SDLK_ESCAPE
299        && event.keysym.sym != SDLK_PAUSE) {
300       bind_key(event.keysym.sym, Control(wait_for_key));
301     }
302     reset();
303     MenuStorage::get_key_options_menu()->update();
304     wait_for_key = -1;
305     return;
306   }
307   if (joystick_manager->wait_for_joystick >= 0) {
308     if (event.keysym.sym == SDLK_ESCAPE) {
309       reset();
310       MenuStorage::get_joystick_options_menu()->update();
311       joystick_manager->wait_for_joystick = -1;
312     }
313     return;
314   }
315
316   Control control;
317   /* we use default keys when the menu is open (to avoid problems when
318    * redefining keys to invalid settings
319    */
320   switch(event.keysym.sym) {
321     case SDLK_UP:
322       control = Controller::UP;
323       break;
324     case SDLK_DOWN:
325       control = Controller::DOWN;
326       break;
327     case SDLK_LEFT:
328       control = Controller::LEFT;
329       break;
330     case SDLK_RIGHT:
331       control = Controller::RIGHT;
332       break;
333     case SDLK_SPACE:
334     case SDLK_RETURN:
335     case SDLK_KP_ENTER:
336       control = Controller::MENU_SELECT;
337       break;
338     case SDLK_ESCAPE:
339     case SDLK_PAUSE:
340       control = Controller::PAUSE_MENU;
341       break;
342     default:
343       return;
344       break;
345   }
346
347   controller->set_control(control, (event.type == SDL_KEYDOWN));
348 }
349
350 void
351 JoystickKeyboardController::bind_key(SDL_Keycode key, Control control)
352 {
353   // remove all previous mappings for that control and for that key
354   for(KeyMap::iterator i = keymap.begin();
355       i != keymap.end(); /* no ++i */) {
356     if (i->second == control) {
357       KeyMap::iterator e = i;
358       ++i;
359       keymap.erase(e);
360     } else {
361       ++i;
362     }
363   }
364
365   KeyMap::iterator i = keymap.find(key);
366   if (i != keymap.end())
367     keymap.erase(i);
368
369   // add new mapping
370   keymap[key] = control;
371 }
372
373 SDL_Keycode
374 JoystickKeyboardController::reversemap_key(Control c)
375 {
376   for(KeyMap::iterator i = keymap.begin(); i != keymap.end(); ++i) {
377     if (i->second == c)
378       return i->first;
379   }
380
381   return SDLK_UNKNOWN;
382 }
383
384 /* EOF */