Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/core/input/InputDevice.h

Last change on this file was 11071, checked in by landauf, 9 years ago

merged branch cpp11_v3 back to trunk

  • Property svn:eol-style set to native
File size: 9.4 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Reto Grieder
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29/**
30@file
31@brief
32    Implementation of InputDevice and InputDeviceTemplated
33*/
34
35#ifndef _InputDevice_H__
36#define _InputDevice_H__
37
38#include "InputPrereqs.h"
39
40#include <vector>
41#include <ois/OISInputManager.h>
42#include <ois/OISException.h>
43
44#include "util/Clock.h"
45#include "util/Output.h"
46#include "util/Exception.h"
47#include "InputState.h"
48
49namespace orxonox
50{
51    /**
52    @brief
53        Abstract base class for all input devices (mouse, keyboard and joy sticks).
54
55        It provides common virtual functions to be used by the InputManager.
56    */
57    class InputDevice
58    {
59    public:
60        //! Only resets the members
61        InputDevice(unsigned int id) : bCalibrating_(false), deviceID_(id) { }
62        virtual ~InputDevice() = default;
63        //! Returns the device class (derived) name as string
64        virtual std::string getClassName() const = 0;
65        //! Updates the device which should in turn distribute events
66        virtual void update(const Clock& time) = 0;
67        //! Clear all button related buffers
68        virtual void clearBuffers() = 0;
69
70        //! Start calibrating (only useful for joy sticks)
71        void startCalibration()
72        {
73            bCalibrating_ = true;
74            this->calibrationStarted();
75        }
76
77        //! Stop calibrating and evaluate the data (only useful for joy sticks)
78        void stopCalibration()
79        {
80            this->calibrationStopped();
81            bCalibrating_ = false;
82        }
83
84        //! Returns a reference to the internal input state vector. Use with care!
85        std::vector<InputState*>& getStateListRef() { return this->inputStates_; }
86        //! Returns the ID of the device (the same as in InputDeviceEnumerator for mouse and keyboard)
87        unsigned int getDeviceID() const { return this->deviceID_; }
88        //! Tells whether the device is in calibration mode
89        bool isCalibrating() const { return bCalibrating_; }
90
91    protected:
92        //! To be ovrridden by the subclass
93        virtual void calibrationStarted() { }
94        //! To be ovrridden by the subclass
95        virtual void calibrationStopped() { }
96
97        //! List of all input states that receive events from this device
98        std::vector<InputState*> inputStates_;
99
100    private:
101        // non-copyable:
102        InputDevice(const InputDevice&) = delete;
103        InputDevice& operator=(const InputDevice&) = delete;
104
105        bool bCalibrating_;                  //!< Whether the device is in calibration mode
106        const unsigned int deviceID_;        //!< ID of the device (the same as in InputDeviceEnumerator for mouse and keyboard)
107    };
108
109    /**
110    @brief
111        Heavily templated base class for all three input devices.
112
113        The purpose of this class is not to provide an interface but rather
114        to reduce code redundancy. This concerns device creation and destruction
115        as well as common code for button events (press, release, hold).
116
117        In order to derive from this class you have to supply it with a struct
118        as template parameter that contains the necessary type traits.
119    */
120    template <class Traits>
121    class InputDeviceTemplated : public InputDevice
122    {
123        typedef typename Traits::DeviceClass DeviceClass;
124        typedef typename Traits::OISDeviceClass OISDeviceClass;
125        typedef typename Traits::ButtonType ButtonType;
126        typedef typename Traits::ButtonTypeParam ButtonTypeParam;
127        static const OIS::Type OISDeviceValue = Traits::OISDeviceValue;
128
129    public:
130        //! Creates the OIS device
131        InputDeviceTemplated(unsigned int id, OIS::InputManager* oisInputManager)
132            : InputDevice(id)
133            , oisInputManager_(oisInputManager)
134        {
135            oisDevice_ = static_cast<OISDeviceClass*>(oisInputManager_->createInputObject(OISDeviceValue, true));
136            // Note: after the static_cast here, the cast this pointer becomes
137            //       invalid right until the subclass has been constructed!
138            oisDevice_->setEventCallback(static_cast<DeviceClass*>(this));
139            orxout(verbose, context::input) << "Instantiated a " << this->getClassName() << endl;
140        }
141
142        //! Destroys the OIS device
143        virtual ~InputDeviceTemplated()
144        {
145            try
146            {
147                oisInputManager_->destroyInputObject(oisDevice_);
148            }
149            catch (const OIS::Exception& ex)
150            {
151                orxout(internal_error, context::input) << this->getClassName() << " destruction failed: " << ex.eText << '\n'
152                                                       << "Potential resource leak!" << endl;
153            }
154        }
155
156        //! Captures OIS events (which then get distributed to the derived class) and creates the button held events
157        virtual void update(const Clock& time) override
158        {
159            oisDevice_->capture();
160
161            // Call all the states with the held button event
162            for (ButtonType& button : pressedButtons_)
163                for (InputState* state : inputStates_)
164                    state->template buttonEvent<ButtonEvent::THold, typename Traits::ButtonTypeParam>(
165                        this->getDeviceID(), static_cast<DeviceClass*>(this)->getButtonEventArg(button));
166
167            // Call states with device update events
168            for (InputState* state : inputStates_)
169                state->update(time.getDeltaTime(), this->getDeviceID());
170
171            static_cast<DeviceClass*>(this)->updateImpl(time);
172        }
173
174        //! Clears the list of pressed buttons and calls the derived class's method
175        virtual void clearBuffers() override
176        {
177            pressedButtons_.clear();
178            static_cast<DeviceClass*>(this)->clearBuffersImpl();
179        }
180
181        // Returns a pointer to the OIS device
182        OISDeviceClass* getOISDevice()   { return this->oisDevice_; }
183        // Returns the name of the derived class as string
184        virtual std::string getClassName() const override { return DeviceClass::getClassNameImpl(); }
185
186    protected:
187        //! Common code for all button pressed events (updates pressed buttons list and calls the input states)
188        ORX_FORCEINLINE void buttonPressed(ButtonTypeParam button)
189        {
190            // check whether the button already is in the list (can happen when focus was lost)
191            unsigned int iButton = 0;
192            while (iButton < pressedButtons_.size() && pressedButtons_[iButton] != button)
193                iButton++;
194            if (iButton == pressedButtons_.size())
195                pressedButtons_.push_back(button);
196            else
197                return; // Button already pressed
198
199            // Call states
200            for (InputState* state : inputStates_)
201                state->template buttonEvent<ButtonEvent::TPress, typename Traits::ButtonTypeParam>(this->getDeviceID(), static_cast<DeviceClass*>(this)->getButtonEventArg(button));
202        }
203
204        //! Common code for all button released events (updates pressed buttons list and calls the input states)
205        ORX_FORCEINLINE void buttonReleased(ButtonTypeParam button)
206        {
207            // remove the button from the pressedButtons_ list
208            bool found = false;
209            for (unsigned int iButton = 0; iButton < pressedButtons_.size(); iButton++)
210            {
211                if (pressedButtons_[iButton] == button)
212                {
213                    pressedButtons_.erase(pressedButtons_.begin() + iButton);
214                    found = true;
215                    break;
216                }
217            }
218            if (!found)
219                return; // We ignore release strokes when the press was not captured
220
221            // Call states
222            for (InputState* state : inputStates_)
223                state->template buttonEvent<ButtonEvent::TRelease, typename Traits::ButtonTypeParam>(this->getDeviceID(), static_cast<DeviceClass*>(this)->getButtonEventArg(button));
224        }
225
226        //! Managed pointer to the OIS device
227        OISDeviceClass* oisDevice_;
228
229    private:
230        //!< Fallback dummy function for static polymorphism
231        void clearBuffersImpl() { }
232        //!< Fallback dummy function for static polymorphism
233        void updateImpl(const Clock& time) { }
234        //!< Fallback dummy function for static polymorphism
235        ButtonType& getButtonEventArg(ButtonType& button) { return button; }
236
237        std::vector<ButtonType> pressedButtons_; //!< List of all buttons that are currently pressed down
238        OIS::InputManager* oisInputManager_;     //!< Pointer to the OIS InputManager that can create and destroy devices
239    };
240}
241
242#endif /* _InputDevice_H__ */
Note: See TracBrowser for help on using the repository browser.