1 //  SuperTuxKart - a fun racing game with go-kart
2 //
3 //  Copyright (C) 2012-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/input_manager.hpp"
20 
21 #include "config/user_config.hpp"
22 #include "graphics/camera_fps.hpp"
23 #include "graphics/irr_driver.hpp"
24 #include "graphics/shader_based_renderer.hpp"
25 #include "graphics/sp/sp_base.hpp"
26 #include "guiengine/engine.hpp"
27 #include "guiengine/event_handler.hpp"
28 #include "guiengine/modaldialog.hpp"
29 #include "guiengine/screen.hpp"
30 #include "guiengine/screen_keyboard.hpp"
31 #include "input/device_manager.hpp"
32 #include "input/gamepad_device.hpp"
33 #include "input/input.hpp"
34 #include "input/keyboard_device.hpp"
35 #include "input/multitouch_device.hpp"
36 #include "input/sdl_controller.hpp"
37 #include "input/wiimote_manager.hpp"
38 #include "karts/controller/controller.hpp"
39 #include "karts/abstract_kart.hpp"
40 #include "modes/demo_world.hpp"
41 #include "modes/world.hpp"
42 #include "network/network_config.hpp"
43 #include "network/protocols/client_lobby.hpp"
44 #include "network/rewind_manager.hpp"
45 #include "physics/physics.hpp"
46 #include "race/history.hpp"
47 #include "replay/replay_recorder.hpp"
48 #include "states_screens/kart_selection.hpp"
49 #include "states_screens/main_menu_screen.hpp"
50 #include "states_screens/online/networking_lobby.hpp"
51 #include "states_screens/options/options_screen_device.hpp"
52 #include "states_screens/state_manager.hpp"
53 #include "utils/debug.hpp"
54 #include "utils/string_utils.hpp"
55 #include "utils/translation.hpp"
56 
57 #include <ISceneManager.h>
58 #include <ICameraSceneNode.h>
59 #include <ISceneNode.h>
60 
61 #include <map>
62 #include <vector>
63 #include <string>
64 #include <iostream>
65 #include <sstream>
66 #include <algorithm>
67 
68 #ifndef SERVER_ONLY
69 #include <SDL.h>
70 #endif
71 
72 InputManager *input_manager;
73 
74 using GUIEngine::EventPropagation;
75 using GUIEngine::EVENT_LET;
76 using GUIEngine::EVENT_BLOCK;
77 
78 #define INPUT_MODE_DEBUG 0
79 
80 //-----------------------------------------------------------------------------
81 /** Initialise input
82  */
InputManager()83 InputManager::InputManager() : m_mode(BOOTSTRAP),
84                                m_mouse_val_x(-1), m_mouse_val_y(-1)
85 {
86     m_device_manager = new DeviceManager();
87     m_device_manager->initialize();
88 
89     m_timer_in_use = false;
90     m_master_player_only = false;
91     m_timer = 0;
92 #ifndef SERVER_ONLY
93     if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) != 0)
94     {
95         Log::error("InputManager", "Failed to init SDL game controller: %s",
96             SDL_GetError());
97     }
98 #endif
99 }
100 
101 // -----------------------------------------------------------------------------
addJoystick()102 void InputManager::addJoystick()
103 {
104 #ifndef SERVER_ONLY
105     // When irrlicht device is reinitialized the joystick added event may be
106     // lost, we look for them and add it back
107     for (int i = 0; i < SDL_NumJoysticks(); i++)
108     {
109         try
110         {
111             SDL_Joystick* joystick = SDL_JoystickOpen(i);
112             if (!joystick)
113                 continue;
114             SDL_JoystickID id = SDL_JoystickInstanceID(joystick);
115             if (m_sdl_controller.find(id) != m_sdl_controller.end())
116                 continue;
117             std::unique_ptr<SDLController> c(
118                 new SDLController(i));
119             id = c->getInstanceID();
120             m_sdl_controller[id] = std::move(c);
121         }
122         catch (std::exception& e)
123         {
124             Log::error("SDLController", "%s", e.what());
125         }
126     }
127 #endif
128 }
129 
130 // -----------------------------------------------------------------------------
131 #ifndef SERVER_ONLY
132 // For CIrrDeviceSDL
handle_joystick(SDL_Event & event)133 extern "C" void handle_joystick(SDL_Event& event)
134 {
135     if (input_manager)
136         input_manager->handleJoystick(event);
137 }   // handle_joystick
138 
139 // -----------------------------------------------------------------------------
handleJoystick(SDL_Event & event)140 void InputManager::handleJoystick(SDL_Event& event)
141 {
142     try
143     {
144         switch (event.type)
145         {
146         case SDL_JOYDEVICEADDED:
147         {
148             std::unique_ptr<SDLController> c(
149                 new SDLController(event.jdevice.which));
150             SDL_JoystickID id = c->getInstanceID();
151             m_sdl_controller[id] = std::move(c);
152             break;
153         }
154         case SDL_JOYDEVICEREMOVED:
155         {
156             m_sdl_controller.erase(event.jdevice.which);
157             break;
158         }
159         case SDL_JOYAXISMOTION:
160         {
161             auto& controller = m_sdl_controller.at(event.jaxis.which);
162             if (m_mode == INPUT_SENSE_GAMEPAD)
163                 controller->handleAxisInputSense(event);
164             if (controller->handleAxis(event) &&
165                 !UserConfigParams::m_gamepad_visualisation)
166                 input(controller->getEvent());
167             break;
168         }
169         case SDL_JOYHATMOTION:
170         {
171             auto& controller = m_sdl_controller.at(event.jhat.which);
172             if (controller->handleHat(event) &&
173                 !UserConfigParams::m_gamepad_visualisation)
174                 input(controller->getEvent());
175             break;
176         }
177         case SDL_JOYBUTTONUP:
178         case SDL_JOYBUTTONDOWN:
179         {
180             auto& controller = m_sdl_controller.at(event.jbutton.which);
181             if (controller->handleButton(event) &&
182                 !UserConfigParams::m_gamepad_visualisation)
183                 input(controller->getEvent());
184             break;
185         }
186         default:
187             break;
188         }
189     }
190     catch (std::exception& e)
191     {
192         Log::error("SDLController", "%s", e.what());
193     }
194 }   // handleJoystick
195 #endif
196 
197 // -----------------------------------------------------------------------------
update(float dt)198 void InputManager::update(float dt)
199 {
200 #ifdef ENABLE_WIIUSE
201     if (wiimote_manager)
202         wiimote_manager->update();
203 #endif
204 
205     if(m_timer_in_use)
206     {
207         m_timer -= dt;
208         if(m_timer < 0) m_timer_in_use = false;
209     }
210 }
211 
212 //-----------------------------------------------------------------------------
213 #ifndef SERVER_ONLY
getEventForGamePad(unsigned i) const214 const irr::SEvent& InputManager::getEventForGamePad(unsigned i) const
215 {
216     auto it = m_sdl_controller.begin();
217     return std::next(it, i)->second->getEvent();
218 }
219 #endif
220 
221 //-----------------------------------------------------------------------------
222 /** Destructor. Frees all data structures.
223  */
~InputManager()224 InputManager::~InputManager()
225 {
226 #ifndef SERVER_ONLY
227     m_sdl_controller.clear();
228 #endif
229     delete m_device_manager;
230 }   // ~InputManager
231 
232 //-----------------------------------------------------------------------------
handleStaticAction(int key,int value)233 void InputManager::handleStaticAction(int key, int value)
234 {
235     static bool control_is_pressed = false;
236     static bool shift_is_pressed   = false;
237 
238     World *world = World::getWorld();
239 
240     // When no players... a cutscene
241     if (RaceManager::get() &&
242         RaceManager::get()->getNumPlayers() == 0 && world != NULL && value > 0 &&
243         (key == IRR_KEY_SPACE || key == IRR_KEY_RETURN ||
244         key == IRR_KEY_BUTTON_A))
245     {
246         world->onFirePressed(NULL);
247     }
248 
249 
250     if (world != NULL && UserConfigParams::m_artist_debug_mode &&
251         control_is_pressed && value > 0)
252     {
253         if (Debug::handleStaticAction(key))
254             return;
255     }
256 
257     // TODO: move debug shortcuts to Debug::handleStaticAction
258     switch (key)
259     {
260 #ifdef DEBUG
261         // Special debug options for profile mode: switch the
262         // camera to show a different kart.
263         case IRR_KEY_1:
264         case IRR_KEY_2:
265         case IRR_KEY_3:
266         case IRR_KEY_4:
267         case IRR_KEY_5:
268         case IRR_KEY_6:
269         case IRR_KEY_7:
270         case IRR_KEY_8:
271         case IRR_KEY_9:
272         {
273             if(!ProfileWorld::isProfileMode() || !world) break;
274             int kart_id = key - IRR_KEY_1;
275             if(kart_id<0 || kart_id>=(int)world->getNumKarts()) break;
276             Camera::getCamera(0)->setKart(world->getKart(kart_id));
277             break;
278         }
279 #endif
280 
281         case IRR_KEY_CONTROL:
282         case IRR_KEY_RCONTROL:
283         case IRR_KEY_LCONTROL:
284         case IRR_KEY_RMENU:
285         case IRR_KEY_LMENU:
286         case IRR_KEY_LWIN:
287             control_is_pressed = value!=0;
288             break;
289         case IRR_KEY_LSHIFT:
290         case IRR_KEY_RSHIFT:
291         case IRR_KEY_SHIFT:
292             shift_is_pressed = value!=0; break;
293 
294         // Flying up and down
295         case IRR_KEY_I:
296         {
297             if (!world || !UserConfigParams::m_artist_debug_mode) break;
298 
299             AbstractKart* kart = world->getLocalPlayerKart(0);
300             if (kart == NULL) break;
301 
302             kart->flyUp();
303             break;
304         }
305         case IRR_KEY_K:
306         {
307             if (!world || !UserConfigParams::m_artist_debug_mode) break;
308 
309             AbstractKart* kart = world->getLocalPlayerKart(0);
310             if (kart == NULL) break;
311 
312             kart->flyDown();
313             break;
314         }
315         // Moving the first person camera
316         case IRR_KEY_W:
317         {
318             CameraFPS *cam = dynamic_cast<CameraFPS*>(Camera::getActiveCamera());
319             if (world && UserConfigParams::m_artist_debug_mode && cam  )
320             {
321                 core::vector3df vel(cam->getLinearVelocity());
322                 vel.Z = value ? cam->getMaximumVelocity() : 0;
323                 cam->setLinearVelocity(vel);
324             }
325             break;
326         }
327         case IRR_KEY_S:
328         {
329             CameraFPS *cam = dynamic_cast<CameraFPS*>(Camera::getActiveCamera());
330             if (world && UserConfigParams::m_artist_debug_mode && cam)
331             {
332                 core::vector3df vel(cam->getLinearVelocity());
333                 vel.Z = value ? -cam->getMaximumVelocity() : 0;
334                 cam->setLinearVelocity(vel);
335             }
336             break;
337         }
338         case IRR_KEY_D:
339         {
340             CameraFPS *cam = dynamic_cast<CameraFPS*>(Camera::getActiveCamera());
341             if (world && !UserConfigParams::m_artist_debug_mode && cam)
342             {
343                 core::vector3df vel(cam->getLinearVelocity());
344                 vel.X = value ? -cam->getMaximumVelocity() : 0;
345                 cam->setLinearVelocity(vel);
346             }
347             break;
348         }
349         case IRR_KEY_A:
350         {
351             CameraFPS *cam = dynamic_cast<CameraFPS*>(Camera::getActiveCamera());
352             if (world && UserConfigParams::m_artist_debug_mode && cam)
353             {
354                 core::vector3df vel(cam->getLinearVelocity());
355                 vel.X = value ? cam->getMaximumVelocity() : 0;
356                 cam->setLinearVelocity(vel);
357             }
358             break;
359         }
360         case IRR_KEY_R:
361         {
362             CameraFPS *cam = dynamic_cast<CameraFPS*>(Camera::getActiveCamera());
363             if (world && UserConfigParams::m_artist_debug_mode && cam)
364             {
365                 core::vector3df vel(cam->getLinearVelocity());
366                 vel.Y = value ? cam->getMaximumVelocity() : 0;
367                 cam->setLinearVelocity(vel);
368             }
369             break;
370         }
371         case IRR_KEY_F:
372         {
373             CameraFPS *cam = dynamic_cast<CameraFPS*>(Camera::getActiveCamera());
374             if (world && UserConfigParams::m_artist_debug_mode && cam)
375             {
376                 core::vector3df vel(cam->getLinearVelocity());
377                 vel.Y = value ? -cam->getMaximumVelocity() : 0;
378                 cam->setLinearVelocity(vel);
379             }
380             break;
381         }
382         // Rotating the first person camera
383         case IRR_KEY_Q:
384         {
385             CameraFPS *cam = dynamic_cast<CameraFPS*>(Camera::getActiveCamera());
386             if (world && UserConfigParams::m_artist_debug_mode && cam )
387             {
388                 cam->setAngularVelocity(value ?
389                     UserConfigParams::m_fpscam_max_angular_velocity : 0.0f);
390             }
391             break;
392         }
393         case IRR_KEY_E:
394         {
395             CameraFPS *cam = dynamic_cast<CameraFPS*>(Camera::getActiveCamera());
396             if (world && UserConfigParams::m_artist_debug_mode && cam)
397             {
398                 cam->setAngularVelocity(value ?
399                     -UserConfigParams::m_fpscam_max_angular_velocity : 0);
400             }
401             break;
402         }
403 
404         case IRR_KEY_SNAPSHOT:
405         case IRR_KEY_PRINT:
406             // on windows we don't get a press event, only release.  So
407             // save on release only (to avoid saving twice on other platforms)
408             if (value == 0)
409             {
410                 if (control_is_pressed)
411                 {
412                     const bool is_recording = irr_driver->isRecording();
413                     irr_driver->setRecording(!is_recording);
414                 }
415                 else
416                 {
417                     irr_driver->requestScreenshot();
418                 }
419             }
420             break;
421         case IRR_KEY_F11:
422             if(value && shift_is_pressed)
423             {
424 #ifndef SERVER_ONLY
425                 ShaderBasedRenderer* sbr = SP::getRenderer();
426                 if (sbr)
427                     sbr->dumpRTT();
428 #endif
429             }
430             break;
431 
432             /*
433             else if (UserConfigParams::m_artist_debug_mode && world)
434             {
435                 AbstractKart* kart = world->getLocalPlayerKart(0);
436 
437                 if (control_is_pressed)
438                     kart->setPowerup(PowerupManager::POWERUP_SWATTER, 10000);
439                 else
440                     kart->setPowerup(PowerupManager::POWERUP_RUBBERBALL, 10000);
441 
442 #ifdef FORCE_RESCUE_ON_FIRST_KART
443                 // Can be useful for debugging places where the AI gets into
444                 // a rescue loop: rescue, drive, crash, rescue to same place
445                 world->getKart(0)->forceRescue();
446 #endif
447             }
448             break;
449         case IRR_KEY_F2:
450             if (UserConfigParams::m_artist_debug_mode && world)
451             {
452                 AbstractKart* kart = world->getLocalPlayerKart(0);
453 
454                 kart->setPowerup(PowerupManager::POWERUP_PLUNGER, 10000);
455             }
456             break;
457         case IRR_KEY_F3:
458             if (UserConfigParams::m_artist_debug_mode && world)
459             {
460                 AbstractKart* kart = world->getLocalPlayerKart(0);
461                 kart->setPowerup(PowerupManager::POWERUP_CAKE, 10000);
462             }
463             break;
464         case IRR_KEY_F4:
465             if (UserConfigParams::m_artist_debug_mode && world)
466             {
467                 AbstractKart* kart = world->getLocalPlayerKart(0);
468                 kart->setPowerup(PowerupManager::POWERUP_SWITCH, 10000);
469             }
470             break;
471         case IRR_KEY_F5:
472             if (UserConfigParams::m_artist_debug_mode && world)
473             {
474                 AbstractKart* kart = world->getLocalPlayerKart(0);
475                 kart->setPowerup(PowerupManager::POWERUP_BOWLING, 10000);
476             }
477             break;
478         case IRR_KEY_F6:
479             if (UserConfigParams::m_artist_debug_mode && world)
480             {
481                 AbstractKart* kart = world->getLocalPlayerKart(0);
482                 kart->setPowerup(PowerupManager::POWERUP_BUBBLEGUM, 10000);
483             }
484             break;
485         case IRR_KEY_F7:
486             if (UserConfigParams::m_artist_debug_mode && world)
487             {
488                 AbstractKart* kart = world->getLocalPlayerKart(0);
489                 kart->setPowerup(PowerupManager::POWERUP_ZIPPER, 10000);
490             }
491             break;
492         case IRR_KEY_F8:
493             if (UserConfigParams::m_artist_debug_mode && value && world)
494             {
495                 if (control_is_pressed)
496                 {
497                     RaceGUIBase* gui = world->getRaceGUI();
498                     if (gui != NULL) gui->m_enabled = !gui->m_enabled;
499 
500                     const int count = World::getWorld()->getNumKarts();
501                     for (int n=0; n<count; n++)
502                     {
503                         if(World::getWorld()->getKart(n)->getController()->isPlayerController())
504                             World::getWorld()->getKart(n)->getNode()
505                                 ->setVisible(gui->m_enabled);
506                     }
507                 }
508                 else
509                 {
510                     AbstractKart* kart = world->getLocalPlayerKart(0);
511                     kart->setEnergy(100.0f);
512                 }
513             }
514             break;
515         case IRR_KEY_F9:
516             if (UserConfigParams::m_artist_debug_mode && world)
517             {
518                 AbstractKart* kart = world->getLocalPlayerKart(0);
519                 if(control_is_pressed && RaceManager::get()->getMinorMode()!=
520                                           RaceManager::MINOR_MODE_3_STRIKES)
521                     kart->setPowerup(PowerupManager::POWERUP_RUBBERBALL,
522                                      10000);
523                 else
524                     kart->setPowerup(PowerupManager::POWERUP_SWATTER, 10000);
525             }
526             break;
527             */
528         case IRR_KEY_F10:
529             if(world && value)
530             {
531                 if(control_is_pressed)
532                     ReplayRecorder::get()->save();
533                 else
534                     history->Save();
535             }
536             break;
537             /*
538         case IRR_KEY_F11:
539             if (UserConfigParams::m_artist_debug_mode && value &&
540                 control_is_pressed && world)
541             {
542                 world->getPhysics()->nextDebugMode();
543             }
544             break;
545             */
546         case IRR_KEY_F12:
547             if(value)
548                 UserConfigParams::m_display_fps =
549                     !UserConfigParams::m_display_fps;
550             break;
551         default:
552             break;
553     } // switch
554 }   // handleStaticAction
555 
556 //-----------------------------------------------------------------------------
557 /**
558   *  Handles input when an input sensing mode (when configuring input)
559   */
inputSensing(Input::InputType type,int deviceID,int button,Input::AxisDirection axisDirection,int value)560 void InputManager::inputSensing(Input::InputType type, int deviceID,
561                                 int button, Input::AxisDirection axisDirection,
562                                 int value)
563 {
564 #if INPUT_MODE_DEBUG
565     Log::info("InputManager::inputSensing", "Start sensing input");
566 #endif
567 
568     // don't store if we're trying to do something like bindings keyboard
569     // keys on a gamepad
570     if (m_mode == INPUT_SENSE_KEYBOARD && type != Input::IT_KEYBOARD)
571         return;
572     if (m_mode == INPUT_SENSE_GAMEPAD  && type != Input::IT_STICKMOTION &&
573         type != Input::IT_STICKBUTTON)
574         return;
575 
576 #if INPUT_MODE_DEBUG
577     Log::info("InputManager::inputSensing", store_new ? "storing it" : "ignoring it");
578 #endif
579 
580 
581     switch(type)
582     {
583     case Input::IT_KEYBOARD:
584         if (value > Input::MAX_VALUE/2)
585         {
586             m_sensed_input_high_kbd.insert(button);
587             break;
588         }
589         if (value != 0) break;   // That shouldn't happen
590         // only notify on key release
591         if (m_sensed_input_high_kbd.find(button)
592             != m_sensed_input_high_kbd.end())
593         {
594             Input sensed_input;
595             sensed_input.m_type           = Input::IT_KEYBOARD;
596             sensed_input.m_device_id      = deviceID;
597             sensed_input.m_button_id      = button;
598             sensed_input.m_character      = deviceID;
599             OptionsScreenDevice::getInstance()->gotSensedInput(sensed_input);
600             return;
601         }
602         break;
603     case Input::IT_STICKBUTTON:
604         if (abs(value) > Input::MAX_VALUE/2.0f)
605         {
606             Input sensed_input;
607             sensed_input.m_type           = Input::IT_STICKBUTTON;
608             sensed_input.m_device_id      = deviceID;
609             sensed_input.m_button_id      = button;
610             sensed_input.m_character      = deviceID;
611             sensed_input.m_axis_direction = Input::AD_NEUTRAL;
612             OptionsScreenDevice::getInstance()->gotSensedInput(sensed_input);
613             return;
614         }
615         break;
616     case Input::IT_STICKMOTION:
617         {
618         // We have to save the direction in which the axis was moved.
619         // This is done by storing it as a sign (and since button can
620         // be zero, we add one before changing the sign).
621         int input_button_id = value>=0 ? 1+button : -(1+button);
622         std::tuple<int, int> input_id(deviceID, input_button_id);
623         std::tuple<int, int> input_id_inv(deviceID, -input_button_id);
624 
625         bool id_was_high         = m_sensed_input_high_gamepad.find(input_id)
626                                    != m_sensed_input_high_gamepad.end();
627         bool inverse_id_was_high = m_sensed_input_high_gamepad.find(input_id_inv)
628                                    != m_sensed_input_high_gamepad.end();
629         bool id_was_zero         = m_sensed_input_zero_gamepad.find(button)
630                                    != m_sensed_input_zero_gamepad.end();
631 
632         // A stick was pushed far enough (for the first time) to count as
633         // 'triggered' - save the axis (coded with direction in the button
634         // value) for later, so that it can be registered when the stick is
635         // released again.
636         // This is mostly legacy behaviour, it is probably good enough
637         // to register this as soon as the value is high enough.
638         if (!id_was_high && abs(value) > Input::MAX_VALUE*6.0f/7.0f)
639         {
640             if(inverse_id_was_high && !id_was_zero) {
641                 Input sensed_input;
642                 sensed_input.m_type           = type;
643                 sensed_input.m_device_id      = deviceID;
644                 sensed_input.m_button_id      = button;
645                 sensed_input.m_axis_direction = (value>=0) ? Input::AD_POSITIVE
646                                                            : Input::AD_NEGATIVE;
647                 sensed_input.m_axis_range     = Input::AR_FULL;
648                 sensed_input.m_character      = deviceID;
649                 OptionsScreenDevice::getInstance()->gotSensedInput(sensed_input);
650 
651             }
652             else m_sensed_input_high_gamepad.insert(input_id);
653         }
654         // At least with xbox controller they can come to a 'rest' with a value of
655         // around 6000! So in order to detect that an axis was released, we need to
656         // test with a rather high deadzone value
657         else if ( abs(value) < Input::MAX_VALUE/3.0f )
658         {
659             if( id_was_high )
660             {
661                 Input sensed_input;
662                 sensed_input.m_type           = type;
663                 sensed_input.m_device_id      = deviceID;
664                 sensed_input.m_button_id      = button;
665                 sensed_input.m_axis_direction = (value>=0) == id_was_zero
666                                                            ? Input::AD_POSITIVE
667                                                            : Input::AD_NEGATIVE;
668                 sensed_input.m_axis_range     = id_was_zero ? Input::AR_HALF
669                                                             : Input::AR_FULL;
670                 sensed_input.m_character      = deviceID;
671                 OptionsScreenDevice::getInstance()->gotSensedInput(sensed_input);
672             }
673             else if( inverse_id_was_high )
674             {
675                 Input sensed_input;
676                 sensed_input.m_type           = type;
677                 sensed_input.m_device_id      = deviceID;
678                 sensed_input.m_button_id      = button;
679                 // Since the inverse direction was high (i.e. stick went from
680                 // +30000 to -100), we have to inverse the sign
681                 sensed_input.m_axis_direction = (value>=0) == id_was_zero
682                                                            ? Input::AD_NEGATIVE
683                                                            : Input::AD_POSITIVE;
684                 sensed_input.m_axis_range     = id_was_zero ? Input::AR_HALF
685                                                             : Input::AR_FULL;
686                 sensed_input.m_character      = deviceID;
687                 OptionsScreenDevice::getInstance()->gotSensedInput(sensed_input);
688             }
689             else
690             {
691                 m_sensed_input_zero_gamepad.insert(button);
692             }
693         }
694         break;
695         }
696 
697         case Input::IT_NONE:
698         case Input::IT_MOUSEMOTION:
699         case Input::IT_MOUSEBUTTON:
700             // uninteresting (but we keep them here to explicitely state we do
701             // nothing with them, and thus to fix warnings)
702             break;
703     }   // switch
704 }   // inputSensing
705 
706 //-----------------------------------------------------------------------------
getPlayerKeyboardID() const707 int InputManager::getPlayerKeyboardID() const
708 {
709     // In no-assign mode, just return the GUI player ID (devices not
710     // assigned yet)
711     if (m_device_manager->getAssignMode() == NO_ASSIGN)
712         return PLAYER_ID_GAME_MASTER;
713 
714     // Otherwise, after devices are assigned, we can check in more depth
715     // Return the first keyboard that is actually being used
716     const int amount = m_device_manager->getKeyboardAmount();
717     for (int k=0; k<amount; k++)
718     {
719         if (m_device_manager->getKeyboard(k) != NULL &&
720             m_device_manager->getKeyboard(k)->getPlayer() != NULL)
721         {
722             return m_device_manager->getKeyboard(k)->getPlayer()->getID();
723         }
724     }
725 
726     return -1;
727 }
728 //-----------------------------------------------------------------------------
729 /** Handles the conversion from some input to a GameAction and its distribution
730  * to the currently active menu.
731  * It also handles whether the game is currently sensing input. It does so by
732  * suppressing the distribution of the input as a GameAction. Instead the
733  * input is stored in 'm_sensed_input' and GA_SENSE_COMPLETE is distributed. If
734  * however the input in question has resolved to GA_LEAVE this is treated as
735  * an attempt of the user to cancel the sensing. In that case GA_SENSE_CANCEL
736  * is distributed.
737  *
738  * Note: It is the obligation of the called menu to switch of the sense mode.
739  *
740  */
dispatchInput(Input::InputType type,int deviceID,int button,Input::AxisDirection axisDirection,int value,bool shift_mask)741 void InputManager::dispatchInput(Input::InputType type, int deviceID,
742                                  int button,
743                                  Input::AxisDirection axisDirection, int value,
744                                  bool shift_mask)
745 {
746     // Updated in rendering from main loop
747     if (!irr_driver->getDevice()->getEventReceiver())
748         return;
749 
750     // Act different in input sensing mode.
751     if (m_mode == INPUT_SENSE_KEYBOARD ||
752         m_mode == INPUT_SENSE_GAMEPAD)
753     {
754         // Do not pick disabled gamepads for input sensing
755          if (type == Input::IT_STICKBUTTON || type == Input::IT_STICKMOTION)
756         {
757              GamePadDevice *gPad = m_device_manager->getGamePadFromIrrID(deviceID);
758              // This can happen in case of automatically ignored accelerator
759              // devices, which are not part of stk's gamepad mapping.
760              if (!gPad) return;
761              DeviceConfig *conf = gPad->getConfiguration();
762              if (!conf->isEnabled())
763                  return;
764          }
765 
766         inputSensing(type, deviceID, button, axisDirection,  value);
767         return;
768     }
769 
770     // Abort demo mode if a key is pressed during the race in demo mode
771     if(dynamic_cast<DemoWorld*>(World::getWorld()))
772     {
773         RaceManager::get()->exitRace();
774         StateManager::get()->resetAndGoToScreen(MainMenuScreen::getInstance());
775         return;
776     }
777 
778     StateManager::ActivePlayer*   player = NULL;
779     PlayerAction    action;
780     bool action_found = m_device_manager->translateInput(type, deviceID,
781                                                          button, axisDirection,
782                                                          &value, m_mode,
783                                                          &player, &action);
784 
785     // in menus, some keyboard keys are standard (before each player selected
786     // his device). So if a key could not be mapped to any known binding,
787     // fall back to check the defaults.
788     if (!action_found &&
789             StateManager::get()->getGameState() != GUIEngine::GAME &&
790             type == Input::IT_KEYBOARD &&
791             m_mode == MENU && m_device_manager->getAssignMode() == NO_ASSIGN)
792     {
793         action = PA_BEFORE_FIRST;
794 
795         if      (button == IRR_KEY_UP)            action = PA_MENU_UP;
796         else if (button == IRR_KEY_DOWN)          action = PA_MENU_DOWN;
797         else if (button == IRR_KEY_LEFT)          action = PA_MENU_LEFT;
798         else if (button == IRR_KEY_RIGHT)         action = PA_MENU_RIGHT;
799         else if (button == IRR_KEY_SPACE)         action = PA_MENU_SELECT;
800         else if (button == IRR_KEY_RETURN)        action = PA_MENU_SELECT;
801         else if (button == IRR_KEY_BUTTON_UP)     action = PA_MENU_DOWN;
802         else if (button == IRR_KEY_BUTTON_DOWN)   action = PA_MENU_UP;
803         else if (button == IRR_KEY_BUTTON_LEFT)   action = PA_MENU_LEFT;
804         else if (button == IRR_KEY_BUTTON_RIGHT)  action = PA_MENU_RIGHT;
805         else if (button == IRR_KEY_BUTTON_A)      action = PA_MENU_SELECT;
806         else if (button == IRR_KEY_TAB)
807         {
808             if (shift_mask)
809             {
810                 action = PA_MENU_UP;
811             }
812             else
813             {
814                 action = PA_MENU_DOWN;
815             }
816         }
817 
818         if (button == IRR_KEY_RETURN || button == IRR_KEY_BUTTON_A)
819         {
820             if (GUIEngine::ModalDialog::isADialogActive() &&
821                 !GUIEngine::ScreenKeyboard::isActive())
822             {
823                 GUIEngine::ModalDialog::onEnterPressed();
824             }
825         }
826 
827         if (action != PA_BEFORE_FIRST)
828         {
829             action_found = true;
830             player = NULL;
831         }
832     }
833 
834     // do something with the key if it matches a binding
835     if (action_found)
836     {
837         // If we're in the kart menu awaiting new players, do special things
838         // when a device presses fire or rescue
839         if (m_device_manager->getAssignMode() == DETECT_NEW)
840         {
841             if (NetworkConfig::get()->isNetworking() &&
842                 NetworkConfig::get()->isAddingNetworkPlayers())
843             {
844                 // Ignore release event
845                 if (value == 0)
846                     return;
847                 InputDevice *device = NULL;
848                 if (type == Input::IT_KEYBOARD)
849                 {
850                     //Log::info("InputManager", "New Player Joining with Key %d", button);
851                     device = m_device_manager->getKeyboardFromBtnID(button);
852                 }
853                 else if (type == Input::IT_STICKBUTTON ||
854                         type == Input::IT_STICKMOTION    )
855                 {
856                     device = m_device_manager->getGamePadFromIrrID(deviceID);
857                 }
858                 if (device && (action == PA_FIRE || action == PA_MENU_SELECT) &&
859                     !GUIEngine::ModalDialog::isADialogActive())
860                 {
861                     GUIEngine::Screen* screen = GUIEngine::getCurrentScreen();
862                     NetworkingLobby* lobby = dynamic_cast<NetworkingLobby*>(screen);
863                     if (lobby!=NULL)
864                     {
865                         lobby->openSplitscreenDialog(device);
866                     }
867                     return;
868                 }
869             }
870 
871             // Player is unjoining
872             if ((player != NULL) && (action == PA_RESCUE ||
873                                      action == PA_MENU_CANCEL ) )
874             {
875                 // returns true if the event was handled
876                 // Ignore release event (otherwise it exit the kart selection screen
877                 // when back from race setup screen)
878                 if (value != 0 &&
879                     KartSelectionScreen::getRunningInstance()->playerQuit( player ))
880                 {
881                     return; // we're done here
882                 }
883             }
884 
885             /* The way this is currently structured, any time an event is
886                received from an input device that is not associated with a
887                player and the device manager is in DETECT_NEW mode, the event
888                is ignored, unless it is a PA_FIRE event (a player is joining)
889 
890                perhaps it will be good to let unassigned devices back out
891                of the kart selection menu?
892             */
893 
894             else if (player == NULL)
895             {
896                 // New player is joining
897                 if (value != 0 && (action == PA_FIRE || action == PA_MENU_SELECT))
898                 {
899                     InputDevice *device = NULL;
900                     if (type == Input::IT_KEYBOARD)
901                     {
902                         //Log::info("InputManager", "New Player Joining with Key %d", button);
903                         device = m_device_manager->getKeyboardFromBtnID(button);
904                     }
905                     else if (type == Input::IT_STICKBUTTON ||
906                              type == Input::IT_STICKMOTION    )
907                     {
908                         device = m_device_manager->getGamePadFromIrrID(deviceID);
909                     }
910 
911                     if (device != NULL)
912                     {
913                         KartSelectionScreen::getRunningInstance()->joinPlayer(device, NULL/*player profile*/);
914                     }
915                 }
916                 else if (value != 0 && (action == PA_MENU_CANCEL))
917                 {
918                     StateManager::get()->escapePressed();
919                 }
920                 return; // we're done here, ignore devices that aren't
921                         // associated with players
922             }
923         }
924 
925         auto cl = LobbyProtocol::get<ClientLobby>();
926         bool is_nw_spectator = cl && cl->isSpectator() &&
927              StateManager::get()->getGameState() == GUIEngine::GAME &&
928              !GUIEngine::ModalDialog::isADialogActive();
929 
930         // ... when in-game
931         if (StateManager::get()->getGameState() == GUIEngine::GAME &&
932              !GUIEngine::ModalDialog::isADialogActive()            &&
933              !GUIEngine::ScreenKeyboard::isActive()                &&
934              !RaceManager::get()->isWatchingReplay() && !is_nw_spectator)
935         {
936             if (player == NULL)
937             {
938                 // Prevent null pointer crash
939                 return;
940             }
941 
942             // Find the corresponding PlayerKart from our ActivePlayer instance
943             AbstractKart* pk = player->getKart();
944 
945             if (pk == NULL)
946             {
947                 Log::error("InputManager::dispatchInput", "Trying to process "
948                     "action for an unknown player");
949                 return;
950             }
951 
952             Controller* controller = pk->getController();
953             if (controller != NULL) controller->action(action, abs(value));
954         }
955         else if (RaceManager::get() &&
956             RaceManager::get()->isWatchingReplay() && !GUIEngine::ModalDialog::isADialogActive())
957         {
958             // Get the first ghost kart
959             World::getWorld()->getKart(0)
960                 ->getController()->action(action, abs(value));
961         }
962         // ... when in menus
963         else
964         {
965             // reset timer when released
966             if (abs(value) == 0 && type == Input::IT_STICKMOTION)
967             {
968                 m_timer_in_use = false;
969                 m_timer = 0;
970             }
971 
972             // When in master-only mode, we can safely assume that players
973             // are set up, contrarly to early menus where we accept every
974             // input because players are not set-up yet
975             if (m_master_player_only && player == NULL && !is_nw_spectator)
976             {
977                 if (type == Input::IT_STICKMOTION ||
978                     type == Input::IT_STICKBUTTON)
979                 {
980                     GamePadDevice* gp =
981                         getDeviceManager()->getGamePadFromIrrID(deviceID);
982 
983                     // Check for deadzone
984                     if (gp != NULL && gp->moved(value))
985                     {
986                         //I18N: message shown when an input device is used but
987                         // is not associated to any player
988                         GUIEngine::showMessage(
989                             _("Ignoring '%s'. You needed to join earlier to play!",
990                             core::stringw(gp->getName().c_str())));
991                     }
992                 }
993                 return;
994             }
995 
996             // menu input
997             if (!m_timer_in_use)
998             {
999                 if (type == Input::IT_STICKMOTION &&
1000                     abs(value) > Input::MAX_VALUE * 2 / 3)
1001                 {
1002                     m_timer_in_use = true;
1003                     m_timer = 0.25;
1004                 }
1005 
1006                 if (is_nw_spectator)
1007                 {
1008                     cl->changeSpectateTarget(action, abs(value), type);
1009                     return;
1010                 }
1011 
1012                 // player may be NULL in early menus, before player setup has
1013                 // been performed
1014                 int playerID = (player == NULL ? 0 : player->getID());
1015 
1016                 // If only the master player can act, and this player is not
1017                 // the master, ignore his input
1018                 if (m_device_manager->getAssignMode() == ASSIGN &&
1019                     m_master_player_only &&
1020                     playerID != PLAYER_ID_GAME_MASTER)
1021                 {
1022                     //I18N: message shown when a player that isn't game master
1023                     //I18N: tries to modify options that only the game master
1024                     //I18N: is allowed to
1025                     GUIEngine::showMessage(
1026                         _("Only the Game Master may act at this point!"));
1027                     return;
1028                 }
1029 
1030                 // all is good, pass the translated input event on to the
1031                 // event handler
1032                 GUIEngine::EventHandler::get()
1033                     ->processGUIAction(action, deviceID, abs(value), type,
1034                                        playerID);
1035             }
1036         }
1037     }
1038     else if (type == Input::IT_KEYBOARD)
1039     {
1040         // keyboard press not handled by device manager / bindings.
1041         // Check static bindings...
1042         handleStaticAction( button, value );
1043     }
1044 }   // input
1045 
1046 //-----------------------------------------------------------------------------
1047 
setMasterPlayerOnly(bool enabled)1048 void InputManager::setMasterPlayerOnly(bool enabled)
1049 {
1050 #if INPUT_MODE_DEBUG
1051     Log::info("InputManager::setMasterPlayerOnly", enabled ? "enabled" : "disabled");
1052 #endif
1053     m_master_player_only = enabled;
1054 }
1055 
1056 //-----------------------------------------------------------------------------
1057 
1058 /** Returns whether only the master player should be allowed to perform changes
1059  *  in menus */
masterPlayerOnly() const1060 bool InputManager::masterPlayerOnly() const
1061 {
1062     return m_device_manager->getAssignMode() == ASSIGN && m_master_player_only;
1063 }
1064 
1065 //-----------------------------------------------------------------------------
1066 
1067 /**
1068  * Called on keyboard events [indirectly] by irrLicht
1069  *
1070  * Analog axes can have any value from [-32768, 32767].
1071  *
1072  * There are no negative values. Instead this is reported as an axis with a
1073  * negative direction. This simplifies input configuration and allows greater
1074  * flexibility (= treat 4 directions as four buttons).
1075  *
1076  * Returns whether to halt the event's propagation here
1077  */
input(const SEvent & event)1078 EventPropagation InputManager::input(const SEvent& event)
1079 {
1080     const float ORIENTATION_MULTIPLIER = 10.0f;
1081     if (event.EventType == EET_JOYSTICK_INPUT_EVENT)
1082     {
1083         for (int axis_id=0; axis_id<SEvent::SJoystickEvent::NUMBER_OF_AXES ;
1084               axis_id++)
1085         {
1086             if (!event.JoystickEvent.IsAxisChanged(axis_id))
1087                 continue;
1088             int value = event.JoystickEvent.Axis[axis_id];
1089 
1090             if (UserConfigParams::m_gamepad_debug)
1091             {
1092                 Log::info("InputManager",
1093                           "axis motion: gamepad_id=%d axis=%d value=%d",
1094                           event.JoystickEvent.Joystick, axis_id, value);
1095             }
1096 
1097             dispatchInput(Input::IT_STICKMOTION, event.JoystickEvent.Joystick,
1098                           axis_id, Input::AD_NEUTRAL, value);
1099         }
1100 
1101         GamePadDevice* gp =
1102             getDeviceManager()->getGamePadFromIrrID(event.JoystickEvent.Joystick);
1103 
1104         if (gp == NULL)
1105         {
1106             // Prevent null pointer crash
1107             return EVENT_BLOCK;
1108         }
1109 
1110         for(int i=0; i<gp->getNumberOfButtons(); i++)
1111         {
1112             const bool isButtonPressed = event.JoystickEvent.IsButtonPressed(i);
1113 
1114             // Only report button events when the state of the button changes
1115             if ((!gp->isButtonPressed(i) &&  isButtonPressed) ||
1116                  (gp->isButtonPressed(i) && !isButtonPressed)    )
1117             {
1118                 if (UserConfigParams::m_gamepad_debug)
1119                 {
1120                     Log::info("InputManager", "button %i, status=%i",
1121                               i, isButtonPressed);
1122                 }
1123 
1124                 dispatchInput(Input::IT_STICKBUTTON,
1125                               event.JoystickEvent.Joystick, i,
1126                               Input::AD_POSITIVE,
1127                               isButtonPressed ? Input::MAX_VALUE : 0);
1128             }
1129             gp->setButtonPressed(i, isButtonPressed);
1130         }
1131 
1132     }
1133     else if (event.EventType == EET_KEY_INPUT_EVENT)
1134     {
1135         // On some systems (linux esp.) certain keys (e.g. [] ) have a 0
1136         // Key value, but do have a value defined in the Char field.
1137         // So to distinguish them (otherwise [] would both be mapped to
1138         // the same value 0, which means we can't distinguish which key
1139         // was actually pressed anymore), we set bit 10 which should
1140         // allow us to distinguish those artifical keys from the
1141         // 'real' keys.
1142         const int key = event.KeyInput.Key ? event.KeyInput.Key
1143                                            : event.KeyInput.Char+1024;
1144 
1145         if (event.KeyInput.PressedDown)
1146         {
1147             // escape is a little special
1148             if (key == IRR_KEY_ESCAPE)
1149             {
1150                 StateManager::get()->escapePressed();
1151                 return EVENT_BLOCK;
1152             }
1153             // 'backspace' in a text control must never be mapped, since user
1154             // can be in a text area trying to erase text (and if it's mapped
1155             // to rescue that would dismiss the dialog instead of erasing a
1156             // single letter). Same for spacebar. Same for letters.
1157             if (GUIEngine::isWithinATextBox())
1158             {
1159                 if (key == IRR_KEY_BACK || key == IRR_KEY_SPACE ||
1160                     key == IRR_KEY_SHIFT)
1161                 {
1162                     return EVENT_LET;
1163                 }
1164                 if (key >= IRR_KEY_0 && key <= IRR_KEY_Z)
1165                 {
1166                     return EVENT_LET;
1167                 }
1168             }
1169 
1170             const bool wasInTextBox = GUIEngine::isWithinATextBox();
1171 
1172             dispatchInput(Input::IT_KEYBOARD, event.KeyInput.Char, key,
1173                           Input::AD_POSITIVE, Input::MAX_VALUE,
1174                           event.KeyInput.Shift);
1175 
1176             // if this action took us into a text box, don't let event continue
1177             // (FIXME not the cleanest solution)
1178             if (!wasInTextBox && GUIEngine::isWithinATextBox())
1179             {
1180                 return EVENT_BLOCK;
1181             }
1182 
1183         }
1184         else
1185         {
1186             // 'backspace' in a text control must never be mapped, since user
1187             // can be in a text area trying to erase text (and if it's mapped
1188             // to rescue that would dismiss the dialog instead of erasing a
1189             // single letter). Same for spacebar. Same for letters.
1190             if (GUIEngine::isWithinATextBox())
1191             {
1192                 if (key == IRR_KEY_BACK || key == IRR_KEY_SPACE ||
1193                     key == IRR_KEY_SHIFT)
1194                 {
1195                     return EVENT_LET;
1196                 }
1197                 if (key >= IRR_KEY_0 && key <= IRR_KEY_Z)
1198                 {
1199                     return EVENT_LET;
1200                 }
1201             }
1202 
1203             dispatchInput(Input::IT_KEYBOARD, event.KeyInput.Char, key,
1204                           Input::AD_POSITIVE, 0, event.KeyInput.Shift);
1205             return EVENT_BLOCK; // Don't propagate key up events
1206         }
1207     }
1208     else if (event.EventType == EET_TOUCH_INPUT_EVENT)
1209     {
1210         MultitouchDevice* device = m_device_manager->getMultitouchDevice();
1211         unsigned int id = (unsigned int)event.TouchInput.ID;
1212 
1213         if (device != NULL && id < device->m_events.size())
1214         {
1215             device->m_events[id].id = id;
1216             device->m_events[id].x = event.TouchInput.X;
1217             device->m_events[id].y = event.TouchInput.Y;
1218 
1219             if (event.TouchInput.Event == ETIE_PRESSED_DOWN)
1220             {
1221                 device->m_events[id].touched = true;
1222             }
1223             else if (event.TouchInput.Event == ETIE_LEFT_UP)
1224             {
1225                 device->m_events[id].touched = false;
1226             }
1227 
1228             m_device_manager->updateMultitouchDevice();
1229             device->updateDeviceState(id);
1230         }
1231     }
1232     // Use the mouse to change the looking direction when first person view is activated
1233     else if (event.EventType == EET_MOUSE_INPUT_EVENT)
1234     {
1235         const int type = event.MouseInput.Event;
1236 
1237         if (type == EMIE_MOUSE_MOVED)
1238         {
1239             CameraFPS *cam = dynamic_cast<CameraFPS*>(Camera::getActiveCamera());
1240             if (cam)
1241             {
1242                 // Center of the screen
1243                 core::dimension2du screen_size = irr_driver->getActualScreenSize();
1244                 int mid_x = (int) screen_size.Width / 2;
1245                 int mid_y = (int) screen_size.Height / 2;
1246                 // Relative mouse movement
1247                 int diff_x = event.MouseInput.X - m_mouse_val_x;
1248                 int diff_y = event.MouseInput.Y - m_mouse_val_y;
1249                 float mouse_x = ((float) diff_x) *
1250                     UserConfigParams::m_fpscam_direction_speed;
1251                 float mouse_y = ((float) diff_y) *
1252                     -UserConfigParams::m_fpscam_direction_speed;
1253 
1254                 // No movement the first time it's used
1255                 // At the moment there's also a hard limit because the mouse
1256                 // gets reset to the middle of the screen and sometimes there
1257                 // are more events fired than expected.
1258                 if (m_mouse_val_x != -1 &&
1259                    (diff_x + diff_y) < 100 && (diff_x + diff_y) > -100)
1260                 {
1261                     // Rotate camera
1262                     cam->applyMouseMovement(mouse_x, mouse_y);
1263 
1264                     // Reset mouse position to the middle of the screen when
1265                     // the mouse is far away
1266                     if (event.MouseInput.X < mid_x / 2 ||
1267                         event.MouseInput.X > (mid_x + mid_x / 2) ||
1268                         event.MouseInput.Y < mid_y / 2 ||
1269                         event.MouseInput.Y > (mid_y + mid_y / 2))
1270                     {
1271                         irr_driver->getDevice()->getCursorControl()->setPosition(mid_x, mid_y);
1272                         m_mouse_val_x = mid_x;
1273                         m_mouse_val_y = mid_y;
1274                     }
1275                     else
1276                     {
1277                         m_mouse_val_x = event.MouseInput.X;
1278                         m_mouse_val_y = event.MouseInput.Y;
1279                     }
1280                 }
1281                 else
1282                 {
1283                     m_mouse_val_x = event.MouseInput.X;
1284                     m_mouse_val_y = event.MouseInput.Y;
1285                 }
1286                 return EVENT_BLOCK;
1287             }
1288             else
1289                 // Reset mouse position
1290                 m_mouse_val_x = m_mouse_val_y = -1;
1291         }
1292         else if (type == EMIE_MOUSE_WHEEL)
1293         {
1294             CameraFPS *cam = dynamic_cast<CameraFPS*>(Camera::getActiveCamera());
1295             if (cam)
1296             {
1297                 // Use scrolling to change the maximum speed
1298                 // Only test if it's more or less than 0 as it seems to be not
1299                 // reliable accross more platforms.
1300                 if (event.MouseInput.Wheel < 0)
1301                 {
1302                     float vel = cam->getMaximumVelocity() - 3;
1303                     if (vel < 0.0f)
1304                         vel = 0.0f;
1305                     cam->setMaximumVelocity(vel);
1306                 }
1307                 else if (event.MouseInput.Wheel > 0)
1308                 {
1309                     cam->setMaximumVelocity(cam->getMaximumVelocity() + 3);
1310                 }
1311             }
1312         }
1313 
1314         // Simulate touch events if there is no real device
1315         if (UserConfigParams::m_multitouch_active > 1 &&
1316             !irr_driver->getDevice()->supportsTouchDevice())
1317         {
1318             MultitouchDevice* device = m_device_manager->getMultitouchDevice();
1319 
1320             if (device != NULL && (type == EMIE_LMOUSE_PRESSED_DOWN ||
1321                 type == EMIE_LMOUSE_LEFT_UP || type == EMIE_MOUSE_MOVED))
1322             {
1323                 device->m_events[0].id = 0;
1324                 device->m_events[0].x = event.MouseInput.X;
1325                 device->m_events[0].y = event.MouseInput.Y;
1326 
1327                 if (type == EMIE_LMOUSE_PRESSED_DOWN)
1328                 {
1329                     device->m_events[0].touched = true;
1330                 }
1331                 else if (type == EMIE_LMOUSE_LEFT_UP)
1332                 {
1333                     device->m_events[0].touched = false;
1334                 }
1335 
1336                 m_device_manager->updateMultitouchDevice();
1337                 device->updateDeviceState(0);
1338             }
1339         }
1340 
1341         /*
1342         EMIE_LMOUSE_PRESSED_DOWN    Left mouse button was pressed down.
1343         EMIE_RMOUSE_PRESSED_DOWN    Right mouse button was pressed down.
1344         EMIE_MMOUSE_PRESSED_DOWN    Middle mouse button was pressed down.
1345         EMIE_LMOUSE_LEFT_UP     Left mouse button was left up.
1346         EMIE_RMOUSE_LEFT_UP     Right mouse button was left up.
1347         EMIE_MMOUSE_LEFT_UP     Middle mouse button was left up.
1348         EMIE_MOUSE_MOVED    The mouse cursor changed its position.
1349         EMIE_MOUSE_WHEEL    The mouse wheel was moved. Use Wheel value in
1350                             event data to find out in what direction and
1351                             how fast.
1352          */
1353     }
1354     else if (event.EventType == EET_ACCELEROMETER_EVENT)
1355     {
1356         MultitouchDevice* device = m_device_manager->getMultitouchDevice();
1357 
1358         if (device && device->isAccelerometerActive())
1359         {
1360             m_device_manager->updateMultitouchDevice();
1361 
1362             float factor = UserConfigParams::m_multitouch_tilt_factor;
1363             factor = std::max(factor, 0.1f);
1364             if (UserConfigParams::m_multitouch_controls == MULTITOUCH_CONTROLS_GYROSCOPE)
1365             {
1366                 device->updateOrientationFromAccelerometer((float)event.AccelerometerEvent.X,
1367                                                            (float)event.AccelerometerEvent.Y);
1368                 device->updateAxisX(device->getOrientation() * ORIENTATION_MULTIPLIER / factor);
1369             }
1370             else
1371             {
1372                 device->updateAxisX(float(event.AccelerometerEvent.Y) / factor);
1373             }
1374         }
1375     }
1376     else if (event.EventType == EET_GYROSCOPE_EVENT)
1377     {
1378         MultitouchDevice* device = m_device_manager->getMultitouchDevice();
1379 
1380         if (device && device->isGyroscopeActive())
1381         {
1382             m_device_manager->updateMultitouchDevice();
1383 
1384             float factor = UserConfigParams::m_multitouch_tilt_factor;
1385             factor = std::max(factor, 0.1f);
1386             device->updateOrientationFromGyroscope((float)event.GyroscopeEvent.Z);
1387             device->updateAxisX(device->getOrientation() * ORIENTATION_MULTIPLIER / factor);
1388         }
1389     }
1390 
1391     // block events in all modes but initial menus (except in text boxes to
1392     // allow typing, and except in modal dialogs in-game)
1393     // FIXME: 1) that's awful logic 2) that's not what the code below does,
1394     // events are never blocked in menus
1395     if (getDeviceManager()->getAssignMode() != NO_ASSIGN &&
1396         !GUIEngine::isWithinATextBox() &&
1397         (!GUIEngine::ModalDialog::isADialogActive() &&
1398         !GUIEngine::ScreenKeyboard::isActive() &&
1399         StateManager::get()->getGameState() == GUIEngine::GAME))
1400     {
1401         return EVENT_BLOCK;
1402     }
1403     else
1404     {
1405         return EVENT_LET;
1406     }
1407 }
1408 
1409 //-----------------------------------------------------------------------------
1410 /** Queries the input driver whether it is in the given expected mode.
1411  */
isInMode(InputDriverMode expMode)1412 bool InputManager::isInMode(InputDriverMode expMode)
1413 {
1414     return m_mode == expMode;
1415 }   // isInMode
1416 
1417 //-----------------------------------------------------------------------------
1418 /** Sets the mode of the input driver.
1419  *
1420  * Switching of the input driver's modes is only needed for special menus
1421  * (those who need typing or input sensing) and the MenuManager (switch to
1422  * ingame/menu mode). Therefore there is a limited amount of legal combinations
1423  * of current and next input driver modes: From the menu mode you can switch
1424  * to any other mode and from any other mode only back to the menu mode.
1425  *
1426  * In input sense mode the pointer is invisible (any movement reports are
1427  * suppressed). If an input happens it is stored internally and can be
1428  * retrieved through drv_getm_sensed_input() *after* GA_SENSE_COMPLETE has been
1429  * distributed to a menu (Normally the menu that received GA_SENSE_COMPLETE
1430  * will request the sensed input ...). If GA_SENSE_CANCEL is received instead
1431  * the user decided to cancel input sensing. No other game action values are
1432  * distributed in this mode.
1433  *
1434  * And there is the bootstrap mode. You cannot switch to it and only leave it
1435  * once per application instance. It is the state the input driver is first.
1436  *
1437  */
setMode(InputDriverMode new_mode)1438 void InputManager::setMode(InputDriverMode new_mode)
1439 {
1440     if (new_mode == m_mode) return; // no change
1441 
1442     switch (new_mode)
1443     {
1444         case MENU:
1445 #if INPUT_MODE_DEBUG
1446             Log::info("InputManager::setMode", "MENU");
1447 #endif
1448             switch (m_mode)
1449             {
1450                 case INGAME:
1451                     // Leaving ingame mode.
1452 
1453                     //if (m_action_map)
1454                     //    delete m_action_map;
1455 
1456                     // Reset the helper values for the relative mouse movement
1457                     // supresses to the notification of them as an input.
1458                     m_mouse_val_x = m_mouse_val_y = -1;
1459 
1460                     //irr_driver->showPointer();
1461                     m_mode = MENU;
1462                     break;
1463 
1464                 case BOOTSTRAP:
1465                     // Leaving boot strap mode.
1466 
1467                     // Installs the action map for the menu.
1468                     //  m_action_map = UserConfigParams::newMenuActionMap();
1469 
1470                     m_mode = MENU;
1471                     m_device_manager->setAssignMode(NO_ASSIGN);
1472 
1473                     break;
1474                 case INPUT_SENSE_KEYBOARD:
1475                 case INPUT_SENSE_GAMEPAD:
1476                     // Leaving input sense mode.
1477 
1478                     //irr_driver->showPointer();
1479                     m_sensed_input_high_gamepad.clear();
1480                     m_sensed_input_zero_gamepad.clear();
1481                     m_sensed_input_high_kbd.clear();
1482 
1483                     // The order is deliberate just in case someone starts
1484                     // to make STK multithreaded: m_sensed_input must not be
1485                     // 0 when mode == INPUT_SENSE_PREFER_{AXIS,BUTTON}.
1486                     m_mode = MENU;
1487 
1488                     break;
1489 
1490                     /*
1491                 case LOWLEVEL:
1492                     // Leaving lowlevel mode.
1493                     //irr_driver->showPointer();
1494 
1495                     m_mode = MENU;
1496 
1497                     break;
1498                      */
1499                 default:
1500                     ;
1501                     // Something is broken.
1502                     //assert (false);
1503             }
1504 
1505             break;
1506         case INGAME:
1507 #if INPUT_MODE_DEBUG
1508             Log::info("InputManager::setMode", "INGAME");
1509 #endif
1510             // We must be in menu mode now in order to switch.
1511             assert (m_mode == MENU);
1512 
1513             //if (m_action_map)
1514             //   delete m_action_map;
1515 
1516             // Installs the action map for the ingame mode.
1517             // m_action_map = UserConfigParams::newIngameActionMap();
1518 
1519             //irr_driver->hidePointer();
1520 
1521             m_mode = INGAME;
1522 
1523             break;
1524         case INPUT_SENSE_KEYBOARD:
1525         case INPUT_SENSE_GAMEPAD:
1526 #if INPUT_MODE_DEBUG
1527             Log::info("InputManager::setMode", "INPUT_SENSE_*");
1528 #endif
1529             // We must be in menu mode now in order to switch.
1530             assert (m_mode == MENU);
1531 
1532             // Reset the helper values for the relative mouse movement
1533             // supresses to the notification of them as an input.
1534             m_mouse_val_x = m_mouse_val_y = -1;
1535             m_mode        = new_mode;
1536 
1537             break;
1538             /*
1539         case LOWLEVEL:
1540 #if INPUT_MODE_DEBUG
1541             Log::info("InputManager::setMode", "LOWLEVEL");
1542 #endif
1543             // We must be in menu mode now in order to switch.
1544             assert (m_mode == MENU);
1545 
1546             //irr_driver->hidePointer();
1547 
1548             m_mode = LOWLEVEL;
1549 
1550             break;
1551              */
1552         default:
1553             // Invalid mode.
1554             assert(false);
1555     }
1556 }
1557 
1558