Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/gui/src/core/input/InputManager.cc @ 1672

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