Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Adjusted InputManager documentation.

  • Property svn:eol-style set to native
File size: 26.0 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);
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, 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));
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    bool InputManager::checkJoyStickID(const std::string& idString) const
267    {
268        for (unsigned int i = InputDeviceEnumerator::FirstJoyStick; i < devices_.size(); ++i)
269            if (static_cast<JoyStick*>(devices_[i])->getIDString() == idString)
270                return false;
271        return true;
272    }
273
274    void InputManager::setKeyDetectorCallback(const std::string& command)
275    {
276        this->keyDetector_->setCallbackCommand(command);
277    }
278
279    // ############################################################
280    // #####                    Destruction                   #####
281    // ##########                                        ##########
282    // ############################################################
283
284    InputManager::~InputManager()
285    {
286        CCOUT(4) << "Destroying..." << std::endl;
287
288        // Destroy calibrator helper handler and state
289        delete keyDetector_;
290        this->destroyState("calibrator");
291        // Destroy KeyDetector and state
292        delete calibratorCallbackHandler_;
293        this->destroyState("detector");
294        // destroy the empty InputState
295        this->destroyStateInternal(this->emptyState_);
296
297        // destroy all user InputStates
298        while (statesByName_.size() > 0)
299            this->destroyStateInternal((*statesByName_.rbegin()).second);
300
301        if (!(internalState_ & Bad))
302            this->destroyDevices();
303
304        CCOUT(4) << "Destruction complete." << std::endl;
305        singletonRef_s = 0;
306    }
307
308    /**
309    @brief
310        Destoys all input devices (joy sticks, mouse, keyboard and OIS::InputManager)
311    @throw
312        Method does not throw
313    */
314    void InputManager::destroyDevices()
315    {
316        CCOUT(3) << "Destroying devices..." << std::endl;
317
318        BOOST_FOREACH(InputDevice*& device, devices_)
319        {
320            if (device == NULL)
321                continue;
322            std::string className = device->getClassName();
323            try
324            {
325                delete device;
326                device = 0;
327                CCOUT(4) << className << " destroyed." << std::endl;
328            }
329            catch (...)
330            {
331                CCOUT(1) << className << " destruction failed! Potential resource leak!" << std::endl;
332            }
333        }
334        devices_.resize(InputDeviceEnumerator::FirstJoyStick);
335
336        assert(oisInputManager_ != NULL);
337        try
338        {
339            OIS::InputManager::destroyInputSystem(oisInputManager_);
340        }
341        catch (...)
342        {
343            CCOUT(1) << "OIS::InputManager destruction failed! Potential resource leak!" << std::endl;
344        }
345        oisInputManager_ = NULL;
346
347        internalState_ |= Bad;
348        CCOUT(3) << "Destroyed devices." << std::endl;
349    }
350
351    // ############################################################
352    // #####                     Reloading                    #####
353    // ##########                                        ##########
354    // ############################################################
355
356    void InputManager::reload()
357    {
358        if (internalState_ & Ticking)
359        {
360            // We cannot destroy OIS right now, because reload was probably
361            // caused by a user clicking on a GUI item. The stack trace would then
362            // include an OIS method. So it would be a very bad thing to destroy it..
363            internalState_ |= ReloadRequest;
364        }
365        else if (internalState_ & Calibrating)
366            CCOUT(2) << "Warning: Cannot reload input system. Joy sticks are currently being calibrated." << std::endl;
367        else
368            reloadInternal();
369    }
370
371    //! Internal reload method. Destroys the OIS devices and loads them again.
372    void InputManager::reloadInternal()
373    {
374        CCOUT(3) << "Reloading ..." << std::endl;
375
376        // Save mouse clipping size
377        int clippingWidth = 800;
378        int clippingHeight = 600;
379        if (devices_[InputDeviceEnumerator::Mouse])
380        {
381            int clippingWidth  = static_cast<Mouse*>(devices_[InputDeviceEnumerator::Mouse])->getClippingWidth();
382            int clippingHeight = static_cast<Mouse*>(devices_[InputDeviceEnumerator::Mouse])->getClippingHeight();
383        }
384
385        this->destroyDevices();
386        this->loadDevices(windowHnd_, clippingWidth, clippingHeight);
387
388        internalState_ &= ~Bad;
389        internalState_ &= ~ReloadRequest;
390        CCOUT(3) << "Reloading complete." << std::endl;
391    }
392
393    // ############################################################
394    // #####                  Runtime Methods                 #####
395    // ##########                                        ##########
396    // ############################################################
397
398    void InputManager::update(const Clock& time)
399    {
400        if (internalState_ & Bad)
401            ThrowException(General, "InputManager was not correctly reloaded.");
402
403        else if (internalState_ & ReloadRequest)
404            reloadInternal();
405
406        // check for states to leave
407        if (!stateLeaveRequests_.empty())
408        {
409            for (std::set<InputState*>::iterator it = stateLeaveRequests_.begin();
410                it != stateLeaveRequests_.end(); ++it)
411            {
412                (*it)->left();
413                // just to be sure that the state actually is registered
414                assert(statesByName_.find((*it)->getName()) != statesByName_.end());
415
416                activeStates_.erase((*it)->getPriority());
417                if ((*it)->getPriority() < InputStatePriority::HighPriority)
418                    (*it)->setPriority(0);
419                updateActiveStates();
420            }
421            stateLeaveRequests_.clear();
422        }
423
424        // check for states to enter
425        if (!stateEnterRequests_.empty())
426        {
427            for (std::set<InputState*>::const_iterator it = stateEnterRequests_.begin();
428                it != stateEnterRequests_.end(); ++it)
429            {
430                // just to be sure that the state actually is registered
431                assert(statesByName_.find((*it)->getName()) != statesByName_.end());
432
433                if ((*it)->getPriority() == 0)
434                {
435                    // Get smallest possible priority between 1 and maxStateStackSize_s
436                    for(std::map<int, InputState*>::reverse_iterator rit = activeStates_.rbegin();
437                        rit != activeStates_.rend(); ++rit)
438                    {
439                        if (rit->first < InputStatePriority::HighPriority)
440                        {
441                            (*it)->setPriority(rit->first + 1);
442                            break;
443                        }
444                    }
445                    // In case no normal handler was on the stack
446                    if ((*it)->getPriority() == 0)
447                        (*it)->setPriority(1);
448                }
449                activeStates_[(*it)->getPriority()] = (*it);
450                updateActiveStates();
451                (*it)->entered();
452            }
453            stateEnterRequests_.clear();
454        }
455
456        // check for states to destroy
457        if (!stateDestroyRequests_.empty())
458        {
459            for (std::set<InputState*>::iterator it = stateDestroyRequests_.begin();
460                it != stateDestroyRequests_.end(); ++it)
461            {
462                destroyStateInternal((*it));
463            }
464            stateDestroyRequests_.clear();
465        }
466
467        // check whether a state has changed its EMPTY situation
468        bool bUpdateRequired = false;
469        for (std::map<int, InputState*>::iterator it = activeStates_.begin(); it != activeStates_.end(); ++it)
470        {
471            if (it->second->hasExpired())
472            {
473                it->second->resetExpiration();
474                bUpdateRequired = true;
475            }
476        }
477        if (bUpdateRequired)
478            updateActiveStates();
479
480        // mark that we now start capturing and distributing input
481        internalState_ |= Ticking;
482
483        // Capture all the input and handle it
484        BOOST_FOREACH(InputDevice* device, devices_)
485            if (device != NULL)
486                device->update(time);
487
488        // Update the states
489        for (unsigned int i = 0; i < activeStatesTicked_.size(); ++i)
490            activeStatesTicked_[i]->update(time.getDeltaTime());
491
492        internalState_ &= ~Ticking;
493    }
494
495    /**
496    @brief
497        Updates the currently active states (according to activeStates_) for each device.
498        Also, a list of all active states (no duplicates!) is compiled for the general update().
499    */
500    void InputManager::updateActiveStates()
501    {
502        // temporary resize
503        for (unsigned int i = 0; i < devices_.size(); ++i)
504        {
505            if (devices_[i] == NULL)
506                continue;
507            std::vector<InputState*>& states = devices_[i]->getStateListRef();
508            bool occupied = false;
509            states.clear();
510            for (std::map<int, InputState*>::reverse_iterator rit = activeStates_.rbegin(); rit != activeStates_.rend(); ++rit)
511            {
512                if (rit->second->isInputDeviceEnabled(i) && (!occupied || rit->second->bAlwaysGetsInput_))
513                {
514                    states.push_back(rit->second);
515                    if (!rit->second->bTransparent_)
516                        occupied = true;
517                }
518            }
519        }
520
521        // update tickables (every state will only appear once)
522        // Using a std::set to avoid duplicates
523        std::set<InputState*> tempSet;
524        for (unsigned int i = 0; i < devices_.size(); ++i)
525            if (devices_[i] != NULL)
526                for (unsigned int iState = 0; iState < devices_[i]->getStateListRef().size(); ++iState)
527                    tempSet.insert(devices_[i]->getStateListRef()[iState]);
528
529        // copy the content of the std::set back to the actual vector
530        activeStatesTicked_.clear();
531        for (std::set<InputState*>::const_iterator it = tempSet.begin();it != tempSet.end(); ++it)
532            activeStatesTicked_.push_back(*it);
533    }
534
535    void InputManager::clearBuffers()
536    {
537        BOOST_FOREACH(InputDevice* device, devices_)
538            if (device != NULL)
539                device->clearBuffers();
540    }
541
542    void InputManager::calibrate()
543    {
544        COUT(0) << "Move all joy stick axes fully in all directions." << std::endl
545                << "When done, put the axex in the middle position and press enter." << std::endl;
546
547        BOOST_FOREACH(InputDevice* device, devices_)
548            if (device != NULL)
549                device->startCalibration();
550
551        internalState_ |= Calibrating;
552        enterState("calibrator");
553    }
554
555    //! Tells all devices to stop the calibration and evaluate it. Buffers are being cleared as well!
556    void InputManager::stopCalibration()
557    {
558        BOOST_FOREACH(InputDevice* device, devices_)
559            if (device != NULL)
560                device->stopCalibration();
561
562        // restore old input state
563        leaveState("calibrator");
564        internalState_ &= ~Calibrating;
565        // Clear buffers to prevent button hold events
566        this->clearBuffers();
567    }
568
569    // ############################################################
570    // #####                    Iput States                   #####
571    // ##########                                        ##########
572    // ############################################################
573
574    InputState* InputManager::createInputState(const std::string& name, bool bAlwaysGetsInput, bool bTransparent, InputStatePriority priority)
575    {
576        if (name == "")
577            return 0;
578        if (statesByName_.find(name) == statesByName_.end())
579        {
580            InputState* state = new InputState;
581            if (priority >= InputStatePriority::HighPriority || priority == InputStatePriority::Empty)
582            {
583                // Make sure we don't add two high priority states with the same priority
584                for (std::map<std::string, InputState*>::const_iterator it = this->statesByName_.begin();
585                    it != this->statesByName_.end(); ++it)
586                {
587                    if (it->second->getPriority() == priority)
588                    {
589                        COUT(2) << "Warning: Could not add an InputState with the same priority '"
590                            << static_cast<int>(priority) << "' != 0." << std::endl;
591                        return false;
592                    }
593                }
594            }
595            statesByName_[name] = state;
596            state->JoyStickQuantityChanged(devices_.size() - InputDeviceEnumerator::FirstJoyStick);
597            state->setName(name);
598            state->bAlwaysGetsInput_ = bAlwaysGetsInput;
599            state->bTransparent_ = bTransparent;
600            if (priority >= InputStatePriority::HighPriority || priority == InputStatePriority::Empty)
601                state->setPriority(priority);
602
603            return state;
604        }
605        else
606        {
607            COUT(2) << "Warning: Could not add an InputState with the same name '" << name << "'." << std::endl;
608            return 0;
609        }
610    }
611
612    InputState* InputManager::getState(const std::string& name)
613    {
614        std::map<std::string, InputState*>::iterator it = statesByName_.find(name);
615        if (it != statesByName_.end())
616            return it->second;
617        else
618            return 0;
619    }
620
621    bool InputManager::enterState(const std::string& name)
622    {
623        // get pointer from the map with all stored handlers
624        std::map<std::string, InputState*>::const_iterator it = statesByName_.find(name);
625        if (it != statesByName_.end())
626        {
627            // exists
628            if (activeStates_.find(it->second->getPriority()) == activeStates_.end())
629            {
630                // not active
631                if (stateDestroyRequests_.find(it->second) == stateDestroyRequests_.end())
632                {
633                    // not scheduled for destruction
634                    // prevents a state being added multiple times
635                    stateEnterRequests_.insert(it->second);
636                    return true;
637                }
638            }
639        }
640        return false;
641    }
642
643    bool InputManager::leaveState(const std::string& name)
644    {
645        if (name == "empty")
646        {
647            COUT(2) << "InputManager: Leaving the empty state is not allowed!" << std::endl;
648            return false;
649        }
650        // get pointer from the map with all stored handlers
651        std::map<std::string, InputState*>::const_iterator it = statesByName_.find(name);
652        if (it != statesByName_.end())
653        {
654            // exists
655            if (activeStates_.find(it->second->getPriority()) != activeStates_.end())
656            {
657                // active
658                stateLeaveRequests_.insert(it->second);
659                return true;
660            }
661        }
662        return false;
663    }
664
665    bool InputManager::destroyState(const std::string& name)
666    {
667        if (name == "empty")
668        {
669            COUT(2) << "InputManager: Removing the empty state is not allowed!" << std::endl;
670            return false;
671        }
672        std::map<std::string, InputState*>::iterator it = statesByName_.find(name);
673        if (it != statesByName_.end())
674        {
675            if (activeStates_.find(it->second->getPriority()) != activeStates_.end())
676            {
677                // The state is still active. We have to postpone
678                stateLeaveRequests_.insert(it->second);
679                stateDestroyRequests_.insert(it->second);
680            }
681            else if (this->internalState_ & Ticking)
682            {
683                // cannot remove state while ticking
684                stateDestroyRequests_.insert(it->second);
685            }
686            else
687                destroyStateInternal(it->second);
688
689            return true;
690        }
691        return false;
692    }
693
694    //! Destroys an InputState internally.
695    void InputManager::destroyStateInternal(InputState* state)
696    {
697        assert(state && !(this->internalState_ & Ticking));
698        std::map<int, InputState*>::iterator it = this->activeStates_.find(state->getPriority());
699        if (it != this->activeStates_.end())
700        {
701            this->activeStates_.erase(it);
702            updateActiveStates();
703        }
704        statesByName_.erase(state->getName());
705        delete state;
706    }
707}
Note: See TracBrowser for help on using the repository browser.