Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/resource2/src/core/input/InputManager.cc @ 5670

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

Added support for non exclusive mouse mode on Windows. This means you get the normal mouse cursor when displaying a GUI menu in windowed mode.
The feature is activated via InputState (InputState::setIsExclusiveMouse(bool)). Whenever that state is on top of the mouse state stack, the input manager reloads if necessary.

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