Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Fixed two issues with input:

  • Buffer gets cleared now when the window focus changes
  • Added a configValue in the InGameConsole:

Until now the input was always transparent to the level when activating the console (exception keyboard input of course)
bHidesAllInput_ can change that setting (configured in orxonox.ini)

@Oli: Sorry, couldn't apply the patch in the network branch because of conflicts (I have already made some changes to the InputManager in the trunk)

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