Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core5/src/libraries/core/input/InputManager.cc @ 5855

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

Moved Clock from core to util (used in Scope anyway).

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