Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 6417 was 6417, checked in by rgrieder, 14 years ago

Merged presentation2 branch back to trunk.
Major new features:

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