Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/core/input/InputManager.cc @ 3356

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

Minor problem with exception catching.

  • 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
[3327]32    Implementation of the InputManager and a static variable from the InputHandler.
33*/
[918]34
[1062]35#include "InputManager.h"
[1519]36
[3327]37#include <cassert>
[1755]38#include <climits>
[3196]39#include <ois/OISException.h>
40#include <ois/OISInputManager.h>
[3327]41#include <boost/foreach.hpp>
[1555]42
[1764]43#include "util/Exception.h"
[3280]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"
[3327]50#include "core/Functor.h"
[1555]51
[1219]52#include "InputBuffer.h"
[1520]53#include "KeyDetector.h"
[3327]54#include "JoyStick.h"
55#include "JoyStickQuantityListener.h"
56#include "Mouse.h"
57#include "Keyboard.h"
[918]58
59namespace orxonox
60{
[3280]61    SetCommandLineSwitch(keyboard_no_grab).information("Whether not to exclusively grab the keyboard");
[1502]62
[3327]63    // Abuse of this source file for the InputHandler
64    InputHandler InputHandler::EMPTY;
65
[1755]66    InputManager* InputManager::singletonRef_s = 0;
[1084]67
[3327]68    //! Defines the |= operator for easier use.
69    inline InputManager::State operator|=(InputManager::State& lval, InputManager::State rval)
[1755]70    {
[3327]71        return (lval = (InputManager::State)(lval | rval));
[1755]72    }
[919]73
[3327]74    //! Defines the &= operator for easier use.
75    inline InputManager::State operator&=(InputManager::State& lval, int rval)
[1755]76    {
[3327]77        return (lval = (InputManager::State)(lval & rval));
[1755]78    }
[1219]79
[1755]80    // ############################################################
81    // #####                  Initialisation                  #####
82    // ##########                                        ##########
83    // ############################################################
[3327]84    InputManager::InputManager(size_t windowHnd)
85        : internalState_(Bad)
86        , oisInputManager_(0)
87        , devices_(2)
[1755]88        , windowHnd_(0)
[3327]89        , emptyState_(0)
[1881]90        , keyDetector_(0)
[3327]91        , calibratorCallbackHandler_(0)
[918]92    {
[1755]93        RegisterRootObject(InputManager);
[1219]94
[1755]95        assert(singletonRef_s == 0);
96        singletonRef_s = this;
[2662]97
[3327]98        CCOUT(4) << "Constructing..." << std::endl;
99
100        this->setConfigValues();
101
102        this->loadDevices(windowHnd);
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
[3327]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    */
[3327]159    void InputManager::loadDevices(size_t windowHnd)
[1755]160    {
[3327]161        CCOUT(3) << "Loading input devices..." << std::endl;
[1755]162
[3327]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
[3327]169        // store handle internally so we can reload OIS
170        windowHnd_ = windowHnd;
[1755]171
[3327]172        OIS::ParamList paramList;
173        std::ostringstream windowHndStr;
[1755]174
[3327]175        // Fill parameter list
176        windowHndStr << static_cast<unsigned int>(windowHnd);
177        paramList.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
[3280]178#if defined(ORXONOX_PLATFORM_WINDOWS)
[3327]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")));
[3280]183#elif defined(ORXONOX_PLATFORM_LINUX)
[3327]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
[3327]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
[3327]202            if (oisInputManager_->getNumberOfDevices(OIS::OISKeyboard) > 0)
203                devices_[InputDeviceEnumerator::Keyboard] = new Keyboard(InputDeviceEnumerator::Keyboard, oisInputManager_);
204            else
205                ThrowException(InitialisationFailed, "InputManager: No keyboard found, cannot proceed!");
[1219]206
[3327]207            // Successful initialisation
208            guard.Dismiss();
[1755]209        }
[3331]210        catch (const std::exception& ex)
[1755]211        {
[3327]212            oisInputManager_ = NULL;
213            internalState_ |= Bad;
214            ThrowException(InitialisationFailed, "Could not initialise the input system: " << ex.what());
[1755]215        }
[1502]216
[3327]217        // TODO: Remove the two parameters
218        this->loadMouse();
219        this->loadJoySticks();
[1502]220
[3327]221        // Reorder states in case some joy sticks were added/removed
222        this->updateActiveStates();
[1502]223
[3327]224        CCOUT(3) << "Input devices loaded." << std::endl;
[1219]225    }
[928]226
[3327]227    //! Creates a new orxonox::Mouse
228    void InputManager::loadMouse()
[1219]229    {
[3327]230        if (oisInputManager_->getNumberOfDevices(OIS::OISMouse) > 0)
[1755]231        {
[3327]232            try
[1755]233            {
[3327]234                devices_[InputDeviceEnumerator::Mouse] = new Mouse(InputDeviceEnumerator::Mouse, oisInputManager_);
[1755]235            }
[3331]236            catch (const std::exception& ex)
[1755]237            {
[3331]238                CCOUT(2) << "Warning: Failed to create Mouse:" << ex.what() << std::endl
[3327]239                         << "Proceeding without mouse support." << std::endl;
[1755]240            }
[1219]241        }
[3327]242        else
243            CCOUT(ORX_WARNING) << "Warning: No mouse found! Proceeding without mouse support." << std::endl;
[1219]244    }
[1755]245
[3327]246    //! Creates as many joy sticks as are available.
247    void InputManager::loadJoySticks()
[1219]248    {
[3327]249        for (int i = 0; i < oisInputManager_->getNumberOfDevices(OIS::OISJoyStick); i++)
[1755]250        {
[3327]251            try
[1755]252            {
[3327]253                devices_.push_back(new JoyStick(InputDeviceEnumerator::FirstJoyStick + i, oisInputManager_));
[1755]254            }
[3331]255            catch (const std::exception& ex)
[1755]256            {
[3327]257                CCOUT(2) << "Warning: Failed to create joy stick: " << ex.what() << std::endl;
[1755]258            }
259        }
[1505]260
[1887]261        // inform all JoyStick Device Number Listeners
[3327]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
[3327]268    void InputManager::setKeyDetectorCallback(const std::string& command)
[1219]269    {
[3327]270        this->keyDetector_->setCallbackCommand(command);
[2662]271    }
[2896]272
[3327]273    // ############################################################
274    // #####                    Destruction                   #####
275    // ##########                                        ##########
276    // ############################################################
[1293]277
[3327]278    InputManager::~InputManager()
[2662]279    {
[3327]280        CCOUT(4) << "Destroying..." << std::endl;
[1219]281
[3327]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
[3327]291        // destroy all user InputStates
292        while (statesByName_.size() > 0)
293            this->destroyStateInternal((*statesByName_.rbegin()).second);
[2662]294
[3327]295        if (!(internalState_ & Bad))
296            this->destroyDevices();
[2662]297
[3327]298        CCOUT(4) << "Destruction complete." << std::endl;
299        singletonRef_s = 0;
[1219]300    }
[928]301
[1755]302    /**
303    @brief
[3327]304        Destoys all input devices (joy sticks, mouse, keyboard and OIS::InputManager)
305    @throw
306        Method does not throw
[1755]307    */
[3327]308    void InputManager::destroyDevices()
[1219]309    {
[3327]310        CCOUT(3) << "Destroying devices..." << std::endl;
311
312        BOOST_FOREACH(InputDevice*& device, devices_)
[1755]313        {
[3327]314            if (device == NULL)
315                continue;
316            std::string className = device->getClassName();
[3280]317            try
318            {
[3327]319                delete device;
320                device = 0;
321                CCOUT(4) << className << " destroyed." << std::endl;
[1755]322            }
[3280]323            catch (...)
[1755]324            {
[3327]325                CCOUT(1) << className << " destruction failed! Potential resource leak!" << std::endl;
[1755]326            }
327        }
[3327]328        devices_.resize(InputDeviceEnumerator::FirstJoyStick);
[2662]329
[3327]330        assert(oisInputManager_ != NULL);
[3280]331        try
332        {
[3327]333            OIS::InputManager::destroyInputSystem(oisInputManager_);
[3280]334        }
335        catch (...)
336        {
[3327]337            CCOUT(1) << "OIS::InputManager destruction failed! Potential resource leak!" << std::endl;
[3280]338        }
[3327]339        oisInputManager_ = NULL;
[1219]340
[3327]341        internalState_ |= Bad;
342        CCOUT(3) << "Destroyed devices." << std::endl;
[1755]343    }
[1219]344
[1755]345    // ############################################################
346    // #####                     Reloading                    #####
347    // ##########                                        ##########
348    // ############################################################
[1219]349
[3327]350    void InputManager::reload()
[1755]351    {
352        if (internalState_ & Ticking)
353        {
354            // We cannot destroy OIS right now, because reload was probably
[3327]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        }
[3327]359        else if (internalState_ & Calibrating)
360            CCOUT(2) << "Warning: Cannot reload input system. Joy sticks are currently being calibrated." << std::endl;
[1502]361        else
[3327]362            reloadInternal();
[1755]363    }
[1502]364
[3327]365    //! Internal reload method. Destroys the OIS devices and loads them again.
366    void InputManager::reloadInternal()
[1755]367    {
[3327]368        CCOUT(3) << "Reloading ..." << std::endl;
[1502]369
[3327]370        this->destroyDevices();
371        this->loadDevices(windowHnd_);
[1502]372
[3327]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    {
[3327]385        if (internalState_ & Bad)
386            ThrowException(General, "InputManager was not correctly reloaded.");
387
[1755]388        else if (internalState_ & ReloadRequest)
[3327]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            {
[3327]397                (*it)->left();
[2662]398                // just to be sure that the state actually is registered
[3327]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);
[3327]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
[3327]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);
[3327]435                updateActiveStates();
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            {
[3327]447                destroyStateInternal((*it));
[2662]448            }
449            stateDestroyRequests_.clear();
[1755]450        }
[1219]451
[3327]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        {
[3327]456            if (it->second->hasExpired())
[1878]457            {
[3327]458                it->second->resetExpiration();
[1878]459                bUpdateRequired = true;
460            }
461        }
462        if (bUpdateRequired)
[3327]463            updateActiveStates();
[1878]464
[2896]465        // mark that we now start capturing and distributing input
[1755]466        internalState_ |= Ticking;
[1293]467
[3327]468        // Capture all the input and handle it
469        BOOST_FOREACH(InputDevice* device, devices_)
470            if (device != NULL)
471                device->update(time);
[1219]472
[3327]473        // Update the states
474        for (unsigned int i = 0; i < activeStatesTicked_.size(); ++i)
475            activeStatesTicked_[i]->update(time.getDeltaTime());
[2896]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    */
[3327]485    void InputManager::updateActiveStates()
[1293]486    {
[3327]487        // temporary resize
488        for (unsigned int i = 0; i < devices_.size(); ++i)
[2896]489        {
[3327]490            if (devices_[i] == NULL)
491                continue;
492            std::vector<InputState*>& states = devices_[i]->getStateListRef();
[2896]493            bool occupied = false;
[3327]494            states.clear();
[2896]495            for (std::map<int, InputState*>::reverse_iterator rit = activeStates_.rbegin(); rit != activeStates_.rend(); ++rit)
496            {
497                if (rit->second->isInputDeviceEnabled(i) && (!occupied || rit->second->bAlwaysGetsInput_))
498                {
[3327]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;
[3327]509        for (unsigned int i = 0; i < devices_.size(); ++i)
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    {
[3327]522        BOOST_FOREACH(InputDevice* device, devices_)
523            if (device != NULL)
524                device->clearBuffers();
[1878]525    }
[1502]526
[3327]527    void InputManager::calibrate()
[1219]528    {
[3327]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;
[1219]531
[3327]532        BOOST_FOREACH(InputDevice* device, devices_)
533            if (device != NULL)
534                device->startCalibration();
[1219]535
[3327]536        internalState_ |= Calibrating;
537        enterState("calibrator");
[1349]538    }
[1755]539
[3327]540    //! Tells all devices to stop the calibration and evaluate it. Buffers are being cleared as well!
541    void InputManager::stopCalibration()
[1349]542    {
[3327]543        BOOST_FOREACH(InputDevice* device, devices_)
544            if (device != NULL)
545                device->stopCalibration();
[1502]546
[3327]547        // restore old input state
548        leaveState("calibrator");
549        internalState_ &= ~Calibrating;
550        // Clear buffers to prevent button hold events
551        this->clearBuffers();
[1293]552
[3327]553        COUT(0) << "Calibration has been stored." << std::endl;
[1755]554    }
[1502]555
[3327]556    //! Gets called by WindowEventListener upon focus change --> clear buffers
557    void InputManager::windowFocusChanged()
[1755]558    {
[3327]559        this->clearBuffers();
[1755]560    }
[1502]561
[1755]562    // ############################################################
[3327]563    // #####                    Iput States                   #####
[1755]564    // ##########                                        ##########
565    // ############################################################
[1219]566
[3327]567    InputState* InputManager::createInputState(const std::string& name, bool bAlwaysGetsInput, bool bTransparent, InputStatePriority priority)
[1219]568    {
[1755]569        if (name == "")
[3327]570            return 0;
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
[3327]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 '"
[3327]582                            << static_cast<int>(priority) << "' != 0." << std::endl;
583                        return 0;
[2896]584                    }
585                }
586            }
[3327]587            InputState* state = new InputState(name, bAlwaysGetsInput, bTransparent, priority);
588            statesByName_[name] = state;
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;
[3327]595            return 0;
[1755]596        }
[1219]597    }
598
[1755]599    InputState* InputManager::getState(const std::string& name)
[1219]600    {
[3327]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
[3327]608    bool InputManager::enterState(const std::string& name)
[1219]609    {
[1755]610        // get pointer from the map with all stored handlers
[3327]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
[3327]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
[3327]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
[3327]652    bool InputManager::destroyState(const std::string& name)
[1219]653    {
[3327]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
[3327]676            return true;
677        }
678        return false;
[1219]679    }
680
[3327]681    //! Destroys an InputState internally.
682    void InputManager::destroyStateInternal(InputState* state)
[1219]683    {
[3327]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.