Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Moved grab/ungrab mouse hack for Linux from InputManager to Mouse.

  • Property svn:eol-style set to native
File size: 31.4 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 that captures all the input from OIS
33    and redirects it to handlers.
34 */
35
36#include "InputManager.h"
37
38#include <climits>
39#include <cassert>
40#include <ois/OISException.h>
41#include <ois/OISInputManager.h>
42#include <boost/foreach.hpp>
43
44#include "util/Convert.h"
45#include "util/Exception.h"
46#include "util/ScopeGuard.h"
47#include "core/Clock.h"
48#include "core/CoreIncludes.h"
49#include "core/ConfigValueIncludes.h"
50#include "core/ConsoleCommand.h"
51#include "core/CommandLine.h"
52#include "core/Functor.h"
53
54#include "InputBuffer.h"
55#include "KeyDetector.h"
56#include "InputHandler.h"
57#include "InputState.h"
58#include "JoyStickQuantityListener.h"
59#include "JoyStick.h"
60#include "Mouse.h"
61#include "Keyboard.h"
62
63namespace orxonox
64{
65    SetConsoleCommand(InputManager, calibrate, true);
66    SetConsoleCommand(InputManager, reload, false);
67    SetCommandLineSwitch(keyboard_no_grab).information("Whether not to exclusively grab the keyboard");
68
69    InputHandler InputHandler::EMPTY;
70    InputManager* InputManager::singletonRef_s = 0;
71
72    /**
73    @brief
74        Defines the |= operator for easier use.
75    */
76    inline InputManager::InputManagerState operator|=(InputManager::InputManagerState& lval,
77                                                      InputManager::InputManagerState rval)
78    {
79        return (lval = (InputManager::InputManagerState)(lval | rval));
80    }
81
82    /**
83    @brief
84        Defines the &= operator for easier use.
85    */
86    inline InputManager::InputManagerState operator&=(InputManager::InputManagerState& lval, int rval)
87    {
88        return (lval = (InputManager::InputManagerState)(lval & rval));
89    }
90
91    // ############################################################
92    // #####                  Initialisation                  #####
93    // ##########                                        ##########
94    // ############################################################
95
96    /**
97    @brief
98        Constructor only sets member fields to initial zero values
99        and registers the class in the class hierarchy.
100    */
101    InputManager::InputManager(size_t windowHnd, unsigned int windowWidth, unsigned int windowHeight)
102        : inputSystem_(0)
103        , devices_(2)
104        , windowHnd_(0)
105        , internalState_(Uninitialised)
106        , stateEmpty_(0)
107        , keyDetector_(0)
108        , calibratorCallbackBuffer_(0)
109    {
110        RegisterRootObject(InputManager);
111
112        assert(singletonRef_s == 0);
113        singletonRef_s = this;
114
115        setConfigValues();
116
117        initialise(windowHnd, windowWidth, windowHeight);
118    }
119
120    /**
121    @brief
122        Sets the configurable values.
123    */
124    void InputManager::setConfigValues()
125    {
126    }
127
128    /**
129    @brief
130        Creates the OIS::InputMananger, the keyboard, the mouse and
131        the joysticks and assigns the key bindings.
132    @param windowHnd
133        The window handle of the render window
134    @param windowWidth
135        The width of the render window
136    @param windowHeight
137        The height of the render window
138    */
139    void InputManager::initialise(size_t windowHnd, unsigned int windowWidth, unsigned int windowHeight)
140    {
141        CCOUT(3) << "Initialising Input System..." << std::endl;
142
143        if (!(internalState_ & OISReady))
144        {
145            CCOUT(4) << "Initialising OIS components..." << std::endl;
146
147            // store handle internally so we can reload OIS
148            windowHnd_ = windowHnd;
149
150            OIS::ParamList paramList;
151            std::ostringstream windowHndStr;
152
153            // Fill parameter list
154            windowHndStr << (unsigned int)windowHnd_;
155            paramList.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
156#if defined(ORXONOX_PLATFORM_WINDOWS)
157            //paramList.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_NONEXCLUSIVE")));
158            //paramList.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_FOREGROUND")));
159            //paramList.insert(std::make_pair(std::string("w32_keyboard"), std::string("DISCL_NONEXCLUSIVE")));
160            //paramList.insert(std::make_pair(std::string("w32_keyboard"), std::string("DISCL_FOREGROUND")));
161#elif defined(ORXONOX_PLATFORM_LINUX)
162            paramList.insert(std::make_pair(std::string("XAutoRepeatOn"), std::string("true")));
163            paramList.insert(std::make_pair(std::string("x11_mouse_grab"), "true"));
164            paramList.insert(std::make_pair(std::string("x11_mouse_hide"), "true"));
165            bool kbNoGrab;
166            CommandLine::getValue("keyboard_no_grab", &kbNoGrab);
167            if (kbNoGrab)
168                paramList.insert(std::make_pair(std::string("x11_keyboard_grab"), std::string("false")));
169            else
170                paramList.insert(std::make_pair(std::string("x11_keyboard_grab"), std::string("true")));
171#endif
172
173            // TODO: clean this up
174            try
175            {
176                inputSystem_ = OIS::InputManager::createInputSystem(paramList);
177                // Exception-safety
178                Loki::ScopeGuard guard = Loki::MakeGuard(OIS::InputManager::destroyInputSystem, inputSystem_);
179                CCOUT(ORX_DEBUG) << "Created OIS input system" << std::endl;
180
181                _initialiseKeyboard();
182
183                // Nothing below should throw anymore, dismiss the guard
184                guard.Dismiss();
185            }
186            catch (OIS::Exception& ex)
187            {
188                ThrowException(InitialisationFailed, "Could not initialise the input system: " << ex.what());
189            }
190
191            // TODO: Remove the two parameters
192            _initialiseMouse(windowWidth, windowHeight);
193
194            _initialiseJoySticks();
195
196            // clear all buffers
197            clearBuffers();
198
199            internalState_ |= OISReady;
200
201            CCOUT(ORX_DEBUG) << "Initialising OIS components done." << std::endl;
202        }
203        else
204        {
205            CCOUT(2) << "Warning: OIS compoments already initialised, skipping" << std::endl;
206        }
207
208        if (!(internalState_ & InternalsReady))
209        {
210            CCOUT(4) << "Initialising InputStates components..." << std::endl;
211
212            // Lowest priority empty InputState
213            stateEmpty_ = createInputState("empty", false, false, InputStatePriority::Empty);
214            stateEmpty_->setHandler(&InputHandler::EMPTY);
215            activeStates_[stateEmpty_->getPriority()] = stateEmpty_;
216
217            // KeyDetector to evaluate a pressed key's name
218            InputState* detector = createInputState("detector", false, false, InputStatePriority::Detector);
219            FunctorMember<InputManager>* bufferFunctor = createFunctor(&InputManager::clearBuffers);
220            bufferFunctor->setObject(this);
221            detector->setLeaveFunctor(bufferFunctor);
222            keyDetector_ = new KeyDetector();
223            detector->setHandler(keyDetector_);
224
225            // Joy stick calibration helper callback
226            InputState* calibrator = createInputState("calibrator", false, false, InputStatePriority::Calibrator);
227            calibrator->setHandler(&InputHandler::EMPTY);
228            calibratorCallbackBuffer_ = new InputBuffer();
229            calibratorCallbackBuffer_->registerListener(this, &InputManager::_stopCalibration, '\r', true);
230            calibrator->setKeyHandler(calibratorCallbackBuffer_);
231
232            internalState_ |= InternalsReady;
233
234            CCOUT(4) << "Initialising InputStates complete." << std::endl;
235        }
236
237        _updateActiveStates();
238
239        CCOUT(3) << "Initialising complete." << std::endl;
240    }
241
242    void InputManager::_initialiseKeyboard()
243    {
244        assert(devices_[InputDeviceEnumerator::Keyboard] == 0);
245        if (inputSystem_->getNumberOfDevices(OIS::OISKeyboard) > 0)
246            devices_[InputDeviceEnumerator::Keyboard] = new Keyboard(InputDeviceEnumerator::Keyboard);
247        else
248            ThrowException(InitialisationFailed, "InputManager: No keyboard found, cannot proceed!");
249    }
250
251    void InputManager::_initialiseMouse(unsigned int windowWidth, unsigned int windowHeight)
252    {
253        assert(devices_[InputDeviceEnumerator::Mouse] == 0);
254        if (inputSystem_->getNumberOfDevices(OIS::OISMouse) > 0)
255        {
256            try
257            {
258                devices_[InputDeviceEnumerator::Mouse] = new Mouse(InputDeviceEnumerator::Mouse, windowWidth, windowHeight);
259            }
260            catch (const OIS::Exception& ex)
261            {
262                CCOUT(2) << "Warning: Failed to create Mouse:" << ex.eText << std::endl
263                         << "Proceeding without mouse support." << std::endl;
264            }
265        }
266        else
267            CCOUT(ORX_WARNING) << "Warning: No mouse found! Proceeding without mouse support." << std::endl;
268    }
269
270    /**
271    @brief
272        Creates all joy sticks and sets the event handler.
273    @return
274        False joy stick stay uninitialised, true otherwise.
275    */
276    void InputManager::_initialiseJoySticks()
277    {
278        assert(devices_.size() == InputDeviceEnumerator::FirstJoyStick);
279
280        for (int i = 0; i < inputSystem_->getNumberOfDevices(OIS::OISJoyStick); i++)
281        {
282            try
283            {
284                devices_.push_back(new JoyStick(InputDeviceEnumerator::FirstJoyStick + i));
285            }
286            catch (std::exception ex)
287            {
288                CCOUT(2) << "Warning: Failed to create joy stick: " << ex.what() << std::endl;
289            }
290        }
291
292        // inform all JoyStick Device Number Listeners
293        for (ObjectList<JoyStickQuantityListener>::iterator it = ObjectList<JoyStickQuantityListener>::begin(); it; ++it)
294            it->JoyStickQuantityChanged(devices_.size() - InputDeviceEnumerator::FirstJoyStick);
295    }
296
297    void InputManager::_startCalibration()
298    {
299        BOOST_FOREACH(InputDevice* device, devices_)
300            device->startCalibration();
301
302        getInstance().internalState_ |= Calibrating;
303        getInstance().requestEnterState("calibrator");
304    }
305
306    void InputManager::_stopCalibration()
307    {
308        BOOST_FOREACH(InputDevice* device, devices_)
309            device->stopCalibration();
310
311        // restore old input state
312        requestLeaveState("calibrator");
313        internalState_ &= ~Calibrating;
314        // Clear buffers to prevent button hold events
315        this->clearBuffers();
316    }
317
318    // ############################################################
319    // #####                    Destruction                   #####
320    // ##########                                        ##########
321    // ############################################################
322
323    /**
324    @brief
325        Destroys all the created input devices and states.
326    */
327    // TODO: export this to be used with reload()
328    InputManager::~InputManager()
329    {
330        if (internalState_ != Uninitialised)
331        {
332            CCOUT(3) << "Destroying ..." << std::endl;
333
334            // Destroy calibrator helper handler and state
335            delete keyDetector_;
336            requestDestroyState("calibrator");
337            // Destroy KeyDetector and state
338            delete calibratorCallbackBuffer_;
339            requestDestroyState("detector");
340            // destroy the empty InputState
341            _destroyState(this->stateEmpty_);
342
343            // destroy all user InputStates
344            while (inputStatesByName_.size() > 0)
345                _destroyState((*inputStatesByName_.rbegin()).second);
346
347            // destroy the devices
348            BOOST_FOREACH(InputDevice*& device, devices_)
349            {
350                std::string className = device->getClassName();
351                try
352                {
353                    if (device)
354                        delete device;
355                    device = 0;
356                    CCOUT(4) << className << " destroyed." << std::endl;
357                }
358                catch (...)
359                {
360                    CCOUT(1) << className << " destruction failed! Potential resource leak!" << std::endl;
361                }
362            }
363            devices_.resize(InputDeviceEnumerator::FirstJoyStick);
364
365            try
366            {
367                OIS::InputManager::destroyInputSystem(inputSystem_);
368            }
369            catch (...)
370            {
371                CCOUT(1) << "OIS::InputManager destruction failed! Potential resource leak!" << std::endl;
372            }
373        }
374
375        singletonRef_s = 0;
376    }
377
378    /**
379    @brief
380        Removes and destroys an InputState.
381    @return
382        True if state was removed immediately, false if postponed.
383    */
384    void InputManager::_destroyState(InputState* state)
385    {
386        assert(state && !(this->internalState_ & Ticking));
387        std::map<int, InputState*>::iterator it = this->activeStates_.find(state->getPriority());
388        if (it != this->activeStates_.end())
389        {
390            this->activeStates_.erase(it);
391            _updateActiveStates();
392        }
393        inputStatesByName_.erase(state->getName());
394        delete state;
395    }
396
397    // ############################################################
398    // #####                     Reloading                    #####
399    // ##########                                        ##########
400    // ############################################################
401
402    /**
403    @brief
404        Public interface. Only reloads immediately if the call stack doesn't
405        include the update() method.
406    */
407    void InputManager::reloadInputSystem()
408    {
409        if (internalState_ & Ticking)
410        {
411            // We cannot destroy OIS right now, because reload was probably
412            // caused by a user clicking on a GUI item. The backtrace would then
413            // include an OIS method. So it would be a very bad thing to destroy it..
414            internalState_ |= ReloadRequest;
415        }
416        else if (internalState_ & OISReady)
417            _reload();
418        else
419        {
420            CCOUT(2) << "Warning: Cannot reload OIS. May not yet be initialised or"
421                     << "joy sticks are currently calibrating." << std::endl;
422        }
423    }
424
425    /**
426    @brief
427        Internal reload method. Destroys the OIS devices and loads them again.
428    */
429    void InputManager::_reload()
430    {
431        try
432        {
433            CCOUT(3) << "Reloading ..." << std::endl;
434
435            // Save mouse clipping size
436            int mouseWidth  = static_cast<Mouse*>(devices_[InputDeviceEnumerator::Mouse])->getClippingWidth();
437            int mouseHeight = static_cast<Mouse*>(devices_[InputDeviceEnumerator::Mouse])->getClippingHeight();
438
439            internalState_ &= ~OISReady;
440
441            // destroy the devices
442            // destroy the devices
443            BOOST_FOREACH(InputDevice*& device, devices_)
444            {
445                try
446                {
447                    if (device)
448                        delete device;
449                    device = 0;
450                    CCOUT(4) << device->getClassName() << " destroyed." << std::endl;
451                }
452                catch (...)
453                {
454                    CCOUT(1) << device->getClassName() << " destruction failed! Potential resource leak!" << std::endl;
455                }
456            }
457            devices_.resize(InputDeviceEnumerator::FirstJoyStick);
458
459            OIS::InputManager::destroyInputSystem(inputSystem_);
460            inputSystem_ = 0;
461
462            // clear all buffers containing input information
463            clearBuffers();
464
465            initialise(windowHnd_, mouseWidth, mouseHeight);
466
467            CCOUT(3) << "Reloading done." << std::endl;
468        }
469        catch (OIS::Exception& ex)
470        {
471            CCOUT(1) << "An exception has occured while reloading:\n" << ex.what() << std::endl;
472        }
473    }
474
475    // ############################################################
476    // #####                  Runtime Methods                 #####
477    // ##########                                        ##########
478    // ############################################################
479
480    /**
481    @brief
482        Updates the states and the InputState situation.
483    @param time
484        Clock holding the current time.
485    */
486    void InputManager::update(const Clock& time)
487    {
488        if (internalState_ == Uninitialised)
489            return;
490        else if (internalState_ & ReloadRequest)
491        {
492            _reload();
493            internalState_ &= ~ReloadRequest;
494        }
495
496        // check for states to leave
497        if (!stateLeaveRequests_.empty())
498        {
499            for (std::set<InputState*>::iterator it = stateLeaveRequests_.begin();
500                it != stateLeaveRequests_.end(); ++it)
501            {
502                (*it)->left();
503                // just to be sure that the state actually is registered
504                assert(inputStatesByName_.find((*it)->getName()) != inputStatesByName_.end());
505
506                activeStates_.erase((*it)->getPriority());
507                if ((*it)->getPriority() < InputStatePriority::HighPriority)
508                    (*it)->setPriority(0);
509                _updateActiveStates();
510            }
511            stateLeaveRequests_.clear();
512        }
513
514        // check for states to enter
515        if (!stateEnterRequests_.empty())
516        {
517            for (std::set<InputState*>::const_iterator it = stateEnterRequests_.begin();
518                it != stateEnterRequests_.end(); ++it)
519            {
520                // just to be sure that the state actually is registered
521                assert(inputStatesByName_.find((*it)->getName()) != inputStatesByName_.end());
522
523                if ((*it)->getPriority() == 0)
524                {
525                    // Get smallest possible priority between 1 and maxStateStackSize_s
526                    for(std::map<int, InputState*>::reverse_iterator rit = activeStates_.rbegin();
527                        rit != activeStates_.rend(); ++rit)
528                    {
529                        if (rit->first < InputStatePriority::HighPriority)
530                        {
531                            (*it)->setPriority(rit->first + 1);
532                            break;
533                        }
534                    }
535                    // In case no normal handler was on the stack
536                    if ((*it)->getPriority() == 0)
537                        (*it)->setPriority(1);
538                }
539                activeStates_[(*it)->getPriority()] = (*it);
540                _updateActiveStates();
541                (*it)->entered();
542            }
543            stateEnterRequests_.clear();
544        }
545
546        // check for states to destroy
547        if (!stateDestroyRequests_.empty())
548        {
549            for (std::set<InputState*>::iterator it = stateDestroyRequests_.begin();
550                it != stateDestroyRequests_.end(); ++it)
551            {
552                _destroyState((*it));
553            }
554            stateDestroyRequests_.clear();
555        }
556
557        // check whether a state has changed its EMPTY situation
558        bool bUpdateRequired = false;
559        for (std::map<int, InputState*>::iterator it = activeStates_.begin(); it != activeStates_.end(); ++it)
560        {
561            if (it->second->hasExpired())
562            {
563                it->second->resetExpiration();
564                bUpdateRequired = true;
565            }
566        }
567        if (bUpdateRequired)
568            _updateActiveStates();
569
570        // mark that we now start capturing and distributing input
571        internalState_ |= Ticking;
572
573        // Capture all the input. This calls the event handlers in InputManager.
574        BOOST_FOREACH(InputDevice* device, devices_)
575            device->update(time);
576
577        if (!(internalState_ & Calibrating))
578        {
579            // update the states with a general tick afterwards
580            for (unsigned int i = 0; i < activeStatesTicked_.size(); ++i)
581                activeStatesTicked_[i]->update(time.getDeltaTime());
582        }
583
584        internalState_ &= ~Ticking;
585    }
586
587    /**
588    @brief
589        Updates the currently active states (according to activeStates_) for each device.
590        Also, a list of all active states (no duplicates!) is compiled for the general update().
591    */
592    void InputManager::_updateActiveStates()
593    {
594        // temporary resize
595        for (unsigned int i = 0; i < devices_.size(); ++i)
596        {
597            std::vector<InputState*>& states = devices_[i]->getStateListRef();
598            bool occupied = false;
599            states.clear();
600            for (std::map<int, InputState*>::reverse_iterator rit = activeStates_.rbegin(); rit != activeStates_.rend(); ++rit)
601            {
602                if (rit->second->isInputDeviceEnabled(i) && (!occupied || rit->second->bAlwaysGetsInput_))
603                {
604                    states.push_back(rit->second);
605                    if (!rit->second->bTransparent_)
606                        occupied = true;
607                }
608            }
609        }
610
611        // update tickables (every state will only appear once)
612        // Using a std::set to avoid duplicates
613        std::set<InputState*> tempSet;
614        for (unsigned int i = 0; i < devices_.size(); ++i)
615            for (unsigned int iState = 0; iState < devices_[i]->getStateListRef().size(); ++iState)
616                tempSet.insert(devices_[i]->getStateListRef()[iState]);
617
618        // copy the content of the std::set back to the actual vector
619        activeStatesTicked_.clear();
620        for (std::set<InputState*>::const_iterator it = tempSet.begin();it != tempSet.end(); ++it)
621            activeStatesTicked_.push_back(*it);
622    }
623
624    /**
625    @brief
626        Clears all buffers that store what keys/buttons are being pressed at the moment.
627    */
628    void InputManager::clearBuffers()
629    {
630        BOOST_FOREACH(InputDevice* device, devices_)
631            device->clearBuffers();
632    }
633
634
635    // ############################################################
636    // #####                Friend functions                  #####
637    // ##########                                        ##########
638    // ############################################################
639
640    /**
641    @brief
642        Checks whether there is already a joy stick with the given ID string.
643    @return
644        Returns true if ID is ok (unique), false otherwise.
645    */
646    bool InputManager::checkJoyStickID(const std::string& idString) const
647    {
648        for (unsigned int i = InputDeviceEnumerator::FirstJoyStick; i < devices_.size(); ++i)
649            if (static_cast<JoyStick*>(devices_[i])->getIDString() == idString)
650                return false;
651        return true;
652    }
653
654
655    // ############################################################
656    // #####         Other Public Interface Methods           #####
657    // ##########                                        ##########
658    // ############################################################
659
660    /**
661    @brief
662        Sets the the name of the command used by the KeyDetector as callback.
663    @param command
664        Command name as string
665    */
666    void InputManager::setKeyDetectorCallback(const std::string& command)
667    {
668        this->keyDetector_->setCallbackCommand(command);
669    }
670
671    // ###### InputStates ######
672
673    /**
674    @brief
675        Creates a new InputState by type, name and priority.
676       
677        You will have to use this method because the
678        c'tors and d'tors are private.
679    @remarks
680        The InputManager will take care of the state completely. That also
681        means it gets deleted when the InputManager is destroyed!
682    @param name
683        Name of the InputState when referenced as string
684    @param priority
685        Priority matters when multiple states are active. You can specify any
686        number, but 1 - 99 is preferred (99 means high).
687    */
688    InputState* InputManager::createInputState(const std::string& name, bool bAlwaysGetsInput, bool bTransparent, InputStatePriority priority)
689    {
690        InputState* state = new InputState;
691        if (_configureInputState(state, name, bAlwaysGetsInput, bTransparent, priority))
692            return state;
693        else
694        {
695            delete state;
696            return 0;
697        }
698    }
699
700    /**
701    @brief
702        Adds a new key handler.
703    @param handler
704        Pointer to the handler object.
705    @param name
706        Unique name of the handler.
707    @param priority
708        Determines which InputState gets the input. Higher is better.
709        Use 0 to handle it implicitely by the order of activation.
710        Otherwise numbers larger than maxStateStackSize_s have to be used!
711    @return
712        True if added, false if name or priority already existed.
713    */
714    bool InputManager::_configureInputState(InputState* state, const std::string& name, bool bAlwaysGetsInput, bool bTransparent, int priority)
715    {
716        if (name == "")
717            return false;
718        if (!state)
719            return false;
720        if (inputStatesByName_.find(name) == inputStatesByName_.end())
721        {
722            if (priority >= InputStatePriority::HighPriority || priority == InputStatePriority::Empty)
723            {
724                // Make sure we don't add two high priority states with the same priority
725                for (std::map<std::string, InputState*>::const_iterator it = this->inputStatesByName_.begin();
726                    it != this->inputStatesByName_.end(); ++it)
727                {
728                    if (it->second->getPriority() == priority)
729                    {
730                        COUT(2) << "Warning: Could not add an InputState with the same priority '"
731                            << priority << "' != 0." << std::endl;
732                        return false;
733                    }
734                }
735            }
736            inputStatesByName_[name] = state;
737            state->JoyStickQuantityChanged(devices_.size() - InputDeviceEnumerator::FirstJoyStick);
738            state->setName(name);
739            state->bAlwaysGetsInput_ = bAlwaysGetsInput;
740            state->bTransparent_ = bTransparent;
741            if (priority >= InputStatePriority::HighPriority || priority == InputStatePriority::Empty)
742                state->setPriority(priority);
743            return true;
744        }
745        else
746        {
747            COUT(2) << "Warning: Could not add an InputState with the same name '" << name << "'." << std::endl;
748            return false;
749        }
750    }
751
752    /**
753    @brief
754        Removes and destroys an input state internally.
755    @param name
756        Name of the handler.
757    @return
758        True if removal was successful, false if name was not found.
759    @remarks
760        You can't remove the internal states "empty", "calibrator" and "detector".
761        The removal process is being postponed if InputManager::update() is currently running.
762    */
763    bool InputManager::requestDestroyState(const std::string& name)
764    {
765        if (name == "empty")
766        {
767            COUT(2) << "InputManager: Removing the empty state is not allowed!" << std::endl;
768            return false;
769        }
770        std::map<std::string, InputState*>::iterator it = inputStatesByName_.find(name);
771        if (it != inputStatesByName_.end())
772        {
773            if (activeStates_.find(it->second->getPriority()) != activeStates_.end())
774            {
775                // The state is still active. We have to postpone
776                stateLeaveRequests_.insert(it->second);
777                stateDestroyRequests_.insert(it->second);
778            }
779            else if (this->internalState_ & Ticking)
780            {
781                // cannot remove state while ticking
782                stateDestroyRequests_.insert(it->second);
783            }
784            else
785                _destroyState(it->second);
786
787            return true;
788        }
789        return false;
790    }
791
792    /**
793    @brief
794        Returns the pointer to the requested InputState.
795    @param name
796        Unique name of the state.
797    @return
798        Pointer to the instance, 0 if name was not found.
799    */
800    InputState* InputManager::getState(const std::string& name)
801    {
802        std::map<std::string, InputState*>::iterator it = inputStatesByName_.find(name);
803        if (it != inputStatesByName_.end())
804            return it->second;
805        else
806            return 0;
807    }
808
809    /**
810    @brief
811        Returns the current input state (there might be others active too!)
812    @return
813        The current highest prioritised active input state.
814    */
815    InputState* InputManager::getCurrentState()
816    {
817        return (*activeStates_.rbegin()).second;
818    }
819
820    /**
821    @brief
822        Activates a specific input state.
823        It might not be really activated if the priority is too low!
824    @param name
825        Unique name of the state.
826    @return
827        False if name was not found, true otherwise.
828    */
829    bool InputManager::requestEnterState(const std::string& name)
830    {
831        // get pointer from the map with all stored handlers
832        std::map<std::string, InputState*>::const_iterator it = inputStatesByName_.find(name);
833        if (it != inputStatesByName_.end())
834        {
835            // exists
836            if (activeStates_.find(it->second->getPriority()) == activeStates_.end())
837            {
838                // not active
839                if (stateDestroyRequests_.find(it->second) == stateDestroyRequests_.end())
840                {
841                    // not scheduled for destruction
842                    // prevents a state being added multiple times
843                    stateEnterRequests_.insert(it->second);
844                    return true;
845                }
846            }
847        }
848        return false;
849    }
850
851    /**
852    @brief
853        Deactivates a specific input state.
854    @param name
855        Unique name of the state.
856    @return
857        False if name was not found, true otherwise.
858    */
859    bool InputManager::requestLeaveState(const std::string& name)
860    {
861        if (name == "empty")
862        {
863            COUT(2) << "InputManager: Leaving the empty state is not allowed!" << std::endl;
864            return false;
865        }
866        // get pointer from the map with all stored handlers
867        std::map<std::string, InputState*>::const_iterator it = inputStatesByName_.find(name);
868        if (it != inputStatesByName_.end())
869        {
870            // exists
871            if (activeStates_.find(it->second->getPriority()) != activeStates_.end())
872            {
873                // active
874                stateLeaveRequests_.insert(it->second);
875                return true;
876            }
877        }
878        return false;
879    }
880
881
882    // ############################################################
883    // #####                Console Commands                  #####
884    // ##########                                        ##########
885    // ############################################################
886
887    /**
888    @brief
889        Starts joy stick calibration.
890    */
891    void InputManager::calibrate()
892    {
893        COUT(0) << "Move all joy stick axes fully in all directions." << std::endl
894                << "When done, put the axex in the middle position and press enter." << std::endl;
895
896        getInstance()._startCalibration();
897    }
898
899    /**
900    @brief
901        Reloads the input system
902    */
903    void InputManager::reload()
904    {
905        getInstance().reloadInputSystem();
906    }
907}
Note: See TracBrowser for help on using the repository browser.