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