Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Extracted joy stick related code from InputManager to a new JoyStick class in order to make the InputManger less of a monster class and to apply a little bit more OO.

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