Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Added and adjusted documentation for the devices.
Also removed one last ugliness where the InputManager was called from within a device (which should not even know about the InputManager).

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