Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 3272 was 3272, checked in by rgrieder, 16 years ago

Removed obsolete feature: ExtendedInputState.
If you need an InputState to handle multiple InputHandlers, simply create two SimpleInputStates and make the one with the higher priority transparent.

  • Property svn:eol-style set to native
File size: 40.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
53#include "InputBuffer.h"
54#include "KeyDetector.h"
55#include "InputState.h"
56#include "SimpleInputState.h"
57#include "JoyStickDeviceNumberListener.h"
58#include "JoyStick.h"
59
60// HACK (include this as last, X11 seems to define some macros...)
61#ifdef ORXONOX_PLATFORM_LINUX
62#  include <ois/linux/LinuxMouse.h>
63#endif
64
65namespace orxonox
66{
67    SetConsoleCommand(InputManager, calibrate, true);
68    SetConsoleCommand(InputManager, reload, false);
69#ifdef ORXONOX_PLATFORM_LINUX
70    SetConsoleCommand(InputManager, grabMouse, true);
71    SetConsoleCommand(InputManager, ungrabMouse, true);
72#endif
73    SetCommandLineSwitch(keyboard_no_grab).information("Whether not to exclusively grab the keyboard");
74
75    EmptyHandler InputManager::EMPTY_HANDLER;
76    InputManager* InputManager::singletonRef_s = 0;
77
78    using namespace InputDevice;
79
80    /**
81    @brief
82        Defines the |= operator for easier use.
83    */
84    inline InputManager::InputManagerState operator|=(InputManager::InputManagerState& lval,
85                                                      InputManager::InputManagerState rval)
86    {
87        return (lval = (InputManager::InputManagerState)(lval | rval));
88    }
89
90    /**
91    @brief
92        Defines the &= operator for easier use.
93    */
94    inline InputManager::InputManagerState operator&=(InputManager::InputManagerState& lval, int rval)
95    {
96        return (lval = (InputManager::InputManagerState)(lval & rval));
97    }
98
99    // ############################################################
100    // #####                  Initialisation                  #####
101    // ##########                                        ##########
102    // ############################################################
103
104    /**
105    @brief
106        Constructor only sets member fields to initial zero values
107        and registers the class in the class hierarchy.
108    */
109    InputManager::InputManager(size_t windowHnd, unsigned int windowWidth, unsigned int windowHeight)
110        : inputSystem_(0)
111        , keyboard_(0)
112        , mouse_(0)
113        , devicesNum_(0)
114        , windowHnd_(0)
115        , internalState_(Uninitialised)
116        , stateEmpty_(0)
117        , keyDetector_(0)
118        , calibratorCallbackBuffer_(0)
119        , keyboardModifiers_(0)
120    {
121        RegisterRootObject(InputManager);
122
123        assert(singletonRef_s == 0);
124        singletonRef_s = this;
125
126        setConfigValues();
127
128        initialise(windowHnd, windowWidth, windowHeight);
129    }
130
131    /**
132    @brief
133        Sets the configurable values.
134    */
135    void InputManager::setConfigValues()
136    {
137    }
138
139    /**
140    @brief
141        Creates the OIS::InputMananger, the keyboard, the mouse and
142        the joysticks and assigns the key bindings.
143    @param windowHnd
144        The window handle of the render window
145    @param windowWidth
146        The width of the render window
147    @param windowHeight
148        The height of the render window
149    */
150    void InputManager::initialise(size_t windowHnd, unsigned int windowWidth, unsigned int windowHeight)
151    {
152        CCOUT(3) << "Initialising Input System..." << std::endl;
153
154        if (!(internalState_ & OISReady))
155        {
156            CCOUT(4) << "Initialising OIS components..." << std::endl;
157
158            // store handle internally so we can reload OIS
159            windowHnd_ = windowHnd;
160
161            OIS::ParamList paramList;
162            std::ostringstream windowHndStr;
163
164            // Fill parameter list
165            windowHndStr << (unsigned int)windowHnd_;
166            paramList.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
167#if defined(ORXONOX_PLATFORM_WINDOWS)
168            //paramList.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_NONEXCLUSIVE")));
169            //paramList.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_FOREGROUND")));
170            //paramList.insert(std::make_pair(std::string("w32_keyboard"), std::string("DISCL_NONEXCLUSIVE")));
171            //paramList.insert(std::make_pair(std::string("w32_keyboard"), std::string("DISCL_FOREGROUND")));
172#elif defined(ORXONOX_PLATFORM_LINUX)
173            paramList.insert(std::make_pair(std::string("XAutoRepeatOn"), std::string("true")));
174            paramList.insert(std::make_pair(std::string("x11_mouse_grab"), "true"));
175            paramList.insert(std::make_pair(std::string("x11_mouse_hide"), "true"));
176            bool kbNoGrab;
177            CommandLine::getValue("keyboard_no_grab", &kbNoGrab);
178            if (kbNoGrab)
179                paramList.insert(std::make_pair(std::string("x11_keyboard_grab"), std::string("false")));
180            else
181                paramList.insert(std::make_pair(std::string("x11_keyboard_grab"), std::string("true")));
182#endif
183
184            try
185            {
186                inputSystem_ = OIS::InputManager::createInputSystem(paramList);
187                // Exception-safety
188                Loki::ScopeGuard guard = Loki::MakeGuard(OIS::InputManager::destroyInputSystem, inputSystem_);
189                CCOUT(ORX_DEBUG) << "Created OIS input system" << std::endl;
190
191                _initialiseKeyboard();
192
193                // Nothing below should throw anymore, dismiss the guard
194                guard.Dismiss();
195            }
196            catch (OIS::Exception& ex)
197            {
198                ThrowException(InitialisationFailed, "Could not initialise the input system: " << ex.what());
199            }
200
201            _initialiseMouse(windowWidth, windowHeight);
202
203            _initialiseJoySticks();
204
205            // clear all buffers
206            clearBuffers();
207
208            internalState_ |= OISReady;
209
210            CCOUT(ORX_DEBUG) << "Initialising OIS components done." << std::endl;
211        }
212        else
213        {
214            CCOUT(2) << "Warning: OIS compoments already initialised, skipping" << std::endl;
215        }
216
217        if (!(internalState_ & InternalsReady))
218        {
219            CCOUT(4) << "Initialising InputStates components..." << std::endl;
220
221            // Lowest priority empty InputState
222            stateEmpty_ = createInputState<SimpleInputState>("empty", false, false, InputStatePriority::Empty);
223            stateEmpty_->setHandler(&EMPTY_HANDLER);
224            activeStates_[stateEmpty_->getPriority()] = stateEmpty_;
225
226            // KeyDetector to evaluate a pressed key's name
227            SimpleInputState* detector = createInputState<SimpleInputState>("detector", false, false, InputStatePriority::Detector);
228            keyDetector_ = new KeyDetector();
229            detector->setHandler(keyDetector_);
230
231            // Joy stick calibration helper callback
232            SimpleInputState* calibrator = createInputState<SimpleInputState>("calibrator", false, false, InputStatePriority::Calibrator);
233            calibrator->setHandler(&EMPTY_HANDLER);
234            calibratorCallbackBuffer_ = new InputBuffer();
235            calibratorCallbackBuffer_->registerListener(this, &InputManager::_completeCalibration, '\r', true);
236            calibrator->setKeyHandler(calibratorCallbackBuffer_);
237
238            internalState_ |= InternalsReady;
239
240            CCOUT(4) << "Initialising InputStates complete." << std::endl;
241        }
242
243        _updateActiveStates();
244
245        CCOUT(3) << "Initialising complete." << std::endl;
246    }
247
248    /**
249    @brief
250        Creates a keyboard and sets the event handler.
251    @return
252        False if keyboard stays uninitialised, true otherwise.
253    */
254    void InputManager::_initialiseKeyboard()
255    {
256        if (keyboard_ != 0)
257        {
258            CCOUT(2) << "Warning: Keyboard already initialised, skipping." << std::endl;
259            return;
260        }
261        if (inputSystem_->getNumberOfDevices(OIS::OISKeyboard) > 0)
262        {
263            keyboard_ = (OIS::Keyboard*)inputSystem_->createInputObject(OIS::OISKeyboard, true);
264            // register our listener in OIS.
265            keyboard_->setEventCallback(this);
266            // note: OIS will not detect keys that have already been down when the keyboard was created.
267            CCOUT(ORX_DEBUG) << "Created OIS keyboard" << std::endl;
268        }
269        else
270        {
271            ThrowException(InitialisationFailed, "InputManager: No keyboard found, cannot proceed!");
272        }
273    }
274
275    /**
276    @brief
277        Creates a mouse and sets the event handler.
278    @return
279        False if mouse stays uninitialised, true otherwise.
280    */
281    void InputManager::_initialiseMouse(unsigned int windowWidth, unsigned int windowHeight)
282    {
283        if (mouse_ != 0)
284        {
285            CCOUT(2) << "Warning: Mouse already initialised, skipping." << std::endl;
286            return;
287        }
288        try
289        {
290            if (inputSystem_->getNumberOfDevices(OIS::OISMouse) > 0)
291            {
292                mouse_ = static_cast<OIS::Mouse*>(inputSystem_->createInputObject(OIS::OISMouse, true));
293                // register our listener in OIS.
294                mouse_->setEventCallback(this);
295                CCOUT(ORX_DEBUG) << "Created OIS mouse" << std::endl;
296
297                // Set mouse region
298                setWindowExtents(windowWidth, windowHeight);
299            }
300            else
301            {
302                CCOUT(ORX_WARNING) << "Warning: No mouse found! Proceeding without mouse support." << std::endl;
303            }
304        }
305        catch (OIS::Exception ex)
306        {
307            CCOUT(ORX_WARNING) << "Warning: Failed to create an OIS mouse\n"
308                << "OIS error message: \"" << ex.eText << "\"\n Proceeding without mouse support." << std::endl;
309            mouse_ = 0;
310        }
311    }
312
313    /**
314    @brief
315        Creates all joy sticks and sets the event handler.
316    @return
317        False joy stick stay uninitialised, true otherwise.
318    */
319    void InputManager::_initialiseJoySticks()
320    {
321        if (!this->joySticks_.empty())
322        {
323            CCOUT(2) << "Warning: Joy sticks already initialised, skipping." << std::endl;
324            return;
325        }
326
327        devicesNum_ = 2 + inputSystem_->getNumberOfDevices(OIS::OISJoyStick);
328        // state management
329        activeStatesTriggered_.resize(devicesNum_);
330
331        for (int i = 0; i < inputSystem_->getNumberOfDevices(OIS::OISJoyStick); i++)
332        {
333            try
334            {
335                joySticks_.push_back(new JoyStick(activeStatesTriggered_[2 + i], i));
336            }
337            catch (std::exception ex)
338            {
339                CCOUT(2) << "Warning: Failed to create joy stick: " << ex.what() << std::endl;
340            }
341        }
342
343        // inform all JoyStick Device Number Listeners
344        for (ObjectList<JoyStickDeviceNumberListener>::iterator it = ObjectList<JoyStickDeviceNumberListener>::begin(); it; ++it)
345            it->JoyStickDeviceNumberChanged(joySticks_.size());
346    }
347
348    void InputManager::_startCalibration()
349    {
350        BOOST_FOREACH(JoyStick* stick, joySticks_)
351            stick->startCalibration();
352
353        getInstance().internalState_ |= Calibrating;
354        getInstance().requestEnterState("calibrator");
355    }
356
357    void InputManager::_completeCalibration()
358    {
359        BOOST_FOREACH(JoyStick* stick, joySticks_)
360            stick->stopCalibration();
361
362        // restore old input state
363        requestLeaveState("calibrator");
364        internalState_ &= ~Calibrating;
365    }
366
367    // ############################################################
368    // #####                    Destruction                   #####
369    // ##########                                        ##########
370    // ############################################################
371
372    /**
373    @brief
374        Destroys all the created input devices and states.
375    */
376    InputManager::~InputManager()
377    {
378        if (internalState_ != Uninitialised)
379        {
380            CCOUT(3) << "Destroying ..." << std::endl;
381
382            // kick all active states 'nicely'
383            for (std::map<int, InputState*>::reverse_iterator rit = activeStates_.rbegin();
384                rit != activeStates_.rend(); ++rit)
385            {
386                (*rit).second->onLeave();
387            }
388
389            // Destroy calibrator helper handler and state
390            delete keyDetector_;
391            requestDestroyState("calibrator");
392            // Destroy KeyDetector and state
393            delete calibratorCallbackBuffer_;
394            requestDestroyState("detector");
395            // destroy the empty InputState
396            _destroyState(this->stateEmpty_);
397
398            // destroy all user InputStates
399            while (inputStatesByName_.size() > 0)
400                _destroyState((*inputStatesByName_.rbegin()).second);
401
402            // destroy the devices
403            _destroyKeyboard();
404            _destroyMouse();
405            _destroyJoySticks();
406
407            try
408            {
409                OIS::InputManager::destroyInputSystem(inputSystem_);
410            }
411            catch (...)
412            {
413                CCOUT(1) << "OIS::InputManager destruction failed! Potential resource leak!" << std::endl;
414            }
415        }
416
417        singletonRef_s = 0;
418    }
419
420    /**
421    @brief
422        Destroys the keyboard and sets it to 0.
423    */
424    void InputManager::_destroyKeyboard()
425    {
426        assert(inputSystem_);
427        try
428        {
429            if (keyboard_)
430                inputSystem_->destroyInputObject(keyboard_);
431            keyboard_ = 0;
432            CCOUT(4) << "Keyboard destroyed." << std::endl;
433        }
434        catch (...)
435        {
436            CCOUT(1) << "Keyboard destruction failed! Potential resource leak!" << std::endl;
437        }
438    }
439
440    /**
441    @brief
442        Destroys the mouse and sets it to 0.
443    */
444    void InputManager::_destroyMouse()
445    {
446        assert(inputSystem_);
447        try
448        {
449            if (mouse_)
450                inputSystem_->destroyInputObject(mouse_);
451            mouse_ = 0;
452            CCOUT(4) << "Mouse destroyed." << std::endl;
453        }
454        catch (...)
455        {
456            CCOUT(1) << "Mouse destruction failed! Potential resource leak!" << std::endl;
457        }
458    }
459
460    /**
461    @brief
462        Destroys all the joy sticks and resizes the lists to 0.
463    */
464    void InputManager::_destroyJoySticks()
465    {
466        assert(inputSystem_);
467        while (!joySticks_.empty())
468        {
469            try
470            {
471                delete joySticks_.back();
472            }
473            catch (...)
474            {
475                CCOUT(1) << "Joy stick destruction failed! Potential resource leak!" << std::endl;
476            }
477            joySticks_.pop_back();
478            devicesNum_ = 2;
479        }
480        CCOUT(4) << "Joy sticks destroyed." << std::endl;
481    }
482
483    /**
484    @brief
485        Removes and destroys an InputState.
486    @return
487        True if state was removed immediately, false if postponed.
488    */
489    void InputManager::_destroyState(InputState* state)
490    {
491        assert(state && !(this->internalState_ & Ticking));
492        std::map<int, InputState*>::iterator it = this->activeStates_.find(state->getPriority());
493        if (it != this->activeStates_.end())
494        {
495            this->activeStates_.erase(it);
496            _updateActiveStates();
497        }
498        inputStatesByName_.erase(state->getName());
499        delete state;
500    }
501
502    // ############################################################
503    // #####                     Reloading                    #####
504    // ##########                                        ##########
505    // ############################################################
506
507    /**
508    @brief
509        Public interface. Only reloads immediately if the call stack doesn't
510        include the update() method.
511    */
512    void InputManager::reloadInputSystem()
513    {
514        if (internalState_ & Ticking)
515        {
516            // We cannot destroy OIS right now, because reload was probably
517            // caused by a user clicking on a GUI item. The backtrace would then
518            // include an OIS method. So it would be a very bad thing to destroy it..
519            internalState_ |= ReloadRequest;
520        }
521        else if (internalState_ & OISReady)
522            _reload();
523        else
524        {
525            CCOUT(2) << "Warning: Cannot reload OIS. May not yet be initialised or"
526                     << "joy sticks are currently calibrating." << std::endl;
527        }
528    }
529
530    /**
531    @brief
532        Internal reload method. Destroys the OIS devices and loads them again.
533    */
534    void InputManager::_reload()
535    {
536        try
537        {
538            CCOUT(3) << "Reloading ..." << std::endl;
539
540            // Save mouse clipping size
541            int mouseWidth  = mouse_->getMouseState().width;
542            int mouseHeight = mouse_->getMouseState().height;
543
544            internalState_ &= ~OISReady;
545
546            // destroy the devices
547            _destroyKeyboard();
548            _destroyMouse();
549            _destroyJoySticks();
550
551            OIS::InputManager::destroyInputSystem(inputSystem_);
552            inputSystem_ = 0;
553
554            // clear all buffers containing input information
555            clearBuffers();
556
557            initialise(windowHnd_, mouseWidth, mouseHeight);
558
559            CCOUT(3) << "Reloading done." << std::endl;
560        }
561        catch (OIS::Exception& ex)
562        {
563            CCOUT(1) << "An exception has occured while reloading:\n" << ex.what() << std::endl;
564        }
565    }
566
567    // ############################################################
568    // #####                  Runtime Methods                 #####
569    // ##########                                        ##########
570    // ############################################################
571
572    /**
573    @brief
574        Updates the states and the InputState situation.
575    @param time
576        Clock holding the current time.
577    */
578    void InputManager::update(const Clock& time)
579    {
580        if (internalState_ == Uninitialised)
581            return;
582        else if (internalState_ & ReloadRequest)
583        {
584            _reload();
585            internalState_ &= ~ReloadRequest;
586        }
587
588        // check for states to leave
589        if (!stateLeaveRequests_.empty())
590        {
591            for (std::set<InputState*>::iterator it = stateLeaveRequests_.begin();
592                it != stateLeaveRequests_.end(); ++it)
593            {
594                (*it)->onLeave();
595                // just to be sure that the state actually is registered
596                assert(inputStatesByName_.find((*it)->getName()) != inputStatesByName_.end());
597
598                activeStates_.erase((*it)->getPriority());
599                if ((*it)->getPriority() < InputStatePriority::HighPriority)
600                    (*it)->setPriority(0);
601                _updateActiveStates();
602            }
603            stateLeaveRequests_.clear();
604        }
605
606        // check for states to enter
607        if (!stateEnterRequests_.empty())
608        {
609            for (std::set<InputState*>::const_iterator it = stateEnterRequests_.begin();
610                it != stateEnterRequests_.end(); ++it)
611            {
612                // just to be sure that the state actually is registered
613                assert(inputStatesByName_.find((*it)->getName()) != inputStatesByName_.end());
614
615                if ((*it)->getPriority() == 0)
616                {
617                    // Get smallest possible priority between 1 and maxStateStackSize_s
618                    for(std::map<int, InputState*>::reverse_iterator rit = activeStates_.rbegin();
619                        rit != activeStates_.rend(); ++rit)
620                    {
621                        if (rit->first < InputStatePriority::HighPriority)
622                        {
623                            (*it)->setPriority(rit->first + 1);
624                            break;
625                        }
626                    }
627                    // In case no normal handler was on the stack
628                    if ((*it)->getPriority() == 0)
629                        (*it)->setPriority(1);
630                }
631                activeStates_[(*it)->getPriority()] = (*it);
632                _updateActiveStates();
633                (*it)->onEnter();
634            }
635            stateEnterRequests_.clear();
636        }
637
638        // check for states to destroy
639        if (!stateDestroyRequests_.empty())
640        {
641            for (std::set<InputState*>::iterator it = stateDestroyRequests_.begin();
642                it != stateDestroyRequests_.end(); ++it)
643            {
644                _destroyState((*it));
645            }
646            stateDestroyRequests_.clear();
647        }
648
649        // check whether a state has changed its EMPTY_HANDLER situation
650        bool bUpdateRequired = false;
651        for (std::map<int, InputState*>::iterator it = activeStates_.begin(); it != activeStates_.end(); ++it)
652        {
653            if (it->second->handlersChanged())
654            {
655                it->second->resetHandlersChanged();
656                bUpdateRequired = true;
657            }
658        }
659        if (bUpdateRequired)
660            _updateActiveStates();
661
662        // mark that we now start capturing and distributing input
663        internalState_ |= Ticking;
664
665        // Capture all the input. This calls the event handlers in InputManager.
666        if (keyboard_)
667            keyboard_->capture();
668        if (mouse_)
669            mouse_->capture();
670        BOOST_FOREACH(JoyStick* stick, joySticks_)
671            stick->capture();
672
673        if (!(internalState_ & Calibrating))
674        {
675            // call all the handlers for the held key events
676            for (unsigned int iKey = 0; iKey < keysDown_.size(); iKey++)
677            {
678                KeyEvent kEvt(keysDown_[iKey], keyboardModifiers_);
679
680                for (unsigned int iState = 0; iState < activeStatesTriggered_[Keyboard].size(); ++iState)
681                    activeStatesTriggered_[Keyboard][iState]->keyHeld(kEvt);
682            }
683
684            // call all the handlers for the held mouse button events
685            for (unsigned int iButton = 0; iButton < mouseButtonsDown_.size(); iButton++)
686            {
687                for (unsigned int iState = 0; iState < activeStatesTriggered_[Mouse].size(); ++iState)
688                    activeStatesTriggered_[Mouse][iState]->mouseButtonHeld(mouseButtonsDown_[iButton]);
689            }
690
691            // update the handlers for each active handler
692            for (unsigned int i = 0; i < devicesNum_; ++i)
693            {
694                for (unsigned int iState = 0; iState < activeStatesTriggered_[i].size(); ++iState)
695                    activeStatesTriggered_[i][iState]->updateInput(time.getDeltaTime(), i);
696            }
697
698            // update the handler with a general tick afterwards
699            for (unsigned int i = 0; i < activeStatesTicked_.size(); ++i)
700                activeStatesTicked_[i]->updateInput(time.getDeltaTime());
701        }
702
703        internalState_ &= ~Ticking;
704    }
705
706    /**
707    @brief
708        Updates the currently active states (according to activeStates_) for each device.
709        Also, a list of all active states (no duplicates!) is compiled for the general update().
710    */
711    void InputManager::_updateActiveStates()
712    {
713        for (unsigned int i = 0; i < devicesNum_; ++i)
714        {
715            bool occupied = false;
716            activeStatesTriggered_[i].clear();
717            for (std::map<int, InputState*>::const_reverse_iterator rit = activeStates_.rbegin(); rit != activeStates_.rend(); ++rit)
718            {
719                if (rit->second->isInputDeviceEnabled(i) && (!occupied || rit->second->bAlwaysGetsInput_))
720                {
721                    activeStatesTriggered_[i].push_back(rit->second);
722                    if (!rit->second->bTransparent_)
723                        occupied = true;
724                }
725            }
726        }
727
728        // update tickables (every state will only appear once)
729        // Using a std::set to avoid duplicates
730        std::set<InputState*> tempSet;
731        for (unsigned int i = 0; i < devicesNum_; ++i)
732            for (unsigned int iState = 0; iState < activeStatesTriggered_[i].size(); ++iState)
733                tempSet.insert(activeStatesTriggered_[i][iState]);
734
735        // copy the content of the std::set back to the actual vector
736        activeStatesTicked_.clear();
737        for (std::set<InputState*>::const_iterator it = tempSet.begin();it != tempSet.end(); ++it)
738            activeStatesTicked_.push_back(*it);
739
740        this->mouseButtonsDown_.clear();
741    }
742
743    /**
744    @brief
745        Clears all buffers that store what keys/buttons are being pressed at the moment.
746    */
747    void InputManager::clearBuffers()
748    {
749        keysDown_.clear();
750        keyboardModifiers_ = 0;
751        mouseButtonsDown_.clear();
752        BOOST_FOREACH(JoyStick* stick, joySticks_)
753            stick->clearBuffer();
754    }
755
756
757    // ############################################################
758    // #####                    OIS events                    #####
759    // ##########                                        ##########
760    // ############################################################
761
762    // ###### Key Events ######
763
764    /**
765    @brief
766        Event handler for the keyPressed Event.
767    @param e
768        Event information
769    */
770    bool InputManager::keyPressed(const OIS::KeyEvent &e)
771    {
772        // check whether the key already is in the list (can happen when focus was lost)
773        unsigned int iKey = 0;
774        while (iKey < keysDown_.size() && keysDown_[iKey].key != (KeyCode::ByEnum)e.key)
775            iKey++;
776        if (iKey == keysDown_.size())
777            keysDown_.push_back(Key(e));
778        else
779        {
780            // This happens when XAutoRepeat is set under linux. The KeyPressed event gets then sent
781            // continuously.
782            return true;
783        }
784
785        // update modifiers
786        if(e.key == OIS::KC_RMENU    || e.key == OIS::KC_LMENU)
787            keyboardModifiers_ |= KeyboardModifier::Alt;   // alt key
788        if(e.key == OIS::KC_RCONTROL || e.key == OIS::KC_LCONTROL)
789            keyboardModifiers_ |= KeyboardModifier::Ctrl;  // ctrl key
790        if(e.key == OIS::KC_RSHIFT   || e.key == OIS::KC_LSHIFT)
791            keyboardModifiers_ |= KeyboardModifier::Shift; // shift key
792
793        KeyEvent kEvt(e, keyboardModifiers_);
794        for (unsigned int iState = 0; iState < activeStatesTriggered_[Keyboard].size(); ++iState)
795            activeStatesTriggered_[Keyboard][iState]->keyPressed(kEvt);
796
797        return true;
798    }
799
800    /**
801    @brief
802        Event handler for the keyReleased Event.
803    @param e
804        Event information
805    */
806    bool InputManager::keyReleased(const OIS::KeyEvent &e)
807    {
808        // remove the key from the keysDown_ list
809        for (unsigned int iKey = 0; iKey < keysDown_.size(); iKey++)
810        {
811            if (keysDown_[iKey].key == (KeyCode::ByEnum)e.key)
812            {
813                keysDown_.erase(keysDown_.begin() + iKey);
814                break;
815            }
816        }
817
818        // update modifiers
819        if(e.key == OIS::KC_RMENU    || e.key == OIS::KC_LMENU)
820            keyboardModifiers_ &= ~KeyboardModifier::Alt;   // alt key
821        if(e.key == OIS::KC_RCONTROL || e.key == OIS::KC_LCONTROL)
822            keyboardModifiers_ &= ~KeyboardModifier::Ctrl;  // ctrl key
823        if(e.key == OIS::KC_RSHIFT   || e.key == OIS::KC_LSHIFT)
824            keyboardModifiers_ &= ~KeyboardModifier::Shift; // shift key
825
826        KeyEvent kEvt(e, keyboardModifiers_);
827        for (unsigned int iState = 0; iState < activeStatesTriggered_[Keyboard].size(); ++iState)
828            activeStatesTriggered_[Keyboard][iState]->keyReleased(kEvt);
829
830        return true;
831    }
832
833
834    // ###### Mouse Events ######
835
836    /**
837    @brief
838        Event handler for the mouseMoved Event.
839    @param e
840        Event information
841    */
842    bool InputManager::mouseMoved(const OIS::MouseEvent &e)
843    {
844        // check for actual moved event
845        if (e.state.X.rel != 0 || e.state.Y.rel != 0)
846        {
847            IntVector2 abs(e.state.X.abs, e.state.Y.abs);
848            IntVector2 rel(e.state.X.rel, e.state.Y.rel);
849            IntVector2 clippingSize(e.state.width, e.state.height);
850            for (unsigned int iState = 0; iState < activeStatesTriggered_[Mouse].size(); ++iState)
851                activeStatesTriggered_[Mouse][iState]->mouseMoved(abs, rel, clippingSize);
852        }
853
854        // check for mouse scrolled event
855        if (e.state.Z.rel != 0)
856        {
857            for (unsigned int iState = 0; iState < activeStatesTriggered_[Mouse].size(); ++iState)
858                activeStatesTriggered_[Mouse][iState]->mouseScrolled(e.state.Z.abs, e.state.Z.rel);
859        }
860
861        return true;
862    }
863
864    /**
865    @brief
866        Event handler for the mousePressed Event.
867    @param e
868        Event information
869    @param id
870        The ID of the mouse button
871    */
872    bool InputManager::mousePressed(const OIS::MouseEvent &e, OIS::MouseButtonID id)
873    {
874        // check whether the button already is in the list (can happen when focus was lost)
875        unsigned int iButton = 0;
876        while (iButton < mouseButtonsDown_.size() && mouseButtonsDown_[iButton] != (MouseButtonCode::ByEnum)id)
877            iButton++;
878        if (iButton == mouseButtonsDown_.size())
879            mouseButtonsDown_.push_back((MouseButtonCode::ByEnum)id);
880
881        for (unsigned int iState = 0; iState < activeStatesTriggered_[Mouse].size(); ++iState)
882            activeStatesTriggered_[Mouse][iState]->mouseButtonPressed((MouseButtonCode::ByEnum)id);
883
884        return true;
885    }
886
887    /**
888    @brief
889        Event handler for the mouseReleased Event.
890    @param e
891        Event information
892    @param id
893        The ID of the mouse button
894    */
895    bool InputManager::mouseReleased(const OIS::MouseEvent &e, OIS::MouseButtonID id)
896    {
897        // remove the button from the keysDown_ list
898        for (unsigned int iButton = 0; iButton < mouseButtonsDown_.size(); iButton++)
899        {
900            if (mouseButtonsDown_[iButton] == (MouseButtonCode::ByEnum)id)
901            {
902                mouseButtonsDown_.erase(mouseButtonsDown_.begin() + iButton);
903                break;
904            }
905        }
906
907        for (unsigned int iState = 0; iState < activeStatesTriggered_[Mouse].size(); ++iState)
908            activeStatesTriggered_[Mouse][iState]->mouseButtonReleased((MouseButtonCode::ByEnum)id);
909
910        return true;
911    }
912
913
914    // ############################################################
915    // #####                Friend functions                  #####
916    // ##########                                        ##########
917    // ############################################################
918
919    /**
920    @brief
921        Checks whether there is already a joy stick with the given ID string.
922    @return
923        Returns true if ID is ok (unique), false otherwise.
924    */
925    bool InputManager::checkJoyStickID(const std::string& idString)
926    {
927        BOOST_FOREACH(JoyStick* stick, joySticks_)
928        {
929            if (stick->getIDString() == idString)
930                return false;
931        }
932        return true;
933    }
934
935
936    // ############################################################
937    // #####         Other Public Interface Methods           #####
938    // ##########                                        ##########
939    // ############################################################
940
941    /**
942    @brief
943        Adjusts the mouse window metrics.
944        This method has to be called every time the size of the window changes.
945    @param width
946        The new width of the render window
947    @param^height
948        The new height of the render window
949    */
950    void InputManager::setWindowExtents(const int width, const int height)
951    {
952        if (mouse_)
953        {
954            // Set mouse region (if window resizes, we should alter this to reflect as well)
955            mouse_->getMouseState().width  = width;
956            mouse_->getMouseState().height = height;
957        }
958    }
959
960    /**
961    @brief
962        Sets the the name of the command used by the KeyDetector as callback.
963    @param command
964        Command name as string
965    */
966    void InputManager::setKeyDetectorCallback(const std::string& command)
967    {
968        this->keyDetector_->setCallbackCommand(command);
969    }
970
971    // ###### InputStates ######
972
973    /**
974    @brief
975        Adds a new key handler.
976    @param handler
977        Pointer to the handler object.
978    @param name
979        Unique name of the handler.
980    @param priority
981        Determines which InputState gets the input. Higher is better.
982        Use 0 to handle it implicitely by the order of activation.
983        Otherwise numbers larger than maxStateStackSize_s have to be used!
984    @return
985        True if added, false if name or priority already existed.
986    */
987    bool InputManager::_configureInputState(InputState* state, const std::string& name, bool bAlwaysGetsInput, bool bTransparent, int priority)
988    {
989        if (name == "")
990            return false;
991        if (!state)
992            return false;
993        if (inputStatesByName_.find(name) == inputStatesByName_.end())
994        {
995            if (priority >= InputStatePriority::HighPriority || priority == InputStatePriority::Empty)
996            {
997                // Make sure we don't add two high priority states with the same priority
998                for (std::map<std::string, InputState*>::const_iterator it = this->inputStatesByName_.begin();
999                    it != this->inputStatesByName_.end(); ++it)
1000                {
1001                    if (it->second->getPriority() == priority)
1002                    {
1003                        COUT(2) << "Warning: Could not add an InputState with the same priority '"
1004                            << priority << "' != 0." << std::endl;
1005                        return false;
1006                    }
1007                }
1008            }
1009            inputStatesByName_[name] = state;
1010            state->JoyStickDeviceNumberChanged(numberOfJoySticks());
1011            state->setName(name);
1012            state->bAlwaysGetsInput_ = bAlwaysGetsInput;
1013            state->bTransparent_ = bTransparent;
1014            if (priority >= InputStatePriority::HighPriority || priority == InputStatePriority::Empty)
1015                state->setPriority(priority);
1016            return true;
1017        }
1018        else
1019        {
1020            COUT(2) << "Warning: Could not add an InputState with the same name '" << name << "'." << std::endl;
1021            return false;
1022        }
1023    }
1024
1025    /**
1026    @brief
1027        Removes and destroys an input state internally.
1028    @param name
1029        Name of the handler.
1030    @return
1031        True if removal was successful, false if name was not found.
1032    @remarks
1033        You can't remove the internal states "empty", "calibrator" and "detector".
1034        The removal process is being postponed if InputManager::update() is currently running.
1035    */
1036    bool InputManager::requestDestroyState(const std::string& name)
1037    {
1038        if (name == "empty")
1039        {
1040            COUT(2) << "InputManager: Removing the empty state is not allowed!" << std::endl;
1041            return false;
1042        }
1043        std::map<std::string, InputState*>::iterator it = inputStatesByName_.find(name);
1044        if (it != inputStatesByName_.end())
1045        {
1046            if (activeStates_.find(it->second->getPriority()) != activeStates_.end())
1047            {
1048                // The state is still active. We have to postpone
1049                stateLeaveRequests_.insert(it->second);
1050                stateDestroyRequests_.insert(it->second);
1051            }
1052            else if (this->internalState_ & Ticking)
1053            {
1054                // cannot remove state while ticking
1055                stateDestroyRequests_.insert(it->second);
1056            }
1057            else
1058                _destroyState(it->second);
1059
1060            return true;
1061        }
1062        return false;
1063    }
1064
1065    /**
1066    @brief
1067        Returns the pointer to the requested InputState.
1068    @param name
1069        Unique name of the state.
1070    @return
1071        Pointer to the instance, 0 if name was not found.
1072    */
1073    InputState* InputManager::getState(const std::string& name)
1074    {
1075        std::map<std::string, InputState*>::iterator it = inputStatesByName_.find(name);
1076        if (it != inputStatesByName_.end())
1077            return it->second;
1078        else
1079            return 0;
1080    }
1081
1082    /**
1083    @brief
1084        Returns the current input state (there might be others active too!)
1085    @return
1086        The current highest prioritised active input state.
1087    */
1088    InputState* InputManager::getCurrentState()
1089    {
1090        return (*activeStates_.rbegin()).second;
1091    }
1092
1093    /**
1094    @brief
1095        Activates a specific input state.
1096        It might not be really activated if the priority is too low!
1097    @param name
1098        Unique name of the state.
1099    @return
1100        False if name was not found, true otherwise.
1101    */
1102    bool InputManager::requestEnterState(const std::string& name)
1103    {
1104        // get pointer from the map with all stored handlers
1105        std::map<std::string, InputState*>::const_iterator it = inputStatesByName_.find(name);
1106        if (it != inputStatesByName_.end())
1107        {
1108            // exists
1109            if (activeStates_.find(it->second->getPriority()) == activeStates_.end())
1110            {
1111                // not active
1112                if (stateDestroyRequests_.find(it->second) == stateDestroyRequests_.end())
1113                {
1114                    // not scheduled for destruction
1115                    // prevents a state being added multiple times
1116                    stateEnterRequests_.insert(it->second);
1117                    return true;
1118                }
1119            }
1120        }
1121        return false;
1122    }
1123
1124    /**
1125    @brief
1126        Deactivates a specific input state.
1127    @param name
1128        Unique name of the state.
1129    @return
1130        False if name was not found, true otherwise.
1131    */
1132    bool InputManager::requestLeaveState(const std::string& name)
1133    {
1134        if (name == "empty")
1135        {
1136            COUT(2) << "InputManager: Leaving the empty state is not allowed!" << std::endl;
1137            return false;
1138        }
1139        // get pointer from the map with all stored handlers
1140        std::map<std::string, InputState*>::const_iterator it = inputStatesByName_.find(name);
1141        if (it != inputStatesByName_.end())
1142        {
1143            // exists
1144            if (activeStates_.find(it->second->getPriority()) != activeStates_.end())
1145            {
1146                // active
1147                stateLeaveRequests_.insert(it->second);
1148                return true;
1149            }
1150        }
1151        return false;
1152    }
1153
1154
1155    // ############################################################
1156    // #####                Console Commands                  #####
1157    // ##########                                        ##########
1158    // ############################################################
1159
1160    /**
1161    @brief
1162        Starts joy stick calibration.
1163    */
1164    void InputManager::calibrate()
1165    {
1166        COUT(0) << "Move all joy stick axes fully in all directions." << std::endl
1167                << "When done, put the axex in the middle position and press enter." << std::endl;
1168
1169        getInstance()._startCalibration();
1170    }
1171
1172    /**
1173    @brief
1174        Reloads the input system
1175    */
1176    void InputManager::reload()
1177    {
1178        getInstance().reloadInputSystem();
1179    }
1180
1181
1182    // ############################################################
1183    // #####                   ugly hacks                     #####
1184    // ##########                                        ##########
1185    // ############################################################
1186
1187#ifdef ORXONOX_PLATFORM_LINUX
1188    void InputManager::grabMouse()
1189    {
1190        OIS::LinuxMouse* linuxMouse = dynamic_cast<OIS::LinuxMouse*>(singletonRef_s->mouse_);
1191        assert(linuxMouse);
1192        linuxMouse->grab(true);
1193    }
1194
1195    void InputManager::ungrabMouse()
1196    {
1197        OIS::LinuxMouse* linuxMouse = dynamic_cast<OIS::LinuxMouse*>(singletonRef_s->mouse_);
1198        assert(linuxMouse);
1199        linuxMouse->grab(false);
1200    }
1201#endif
1202}
Note: See TracBrowser for help on using the repository browser.