Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 5738 was 5738, checked in by landauf, 15 years ago

merged libraries2 back to trunk

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