Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/core/input/InputManager.cc @ 1881

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

Changed initialisation of internally handled InputStates and InputHandlers.

  • Property svn:eol-style set to native
File size: 47.6 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
41#include "ois/OISException.h"
42#include "ois/OISInputManager.h"
43
44#include "util/Exception.h"
45#include "core/CoreIncludes.h"
46#include "core/ConfigValueIncludes.h"
47#include "core/CommandExecutor.h"
48#include "core/ConsoleCommand.h"
49#include "util/Debug.h"
50
51#include "InputBuffer.h"
52#include "KeyBinder.h"
53#include "KeyDetector.h"
54#include "CalibratorCallback.h"
55#include "InputState.h"
56#include "SimpleInputState.h"
57#include "ExtendedInputState.h"
58
59namespace orxonox
60{
61    SetConsoleCommand(InputManager, keyBind, true);
62    SetConsoleCommand(InputManager, storeKeyStroke, true);
63    SetConsoleCommand(InputManager, calibrate, true);
64    SetConsoleCommand(InputManager, reload, false);
65
66    std::string InputManager::bindingCommmandString_s = "";
67    EmptyHandler InputManager::EMPTY_HANDLER;
68    InputManager* InputManager::singletonRef_s = 0;
69
70    using namespace InputDevice;
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()
102        : inputSystem_(0)
103        , keyboard_(0)
104        , mouse_(0)
105        , joySticksSize_(0)
106        , devicesNum_(0)
107        , windowHnd_(0)
108        , internalState_(Uninitialised)
109        , stateEmpty_(0)
110        , stateMaster_(0)
111        , keyDetector_(0)
112        , calibratorCallbackBuffer_(0)
113        , bCalibrating_(false)
114        , keyboardModifiers_(0)
115    {
116        RegisterRootObject(InputManager);
117
118        assert(singletonRef_s == 0);
119        singletonRef_s = this;
120    }
121
122    /**
123    @brief
124        Creates the OIS::InputMananger, the keyboard, the mouse and
125        the joysticks and assigns the key bindings.
126    @param windowHnd
127        The window handle of the render window
128    @param windowWidth
129        The width of the render window
130    @param windowHeight
131        The height of the render window
132    @param joyStickSupport
133        Whether or not to load the joy sticks as well
134    */
135    void InputManager::initialise(size_t windowHnd, int windowWidth, int windowHeight, bool joyStickSupport)
136    {
137        CCOUT(3) << "Initialising Input System..." << std::endl;
138
139        if (!(internalState_ & OISReady))
140        {
141            CCOUT(4) << "Initialising OIS components..." << std::endl;
142
143            // store handle internally so we can reload OIS
144            windowHnd_ = windowHnd;
145
146            OIS::ParamList paramList;
147            std::ostringstream windowHndStr;
148
149            // Fill parameter list
150            windowHndStr << (unsigned int)windowHnd_;
151            paramList.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
152            //paramList.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_NONEXCLUSIVE")));
153            //paramList.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_FOREGROUND")));
154#if defined OIS_LINUX_PLATFORM
155            paramList.insert(std::make_pair(std::string("XAutoRepeatOn"), std::string("true")));
156#endif
157
158            inputSystem_ = OIS::InputManager::createInputSystem(paramList);
159            CCOUT(ORX_DEBUG) << "Created OIS input system" << std::endl;
160
161            _initialiseKeyboard();
162
163            _initialiseMouse();
164
165            if (joyStickSupport)
166                _initialiseJoySticks();
167
168            // Set mouse/joystick region
169            if (mouse_)
170                setWindowExtents(windowWidth, windowHeight);
171
172            // clear all buffers
173            _clearBuffers();
174
175            // load joy stick calibration
176            setConfigValues();
177
178            internalState_ |= OISReady;
179
180            CCOUT(ORX_DEBUG) << "Initialising OIS components done." << std::endl;
181        }
182        else
183        {
184            CCOUT(2) << "Warning: OIS compoments already initialised, skipping" << std::endl;
185        }
186
187        if (!(internalState_ & InternalsReady))
188        {
189            CCOUT(4) << "Initialising InputStates components..." << std::endl;
190
191            // Lowest priority empty InputState
192            stateEmpty_ = createInputState<SimpleInputState>("empty", -1);
193            stateEmpty_->setHandler(&EMPTY_HANDLER);
194            activeStates_[stateEmpty_->getPriority()] = stateEmpty_;
195
196            // Always active master InputState
197            stateMaster_ = new ExtendedInputState();
198            stateMaster_->setName("master");
199
200            // KeyDetector to evaluate a pressed key's name
201            SimpleInputState* detector = createInputState<SimpleInputState>("detector", 101);
202            keyDetector_ = new KeyDetector();
203            keyDetector_->loadBindings("storeKeyStroke");
204            detector->setHandler(keyDetector_);
205
206            // Joy stick calibration helper callback
207            SimpleInputState* calibrator = createInputState<SimpleInputState>("calibrator", 100);
208            calibrator->setHandler(&EMPTY_HANDLER);
209            calibratorCallbackBuffer_ = new InputBuffer();
210            calibratorCallbackBuffer_->registerListener(this, &InputManager::_completeCalibration, '\r', true);
211            calibrator->setKeyHandler(calibratorCallbackBuffer_);
212
213            internalState_ |= InternalsReady;
214
215            CCOUT(4) << "Initialising InputStates complete." << std::endl;
216        }
217
218        _updateActiveStates();
219
220        CCOUT(3) << "Initialising complete." << std::endl;
221    }
222
223    /**
224    @brief
225        Creates a keyboard and sets the event handler.
226    @return
227        False if keyboard stays uninitialised, true otherwise.
228    */
229    void InputManager::_initialiseKeyboard()
230    {
231        if (keyboard_ != 0)
232        {
233            CCOUT(2) << "Warning: Keyboard already initialised, skipping." << std::endl;
234            return;
235        }
236        if (inputSystem_->getNumberOfDevices(OIS::OISKeyboard) > 0)
237        {
238            keyboard_ = (OIS::Keyboard*)inputSystem_->createInputObject(OIS::OISKeyboard, true);
239            // register our listener in OIS.
240            keyboard_->setEventCallback(this);
241            // note: OIS will not detect keys that have already been down when the keyboard was created.
242            CCOUT(ORX_DEBUG) << "Created OIS keyboard" << std::endl;
243        }
244        else
245        {
246            ThrowException(InitialisationFailed, "No keyboard found!");
247        }
248    }
249
250    /**
251    @brief
252        Creates a mouse and sets the event handler.
253    @return
254        False if mouse stays uninitialised, true otherwise.
255    */
256    void InputManager::_initialiseMouse()
257    {
258        if (mouse_ != 0)
259        {
260            CCOUT(2) << "Warning: Mouse already initialised, skipping." << std::endl;
261            return;
262        }
263        try
264        {
265            if (inputSystem_->getNumberOfDevices(OIS::OISMouse) > 0)
266            {
267                mouse_ = static_cast<OIS::Mouse*>(inputSystem_->createInputObject(OIS::OISMouse, true));
268                // register our listener in OIS.
269                mouse_->setEventCallback(this);
270                CCOUT(ORX_DEBUG) << "Created OIS mouse" << std::endl;
271            }
272            else
273            {
274                CCOUT(ORX_WARNING) << "Warning: No mouse found!" << std::endl;
275            }
276        }
277        catch (OIS::Exception ex)
278        {
279            CCOUT(ORX_WARNING) << "Warning: Failed to create an OIS mouse\n"
280                << "OIS error message: \"" << ex.eText << "\"" << std::endl;
281            mouse_ = 0;
282        }
283    }
284
285    /**
286    @brief
287        Creates all joy sticks and sets the event handler.
288    @return
289        False joy stick stay uninitialised, true otherwise.
290    */
291    void InputManager::_initialiseJoySticks()
292    {
293        if (joySticksSize_ > 0)
294        {
295            CCOUT(2) << "Warning: Joy sticks already initialised, skipping." << std::endl;
296            return;
297        }
298        if (inputSystem_->getNumberOfDevices(OIS::OISJoyStick) > 0)
299        {
300            for (int i = 0; i < inputSystem_->getNumberOfDevices(OIS::OISJoyStick); i++)
301            {
302                try
303                {
304                    OIS::JoyStick* stig = static_cast<OIS::JoyStick*>
305                        (inputSystem_->createInputObject(OIS::OISJoyStick, true));
306                    CCOUT(ORX_DEBUG) << "Created OIS joy stick with ID " << stig->getID() << std::endl;
307                    joySticks_.push_back(stig);
308                    // register our listener in OIS.
309                    stig->setEventCallback(this);
310                }
311                catch (OIS::Exception ex)
312                {
313                    CCOUT(ORX_WARNING) << "Warning: Failed to create OIS joy number" << i << "\n"
314                        << "OIS error message: \"" << ex.eText << "\"" << std::endl;
315                }
316            }
317        }
318        else
319        {
320            //CCOUT(ORX_WARNING) << "Warning: Joy stick support requested, but no joy stick was found" << std::endl;
321        }
322        _redimensionLists();
323    }
324
325    /**
326    @brief
327        Sets the size of all the different lists that are dependent on the number
328        of joy stick devices created.
329    @remarks
330        No matter whether there are a mouse and/or keyboard, they will always
331        occupy 2 places in the device number dependent lists.
332    */
333    void InputManager::_redimensionLists()
334    {
335        joySticksSize_ = joySticks_.size();
336        devicesNum_ = 2 + joySticksSize_;
337        joyStickButtonsDown_ .resize(joySticksSize_);
338        povStates_           .resize(joySticksSize_);
339        sliderStates_        .resize(joySticksSize_);
340        joySticksCalibration_.resize(joySticksSize_);
341
342        for (unsigned int iJoyStick = 0; iJoyStick < joySticksSize_; iJoyStick++)
343        {
344            // reset the calibration with default values
345            for (unsigned int i = 0; i < 24; i++)
346            {
347                joySticksCalibration_[iJoyStick].negativeCoeff[i] = 1.0f/32767.0f;
348                joySticksCalibration_[iJoyStick].positiveCoeff[i] = 1.0f/32768.0f;
349                joySticksCalibration_[iJoyStick].zeroStates[i] = 0;
350            }
351        }
352
353        // state management
354        activeStatesTop_.resize(devicesNum_);
355
356        // inform all states
357        for (std::map<int, InputState*>::const_iterator it = inputStatesByPriority_.begin();
358            it != inputStatesByPriority_.end(); ++it)
359            it->second->setNumOfJoySticks(joySticksSize_);
360    }
361
362    /**
363    @brief
364        Sets the configurable values.
365        This mainly concerns joy stick calibrations.
366    */
367    void InputManager::setConfigValues()
368    {
369        if (joySticksSize_ > 0)
370        {
371            std::vector<double> coeffPos;
372            std::vector<double> coeffNeg;
373            std::vector<int> zero;
374            coeffPos.resize(24);
375            coeffNeg.resize(24);
376            zero.resize(24);
377            for (unsigned int i = 0; i < 24; i++)
378            {
379                coeffPos[i] =  1.0f/32767.0f;
380                coeffNeg[i] =  1.0f/32768.0f;
381                zero[i]     =  0;
382            }
383
384            ConfigValueContainer* cont = getIdentifier()->getConfigValueContainer("CoeffPos");
385            if (!cont)
386            {
387                cont = new ConfigValueContainer(CFT_Settings, getIdentifier(), "CoeffPos", coeffPos);
388                getIdentifier()->addConfigValueContainer("CoeffPos", cont);
389            }
390            cont->getValue(&coeffPos, this);
391
392            cont = getIdentifier()->getConfigValueContainer("CoeffNeg");
393            if (!cont)
394            {
395                cont = new ConfigValueContainer(CFT_Settings, getIdentifier(), "CoeffNeg", coeffNeg);
396                getIdentifier()->addConfigValueContainer("CoeffNeg", cont);
397            }
398            cont->getValue(&coeffNeg, this);
399
400            cont = getIdentifier()->getConfigValueContainer("Zero");
401            if (!cont)
402            {
403                cont = new ConfigValueContainer(CFT_Settings, getIdentifier(), "Zero", zero);
404                getIdentifier()->addConfigValueContainer("Zero", cont);
405            }
406            cont->getValue(&zero, this);
407
408            // copy values to our own variables
409            for (unsigned int i = 0; i < 24; i++)
410            {
411                joySticksCalibration_[0].positiveCoeff[i] = coeffPos[i];
412                joySticksCalibration_[0].negativeCoeff[i] = coeffNeg[i];
413                joySticksCalibration_[0].zeroStates[i]    = zero[i];
414            }
415        }
416    }
417
418
419    // ############################################################
420    // #####                    Destruction                   #####
421    // ##########                                        ##########
422    // ############################################################
423
424    /**
425    @brief
426        Destroys all the created input devices and states.
427    */
428    InputManager::~InputManager()
429    {
430        if (internalState_ != Uninitialised)
431        {
432            try
433            {
434                CCOUT(3) << "Destroying ..." << std::endl;
435
436                // kick all active states 'nicely'
437                for (std::map<int, InputState*>::reverse_iterator rit = activeStates_.rbegin();
438                    rit != activeStates_.rend(); ++rit)
439                {
440                    (*rit).second->onLeave();
441                }
442
443                // Destroy calibrator helper handler and state
444                delete keyDetector_;
445                requestDestroyState("calibrator");
446                // Destroy KeyDetector and state
447                delete calibratorCallbackBuffer_;
448                requestDestroyState("detector");
449                // destroy the empty InputState
450                _destroyState(this->stateEmpty_);
451                // destroy the master input state. This might trigger a memory leak
452                // because the user has forgotten to destroy the KeyBinder or any Handler!
453                delete stateMaster_;
454
455                // destroy all user InputStates
456                while (inputStatesByPriority_.size() > 0)
457                    _destroyState((*inputStatesByPriority_.rbegin()).second);
458
459                // destroy the devices
460                _destroyKeyboard();
461                _destroyMouse();
462                _destroyJoySticks();
463
464                OIS::InputManager::destroyInputSystem(inputSystem_);
465
466                CCOUT(3) << "Destroying done." << std::endl;
467            }
468            catch (OIS::Exception& ex)
469            {
470                CCOUT(1) << "An exception has occured while destroying:\n" << ex.what()
471                         << "This could lead to a possible memory/resource leak!" << std::endl;
472            }
473        }
474        singletonRef_s = 0;
475    }
476
477    /**
478    @brief
479        Destroys the keyboard and sets it to 0.
480    */
481    void InputManager::_destroyKeyboard()
482    {
483        assert(inputSystem_);
484        if (keyboard_)
485            inputSystem_->destroyInputObject(keyboard_);
486        keyboard_ = 0;
487        CCOUT(4) << "Keyboard destroyed." << std::endl;
488    }
489
490    /**
491    @brief
492        Destroys the mouse and sets it to 0.
493    */
494    void InputManager::_destroyMouse()
495    {
496        assert(inputSystem_);
497        if (mouse_)
498            inputSystem_->destroyInputObject(mouse_);
499        mouse_ = 0;
500        CCOUT(4) << "Mouse destroyed." << std::endl;
501    }
502
503    /**
504    @brief
505        Destroys all the joy sticks and resizes the lists to 0.
506    */
507    void InputManager::_destroyJoySticks()
508    {
509        if (joySticksSize_ > 0)
510        {
511            assert(inputSystem_);
512            for (unsigned int i = 0; i < joySticksSize_; i++)
513                if (joySticks_[i] != 0)
514                    inputSystem_->destroyInputObject(joySticks_[i]);
515
516            joySticks_.clear();
517            // don't use _redimensionLists(), might mess with registered handler if
518            // downgrading from 2 to 1 joystick
519            //_redimensionLists();
520            joySticksSize_ = 0;
521        }
522        CCOUT(4) << "Joy sticks destroyed." << std::endl;
523    }
524
525    /**
526    @brief
527        Removes and destroys an InputState.
528    @return
529        True if state was removed immediately, false if postponed.
530    */
531    void InputManager::_destroyState(InputState* state)
532    {
533        assert(state && !(this->internalState_ & Ticking));
534        std::map<int, InputState*>::iterator it = this->activeStates_.find(state->getPriority());
535        if (it != this->activeStates_.end())
536        {
537            this->activeStates_.erase(it);
538            _updateActiveStates();
539        }
540        inputStatesByPriority_.erase(state->getPriority());
541        inputStatesByName_.erase(state->getName());
542        delete state;
543    }
544
545    void InputManager::_clearBuffers()
546    {
547        keysDown_.clear();
548        keyboardModifiers_ = 0;
549        mouseButtonsDown_.clear();
550        for (unsigned int i = 0; i < joySticksSize_; ++i)
551        {
552            joyStickButtonsDown_[i].clear();
553            for (int j = 0; j < 4; ++j)
554            {
555                sliderStates_[i].sliderStates[j].x = 0;
556                sliderStates_[i].sliderStates[j].y = 0;
557                povStates_[i][j] = 0;
558            }
559        }
560    }
561
562
563    // ############################################################
564    // #####                     Reloading                    #####
565    // ##########                                        ##########
566    // ############################################################
567
568    /**
569    @brief
570        Public interface. Only reloads immediately if the call stack doesn't
571        include the tick() method.
572    @param joyStickSupport
573        Whether or not to initialise joy sticks as well.
574    */
575    void InputManager::reloadInputSystem(bool joyStickSupport)
576    {
577        if (internalState_ & Ticking)
578        {
579            // We cannot destroy OIS right now, because reload was probably
580            // caused by a user clicking on a GUI item. The backtrace would then
581            // include an OIS method. So it would be a very bad thing to destroy it..
582            internalState_ |= ReloadRequest;
583            // Misuse of internalState_: We can easily store the joyStickSupport bool.
584            // use Uninitialised as 0 value in order to make use of the overloaded |= operator
585            internalState_ |= joyStickSupport ? JoyStickSupport : Uninitialised;
586        }
587        else if (internalState_ & OISReady)
588        {
589            _reload(joyStickSupport);
590        }
591        else
592        {
593            CCOUT(2) << "Warning: Cannot reload OIS. May not yet be initialised or"
594                     << "joy sticks are currently calibrating." << std::endl;
595        }
596    }
597
598    /**
599    @brief
600        Internal reload method. Destroys the OIS devices and loads them again.
601    */
602    void InputManager::_reload(bool joyStickSupport)
603    {
604        try
605        {
606            CCOUT(3) << "Reloading ..." << std::endl;
607
608            // Save mouse clipping size
609            int mouseWidth  = mouse_->getMouseState().width;
610            int mouseHeight = mouse_->getMouseState().height;
611
612            internalState_ &= ~OISReady;
613
614            // destroy the devices
615            _destroyKeyboard();
616            _destroyMouse();
617            _destroyJoySticks();
618
619            OIS::InputManager::destroyInputSystem(inputSystem_);
620            inputSystem_ = 0;
621
622            // clear all buffers containing input information
623            _clearBuffers();
624
625            initialise(windowHnd_, mouseWidth, mouseHeight, joyStickSupport);
626
627            CCOUT(3) << "Reloading done." << std::endl;
628        }
629        catch (OIS::Exception& ex)
630        {
631            CCOUT(1) << "An exception has occured while reloading:\n" << ex.what() << std::endl;
632        }
633    }
634
635    // ############################################################
636    // #####                  Runtime Methods                 #####
637    // ##########                                        ##########
638    // ############################################################
639
640    /**
641    @brief
642        Updates the InputManager. Tick is called by the Core class.
643    @param dt
644        Delta time
645    */
646    void InputManager::tick(float dt)
647    {
648        if (internalState_ == Uninitialised)
649            return;
650        else if (internalState_ & ReloadRequest)
651        {
652            _reload(internalState_ & JoyStickSupport);
653            internalState_ &= ~ReloadRequest;
654            internalState_ &= ~JoyStickSupport;
655        }
656
657        // check for states to leave
658        for (std::set<InputState*>::reverse_iterator rit = stateLeaveRequests_.rbegin();
659            rit != stateLeaveRequests_.rend(); ++rit)
660        {
661            (*rit)->onLeave();
662            // just to be sure that the state actually is registered
663            assert(inputStatesByName_.find((*rit)->getName()) != inputStatesByName_.end());
664
665            activeStates_.erase((*rit)->getPriority());
666            _updateActiveStates();
667        }
668        stateLeaveRequests_.clear();
669
670        // check for states to enter
671        for (std::set<InputState*>::reverse_iterator rit = stateEnterRequests_.rbegin();
672            rit != stateEnterRequests_.rend(); ++rit)
673        {
674            // just to be sure that the state actually is registered
675            assert(inputStatesByName_.find((*rit)->getName()) != inputStatesByName_.end());
676
677            activeStates_[(*rit)->getPriority()] = (*rit);
678            _updateActiveStates();
679            (*rit)->onEnter();
680        }
681        stateEnterRequests_.clear();
682
683        // check for states to destroy
684        for (std::set<InputState*>::reverse_iterator rit = stateDestroyRequests_.rbegin();
685            rit != stateDestroyRequests_.rend(); ++rit)
686        {
687            _destroyState((*rit));
688        }
689        stateDestroyRequests_.clear();
690
691        // check whether a state has changed its EMPTY_HANDLER situation
692        bool bUpdateRequired = false;
693        for (std::map<int, InputState*>::iterator it = activeStates_.begin(); it != activeStates_.end(); ++it)
694        {
695            if (it->second->handlersChanged())
696            {
697                it->second->resetHandlersChanged();
698                bUpdateRequired = true;
699            }
700        }
701        if (bUpdateRequired)
702            _updateActiveStates();
703
704        // mark that we capture and distribute input
705        internalState_ |= Ticking;
706
707        // Capture all the input. This calls the event handlers in InputManager.
708        if (keyboard_)
709            keyboard_->capture();
710        if (mouse_)
711            mouse_->capture();
712        for (unsigned  int i = 0; i < joySticksSize_; i++)
713            joySticks_[i]->capture();
714
715        if (!bCalibrating_)
716        {
717            // call all the handlers for the held key events
718            for (unsigned int iKey = 0; iKey < keysDown_.size(); iKey++)
719            {
720                KeyEvent kEvt(keysDown_[iKey], keyboardModifiers_);
721                activeStatesTop_[Keyboard]->keyHeld(kEvt);
722                stateMaster_->keyHeld(kEvt);
723            }
724
725            // call all the handlers for the held mouse button events
726            for (unsigned int iButton = 0; iButton < mouseButtonsDown_.size(); iButton++)
727            {
728                activeStatesTop_[Mouse]->mouseButtonHeld(mouseButtonsDown_[iButton]);
729                stateMaster_->mouseButtonHeld(mouseButtonsDown_[iButton]);
730            }
731
732            // call all the handlers for the held joy stick button events
733            for (unsigned int iJoyStick  = 0; iJoyStick < joySticksSize_; iJoyStick++)
734                for (unsigned int iButton   = 0; iButton   < joyStickButtonsDown_[iJoyStick].size(); iButton++)
735                {
736                    activeStatesTop_[JoyStick0 + iJoyStick]
737                        ->joyStickButtonHeld(iJoyStick, joyStickButtonsDown_[iJoyStick][iButton]);
738                    stateMaster_->joyStickButtonHeld(iJoyStick, joyStickButtonsDown_[iJoyStick][iButton]);
739                }
740
741            // tick the handlers for each active handler
742            for (unsigned int i = 0; i < devicesNum_; ++i)
743            {
744                activeStatesTop_[i]->tickInput(dt, i);
745                if (stateMaster_->isInputDeviceEnabled(i))
746                    stateMaster_->tickInput(dt, i);
747            }
748
749            // tick the handler with a general tick afterwards
750            for (unsigned int i = 0; i < activeStatesTicked_.size(); ++i)
751                activeStatesTicked_[i]->tickInput(dt);
752            stateMaster_->tickInput(dt);
753        }
754
755        internalState_ &= ~Ticking;
756    }
757
758    /**
759    @brief
760        Updates the currently active states (according to activeStates_) for each device.
761        Also, a list of all active states (no duplicates!) is compiled for the general tick.
762    */
763    void InputManager::_updateActiveStates()
764    {
765        for (std::map<int, InputState*>::const_iterator it = activeStates_.begin(); it != activeStates_.end(); ++it)
766            for (unsigned int i = 0; i < devicesNum_; ++i)
767                if (it->second->isInputDeviceEnabled(i))
768                    activeStatesTop_[i] = it->second;
769
770        // update tickables (every state will only appear once)
771        // Using a std::set to avoid duplicates
772        std::set<InputState*> tempSet;
773        for (unsigned int i = 0; i < devicesNum_; ++i)
774            tempSet.insert(activeStatesTop_[i]);
775
776        // copy the content of the set back to the actual vector
777        activeStatesTicked_.clear();
778        for (std::set<InputState*>::const_iterator it = tempSet.begin();it != tempSet.end(); ++it)
779            activeStatesTicked_.push_back(*it);
780
781        this->mouseButtonsDown_.clear();
782    }
783
784    /**
785    @brief
786        Processes the accumultated data for the joy stick calibration.
787    */
788    void InputManager::_completeCalibration()
789    {
790        for (unsigned int i = 0; i < 24; i++)
791        {
792            // positive coefficient
793            if (marginalsMax_[i] == INT_MIN)
794                marginalsMax_[i] =  32767;
795            // coefficients
796            if (marginalsMax_[i] - joySticksCalibration_[0].zeroStates[i])
797            {
798                joySticksCalibration_[0].positiveCoeff[i]
799                    = 1.0f/(marginalsMax_[i] - joySticksCalibration_[0].zeroStates[i]);
800            }
801            else
802                joySticksCalibration_[0].positiveCoeff[i] =  1.0f;
803
804            // config value
805            ConfigValueContainer* cont = getIdentifier()->getConfigValueContainer("CoeffPos");
806            assert(cont);
807            cont->set(i, joySticksCalibration_[0].positiveCoeff[i]);
808
809            // negative coefficient
810            if (marginalsMin_[i] == INT_MAX)
811                marginalsMin_[i] = -32768;
812            // coefficients
813            if (marginalsMin_[i] - joySticksCalibration_[0].zeroStates[i])
814            {
815                joySticksCalibration_[0].negativeCoeff[i] = -1.0f
816                    / (marginalsMin_[i] - joySticksCalibration_[0].zeroStates[i]);
817            }
818            else
819                joySticksCalibration_[0].negativeCoeff[i] =  1.0f;
820            // config value
821            cont = getIdentifier()->getConfigValueContainer("CoeffNeg");
822            assert(cont);
823            cont->set(i, joySticksCalibration_[0].negativeCoeff[i]);
824
825            // zero states
826            if (i < 8)
827            {
828                if (!(i & 1))
829                    joySticksCalibration_[0].zeroStates[i] = joySticks_[0]->getJoyStickState().mSliders[i/2].abX;
830                else
831                    joySticksCalibration_[0].zeroStates[i] = joySticks_[0]->getJoyStickState().mSliders[i/2].abY;
832            }
833            else
834            {
835                if (i - 8 < joySticks_[0]->getJoyStickState().mAxes.size())
836                    joySticksCalibration_[0].zeroStates[i] = joySticks_[0]->getJoyStickState().mAxes[i - 8].abs;
837                else
838                    joySticksCalibration_[0].zeroStates[i] = 0;
839            }
840            // config value
841            cont = getIdentifier()->getConfigValueContainer("Zero");
842            assert(cont);
843            cont->set(i, joySticksCalibration_[0].zeroStates[i]);
844        }
845
846        // restore old input state
847        requestLeaveState("calibrator");
848        bCalibrating_ = false;
849    }
850
851    void InputManager::clearBuffers()
852    {
853        this->keysDown_.clear();
854        this->mouseButtonsDown_.clear();
855        for (unsigned int i = 0; i < this->joySticksSize_; ++i)
856            this->joyStickButtonsDown_[i].clear();
857    }
858
859
860    // ############################################################
861    // #####                    OIS events                    #####
862    // ##########                                        ##########
863    // ############################################################
864
865    // ###### Key Events ######
866
867    /**
868    @brief
869        Event handler for the keyPressed Event.
870    @param e
871        Event information
872    */
873    bool InputManager::keyPressed(const OIS::KeyEvent &e)
874    {
875        // check whether the key already is in the list (can happen when focus was lost)
876        unsigned int iKey = 0;
877        while (iKey < keysDown_.size() && keysDown_[iKey].key != (KeyCode::Enum)e.key)
878            iKey++;
879        if (iKey == keysDown_.size())
880            keysDown_.push_back(Key(e));
881        else
882        {
883            // This happens when XAutoRepeat is set under linux. The KeyPressed event gets then sent
884            // continuously.
885            return true;
886        }
887
888        // update modifiers
889        if(e.key == OIS::KC_RMENU    || e.key == OIS::KC_LMENU)
890            keyboardModifiers_ |= KeyboardModifier::Alt;   // alt key
891        if(e.key == OIS::KC_RCONTROL || e.key == OIS::KC_LCONTROL)
892            keyboardModifiers_ |= KeyboardModifier::Ctrl;  // ctrl key
893        if(e.key == OIS::KC_RSHIFT   || e.key == OIS::KC_LSHIFT)
894            keyboardModifiers_ |= KeyboardModifier::Shift; // shift key
895
896        KeyEvent kEvt(e, keyboardModifiers_);
897        activeStatesTop_[Keyboard]->keyPressed(kEvt);
898        stateMaster_->keyPressed(kEvt);
899
900        return true;
901    }
902
903    /**
904    @brief
905        Event handler for the keyReleased Event.
906    @param e
907        Event information
908    */
909    bool InputManager::keyReleased(const OIS::KeyEvent &e)
910    {
911        // remove the key from the keysDown_ list
912        for (unsigned int iKey = 0; iKey < keysDown_.size(); iKey++)
913        {
914            if (keysDown_[iKey].key == (KeyCode::Enum)e.key)
915            {
916                keysDown_.erase(keysDown_.begin() + iKey);
917                break;
918            }
919        }
920
921        // update modifiers
922        if(e.key == OIS::KC_RMENU    || e.key == OIS::KC_LMENU)
923            keyboardModifiers_ &= ~KeyboardModifier::Alt;   // alt key
924        if(e.key == OIS::KC_RCONTROL || e.key == OIS::KC_LCONTROL)
925            keyboardModifiers_ &= ~KeyboardModifier::Ctrl;  // ctrl key
926        if(e.key == OIS::KC_RSHIFT   || e.key == OIS::KC_LSHIFT)
927            keyboardModifiers_ &= ~KeyboardModifier::Shift; // shift key
928
929        KeyEvent kEvt(e, keyboardModifiers_);
930        activeStatesTop_[Keyboard]->keyReleased(kEvt);
931        stateMaster_->keyReleased(kEvt);
932
933        return true;
934    }
935
936
937    // ###### Mouse Events ######
938
939    /**
940    @brief
941        Event handler for the mouseMoved Event.
942    @param e
943        Event information
944    */
945    bool InputManager::mouseMoved(const OIS::MouseEvent &e)
946    {
947        // check for actual moved event
948        if (e.state.X.rel != 0 || e.state.Y.rel != 0)
949        {
950            IntVector2 abs(e.state.X.abs, e.state.Y.abs);
951            IntVector2 rel(e.state.X.rel, e.state.Y.rel);
952            IntVector2 clippingSize(e.state.width, e.state.height);
953            activeStatesTop_[Mouse]->mouseMoved(abs, rel, clippingSize);
954            stateMaster_->mouseMoved(abs, rel, clippingSize);
955        }
956
957        // check for mouse scrolled event
958        if (e.state.Z.rel != 0)
959        {
960            activeStatesTop_[Mouse]->mouseScrolled(e.state.Z.abs, e.state.Z.rel);
961            stateMaster_->mouseScrolled(e.state.Z.abs, e.state.Z.rel);
962        }
963
964        return true;
965    }
966
967    /**
968    @brief
969        Event handler for the mousePressed Event.
970    @param e
971        Event information
972    @param id
973        The ID of the mouse button
974    */
975    bool InputManager::mousePressed(const OIS::MouseEvent &e, OIS::MouseButtonID id)
976    {
977        // check whether the button already is in the list (can happen when focus was lost)
978        unsigned int iButton = 0;
979        while (iButton < mouseButtonsDown_.size() && mouseButtonsDown_[iButton] != (MouseButton::Enum)id)
980            iButton++;
981        if (iButton == mouseButtonsDown_.size())
982            mouseButtonsDown_.push_back((MouseButton::Enum)id);
983
984        activeStatesTop_[Mouse]->mouseButtonPressed((MouseButton::Enum)id);
985        stateMaster_->mouseButtonPressed((MouseButton::Enum)id);
986
987        return true;
988    }
989
990    /**
991    @brief
992        Event handler for the mouseReleased Event.
993    @param e
994        Event information
995    @param id
996        The ID of the mouse button
997    */
998    bool InputManager::mouseReleased(const OIS::MouseEvent &e, OIS::MouseButtonID id)
999    {
1000        // remove the button from the keysDown_ list
1001        for (unsigned int iButton = 0; iButton < mouseButtonsDown_.size(); iButton++)
1002        {
1003            if (mouseButtonsDown_[iButton] == (MouseButton::Enum)id)
1004            {
1005                mouseButtonsDown_.erase(mouseButtonsDown_.begin() + iButton);
1006                break;
1007            }
1008        }
1009
1010        activeStatesTop_[Mouse]->mouseButtonReleased((MouseButton::Enum)id);
1011        stateMaster_->mouseButtonReleased((MouseButton::Enum)id);
1012
1013        return true;
1014    }
1015
1016
1017    // ###### Joy Stick Events ######
1018
1019    /**
1020    @brief
1021        Returns the joy stick ID (orxonox) according to a OIS::JoyStickEvent
1022    */
1023    inline unsigned int InputManager::_getJoystick(const OIS::JoyStickEvent& arg)
1024    {
1025        // use the device to identify which one called the method
1026        OIS::JoyStick* joyStick = (OIS::JoyStick*)arg.device;
1027        unsigned int iJoyStick = 0;
1028        while (joySticks_[iJoyStick] != joyStick)
1029            iJoyStick++;
1030        // assert: Unknown joystick fired an event.
1031        assert(iJoyStick != joySticksSize_);
1032        return iJoyStick;
1033    }
1034
1035    bool InputManager::buttonPressed(const OIS::JoyStickEvent &arg, int button)
1036    {
1037        unsigned int iJoyStick = _getJoystick(arg);
1038
1039        // check whether the button already is in the list (can happen when focus was lost)
1040        std::vector<JoyStickButton::Enum>& buttonsDown = joyStickButtonsDown_[iJoyStick];
1041        unsigned int iButton = 0;
1042        while (iButton < buttonsDown.size() && buttonsDown[iButton] != button)
1043            iButton++;
1044        if (iButton == buttonsDown.size())
1045            buttonsDown.push_back((JoyStickButton::Enum)button);
1046
1047        activeStatesTop_[2 + iJoyStick]->joyStickButtonPressed(iJoyStick, (JoyStickButton::Enum)button);
1048        stateMaster_->joyStickButtonPressed(iJoyStick, (JoyStickButton::Enum)button);
1049
1050        return true;
1051    }
1052
1053    bool InputManager::buttonReleased(const OIS::JoyStickEvent &arg, int button)
1054    {
1055        unsigned int iJoyStick = _getJoystick(arg);
1056
1057        // remove the button from the joyStickButtonsDown_ list
1058        std::vector<JoyStickButton::Enum>& buttonsDown = joyStickButtonsDown_[iJoyStick];
1059        for (unsigned int iButton = 0; iButton < buttonsDown.size(); iButton++)
1060        {
1061            if (buttonsDown[iButton] == button)
1062            {
1063                buttonsDown.erase(buttonsDown.begin() + iButton);
1064                break;
1065            }
1066        }
1067
1068        activeStatesTop_[2 + iJoyStick]->joyStickButtonReleased(iJoyStick, (JoyStickButton::Enum)button);
1069        stateMaster_->joyStickButtonReleased(iJoyStick, (JoyStickButton::Enum)button);
1070
1071        return true;
1072    }
1073
1074    /**
1075    @brief
1076        Calls the states for a particular axis with our enumeration.
1077        Used by OIS sliders and OIS axes.
1078    */
1079    void InputManager::_fireAxis(unsigned int iJoyStick, int axis, int value)
1080    {
1081        if (bCalibrating_)
1082        {
1083            if (value > marginalsMax_[axis])
1084                marginalsMax_[axis] = value;
1085            if (value < marginalsMin_[axis])
1086                marginalsMin_[axis] = value;
1087        }
1088        else
1089        {
1090            float fValue = value - joySticksCalibration_[iJoyStick].zeroStates[axis];
1091            if (fValue > 0.0f)
1092                fValue *= joySticksCalibration_[iJoyStick].positiveCoeff[axis];
1093            else
1094                fValue *= joySticksCalibration_[iJoyStick].negativeCoeff[axis];
1095
1096            activeStatesTop_[2 + iJoyStick]->joyStickAxisMoved(iJoyStick, axis, fValue);
1097            stateMaster_->joyStickAxisMoved(iJoyStick, axis, fValue);
1098        }
1099    }
1100
1101    bool InputManager::axisMoved(const OIS::JoyStickEvent &arg, int axis)
1102    {
1103        unsigned int iJoyStick = _getJoystick(arg);
1104
1105        // keep in mind that the first 8 axes are reserved for the sliders
1106        _fireAxis(iJoyStick, axis + 8, arg.state.mAxes[axis].abs);
1107
1108        return true;
1109    }
1110
1111    bool InputManager::sliderMoved(const OIS::JoyStickEvent &arg, int id)
1112    {
1113        unsigned int iJoyStick = _getJoystick(arg);
1114
1115        if (sliderStates_[iJoyStick].sliderStates[id].x != arg.state.mSliders[id].abX)
1116            _fireAxis(iJoyStick, id * 2, arg.state.mSliders[id].abX);
1117        else if (sliderStates_[iJoyStick].sliderStates[id].y != arg.state.mSliders[id].abY)
1118            _fireAxis(iJoyStick, id * 2 + 1, arg.state.mSliders[id].abY);
1119
1120        return true;
1121    }
1122
1123    bool InputManager::povMoved(const OIS::JoyStickEvent &arg, int id)
1124    {
1125        unsigned int iJoyStick = _getJoystick(arg);
1126
1127        // translate the POV into 8 simple buttons
1128
1129        int lastState = povStates_[iJoyStick][id];
1130        if (lastState & OIS::Pov::North)
1131            buttonReleased(arg, 32 + id * 4 + 0);
1132        if (lastState & OIS::Pov::South)
1133            buttonReleased(arg, 32 + id * 4 + 1);
1134        if (lastState & OIS::Pov::East)
1135            buttonReleased(arg, 32 + id * 4 + 2);
1136        if (lastState & OIS::Pov::West)
1137            buttonReleased(arg, 32 + id * 4 + 3);
1138
1139        povStates_[iJoyStick].povStates[id] = arg.state.mPOV[id].direction;
1140
1141        int currentState = povStates_[iJoyStick][id];
1142        if (currentState & OIS::Pov::North)
1143            buttonPressed(arg, 32 + id * 4 + 0);
1144        if (currentState & OIS::Pov::South)
1145            buttonPressed(arg, 32 + id * 4 + 1);
1146        if (currentState & OIS::Pov::East)
1147            buttonPressed(arg, 32 + id * 4 + 2);
1148        if (currentState & OIS::Pov::West)
1149            buttonPressed(arg, 32 + id * 4 + 3);
1150
1151        return true;
1152    }
1153
1154
1155    // ############################################################
1156    // #####         Other Public Interface Methods           #####
1157    // ##########                                        ##########
1158    // ############################################################
1159
1160    /**
1161    @brief
1162        Adjusts the mouse window metrics.
1163        This method has to be called every time the size of the window changes.
1164    @param width
1165        The new width of the render window
1166    @param^height
1167        The new height of the render window
1168    */
1169    void InputManager::setWindowExtents(const int width, const int height)
1170    {
1171        if (mouse_)
1172        {
1173            // Set mouse region (if window resizes, we should alter this to reflect as well)
1174            mouse_->getMouseState().width  = width;
1175            mouse_->getMouseState().height = height;
1176        }
1177    }
1178
1179
1180    // ###### InputStates ######
1181
1182    /**
1183    @brief
1184        Adds a new key handler.
1185    @param handler
1186        Pointer to the handler object.
1187    @param name
1188        Unique name of the handler.
1189    @param priority
1190        Unique integer number. Higher means more prioritised.
1191    @return
1192        True if added, false if name or priority already existed.
1193    */
1194    bool InputManager::_configureInputState(InputState* state, const std::string& name, int priority)
1195    {
1196        if (name == "")
1197            return false;
1198        if (!state)
1199            return false;
1200        if (inputStatesByName_.find(name) == inputStatesByName_.end())
1201        {
1202            if (inputStatesByPriority_.find(priority)
1203                == inputStatesByPriority_.end())
1204            {
1205                inputStatesByName_[name] = state;
1206                inputStatesByPriority_[priority] = state;
1207                state->setNumOfJoySticks(numberOfJoySticks());
1208                state->setName(name);
1209                state->setPriority(priority);
1210                return true;
1211            }
1212            else
1213            {
1214                COUT(2) << "Warning: Could not add an InputState with the same priority '"
1215                    << priority << "'." << std::endl;
1216                return false;
1217            }
1218        }
1219        else
1220        {
1221            COUT(2) << "Warning: Could not add an InputState with the same name '" << name << "'." << std::endl;
1222            return false;
1223        }
1224    }
1225
1226    /**
1227    @brief
1228        Removes and destroys an input state internally.
1229    @param name
1230        Name of the handler.
1231    @return
1232        True if removal was successful, false if name was not found.
1233    @remarks
1234        You can't remove the internal states "empty", "calibrator" and "detector".
1235        The removal process is being postponed if InputManager::tick() is currently running.
1236    */
1237    bool InputManager::requestDestroyState(const std::string& name)
1238    {
1239        if (name == "empty")
1240        {
1241            COUT(2) << "InputManager: Removing the empty state is not allowed!" << std::endl;
1242            return false;
1243        }
1244        std::map<std::string, InputState*>::iterator it = inputStatesByName_.find(name);
1245        if (it != inputStatesByName_.end())
1246        {
1247            if (activeStates_.find(it->second->getPriority()) != activeStates_.end())
1248            {
1249                // The state is still active. We have to postpone
1250                stateLeaveRequests_.insert(it->second);
1251                stateDestroyRequests_.insert(it->second);
1252            }
1253            else if (this->internalState_ & Ticking)
1254            {
1255                // cannot remove state while ticking
1256                stateDestroyRequests_.insert(it->second);
1257            }
1258            else
1259                _destroyState(it->second);
1260
1261            return true;
1262        }
1263        return false;
1264    }
1265
1266    /**
1267    @brief
1268        Returns the pointer to the requested InputState.
1269    @param name
1270        Unique name of the state.
1271    @return
1272        Pointer to the instance, 0 if name was not found.
1273    */
1274    InputState* InputManager::getState(const std::string& name)
1275    {
1276        std::map<std::string, InputState*>::iterator it = inputStatesByName_.find(name);
1277        if (it != inputStatesByName_.end())
1278            return it->second;
1279        else
1280            return 0;
1281    }
1282
1283    /**
1284    @brief
1285        Returns the current input state (there might be others active too!)
1286    @return
1287        The current highest prioritised active input state.
1288    */
1289    InputState* InputManager::getCurrentState()
1290    {
1291        return (*activeStates_.rbegin()).second;
1292    }
1293
1294    /**
1295    @brief
1296        Activates a specific input state.
1297        It might not be really activated if the priority is too low!
1298    @param name
1299        Unique name of the state.
1300    @return
1301        False if name was not found, true otherwise.
1302    */
1303    bool InputManager::requestEnterState(const std::string& name)
1304    {
1305        // get pointer from the map with all stored handlers
1306        std::map<std::string, InputState*>::const_iterator it = inputStatesByName_.find(name);
1307        if (it != inputStatesByName_.end())
1308        {
1309            // exists
1310            if (activeStates_.find(it->second->getPriority()) == activeStates_.end())
1311            {
1312                // not active
1313                if (stateDestroyRequests_.find(it->second) == stateDestroyRequests_.end())
1314                {
1315                    // not scheduled for destruction
1316                    // set prevents a state being added multiple times
1317                    stateEnterRequests_.insert(it->second);
1318                    return true;
1319                }
1320            }
1321        }
1322        return false;
1323    }
1324
1325    /**
1326    @brief
1327        Deactivates a specific input state.
1328    @param name
1329        Unique name of the state.
1330    @return
1331        False if name was not found, true otherwise.
1332    */
1333    bool InputManager::requestLeaveState(const std::string& name)
1334    {
1335        // get pointer from the map with all stored handlers
1336        std::map<std::string, InputState*>::const_iterator it = inputStatesByName_.find(name);
1337        if (it != inputStatesByName_.end())
1338        {
1339            // exists
1340            if (activeStates_.find(it->second->getPriority()) != activeStates_.end())
1341            {
1342                // active
1343                stateLeaveRequests_.insert(it->second);
1344                return true;
1345            }
1346        }
1347        return false;
1348    }
1349
1350
1351    // ############################################################
1352    // #####                Console Commands                  #####
1353    // ##########                                        ##########
1354    // ############################################################
1355
1356    /**
1357    @brief
1358        Method for easily storing a string with the command executor. It is used by the
1359        KeyDetector to get assign commands. The KeyDetector simply executes
1360        the command 'storeKeyStroke myName' for each button/axis.
1361    @remarks
1362        This is only a temporary hack until we thourouhgly support multiple KeyBinders.
1363    @param name
1364        The name of the button/axis.
1365    */
1366    void InputManager::storeKeyStroke(const std::string& name)
1367    {
1368        getInstance().requestLeaveState("detector");
1369        COUT(0) << "Binding string \"" << bindingCommmandString_s << "\" on key '" << name << "'" << std::endl;
1370        CommandExecutor::execute("config KeyBinder " + name + " " + bindingCommmandString_s, false);
1371    }
1372
1373    /**
1374    @brief
1375        Assigns a command string to a key/button/axis. The name is determined via KeyDetector
1376        and InputManager::storeKeyStroke(.).
1377    @param command
1378        Command string that can be executed by the CommandExecutor
1379    */
1380    void InputManager::keyBind(const std::string& command)
1381    {
1382        bindingCommmandString_s = command;
1383        getInstance().requestEnterState("detector");
1384        COUT(0) << "Press any button/key or move a mouse/joystick axis" << std::endl;
1385    }
1386
1387    /**
1388    @brief
1389        Starts joy stick calibration.
1390    */
1391    void InputManager::calibrate()
1392    {
1393        getInstance().bCalibrating_ = true;
1394        getInstance().requestEnterState("calibrator");
1395    }
1396
1397    /**
1398    @brief
1399        Reloads the input system
1400    */
1401    void InputManager::reload(bool joyStickSupport)
1402    {
1403        getInstance().reloadInputSystem(joyStickSupport);
1404    }
1405}
Note: See TracBrowser for help on using the repository browser.