1 //
2 //  SuperTuxKart - a fun racing game with go-kart
3 //  Copyright (C) 2010-2015 SuperTuxKart-Team
4 //
5 //  This program is free software; you can redistribute it and/or
6 //  modify it under the terms of the GNU General Public License
7 //  as published by the Free Software Foundation; either version 3
8 //  of the License, or (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, write to the Free Software
17 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 #include "input/device_manager.hpp"
20 
21 #include <iostream>
22 #include <fstream>
23 
24 #include "config/user_config.hpp"
25 #include "graphics/irr_driver.hpp"
26 #include "input/gamepad_device.hpp"
27 #include "input/keyboard_device.hpp"
28 #include "input/multitouch_device.hpp"
29 #include "input/wiimote_manager.hpp"
30 #include "io/file_manager.hpp"
31 #include "states_screens/kart_selection.hpp"
32 #include "states_screens/state_manager.hpp"
33 #include "utils/file_utils.hpp"
34 #include "utils/log.hpp"
35 #include "utils/string_utils.hpp"
36 #include "utils/translation.hpp"
37 
38 #define INPUT_MODE_DEBUG 0
39 
40 static const char  INPUT_FILE_NAME[]  = "input.xml";
41 static const int   INPUT_FILE_VERSION = 1;
42 
DeviceManager()43 DeviceManager::DeviceManager()
44 {
45     m_latest_used_device = NULL;
46     m_assign_mode = NO_ASSIGN;
47     m_single_player = NULL;
48     m_multitouch_device = NULL;
49 }   // DeviceManager
50 
51 // -----------------------------------------------------------------------------
~DeviceManager()52 DeviceManager::~DeviceManager()
53 {
54     delete m_multitouch_device;
55 }   // ~DeviceManager
56 
57 // -----------------------------------------------------------------------------
initialize()58 bool DeviceManager::initialize()
59 {
60     m_map_fire_to_select         = false;
61     bool created                 = false;
62 
63 
64     // Shutdown in case the device manager is being re-initialized
65     shutdown();
66 
67     if(UserConfigParams::logMisc())
68     {
69         Log::info("Device manager","Initializing Device Manager");
70         Log::info("-","---------------------------");
71     }
72 
73     load();
74 
75     // Assign a configuration to the keyboard, or create one if we haven't yet
76     if(UserConfigParams::logMisc()) Log::info("Device manager","Initializing keyboard support.");
77     if (m_keyboard_configs.size() == 0)
78     {
79         if(UserConfigParams::logMisc())
80             Log::info("Device manager","No keyboard configuration exists, creating one.");
81         m_keyboard_configs.push_back(new KeyboardConfig());
82 
83         created = true;
84     }
85 
86     const int keyboard_amount = m_keyboard_configs.size();
87     for (int n = 0; n < keyboard_amount; n++)
88     {
89         m_keyboards.push_back(new KeyboardDevice(m_keyboard_configs.get(n)));
90     }
91 
92     if ((UserConfigParams::m_multitouch_active == 1 &&
93         irr_driver->getDevice()->supportsTouchDevice()) ||
94         UserConfigParams::m_multitouch_active > 1)
95     {
96         m_multitouch_device = new MultitouchDevice();
97     }
98 
99     if (created) save();
100 
101     return created;
102 }   // initialize
103 
104 // -----------------------------------------------------------------------------
clearKeyboard()105 void DeviceManager::clearKeyboard()
106 {
107     m_keyboards.clearAndDeleteAll();
108 }   // clearKeyboard
109 
110 // -----------------------------------------------------------------------------
clearGamepads()111 void DeviceManager::clearGamepads()
112 {
113     m_gamepads.clearAndDeleteAll();
114 }   // clearGamepads
115 // -----------------------------------------------------------------------------
clearMultitouchDevices()116 void DeviceManager::clearMultitouchDevices()
117 {
118     delete m_multitouch_device;
119     m_multitouch_device = NULL;
120 }   // clearMultitouchDevices
121 
122 // -----------------------------------------------------------------------------
setAssignMode(const PlayerAssignMode assignMode)123 void DeviceManager::setAssignMode(const PlayerAssignMode assignMode)
124 {
125     m_assign_mode = assignMode;
126 
127 #if INPUT_MODE_DEBUG
128     if (assignMode == NO_ASSIGN) Log::info("DeviceManager::setAssignMode(NO_ASSIGN)");
129     if (assignMode == ASSIGN) Log::info("DeviceManager::setAssignMode(ASSIGN)");
130     if (assignMode == DETECT_NEW) Log::info("DeviceManager::setAssignMode(DETECT_NEW)");
131 #endif
132 
133     // when going back to no-assign mode, do some cleanup
134     if (assignMode == NO_ASSIGN)
135     {
136         for (unsigned int i=0; i < m_gamepads.size(); i++)
137         {
138             m_gamepads[i].setPlayer(NULL);
139         }
140         for (unsigned int i=0; i < m_keyboards.size(); i++)
141         {
142             m_keyboards[i].setPlayer(NULL);
143         }
144 
145         if (m_multitouch_device != NULL)
146             m_multitouch_device->setPlayer(NULL);
147     }
148 }   // setAssignMode
149 
150 // -----------------------------------------------------------------------------
getGamePadFromIrrID(const int id)151 GamePadDevice* DeviceManager::getGamePadFromIrrID(const int id)
152 {
153     const int count = m_gamepads.size();
154     for (int i = 0; i < count; i++)
155     {
156         if (m_gamepads[i].getIrrIndex()== id)
157         {
158 
159             return m_gamepads.get(i);
160         }
161     }
162     return NULL;
163 }   // getGamePadFromIrrID
164 
165 // -----------------------------------------------------------------------------
166 /**
167  * Check if we already have a config object for gamepad 'irr_id' as reported by
168  * irrLicht, If no, create one. Returns true if new configuration was created,
169  *  otherwise false.
170  */
getConfigForGamepad(const int irr_id,const std::string & name,GamepadConfig ** config)171 bool DeviceManager::getConfigForGamepad(const int irr_id,
172                                         const std::string& name,
173                                         GamepadConfig **config)
174 {
175     bool found = false;
176     bool configCreated = false;
177 
178     // Find appropriate configuration
179     for(unsigned int n=0; n < m_gamepad_configs.size(); n++)
180     {
181         if(m_gamepad_configs[n].getName() == name)
182         {
183             *config = m_gamepad_configs.get(n);
184             found = true;
185         }
186     }
187 
188     // If we can't find an appropriate configuration then create one.
189     if (!found)
190     {
191         // The Wiimote manager and SDL controller will set number of buttons and
192         // axes
193         *config = new GamepadConfig(name.c_str());
194         // Add new config to list
195         m_gamepad_configs.push_back(*config);
196         configCreated = true;
197     }
198 
199     return configCreated;
200 }   // getConfigForGamepad
201 
202 // -----------------------------------------------------------------------------
addKeyboard(KeyboardDevice * d)203 void DeviceManager::addKeyboard(KeyboardDevice* d)
204 {
205     m_keyboards.push_back(d);
206 }   // addKeyboard
207 
208 // -----------------------------------------------------------------------------
addEmptyKeyboard()209 void DeviceManager::addEmptyKeyboard()
210 {
211     KeyboardConfig* newConf = new KeyboardConfig();
212     m_keyboard_configs.push_back(newConf);
213     m_keyboards.push_back( new KeyboardDevice(newConf) );
214 }   // addEmptyKeyboard
215 
216 // -----------------------------------------------------------------------------
217 
addGamepad(GamePadDevice * d)218 void DeviceManager::addGamepad(GamePadDevice* d)
219 {
220     m_gamepads.push_back(d);
221 }   // addGamepad
222 
223 // -----------------------------------------------------------------------------
224 
deleteConfig(DeviceConfig * config)225 bool DeviceManager::deleteConfig(DeviceConfig* config)
226 {
227     for (unsigned int n=0; n<m_keyboards.size(); n++)
228     {
229         if (m_keyboards[n].getConfiguration() == config)
230         {
231             m_keyboards.erase(n);
232             n--;
233         }
234     }
235     for (unsigned int n=0; n<m_gamepads.size(); n++)
236     {
237         if (m_gamepads[n].getConfiguration() == config)
238         {
239             m_gamepads.erase(n);
240             n--;
241         }
242     }
243 
244     if (m_keyboard_configs.erase(config))
245     {
246         return true;
247     }
248 
249     if (m_gamepad_configs.erase(config))
250     {
251         return true;
252     }
253 
254     return false;
255 }   // deleteConfig
256 
257 // -----------------------------------------------------------------------------
258 /** Helper method, only used internally. Takes care of analyzing keyboard input.
259  *  \param[in]   button_id  Id of the key pressed.
260  *  \param[in]   mode       Used to determine whether to determine menu actions
261  *                          or game actions
262  *  \param[out]  player     Which player this input belongs to (only set in
263  *                          ASSIGN mode).
264  *  \param[out]  action     Which action is related to this input trigger.
265  *  \return                 The device to which this input belongs
266  */
mapKeyboardInput(int button_id,InputManager::InputDriverMode mode,StateManager::ActivePlayer ** player,PlayerAction * action)267 InputDevice* DeviceManager::mapKeyboardInput(int button_id,
268                                              InputManager::InputDriverMode mode,
269                                              StateManager::ActivePlayer **player,
270                                              PlayerAction *action /* out */)
271 {
272     const int keyboard_amount = m_keyboards.size();
273 
274     for (int n=0; n<keyboard_amount; n++)
275     {
276         KeyboardDevice *keyboard = m_keyboards.get(n);
277 
278         if (keyboard->processAndMapInput(Input::IT_KEYBOARD, button_id, mode, action))
279         {
280             if (m_single_player != NULL)
281             {
282                 *player = m_single_player;
283             }
284             else if (m_assign_mode == NO_ASSIGN) // Don't set the player in NO_ASSIGN mode
285             {
286                 *player = NULL;
287             }
288             else
289             {
290                 *player = keyboard->getPlayer();
291             }
292             return keyboard;
293         }
294     }
295 
296     return NULL; // no appropriate binding found
297 }   // mapKeyboardInput
298 
299 //-----------------------------------------------------------------------------
300 /** Helper method, only used internally. Takes care of analyzing gamepad
301  *  input.
302  *  \param[in]  type    Type of gamepad event (IT_STICKMOTION etc).
303  *  \param[out] player  Which player this input belongs to (only set in
304  *                      ASSIGN mode)
305  *  \param[out] action  Which action is related to this input trigger
306  *  \param      mode    Used to determine whether to determine menu actions
307  *                      or game actions
308  *  \return             The device to which this input belongs
309  */
310 
mapGamepadInput(Input::InputType type,int device_id,int button_id,int axis_dir,int * value,InputManager::InputDriverMode mode,StateManager::ActivePlayer ** player,PlayerAction * action)311 InputDevice *DeviceManager::mapGamepadInput(Input::InputType type,
312                                              int device_id,
313                                              int button_id,
314                                              int axis_dir,
315                                              int *value /* inout */,
316                                              InputManager::InputDriverMode mode,
317                                              StateManager::ActivePlayer **player /* out */,
318                                              PlayerAction *action /* out */)
319 {
320     GamePadDevice  *gPad = getGamePadFromIrrID(device_id);
321 
322     if (gPad != NULL)
323     {
324         // Ignore deadzone events if this isn't the latest used device in
325         // single-player mode (allowing the player to switch device at any time)
326         int dz = static_cast<GamepadConfig*>(gPad->getConfiguration())->getDeadzone();
327         if (m_single_player != NULL && m_latest_used_device != gPad
328             && *value > -dz && *value < dz)
329         {
330             *player = NULL;
331             return NULL;
332         }
333 
334         if (gPad->processAndMapInput(type, button_id, mode, action, value))
335         {
336             if (m_single_player != NULL)
337             {
338                 *player = m_single_player;
339 
340                 // in single-player mode, assign the gamepad as needed
341                 if (gPad->getPlayer() != m_single_player) gPad->setPlayer(m_single_player);
342             }
343             else if (m_assign_mode == NO_ASSIGN) // Don't set the player in NO_ASSIGN mode
344             {
345                 *player = NULL;
346             }
347             else
348             {
349                 *player = gPad->getPlayer();
350             }
351         }
352         else gPad = NULL; // If no bind was found, return NULL
353     }
354 
355     return gPad;
356 }   // mapGamepadInput
357 
358 //-----------------------------------------------------------------------------
359 
updateMultitouchDevice()360 void DeviceManager::updateMultitouchDevice()
361 {
362     if (m_multitouch_device == NULL)
363         return;
364 
365     if (m_single_player != NULL)
366     {
367         // in single-player mode, assign the gamepad as needed
368         if (m_multitouch_device->getPlayer() != m_single_player)
369             m_multitouch_device->setPlayer(m_single_player);
370     }
371     else
372     {
373         m_multitouch_device->setPlayer(NULL);
374     }
375 
376     m_multitouch_device->updateController();
377 }   // updateMultitouchDevice
378 
379 //-----------------------------------------------------------------------------
380 
translateInput(Input::InputType type,int device_id,int button_id,int axis_dir,int * value,InputManager::InputDriverMode mode,StateManager::ActivePlayer ** player,PlayerAction * action)381 bool DeviceManager::translateInput( Input::InputType type,
382                                     int device_id,
383                                     int button_id,
384                                     int axis_dir,
385                                     int* value /* inout */,
386                                     InputManager::InputDriverMode mode,
387                                     StateManager::ActivePlayer** player /* out */,
388                                     PlayerAction* action /* out */ )
389 {
390     if (GUIEngine::getCurrentScreen() != NULL)
391     {
392         GUIEngine::getCurrentScreen()->filterInput(type, device_id, button_id, axis_dir, *value);
393     }
394 
395     InputDevice *device = NULL;
396 
397     // If the input event matches a bind on an input device, get a pointer to the device
398     switch (type)
399     {
400         case Input::IT_KEYBOARD:
401             device = mapKeyboardInput(button_id, mode, player, action);
402             // If the action is not recognised, check if it's a fire key
403             // that should be mapped to select
404             if(!device && m_map_fire_to_select)
405             {
406                 PlayerAction fire_action = PA_BEFORE_FIRST;
407                 device = mapKeyboardInput(button_id, InputManager::INGAME, player,
408                                           &fire_action);
409                 if (device && fire_action == PA_FIRE)
410                     *action = PA_MENU_SELECT;
411                 else
412                     device = NULL;
413             }
414             break;
415         case Input::IT_STICKBUTTON:
416         case Input::IT_STICKMOTION:
417             device = mapGamepadInput(type, device_id, button_id, axis_dir, value,
418                                      mode, player, action);
419             if(!device && m_map_fire_to_select)
420             {
421                 PlayerAction fire_action = PA_BEFORE_FIRST;
422                 device = mapGamepadInput(type, device_id, button_id, axis_dir, value,
423                                          InputManager::INGAME, player, &fire_action);
424                 if (device && fire_action == PA_FIRE)
425                     *action = PA_MENU_SELECT;
426                 else
427                     device = NULL;
428             }
429             break;
430         default:
431             break;
432     };
433 
434 
435     // Return true if input was successfully translated to an action and player
436     if (device != NULL && abs(*value) > Input::MAX_VALUE/2)
437     {
438         m_latest_used_device = device;
439     }
440 
441     return (device != NULL);
442 }   // translateInput
443 
444 //-----------------------------------------------------------------------------
getLatestUsedDevice()445 InputDevice* DeviceManager::getLatestUsedDevice()
446 {
447     // If none, probably the user clicked or used enter; give keyboard by default
448 
449     if (m_latest_used_device == NULL)
450     {
451         //Log::info("DeviceManager", "No latest device, returning keyboard);
452         return m_keyboards.get(0); // FIXME: is this right?
453     }
454 
455     return m_latest_used_device;
456 }   // getLatestUsedDevice
457 
458 // -----------------------------------------------------------------------------
clearLatestUsedDevice()459 void DeviceManager::clearLatestUsedDevice()
460 {
461     m_latest_used_device = NULL;
462 }   // clearLatestUsedDevice
463 
464 // -----------------------------------------------------------------------------
465 /** Loads the configuration from the user's input.xml file.
466  */
load()467 bool DeviceManager::load()
468 {
469     std::string filepath = file_manager->getUserConfigFile(INPUT_FILE_NAME);
470 
471     if(UserConfigParams::logMisc())
472         Log::info("Device manager","Loading input.xml...");
473 
474     const XMLNode *input = file_manager->createXMLTree(filepath);
475 
476     if(!input)
477     {
478         if(UserConfigParams::logMisc())
479             Log::warn("Device manager","No configuration file exists.");
480         return false;
481     }
482 
483     if(input->getName()!="input")
484     {
485         Log::warn("DeviceManager", "Invalid input.xml file - no input node.");
486         delete input;
487         return false;
488     }
489 
490     int version=0;
491     if(!input->get("version", &version) || version != INPUT_FILE_VERSION )
492     {
493         //I18N: shown when config file is too old
494         GUIEngine::showMessage(_("Please re-configure your key bindings."));
495         GUIEngine::showMessage(_("Your input config file is not compatible "
496                                  "with this version of STK."));
497         delete input;
498         return false;
499     }
500 
501     for(unsigned int i=0; i<input->getNumNodes(); i++)
502     {
503         const XMLNode *config = input->getNode(i);
504         DeviceConfig *device_config = DeviceConfig::create(config);
505         if(!device_config)
506         {
507             Log::warn("DeviceManager",
508                       "Invalid node '%s' in input.xml - ignored.",
509                       config->getName().c_str());
510             continue;
511         }
512         if (config->getName() == "keyboard")
513         {
514             KeyboardConfig *kc = static_cast<KeyboardConfig*>(device_config);
515             m_keyboard_configs.push_back(kc);
516         }
517         else if (config->getName() == "gamepad")
518         {
519             GamepadConfig *gc = static_cast<GamepadConfig*>(device_config);
520             m_gamepad_configs.push_back(gc);
521         }
522     }   // for i < getNumNodes
523 
524     if (UserConfigParams::logMisc())
525     {
526         Log::info("Device manager",
527                   "Found %d keyboard and %d gamepad configurations.",
528                   m_keyboard_configs.size(), m_gamepad_configs.size());
529     }
530 
531     // For Debugging....
532     /*
533     for (int n = 0; n < m_keyboard_configs.size(); n++)
534         printf("Config #%d\n%s", n + 1, m_keyboard_configs[n].toString().c_str());
535 
536     for (int n = 0; n < m_gamepad_configs.size(); n++)
537         printf("%s", m_gamepad_configs[n].toString().c_str());
538     */
539 
540     delete input;
541 
542     return true;
543 }   // load
544 
545 // -----------------------------------------------------------------------------
save()546 void DeviceManager::save()
547 {
548     static std::string filepath = file_manager->getUserConfigFile(INPUT_FILE_NAME);
549     if(UserConfigParams::logMisc()) Log::info("Device manager","Serializing input.xml...");
550 
551 
552     std::ofstream configfile(FileUtils::getPortableWritingPath(filepath));
553 
554     if(!configfile.is_open())
555     {
556         Log::error("Device manager","Failed to open %s for writing, controls won't be saved",filepath.c_str());
557         return;
558     }
559 
560 
561     configfile << "<input version=\"" << INPUT_FILE_VERSION << "\">\n\n";
562 
563     configfile << "<!--\n"
564         << "Event 1 : Keyboard button press\n"
565         << "    'id' indicates which button, as defined by irrlicht's EKEY_CODE enum\n"
566         << "    'character' contains the associated unicode character.\n"
567         << "        Only used as fallback when displaying special characters in the UI.\n"
568         << "Event 2 : Gamepad stick motion\n"
569         << "    'id' indicates which stick, starting from 0\n"
570         << "    'direction' 0 means negative, 1 means positive\n"
571         << "Event 3 : Gamepad button press\n"
572         << "    'id' indicates which button, starting from 0\n"
573         << "-->\n\n";
574 
575     for(unsigned int n=0; n<m_keyboard_configs.size(); n++)
576     {
577         m_keyboard_configs[n].save(configfile);
578     }
579     for(unsigned int n=0; n<m_gamepad_configs.size(); n++)
580     {
581         m_gamepad_configs[n].save(configfile);
582     }
583 
584     configfile << "</input>\n";
585     configfile.close();
586     if(UserConfigParams::logMisc()) Log::info("Device manager","Serialization complete.");
587 }   // save
588 
589 // -----------------------------------------------------------------------------
590 
getKeyboardFromBtnID(const int button_id)591 KeyboardDevice* DeviceManager::getKeyboardFromBtnID(const int button_id)
592 {
593     const int keyboard_amount = m_keyboards.size();
594     for (int n=0; n<keyboard_amount; n++)
595     {
596         if (m_keyboards[n].getConfiguration()->hasBindingFor(button_id))
597             return m_keyboards.get(n);
598     }
599 
600     return NULL;
601 }   // getKeyboardFromButtonID
602 
603 // -----------------------------------------------------------------------------
604 
shutdown()605 void DeviceManager::shutdown()
606 {
607     m_gamepads.clearAndDeleteAll();
608     m_keyboards.clearAndDeleteAll();
609     m_gamepad_configs.clearAndDeleteAll();
610     m_keyboard_configs.clearAndDeleteAll();
611     delete m_multitouch_device;
612     m_multitouch_device = NULL;
613     m_latest_used_device = NULL;
614 }   // shutdown
615