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