Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/archive/tutorialHS08/src/core/input/InputManager.cc @ 10233

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

Added a master InputState that is always active (except of course in game state 'ioConsole' when there is no InputManager in the first place)
This is necessary to call the console whenever you like. The state is of 'extended' nature, so it can hold an arbitrary number of Handlers.
The KeyBinder however is not yet configured to manage multiple keybindings.ini —> next job ;)

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