Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Optimisations in the pathway of the input. Nobody will ever notice the difference in performance (immeasurable), but I love the beauty of having all my template code inlined when it even decreases code size (because the code gets inlined exactly once).

  • Property svn:eol-style set to native
File size: 25.0 KB
RevLine 
[918]1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
[1502]3 *                    > www.orxonox.net <
[918]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:
[934]25 *      ...
[918]26 *
27 */
[973]28
[918]29/**
[1755]30@file
31@brief
[3281]32    Implementation of the InputManager and a static variable from the InputHandler.
33*/
[918]34
[1062]35#include "InputManager.h"
[1519]36
[3279]37#include <cassert>
[1755]38#include <climits>
[3196]39#include <ois/OISException.h>
40#include <ois/OISInputManager.h>
[3270]41#include <boost/foreach.hpp>
[1555]42
[1764]43#include "util/Exception.h"
[3237]44#include "util/ScopeGuard.h"
[2896]45#include "core/Clock.h"
[1519]46#include "core/CoreIncludes.h"
47#include "core/ConfigValueIncludes.h"
[3196]48#include "core/ConsoleCommand.h"
[1934]49#include "core/CommandLine.h"
[3274]50#include "core/Functor.h"
[1555]51
[1219]52#include "InputBuffer.h"
[1520]53#include "KeyDetector.h"
[3279]54#include "JoyStick.h"
[3274]55#include "JoyStickQuantityListener.h"
56#include "Mouse.h"
57#include "Keyboard.h"
[918]58
59namespace orxonox
60{
[3255]61    SetCommandLineSwitch(keyboard_no_grab).information("Whether not to exclusively grab the keyboard");
[1502]62
[3279]63    // Abuse of this source file for the InputHandler
[3274]64    InputHandler InputHandler::EMPTY;
[3279]65
[1755]66    InputManager* InputManager::singletonRef_s = 0;
[1084]67
[3281]68    //! Defines the |= operator for easier use.
[3279]69    inline InputManager::State operator|=(InputManager::State& lval, InputManager::State rval)
[1755]70    {
[3279]71        return (lval = (InputManager::State)(lval | rval));
[1755]72    }
[919]73
[3281]74    //! Defines the &= operator for easier use.
[3279]75    inline InputManager::State operator&=(InputManager::State& lval, int rval)
[1755]76    {
[3279]77        return (lval = (InputManager::State)(lval & rval));
[1755]78    }
[1219]79
[1755]80    // ############################################################
81    // #####                  Initialisation                  #####
82    // ##########                                        ##########
83    // ############################################################
[3291]84    InputManager::InputManager(size_t windowHnd)
[3279]85        : internalState_(Bad)
86        , oisInputManager_(0)
[3274]87        , devices_(2)
[1755]88        , windowHnd_(0)
[3279]89        , emptyState_(0)
[1881]90        , keyDetector_(0)
[3279]91        , calibratorCallbackHandler_(0)
[918]92    {
[1755]93        RegisterRootObject(InputManager);
[1219]94
[1755]95        assert(singletonRef_s == 0);
96        singletonRef_s = this;
[2662]97
[3279]98        CCOUT(4) << "Constructing..." << std::endl;
[3270]99
[3279]100        this->setConfigValues();
101
[3291]102        this->loadDevices(windowHnd);
[3279]103
104        // Lowest priority empty InputState
105        emptyState_ = createInputState("empty", false, false, InputStatePriority::Empty);
106        emptyState_->setHandler(&InputHandler::EMPTY);
107        activeStates_[emptyState_->getPriority()] = emptyState_;
108
109        // KeyDetector to evaluate a pressed key's name
110        InputState* detector = createInputState("detector", false, false, InputStatePriority::Detector);
111        // Create a callback to avoid buttonHeld events after the key has been detected
112        FunctorMember<InputManager>* bufferFunctor = createFunctor(&InputManager::clearBuffers);
113        bufferFunctor->setObject(this);
114        detector->setLeaveFunctor(bufferFunctor);
115        keyDetector_ = new KeyDetector();
116        detector->setHandler(keyDetector_);
117
118        // Joy stick calibration helper callback
119        InputState* calibrator = createInputState("calibrator", false, false, InputStatePriority::Calibrator);
120        calibrator->setHandler(&InputHandler::EMPTY);
121        calibratorCallbackHandler_ = new InputBuffer();
122        calibratorCallbackHandler_->registerListener(this, &InputManager::stopCalibration, '\r', true);
123        calibrator->setKeyHandler(calibratorCallbackHandler_);
124
125        this->updateActiveStates();
126
127        {
128            // calibrate console command
129            FunctorMember<InputManager>* functor = createFunctor(&InputManager::calibrate);
130            functor->setObject(this);
131            this->getIdentifier()->addConsoleCommand(createConsoleCommand(functor, "calibrate"), true);
132        }
133        {
134            // reload console command
135            FunctorMember<InputManager>* functor = createFunctor(&InputManager::reload);
136            functor->setObject(this);
137            this->getIdentifier()->addConsoleCommand(createConsoleCommand(functor, "reload"), false);
138        }
139
140        internalState_ = Nothing;
141        CCOUT(4) << "Construction complete." << std::endl;
[1755]142    }
[918]143
[2662]144    void InputManager::setConfigValues()
145    {
146    }
147
148    /**
149    @brief
[1755]150        Creates the OIS::InputMananger, the keyboard, the mouse and
[3281]151        the joys ticks. If either of the first two fail, this method throws an exception.
[1755]152    @param windowHnd
153        The window handle of the render window
154    @param windowWidth
155        The width of the render window
156    @param windowHeight
157        The height of the render window
158    */
[3291]159    void InputManager::loadDevices(size_t windowHnd)
[1755]160    {
[3279]161        CCOUT(3) << "Loading input devices..." << std::endl;
[1755]162
[3279]163        // When loading the devices they should not already be loaded
164        assert(internalState_ & Bad);
165        assert(devices_[InputDeviceEnumerator::Mouse] == 0);
166        assert(devices_[InputDeviceEnumerator::Keyboard] == 0);
167        assert(devices_.size() == InputDeviceEnumerator::FirstJoyStick);
[1755]168
[3279]169        // store handle internally so we can reload OIS
170        windowHnd_ = windowHnd;
[1755]171
[3279]172        OIS::ParamList paramList;
173        std::ostringstream windowHndStr;
[1755]174
[3279]175        // Fill parameter list
176        windowHndStr << (unsigned int)windowHnd_;
177        paramList.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
[3237]178#if defined(ORXONOX_PLATFORM_WINDOWS)
[3310]179        paramList.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_NONEXCLUSIVE")));
180        paramList.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_FOREGROUND")));
181        paramList.insert(std::make_pair(std::string("w32_keyboard"), std::string("DISCL_NONEXCLUSIVE")));
182        paramList.insert(std::make_pair(std::string("w32_keyboard"), std::string("DISCL_FOREGROUND")));
[3237]183#elif defined(ORXONOX_PLATFORM_LINUX)
[3279]184        paramList.insert(std::make_pair(std::string("XAutoRepeatOn"), std::string("true")));
185        paramList.insert(std::make_pair(std::string("x11_mouse_grab"), "true"));
186        paramList.insert(std::make_pair(std::string("x11_mouse_hide"), "true"));
187        bool kbNoGrab;
188        CommandLine::getValue("keyboard_no_grab", &kbNoGrab);
189        if (kbNoGrab)
190            paramList.insert(std::make_pair(std::string("x11_keyboard_grab"), std::string("false")));
191        else
192            paramList.insert(std::make_pair(std::string("x11_keyboard_grab"), std::string("true")));
[1735]193#endif
[928]194
[3279]195        try
196        {
197            oisInputManager_ = OIS::InputManager::createInputSystem(paramList);
198            // Exception-safety
199            Loki::ScopeGuard guard = Loki::MakeGuard(OIS::InputManager::destroyInputSystem, oisInputManager_);
200            CCOUT(ORX_DEBUG) << "Created OIS input manager." << std::endl;
[1219]201
[3279]202            if (oisInputManager_->getNumberOfDevices(OIS::OISKeyboard) > 0)
[3286]203                devices_[InputDeviceEnumerator::Keyboard] = new Keyboard(InputDeviceEnumerator::Keyboard, oisInputManager_);
[3279]204            else
205                ThrowException(InitialisationFailed, "InputManager: No keyboard found, cannot proceed!");
[1219]206
[3279]207            // Successful initialisation
208            guard.Dismiss();
[1755]209        }
[3279]210        catch (std::exception& ex)
[1755]211        {
[3279]212            oisInputManager_ = NULL;
213            internalState_ |= Bad;
214            ThrowException(InitialisationFailed, "Could not initialise the input system: " << ex.what());
[1755]215        }
[1502]216
[3279]217        // TODO: Remove the two parameters
[3291]218        this->loadMouse();
[3279]219        this->loadJoySticks();
[1502]220
[3279]221        // Reorder states in case some joy sticks were added/removed
222        this->updateActiveStates();
[1502]223
[3279]224        CCOUT(3) << "Input devices loaded." << std::endl;
[1219]225    }
[928]226
[3281]227    //! Creates a new orxonox::Mouse
[3291]228    void InputManager::loadMouse()
[1219]229    {
[3279]230        if (oisInputManager_->getNumberOfDevices(OIS::OISMouse) > 0)
[1755]231        {
[3274]232            try
[1755]233            {
[3291]234                devices_[InputDeviceEnumerator::Mouse] = new Mouse(InputDeviceEnumerator::Mouse, oisInputManager_);
[1755]235            }
[3274]236            catch (const OIS::Exception& ex)
[1755]237            {
[3274]238                CCOUT(2) << "Warning: Failed to create Mouse:" << ex.eText << std::endl
239                         << "Proceeding without mouse support." << std::endl;
[1755]240            }
[1219]241        }
[3274]242        else
243            CCOUT(ORX_WARNING) << "Warning: No mouse found! Proceeding without mouse support." << std::endl;
[1219]244    }
[1755]245
[3281]246    //! Creates as many joy sticks as are available.
[3279]247    void InputManager::loadJoySticks()
[1219]248    {
[3279]249        for (int i = 0; i < oisInputManager_->getNumberOfDevices(OIS::OISJoyStick); i++)
[2662]250        {
[3270]251            try
[1755]252            {
[3286]253                devices_.push_back(new JoyStick(InputDeviceEnumerator::FirstJoyStick + i, oisInputManager_));
[1755]254            }
[3270]255            catch (std::exception ex)
256            {
257                CCOUT(2) << "Warning: Failed to create joy stick: " << ex.what() << std::endl;
258            }
[1755]259        }
[1505]260
[1887]261        // inform all JoyStick Device Number Listeners
[3288]262        std::vector<JoyStick*> joyStickList;
263        for (unsigned int i = InputDeviceEnumerator::FirstJoyStick; i < devices_.size(); ++i)
264            joyStickList.push_back(static_cast<JoyStick*>(devices_[i]));
265        JoyStickQuantityListener::changeJoyStickQuantity(joyStickList);
[1505]266    }
[1502]267
[3279]268    void InputManager::setKeyDetectorCallback(const std::string& command)
[2662]269    {
[3279]270        this->keyDetector_->setCallbackCommand(command);
[1219]271    }
[928]272
[1755]273    // ############################################################
274    // #####                    Destruction                   #####
275    // ##########                                        ##########
276    // ############################################################
[1219]277
[1755]278    InputManager::~InputManager()
[1219]279    {
[3279]280        CCOUT(4) << "Destroying..." << std::endl;
[3237]281
[3279]282        // Destroy calibrator helper handler and state
283        delete keyDetector_;
284        this->destroyState("calibrator");
285        // Destroy KeyDetector and state
286        delete calibratorCallbackHandler_;
287        this->destroyState("detector");
288        // destroy the empty InputState
289        this->destroyStateInternal(this->emptyState_);
[1502]290
[3279]291        // destroy all user InputStates
292        while (statesByName_.size() > 0)
293            this->destroyStateInternal((*statesByName_.rbegin()).second);
[1788]294
[3279]295        if (!(internalState_ & Bad))
296            this->destroyDevices();
[1881]297
[3279]298        CCOUT(4) << "Destruction complete." << std::endl;
299        singletonRef_s = 0;
300    }
301
[3281]302    /**
303    @brief
304        Destoys all input devices (joy sticks, mouse, keyboard and OIS::InputManager)
305    @throw
306        Method does not throw
307    */
[3279]308    void InputManager::destroyDevices()
309    {
310        CCOUT(3) << "Destroying devices..." << std::endl;
311
312        BOOST_FOREACH(InputDevice*& device, devices_)
313        {
314            if (device == NULL)
315                continue;
316            std::string className = device->getClassName();
[3237]317            try
318            {
[3279]319                delete device;
320                device = 0;
321                CCOUT(4) << className << " destroyed." << std::endl;
[1755]322            }
[3237]323            catch (...)
[1755]324            {
[3279]325                CCOUT(1) << className << " destruction failed! Potential resource leak!" << std::endl;
[1755]326            }
327        }
[3279]328        devices_.resize(InputDeviceEnumerator::FirstJoyStick);
[2662]329
[3279]330        assert(oisInputManager_ != NULL);
331        try
[1755]332        {
[3279]333            OIS::InputManager::destroyInputSystem(oisInputManager_);
[1755]334        }
[3279]335        catch (...)
336        {
337            CCOUT(1) << "OIS::InputManager destruction failed! Potential resource leak!" << std::endl;
338        }
339        oisInputManager_ = NULL;
340
341        internalState_ |= Bad;
342        CCOUT(3) << "Destroyed devices." << std::endl;
[1755]343    }
[1502]344
[1755]345    // ############################################################
346    // #####                     Reloading                    #####
347    // ##########                                        ##########
348    // ############################################################
[1219]349
[3279]350    void InputManager::reload()
[1755]351    {
352        if (internalState_ & Ticking)
353        {
354            // We cannot destroy OIS right now, because reload was probably
[3279]355            // caused by a user clicking on a GUI item. The stack trace would then
[1755]356            // include an OIS method. So it would be a very bad thing to destroy it..
357            internalState_ |= ReloadRequest;
[1219]358        }
[3279]359        else if (internalState_ & Calibrating)
360            CCOUT(2) << "Warning: Cannot reload input system. Joy sticks are currently being calibrated." << std::endl;
[1502]361        else
[3279]362            reloadInternal();
[1755]363    }
[1502]364
[3281]365    //! Internal reload method. Destroys the OIS devices and loads them again.
[3279]366    void InputManager::reloadInternal()
[1755]367    {
[3279]368        CCOUT(3) << "Reloading ..." << std::endl;
369
370        this->destroyDevices();
[3291]371        this->loadDevices(windowHnd_);
[1502]372
[3279]373        internalState_ &= ~Bad;
374        internalState_ &= ~ReloadRequest;
375        CCOUT(3) << "Reloading complete." << std::endl;
[1502]376    }
[1219]377
[1755]378    // ############################################################
379    // #####                  Runtime Methods                 #####
380    // ##########                                        ##########
381    // ############################################################
[1555]382
[2896]383    void InputManager::update(const Clock& time)
[1502]384    {
[3279]385        if (internalState_ & Bad)
386            ThrowException(General, "InputManager was not correctly reloaded.");
387
[1755]388        else if (internalState_ & ReloadRequest)
[3279]389            reloadInternal();
[1349]390
[1755]391        // check for states to leave
[2662]392        if (!stateLeaveRequests_.empty())
[1755]393        {
[2896]394            for (std::set<InputState*>::iterator it = stateLeaveRequests_.begin();
395                it != stateLeaveRequests_.end(); ++it)
[2662]396            {
[3274]397                (*it)->left();
[2662]398                // just to be sure that the state actually is registered
[3279]399                assert(statesByName_.find((*it)->getName()) != statesByName_.end());
[1505]400
[2896]401                activeStates_.erase((*it)->getPriority());
402                if ((*it)->getPriority() < InputStatePriority::HighPriority)
403                    (*it)->setPriority(0);
[3279]404                updateActiveStates();
[2662]405            }
406            stateLeaveRequests_.clear();
[1755]407        }
[1505]408
[1755]409        // check for states to enter
[2662]410        if (!stateEnterRequests_.empty())
[1755]411        {
[2896]412            for (std::set<InputState*>::const_iterator it = stateEnterRequests_.begin();
413                it != stateEnterRequests_.end(); ++it)
[2662]414            {
415                // just to be sure that the state actually is registered
[3279]416                assert(statesByName_.find((*it)->getName()) != statesByName_.end());
[1219]417
[2896]418                if ((*it)->getPriority() == 0)
419                {
420                    // Get smallest possible priority between 1 and maxStateStackSize_s
421                    for(std::map<int, InputState*>::reverse_iterator rit = activeStates_.rbegin();
422                        rit != activeStates_.rend(); ++rit)
423                    {
424                        if (rit->first < InputStatePriority::HighPriority)
425                        {
426                            (*it)->setPriority(rit->first + 1);
427                            break;
428                        }
429                    }
430                    // In case no normal handler was on the stack
431                    if ((*it)->getPriority() == 0)
432                        (*it)->setPriority(1);
433                }
434                activeStates_[(*it)->getPriority()] = (*it);
[3279]435                updateActiveStates();
[3274]436                (*it)->entered();
[2662]437            }
438            stateEnterRequests_.clear();
[1755]439        }
[1219]440
[1755]441        // check for states to destroy
[2662]442        if (!stateDestroyRequests_.empty())
[1755]443        {
[2896]444            for (std::set<InputState*>::iterator it = stateDestroyRequests_.begin();
445                it != stateDestroyRequests_.end(); ++it)
[2662]446            {
[3279]447                destroyStateInternal((*it));
[2662]448            }
449            stateDestroyRequests_.clear();
[1755]450        }
[1219]451
[3274]452        // check whether a state has changed its EMPTY situation
[1878]453        bool bUpdateRequired = false;
454        for (std::map<int, InputState*>::iterator it = activeStates_.begin(); it != activeStates_.end(); ++it)
455        {
[3274]456            if (it->second->hasExpired())
[1878]457            {
[3274]458                it->second->resetExpiration();
[1878]459                bUpdateRequired = true;
460            }
461        }
462        if (bUpdateRequired)
[3279]463            updateActiveStates();
[1878]464
[2896]465        // mark that we now start capturing and distributing input
[1755]466        internalState_ |= Ticking;
[1293]467
[3279]468        // Capture all the input and handle it
[3274]469        BOOST_FOREACH(InputDevice* device, devices_)
[3279]470            if (device != NULL)
471                device->update(time);
[1219]472
[3279]473        // Update the states
474        for (unsigned int i = 0; i < activeStatesTicked_.size(); ++i)
475            activeStatesTicked_[i]->update(time.getDeltaTime());
[1219]476
[1755]477        internalState_ &= ~Ticking;
[1293]478    }
[1219]479
[1755]480    /**
481    @brief
482        Updates the currently active states (according to activeStates_) for each device.
[2896]483        Also, a list of all active states (no duplicates!) is compiled for the general update().
[1755]484    */
[3279]485    void InputManager::updateActiveStates()
[1293]486    {
[3274]487        // temporary resize
488        for (unsigned int i = 0; i < devices_.size(); ++i)
[2896]489        {
[3279]490            if (devices_[i] == NULL)
491                continue;
[3274]492            std::vector<InputState*>& states = devices_[i]->getStateListRef();
[2896]493            bool occupied = false;
[3274]494            states.clear();
495            for (std::map<int, InputState*>::reverse_iterator rit = activeStates_.rbegin(); rit != activeStates_.rend(); ++rit)
[2896]496            {
497                if (rit->second->isInputDeviceEnabled(i) && (!occupied || rit->second->bAlwaysGetsInput_))
498                {
[3274]499                    states.push_back(rit->second);
[2896]500                    if (!rit->second->bTransparent_)
501                        occupied = true;
502                }
503            }
504        }
[1293]505
[1755]506        // update tickables (every state will only appear once)
507        // Using a std::set to avoid duplicates
508        std::set<InputState*> tempSet;
[3274]509        for (unsigned int i = 0; i < devices_.size(); ++i)
[3279]510            if (devices_[i] != NULL)
511                for (unsigned int iState = 0; iState < devices_[i]->getStateListRef().size(); ++iState)
512                    tempSet.insert(devices_[i]->getStateListRef()[iState]);
[1219]513
[2896]514        // copy the content of the std::set back to the actual vector
[1755]515        activeStatesTicked_.clear();
516        for (std::set<InputState*>::const_iterator it = tempSet.begin();it != tempSet.end(); ++it)
517            activeStatesTicked_.push_back(*it);
518    }
[1219]519
[1878]520    void InputManager::clearBuffers()
521    {
[3274]522        BOOST_FOREACH(InputDevice* device, devices_)
[3279]523            if (device != NULL)
524                device->clearBuffers();
[1878]525    }
[1502]526
[3279]527    void InputManager::calibrate()
[1755]528    {
[3279]529        COUT(0) << "Move all joy stick axes fully in all directions." << std::endl
530                << "When done, put the axex in the middle position and press enter." << std::endl;
531
532        BOOST_FOREACH(InputDevice* device, devices_)
533            if (device != NULL)
534                device->startCalibration();
535
536        internalState_ |= Calibrating;
537        enterState("calibrator");
[1755]538    }
[1219]539
[3281]540    //! Tells all devices to stop the calibration and evaluate it. Buffers are being cleared as well!
[3279]541    void InputManager::stopCalibration()
542    {
543        BOOST_FOREACH(InputDevice* device, devices_)
544            if (device != NULL)
545                device->stopCalibration();
[1219]546
[3279]547        // restore old input state
548        leaveState("calibrator");
549        internalState_ &= ~Calibrating;
550        // Clear buffers to prevent button hold events
551        this->clearBuffers();
[3286]552
553        COUT(0) << "Calibration has been stored." << std::endl;
[3279]554    }
555
[3291]556    //! Gets called by WindowEventListener upon focus change --> clear buffers
557    void InputManager::windowFocusChanged()
558    {
559        this->clearBuffers();
560    }
561
[1755]562    // ############################################################
[3279]563    // #####                    Iput States                   #####
[1755]564    // ##########                                        ##########
565    // ############################################################
[1219]566
[3274]567    InputState* InputManager::createInputState(const std::string& name, bool bAlwaysGetsInput, bool bTransparent, InputStatePriority priority)
568    {
[3281]569        if (name == "")
[3274]570            return 0;
[3279]571        if (statesByName_.find(name) == statesByName_.end())
[1755]572        {
[2896]573            if (priority >= InputStatePriority::HighPriority || priority == InputStatePriority::Empty)
[1755]574            {
[2896]575                // Make sure we don't add two high priority states with the same priority
[3279]576                for (std::map<std::string, InputState*>::const_iterator it = this->statesByName_.begin();
577                    it != this->statesByName_.end(); ++it)
[2896]578                {
579                    if (it->second->getPriority() == priority)
580                    {
581                        COUT(2) << "Warning: Could not add an InputState with the same priority '"
[3281]582                            << static_cast<int>(priority) << "' != 0." << std::endl;
[3288]583                        return 0;
[2896]584                    }
585                }
586            }
[3288]587            InputState* state = new InputState(name, bAlwaysGetsInput, bTransparent, priority);
[3279]588            statesByName_[name] = state;
[3281]589
590            return state;
[1755]591        }
592        else
593        {
594            COUT(2) << "Warning: Could not add an InputState with the same name '" << name << "'." << std::endl;
[3281]595            return 0;
[1755]596        }
[1219]597    }
598
[1755]599    InputState* InputManager::getState(const std::string& name)
[1219]600    {
[3279]601        std::map<std::string, InputState*>::iterator it = statesByName_.find(name);
602        if (it != statesByName_.end())
[1755]603            return it->second;
604        else
605            return 0;
[1219]606    }
607
[3279]608    bool InputManager::enterState(const std::string& name)
[1219]609    {
[1755]610        // get pointer from the map with all stored handlers
[3279]611        std::map<std::string, InputState*>::const_iterator it = statesByName_.find(name);
612        if (it != statesByName_.end())
[1755]613        {
614            // exists
615            if (activeStates_.find(it->second->getPriority()) == activeStates_.end())
616            {
617                // not active
618                if (stateDestroyRequests_.find(it->second) == stateDestroyRequests_.end())
619                {
620                    // not scheduled for destruction
[2896]621                    // prevents a state being added multiple times
[1755]622                    stateEnterRequests_.insert(it->second);
623                    return true;
624                }
625            }
626        }
627        return false;
[1219]628    }
629
[3279]630    bool InputManager::leaveState(const std::string& name)
[1219]631    {
[2896]632        if (name == "empty")
633        {
634            COUT(2) << "InputManager: Leaving the empty state is not allowed!" << std::endl;
635            return false;
636        }
[1755]637        // get pointer from the map with all stored handlers
[3279]638        std::map<std::string, InputState*>::const_iterator it = statesByName_.find(name);
639        if (it != statesByName_.end())
[1755]640        {
641            // exists
642            if (activeStates_.find(it->second->getPriority()) != activeStates_.end())
643            {
644                // active
645                stateLeaveRequests_.insert(it->second);
646                return true;
647            }
648        }
649        return false;
[1219]650    }
651
[3279]652    bool InputManager::destroyState(const std::string& name)
[1219]653    {
[3279]654        if (name == "empty")
655        {
656            COUT(2) << "InputManager: Removing the empty state is not allowed!" << std::endl;
657            return false;
658        }
659        std::map<std::string, InputState*>::iterator it = statesByName_.find(name);
660        if (it != statesByName_.end())
661        {
662            if (activeStates_.find(it->second->getPriority()) != activeStates_.end())
663            {
664                // The state is still active. We have to postpone
665                stateLeaveRequests_.insert(it->second);
666                stateDestroyRequests_.insert(it->second);
667            }
668            else if (this->internalState_ & Ticking)
669            {
670                // cannot remove state while ticking
671                stateDestroyRequests_.insert(it->second);
672            }
673            else
674                destroyStateInternal(it->second);
[2662]675
[3279]676            return true;
677        }
678        return false;
[1219]679    }
680
[3281]681    //! Destroys an InputState internally.
[3279]682    void InputManager::destroyStateInternal(InputState* state)
[1219]683    {
[3279]684        assert(state && !(this->internalState_ & Ticking));
685        std::map<int, InputState*>::iterator it = this->activeStates_.find(state->getPriority());
686        if (it != this->activeStates_.end())
687        {
688            this->activeStates_.erase(it);
689            updateActiveStates();
690        }
691        statesByName_.erase(state->getName());
692        delete state;
[1219]693    }
[918]694}
Note: See TracBrowser for help on using the repository browser.