Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core4/src/core/input/InputManager.cc @ 3274

Last change on this file since 3274 was 3274, checked in by rgrieder, 15 years ago

Added a few more generic parts to the input library:

  • Created Mouse and Keyboard to join JoyStick and provided them with a templated base class (InputDeviceTemplated) that does most of the work (reduces quite some redundancy)
  • Created InputPrereqs.h from InputInterfaces.h and destroyed the latter
  • Exported InputHandler to its own file and replaced KeyHandler, MouseHandler and JoyStickHandler with the single InputHandler.
  • Deleted the SimpleInputState: There is only one class now which fulfills all our needs.

In general there is now less code and the code itself has more 'pluses'. However I haven't really thrown away any feature at all.

  • Property svn:eol-style set to native
File size: 32.4 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Reto Grieder
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29/**
30@file
31@brief
32    Implementation of the InputManager that captures all the input from OIS
33    and redirects it to handlers.
34 */
35
36#include "InputManager.h"
37
38#include <climits>
39#include <cassert>
40#include <ois/OISException.h>
41#include <ois/OISInputManager.h>
42#include <boost/foreach.hpp>
43
44#include "util/Convert.h"
45#include "util/Exception.h"
46#include "util/ScopeGuard.h"
47#include "core/Clock.h"
48#include "core/CoreIncludes.h"
49#include "core/ConfigValueIncludes.h"
50#include "core/ConsoleCommand.h"
51#include "core/CommandLine.h"
52#include "core/Functor.h"
53
54#include "InputBuffer.h"
55#include "KeyDetector.h"
56#include "InputHandler.h"
57#include "InputState.h"
58#include "JoyStickQuantityListener.h"
59#include "JoyStick.h"
60#include "Mouse.h"
61#include "Keyboard.h"
62
63// HACK (include this as last, X11 seems to define some macros...)
64#ifdef ORXONOX_PLATFORM_LINUX
65#  include <ois/linux/LinuxMouse.h>
66#endif
67
68namespace orxonox
69{
70    SetConsoleCommand(InputManager, calibrate, true);
71    SetConsoleCommand(InputManager, reload, false);
72#ifdef ORXONOX_PLATFORM_LINUX
73    SetConsoleCommand(InputManager, grabMouse, true);
74    SetConsoleCommand(InputManager, ungrabMouse, true);
75#endif
76    SetCommandLineSwitch(keyboard_no_grab).information("Whether not to exclusively grab the keyboard");
77
78    InputHandler InputHandler::EMPTY;
79    InputManager* InputManager::singletonRef_s = 0;
80
81    /**
82    @brief
83        Defines the |= operator for easier use.
84    */
85    inline InputManager::InputManagerState operator|=(InputManager::InputManagerState& lval,
86                                                      InputManager::InputManagerState rval)
87    {
88        return (lval = (InputManager::InputManagerState)(lval | rval));
89    }
90
91    /**
92    @brief
93        Defines the &= operator for easier use.
94    */
95    inline InputManager::InputManagerState operator&=(InputManager::InputManagerState& lval, int rval)
96    {
97        return (lval = (InputManager::InputManagerState)(lval & rval));
98    }
99
100    // ############################################################
101    // #####                  Initialisation                  #####
102    // ##########                                        ##########
103    // ############################################################
104
105    /**
106    @brief
107        Constructor only sets member fields to initial zero values
108        and registers the class in the class hierarchy.
109    */
110    InputManager::InputManager(size_t windowHnd, unsigned int windowWidth, unsigned int windowHeight)
111        : inputSystem_(0)
112        , devices_(2)
113        , windowHnd_(0)
114        , internalState_(Uninitialised)
115        , stateEmpty_(0)
116        , keyDetector_(0)
117        , calibratorCallbackBuffer_(0)
118    {
119        RegisterRootObject(InputManager);
120
121        assert(singletonRef_s == 0);
122        singletonRef_s = this;
123
124        setConfigValues();
125
126        initialise(windowHnd, windowWidth, windowHeight);
127    }
128
129    /**
130    @brief
131        Sets the configurable values.
132    */
133    void InputManager::setConfigValues()
134    {
135    }
136
137    /**
138    @brief
139        Creates the OIS::InputMananger, the keyboard, the mouse and
140        the joysticks and assigns the key bindings.
141    @param windowHnd
142        The window handle of the render window
143    @param windowWidth
144        The width of the render window
145    @param windowHeight
146        The height of the render window
147    */
148    void InputManager::initialise(size_t windowHnd, unsigned int windowWidth, unsigned int windowHeight)
149    {
150        CCOUT(3) << "Initialising Input System..." << std::endl;
151
152        if (!(internalState_ & OISReady))
153        {
154            CCOUT(4) << "Initialising OIS components..." << std::endl;
155
156            // store handle internally so we can reload OIS
157            windowHnd_ = windowHnd;
158
159            OIS::ParamList paramList;
160            std::ostringstream windowHndStr;
161
162            // Fill parameter list
163            windowHndStr << (unsigned int)windowHnd_;
164            paramList.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
165#if defined(ORXONOX_PLATFORM_WINDOWS)
166            //paramList.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_NONEXCLUSIVE")));
167            //paramList.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_FOREGROUND")));
168            //paramList.insert(std::make_pair(std::string("w32_keyboard"), std::string("DISCL_NONEXCLUSIVE")));
169            //paramList.insert(std::make_pair(std::string("w32_keyboard"), std::string("DISCL_FOREGROUND")));
170#elif defined(ORXONOX_PLATFORM_LINUX)
171            paramList.insert(std::make_pair(std::string("XAutoRepeatOn"), std::string("true")));
172            paramList.insert(std::make_pair(std::string("x11_mouse_grab"), "true"));
173            paramList.insert(std::make_pair(std::string("x11_mouse_hide"), "true"));
174            bool kbNoGrab;
175            CommandLine::getValue("keyboard_no_grab", &kbNoGrab);
176            if (kbNoGrab)
177                paramList.insert(std::make_pair(std::string("x11_keyboard_grab"), std::string("false")));
178            else
179                paramList.insert(std::make_pair(std::string("x11_keyboard_grab"), std::string("true")));
180#endif
181
182            // TODO: clean this up
183            try
184            {
185                inputSystem_ = OIS::InputManager::createInputSystem(paramList);
186                // Exception-safety
187                Loki::ScopeGuard guard = Loki::MakeGuard(OIS::InputManager::destroyInputSystem, inputSystem_);
188                CCOUT(ORX_DEBUG) << "Created OIS input system" << std::endl;
189
190                _initialiseKeyboard();
191
192                // Nothing below should throw anymore, dismiss the guard
193                guard.Dismiss();
194            }
195            catch (OIS::Exception& ex)
196            {
197                ThrowException(InitialisationFailed, "Could not initialise the input system: " << ex.what());
198            }
199
200            // TODO: Remove the two parameters
201            _initialiseMouse(windowWidth, windowHeight);
202
203            _initialiseJoySticks();
204
205            // clear all buffers
206            clearBuffers();
207
208            internalState_ |= OISReady;
209
210            CCOUT(ORX_DEBUG) << "Initialising OIS components done." << std::endl;
211        }
212        else
213        {
214            CCOUT(2) << "Warning: OIS compoments already initialised, skipping" << std::endl;
215        }
216
217        if (!(internalState_ & InternalsReady))
218        {
219            CCOUT(4) << "Initialising InputStates components..." << std::endl;
220
221            // Lowest priority empty InputState
222            stateEmpty_ = createInputState("empty", false, false, InputStatePriority::Empty);
223            stateEmpty_->setHandler(&InputHandler::EMPTY);
224            activeStates_[stateEmpty_->getPriority()] = stateEmpty_;
225
226            // KeyDetector to evaluate a pressed key's name
227            InputState* detector = createInputState("detector", false, false, InputStatePriority::Detector);
228            FunctorMember<InputManager>* bufferFunctor = createFunctor(&InputManager::clearBuffers);
229            bufferFunctor->setObject(this);
230            detector->setLeaveFunctor(bufferFunctor);
231            keyDetector_ = new KeyDetector();
232            detector->setHandler(keyDetector_);
233
234            // Joy stick calibration helper callback
235            InputState* calibrator = createInputState("calibrator", false, false, InputStatePriority::Calibrator);
236            calibrator->setHandler(&InputHandler::EMPTY);
237            calibratorCallbackBuffer_ = new InputBuffer();
238            calibratorCallbackBuffer_->registerListener(this, &InputManager::_stopCalibration, '\r', true);
239            calibrator->setKeyHandler(calibratorCallbackBuffer_);
240
241            internalState_ |= InternalsReady;
242
243            CCOUT(4) << "Initialising InputStates complete." << std::endl;
244        }
245
246        _updateActiveStates();
247
248        CCOUT(3) << "Initialising complete." << std::endl;
249    }
250
251    void InputManager::_initialiseKeyboard()
252    {
253        assert(devices_[InputDeviceEnumerator::Keyboard] == 0);
254        if (inputSystem_->getNumberOfDevices(OIS::OISKeyboard) > 0)
255            devices_[InputDeviceEnumerator::Keyboard] = new Keyboard(InputDeviceEnumerator::Keyboard);
256        else
257            ThrowException(InitialisationFailed, "InputManager: No keyboard found, cannot proceed!");
258    }
259
260    void InputManager::_initialiseMouse(unsigned int windowWidth, unsigned int windowHeight)
261    {
262        assert(devices_[InputDeviceEnumerator::Mouse] == 0);
263        if (inputSystem_->getNumberOfDevices(OIS::OISMouse) > 0)
264        {
265            try
266            {
267                devices_[InputDeviceEnumerator::Mouse] = new Mouse(InputDeviceEnumerator::Mouse, windowWidth, windowHeight);
268            }
269            catch (const OIS::Exception& ex)
270            {
271                CCOUT(2) << "Warning: Failed to create Mouse:" << ex.eText << std::endl
272                         << "Proceeding without mouse support." << std::endl;
273            }
274        }
275        else
276            CCOUT(ORX_WARNING) << "Warning: No mouse found! Proceeding without mouse support." << std::endl;
277    }
278
279    /**
280    @brief
281        Creates all joy sticks and sets the event handler.
282    @return
283        False joy stick stay uninitialised, true otherwise.
284    */
285    void InputManager::_initialiseJoySticks()
286    {
287        assert(devices_.size() == InputDeviceEnumerator::FirstJoyStick);
288
289        for (int i = 0; i < inputSystem_->getNumberOfDevices(OIS::OISJoyStick); i++)
290        {
291            try
292            {
293                devices_.push_back(new JoyStick(InputDeviceEnumerator::FirstJoyStick + i));
294            }
295            catch (std::exception ex)
296            {
297                CCOUT(2) << "Warning: Failed to create joy stick: " << ex.what() << std::endl;
298            }
299        }
300
301        // inform all JoyStick Device Number Listeners
302        for (ObjectList<JoyStickQuantityListener>::iterator it = ObjectList<JoyStickQuantityListener>::begin(); it; ++it)
303            it->JoyStickQuantityChanged(devices_.size() - InputDeviceEnumerator::FirstJoyStick);
304    }
305
306    void InputManager::_startCalibration()
307    {
308        BOOST_FOREACH(InputDevice* device, devices_)
309            device->startCalibration();
310
311        getInstance().internalState_ |= Calibrating;
312        getInstance().requestEnterState("calibrator");
313    }
314
315    void InputManager::_stopCalibration()
316    {
317        BOOST_FOREACH(InputDevice* device, devices_)
318            device->stopCalibration();
319
320        // restore old input state
321        requestLeaveState("calibrator");
322        internalState_ &= ~Calibrating;
323        // Clear buffers to prevent button hold events
324        this->clearBuffers();
325    }
326
327    // ############################################################
328    // #####                    Destruction                   #####
329    // ##########                                        ##########
330    // ############################################################
331
332    /**
333    @brief
334        Destroys all the created input devices and states.
335    */
336    // TODO: export this to be used with reload()
337    InputManager::~InputManager()
338    {
339        if (internalState_ != Uninitialised)
340        {
341            CCOUT(3) << "Destroying ..." << std::endl;
342
343            // Destroy calibrator helper handler and state
344            delete keyDetector_;
345            requestDestroyState("calibrator");
346            // Destroy KeyDetector and state
347            delete calibratorCallbackBuffer_;
348            requestDestroyState("detector");
349            // destroy the empty InputState
350            _destroyState(this->stateEmpty_);
351
352            // destroy all user InputStates
353            while (inputStatesByName_.size() > 0)
354                _destroyState((*inputStatesByName_.rbegin()).second);
355
356            // destroy the devices
357            BOOST_FOREACH(InputDevice*& device, devices_)
358            {
359                std::string className = device->getClassName();
360                try
361                {
362                    if (device)
363                        delete device;
364                    device = 0;
365                    CCOUT(4) << className << " destroyed." << std::endl;
366                }
367                catch (...)
368                {
369                    CCOUT(1) << className << " destruction failed! Potential resource leak!" << std::endl;
370                }
371            }
372            devices_.resize(InputDeviceEnumerator::FirstJoyStick);
373
374            try
375            {
376                OIS::InputManager::destroyInputSystem(inputSystem_);
377            }
378            catch (...)
379            {
380                CCOUT(1) << "OIS::InputManager destruction failed! Potential resource leak!" << std::endl;
381            }
382        }
383
384        singletonRef_s = 0;
385    }
386
387    /**
388    @brief
389        Removes and destroys an InputState.
390    @return
391        True if state was removed immediately, false if postponed.
392    */
393    void InputManager::_destroyState(InputState* state)
394    {
395        assert(state && !(this->internalState_ & Ticking));
396        std::map<int, InputState*>::iterator it = this->activeStates_.find(state->getPriority());
397        if (it != this->activeStates_.end())
398        {
399            this->activeStates_.erase(it);
400            _updateActiveStates();
401        }
402        inputStatesByName_.erase(state->getName());
403        delete state;
404    }
405
406    // ############################################################
407    // #####                     Reloading                    #####
408    // ##########                                        ##########
409    // ############################################################
410
411    /**
412    @brief
413        Public interface. Only reloads immediately if the call stack doesn't
414        include the update() method.
415    */
416    void InputManager::reloadInputSystem()
417    {
418        if (internalState_ & Ticking)
419        {
420            // We cannot destroy OIS right now, because reload was probably
421            // caused by a user clicking on a GUI item. The backtrace would then
422            // include an OIS method. So it would be a very bad thing to destroy it..
423            internalState_ |= ReloadRequest;
424        }
425        else if (internalState_ & OISReady)
426            _reload();
427        else
428        {
429            CCOUT(2) << "Warning: Cannot reload OIS. May not yet be initialised or"
430                     << "joy sticks are currently calibrating." << std::endl;
431        }
432    }
433
434    /**
435    @brief
436        Internal reload method. Destroys the OIS devices and loads them again.
437    */
438    void InputManager::_reload()
439    {
440        try
441        {
442            CCOUT(3) << "Reloading ..." << std::endl;
443
444            // Save mouse clipping size
445            int mouseWidth  = static_cast<Mouse*>(devices_[InputDeviceEnumerator::Mouse])->getClippingWidth();
446            int mouseHeight = static_cast<Mouse*>(devices_[InputDeviceEnumerator::Mouse])->getClippingHeight();
447
448            internalState_ &= ~OISReady;
449
450            // destroy the devices
451            // destroy the devices
452            BOOST_FOREACH(InputDevice*& device, devices_)
453            {
454                try
455                {
456                    if (device)
457                        delete device;
458                    device = 0;
459                    CCOUT(4) << device->getClassName() << " destroyed." << std::endl;
460                }
461                catch (...)
462                {
463                    CCOUT(1) << device->getClassName() << " destruction failed! Potential resource leak!" << std::endl;
464                }
465            }
466            devices_.resize(InputDeviceEnumerator::FirstJoyStick);
467
468            OIS::InputManager::destroyInputSystem(inputSystem_);
469            inputSystem_ = 0;
470
471            // clear all buffers containing input information
472            clearBuffers();
473
474            initialise(windowHnd_, mouseWidth, mouseHeight);
475
476            CCOUT(3) << "Reloading done." << std::endl;
477        }
478        catch (OIS::Exception& ex)
479        {
480            CCOUT(1) << "An exception has occured while reloading:\n" << ex.what() << std::endl;
481        }
482    }
483
484    // ############################################################
485    // #####                  Runtime Methods                 #####
486    // ##########                                        ##########
487    // ############################################################
488
489    /**
490    @brief
491        Updates the states and the InputState situation.
492    @param time
493        Clock holding the current time.
494    */
495    void InputManager::update(const Clock& time)
496    {
497        if (internalState_ == Uninitialised)
498            return;
499        else if (internalState_ & ReloadRequest)
500        {
501            _reload();
502            internalState_ &= ~ReloadRequest;
503        }
504
505        // check for states to leave
506        if (!stateLeaveRequests_.empty())
507        {
508            for (std::set<InputState*>::iterator it = stateLeaveRequests_.begin();
509                it != stateLeaveRequests_.end(); ++it)
510            {
511                (*it)->left();
512                // just to be sure that the state actually is registered
513                assert(inputStatesByName_.find((*it)->getName()) != inputStatesByName_.end());
514
515                activeStates_.erase((*it)->getPriority());
516                if ((*it)->getPriority() < InputStatePriority::HighPriority)
517                    (*it)->setPriority(0);
518                _updateActiveStates();
519            }
520            stateLeaveRequests_.clear();
521        }
522
523        // check for states to enter
524        if (!stateEnterRequests_.empty())
525        {
526            for (std::set<InputState*>::const_iterator it = stateEnterRequests_.begin();
527                it != stateEnterRequests_.end(); ++it)
528            {
529                // just to be sure that the state actually is registered
530                assert(inputStatesByName_.find((*it)->getName()) != inputStatesByName_.end());
531
532                if ((*it)->getPriority() == 0)
533                {
534                    // Get smallest possible priority between 1 and maxStateStackSize_s
535                    for(std::map<int, InputState*>::reverse_iterator rit = activeStates_.rbegin();
536                        rit != activeStates_.rend(); ++rit)
537                    {
538                        if (rit->first < InputStatePriority::HighPriority)
539                        {
540                            (*it)->setPriority(rit->first + 1);
541                            break;
542                        }
543                    }
544                    // In case no normal handler was on the stack
545                    if ((*it)->getPriority() == 0)
546                        (*it)->setPriority(1);
547                }
548                activeStates_[(*it)->getPriority()] = (*it);
549                _updateActiveStates();
550                (*it)->entered();
551            }
552            stateEnterRequests_.clear();
553        }
554
555        // check for states to destroy
556        if (!stateDestroyRequests_.empty())
557        {
558            for (std::set<InputState*>::iterator it = stateDestroyRequests_.begin();
559                it != stateDestroyRequests_.end(); ++it)
560            {
561                _destroyState((*it));
562            }
563            stateDestroyRequests_.clear();
564        }
565
566        // check whether a state has changed its EMPTY situation
567        bool bUpdateRequired = false;
568        for (std::map<int, InputState*>::iterator it = activeStates_.begin(); it != activeStates_.end(); ++it)
569        {
570            if (it->second->hasExpired())
571            {
572                it->second->resetExpiration();
573                bUpdateRequired = true;
574            }
575        }
576        if (bUpdateRequired)
577            _updateActiveStates();
578
579        // mark that we now start capturing and distributing input
580        internalState_ |= Ticking;
581
582        // Capture all the input. This calls the event handlers in InputManager.
583        BOOST_FOREACH(InputDevice* device, devices_)
584            device->update(time);
585
586        if (!(internalState_ & Calibrating))
587        {
588            // update the states with a general tick afterwards
589            for (unsigned int i = 0; i < activeStatesTicked_.size(); ++i)
590                activeStatesTicked_[i]->update(time.getDeltaTime());
591        }
592
593        internalState_ &= ~Ticking;
594    }
595
596    /**
597    @brief
598        Updates the currently active states (according to activeStates_) for each device.
599        Also, a list of all active states (no duplicates!) is compiled for the general update().
600    */
601    void InputManager::_updateActiveStates()
602    {
603        // temporary resize
604        for (unsigned int i = 0; i < devices_.size(); ++i)
605        {
606            std::vector<InputState*>& states = devices_[i]->getStateListRef();
607            bool occupied = false;
608            states.clear();
609            for (std::map<int, InputState*>::reverse_iterator rit = activeStates_.rbegin(); rit != activeStates_.rend(); ++rit)
610            {
611                if (rit->second->isInputDeviceEnabled(i) && (!occupied || rit->second->bAlwaysGetsInput_))
612                {
613                    states.push_back(rit->second);
614                    if (!rit->second->bTransparent_)
615                        occupied = true;
616                }
617            }
618        }
619
620        // update tickables (every state will only appear once)
621        // Using a std::set to avoid duplicates
622        std::set<InputState*> tempSet;
623        for (unsigned int i = 0; i < devices_.size(); ++i)
624            for (unsigned int iState = 0; iState < devices_[i]->getStateListRef().size(); ++iState)
625                tempSet.insert(devices_[i]->getStateListRef()[iState]);
626
627        // copy the content of the std::set back to the actual vector
628        activeStatesTicked_.clear();
629        for (std::set<InputState*>::const_iterator it = tempSet.begin();it != tempSet.end(); ++it)
630            activeStatesTicked_.push_back(*it);
631    }
632
633    /**
634    @brief
635        Clears all buffers that store what keys/buttons are being pressed at the moment.
636    */
637    void InputManager::clearBuffers()
638    {
639        BOOST_FOREACH(InputDevice* device, devices_)
640            device->clearBuffers();
641    }
642
643
644    // ############################################################
645    // #####                Friend functions                  #####
646    // ##########                                        ##########
647    // ############################################################
648
649    /**
650    @brief
651        Checks whether there is already a joy stick with the given ID string.
652    @return
653        Returns true if ID is ok (unique), false otherwise.
654    */
655    bool InputManager::checkJoyStickID(const std::string& idString) const
656    {
657        for (unsigned int i = InputDeviceEnumerator::FirstJoyStick; i < devices_.size(); ++i)
658            if (static_cast<JoyStick*>(devices_[i])->getIDString() == idString)
659                return false;
660        return true;
661    }
662
663
664    // ############################################################
665    // #####         Other Public Interface Methods           #####
666    // ##########                                        ##########
667    // ############################################################
668
669    /**
670    @brief
671        Sets the the name of the command used by the KeyDetector as callback.
672    @param command
673        Command name as string
674    */
675    void InputManager::setKeyDetectorCallback(const std::string& command)
676    {
677        this->keyDetector_->setCallbackCommand(command);
678    }
679
680    // ###### InputStates ######
681
682    /**
683    @brief
684        Creates a new InputState by type, name and priority.
685       
686        You will have to use this method because the
687        c'tors and d'tors are private.
688    @remarks
689        The InputManager will take care of the state completely. That also
690        means it gets deleted when the InputManager is destroyed!
691    @param name
692        Name of the InputState when referenced as string
693    @param priority
694        Priority matters when multiple states are active. You can specify any
695        number, but 1 - 99 is preferred (99 means high).
696    */
697    InputState* InputManager::createInputState(const std::string& name, bool bAlwaysGetsInput, bool bTransparent, InputStatePriority priority)
698    {
699        InputState* state = new InputState;
700        if (_configureInputState(state, name, bAlwaysGetsInput, bTransparent, priority))
701            return state;
702        else
703        {
704            delete state;
705            return 0;
706        }
707    }
708
709    /**
710    @brief
711        Adds a new key handler.
712    @param handler
713        Pointer to the handler object.
714    @param name
715        Unique name of the handler.
716    @param priority
717        Determines which InputState gets the input. Higher is better.
718        Use 0 to handle it implicitely by the order of activation.
719        Otherwise numbers larger than maxStateStackSize_s have to be used!
720    @return
721        True if added, false if name or priority already existed.
722    */
723    bool InputManager::_configureInputState(InputState* state, const std::string& name, bool bAlwaysGetsInput, bool bTransparent, int priority)
724    {
725        if (name == "")
726            return false;
727        if (!state)
728            return false;
729        if (inputStatesByName_.find(name) == inputStatesByName_.end())
730        {
731            if (priority >= InputStatePriority::HighPriority || priority == InputStatePriority::Empty)
732            {
733                // Make sure we don't add two high priority states with the same priority
734                for (std::map<std::string, InputState*>::const_iterator it = this->inputStatesByName_.begin();
735                    it != this->inputStatesByName_.end(); ++it)
736                {
737                    if (it->second->getPriority() == priority)
738                    {
739                        COUT(2) << "Warning: Could not add an InputState with the same priority '"
740                            << priority << "' != 0." << std::endl;
741                        return false;
742                    }
743                }
744            }
745            inputStatesByName_[name] = state;
746            state->JoyStickQuantityChanged(devices_.size() - InputDeviceEnumerator::FirstJoyStick);
747            state->setName(name);
748            state->bAlwaysGetsInput_ = bAlwaysGetsInput;
749            state->bTransparent_ = bTransparent;
750            if (priority >= InputStatePriority::HighPriority || priority == InputStatePriority::Empty)
751                state->setPriority(priority);
752            return true;
753        }
754        else
755        {
756            COUT(2) << "Warning: Could not add an InputState with the same name '" << name << "'." << std::endl;
757            return false;
758        }
759    }
760
761    /**
762    @brief
763        Removes and destroys an input state internally.
764    @param name
765        Name of the handler.
766    @return
767        True if removal was successful, false if name was not found.
768    @remarks
769        You can't remove the internal states "empty", "calibrator" and "detector".
770        The removal process is being postponed if InputManager::update() is currently running.
771    */
772    bool InputManager::requestDestroyState(const std::string& name)
773    {
774        if (name == "empty")
775        {
776            COUT(2) << "InputManager: Removing the empty state is not allowed!" << std::endl;
777            return false;
778        }
779        std::map<std::string, InputState*>::iterator it = inputStatesByName_.find(name);
780        if (it != inputStatesByName_.end())
781        {
782            if (activeStates_.find(it->second->getPriority()) != activeStates_.end())
783            {
784                // The state is still active. We have to postpone
785                stateLeaveRequests_.insert(it->second);
786                stateDestroyRequests_.insert(it->second);
787            }
788            else if (this->internalState_ & Ticking)
789            {
790                // cannot remove state while ticking
791                stateDestroyRequests_.insert(it->second);
792            }
793            else
794                _destroyState(it->second);
795
796            return true;
797        }
798        return false;
799    }
800
801    /**
802    @brief
803        Returns the pointer to the requested InputState.
804    @param name
805        Unique name of the state.
806    @return
807        Pointer to the instance, 0 if name was not found.
808    */
809    InputState* InputManager::getState(const std::string& name)
810    {
811        std::map<std::string, InputState*>::iterator it = inputStatesByName_.find(name);
812        if (it != inputStatesByName_.end())
813            return it->second;
814        else
815            return 0;
816    }
817
818    /**
819    @brief
820        Returns the current input state (there might be others active too!)
821    @return
822        The current highest prioritised active input state.
823    */
824    InputState* InputManager::getCurrentState()
825    {
826        return (*activeStates_.rbegin()).second;
827    }
828
829    /**
830    @brief
831        Activates a specific input state.
832        It might not be really activated if the priority is too low!
833    @param name
834        Unique name of the state.
835    @return
836        False if name was not found, true otherwise.
837    */
838    bool InputManager::requestEnterState(const std::string& name)
839    {
840        // get pointer from the map with all stored handlers
841        std::map<std::string, InputState*>::const_iterator it = inputStatesByName_.find(name);
842        if (it != inputStatesByName_.end())
843        {
844            // exists
845            if (activeStates_.find(it->second->getPriority()) == activeStates_.end())
846            {
847                // not active
848                if (stateDestroyRequests_.find(it->second) == stateDestroyRequests_.end())
849                {
850                    // not scheduled for destruction
851                    // prevents a state being added multiple times
852                    stateEnterRequests_.insert(it->second);
853                    return true;
854                }
855            }
856        }
857        return false;
858    }
859
860    /**
861    @brief
862        Deactivates a specific input state.
863    @param name
864        Unique name of the state.
865    @return
866        False if name was not found, true otherwise.
867    */
868    bool InputManager::requestLeaveState(const std::string& name)
869    {
870        if (name == "empty")
871        {
872            COUT(2) << "InputManager: Leaving the empty state is not allowed!" << std::endl;
873            return false;
874        }
875        // get pointer from the map with all stored handlers
876        std::map<std::string, InputState*>::const_iterator it = inputStatesByName_.find(name);
877        if (it != inputStatesByName_.end())
878        {
879            // exists
880            if (activeStates_.find(it->second->getPriority()) != activeStates_.end())
881            {
882                // active
883                stateLeaveRequests_.insert(it->second);
884                return true;
885            }
886        }
887        return false;
888    }
889
890
891    // ############################################################
892    // #####                Console Commands                  #####
893    // ##########                                        ##########
894    // ############################################################
895
896    /**
897    @brief
898        Starts joy stick calibration.
899    */
900    void InputManager::calibrate()
901    {
902        COUT(0) << "Move all joy stick axes fully in all directions." << std::endl
903                << "When done, put the axex in the middle position and press enter." << std::endl;
904
905        getInstance()._startCalibration();
906    }
907
908    /**
909    @brief
910        Reloads the input system
911    */
912    void InputManager::reload()
913    {
914        getInstance().reloadInputSystem();
915    }
916
917
918    // ############################################################
919    // #####                   ugly hacks                     #####
920    // ##########                                        ##########
921    // ############################################################
922
923#ifdef ORXONOX_PLATFORM_LINUX
924    void InputManager::grabMouse()
925    {
926        OIS::LinuxMouse* linuxMouse = dynamic_cast<OIS::LinuxMouse*>(singletonRef_s->mouse_);
927        assert(linuxMouse);
928        linuxMouse->grab(true);
929    }
930
931    void InputManager::ungrabMouse()
932    {
933        OIS::LinuxMouse* linuxMouse = dynamic_cast<OIS::LinuxMouse*>(singletonRef_s->mouse_);
934        assert(linuxMouse);
935        linuxMouse->grab(false);
936    }
937#endif
938}
Note: See TracBrowser for help on using the repository browser.