Sirikata
libogre/include/sirikata/ogre/input/InputDevice.hpp
Go to the documentation of this file.
00001 /*  Sirikata Input Plugin -- plugins/input
00002  *  InputDevice.hpp
00003  *
00004  *  Copyright (c) 2009, Patrick Reiter Horn
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions are
00009  *  met:
00010  *  * Redistributions of source code must retain the above copyright
00011  *    notice, this list of conditions and the following disclaimer.
00012  *  * Redistributions in binary form must reproduce the above copyright
00013  *    notice, this list of conditions and the following disclaimer in
00014  *    the documentation and/or other materials provided with the
00015  *    distribution.
00016  *  * Neither the name of Sirikata nor the names of its contributors may
00017  *    be used to endorse or promote products derived from this software
00018  *    without specific prior written permission.
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
00021  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
00022  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00023  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
00024  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00025  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00026  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00027  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00028  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00029  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00030  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00031  */
00032 
00033 #ifndef SIRIKATA_INPUT_InputDevice_HPP__
00034 #define SIRIKATA_INPUT_InputDevice_HPP__
00035 
00036 #include <sirikata/ogre/Platform.hpp>
00037 #include <sirikata/core/util/Time.hpp>
00038 #include <sirikata/core/util/Timer.hpp>
00039 
00040 namespace Sirikata {
00041 namespace Input {
00042 
00043 /*
00044 
00045 ==== AVATAR IS FOCUSED ====
00046 
00047 Walk Forward/Backward: <Axis Type>
00048     Mouse X [Edit] "M/0/x"
00049     Mouse Y [Edit] "M/0/y"
00050     Joystick Axis 0 [Edit] "J/0/0"
00051     Joystick Axis 1 [Edit] "J/0/1"
00052     Joystick Axis 2 [Edit] "J/0/2"
00053     Tablet/Touchscreen [Edit] "MA/0/x"
00054     Up/Down arrow keys [Edit] "KA/0"
00055     [Keyboard/Hatswitch]
00056     [New Tablet Mode]
00057 Walk Left/Right: <A/D>
00058 Turn Left/Right: <Mouse X>
00059 Turn Up/Down: <W/S>
00060 
00061 Jump: [Space]
00062 Select: [Type or pick key]
00063     Mouse up [Edit]
00064     [Make new analog Hatswitch / key from axis.]
00065 
00066 
00067 ==== SCENE HAS FOCUS (or null) ====
00068 
00069          Absolute pointer 0: [Mouse 1 Cursor]
00070          Absolute pointer 1: [Touchpad]
00071          Absolute pointer 2: [Joystick Axis 1+2]
00072          Absolute pointer 3: [Keyboard Axis "Up/Down arrow keys"/"Left/Right arrow keys"]
00073          Return from UI: [ESCAPE]
00074 
00075          Key bindings:
00076 [Not implemented, but you can bind buttons to individual keys if you want]
00077 
00078 ==== FLASH GAME IS FOCUSED ====
00079 Choose two analog inputs and one keyboard/joystick->key bindings
00080 
00081 */
00082 
00083 struct AxisValue {
00084     float value;
00085     float get01() const {
00086         return (value + 1.0f)/2.0f;
00087     }
00088     float getCentered() const {
00089         return value;
00090     }
00091     static AxisValue fromCentered(float val) {
00092         AxisValue ret = {val};
00093         return ret;
00094     }
00095     static AxisValue from01(float val) {
00096         AxisValue ret = {(val-0.5f)*2.0f};
00097         return ret;
00098     }
00099     static AxisValue null() {
00100         return fromCentered(0.0f);
00101     }
00102 
00103     bool isNegative() const {
00104         return value < 0;
00105     }
00106     bool isPositive() const {
00107         return value > 0;
00108     }
00109 
00110     void clip() {
00111         if (value > 1.0) {
00112             value = 1.0;
00113         }
00114         if (value < -1.0) {
00115             value = -1.0;
00116         }
00117     }
00118     bool operator == (const AxisValue &other) const {
00119         return value == other.value;
00120     }
00121     AxisValue operator - () const {
00122         return fromCentered(-getCentered());
00123     }
00124     bool operator != (const AxisValue &other) const {
00125         return value != other.value;
00126     }
00127 
00128     friend std::ostream &operator <<(std::ostream &os, const AxisValue &val) {
00129         return os << (int)(100*val.getCentered()) << '%';
00130     }
00131 };
00132 
00133 class InputManager;
00134 
00135 class InputDevice;
00136 typedef std::tr1::shared_ptr<InputDevice> InputDevicePtr;
00137 typedef std::tr1::weak_ptr<InputDevice> InputDeviceWPtr;
00138 
00139 class PointerDevice;
00140 typedef std::tr1::shared_ptr<PointerDevice> PointerDevicePtr;
00141 
00142 /* SDL Defines these on some platforms */
00143 #ifdef MOD_SHIFT
00144 #undef MOD_SHIFT
00145 #endif
00146 #ifdef MOD_CTRL
00147 #undef MOD_CTRL
00148 #endif
00149 #ifdef MOD_GUI
00150 #undef MOD_GUI
00151 #endif
00152 #ifdef MOD_ALT
00153 #undef MOD_ALT
00154 #endif
00155 
00156 typedef uint32 Modifier;
00157 enum KeyboardModifiers {
00158     MOD_NONE  = 0,
00159     MOD_SHIFT = 1,
00160     MOD_CTRL  = 2,
00161     MOD_ALT   = 4,
00162     MOD_GUI   = 8
00163 };
00164 enum PointerModifiers {
00165     //POINTER_STYLUS = 0, // default
00166     POINTER_ERASER = (1<<0),
00167     POINTER_CURSOR = (1<<1)
00168 };
00169 
00170 enum Axes {
00171     AXIS_CURSORX,
00172     AXIS_CURSORY,
00173     AXIS_RELX,
00174     AXIS_RELY,
00175     NUM_POINTER_AXES
00176 };
00177 
00178 typedef uint32 AxisIndex;
00179 
00180 typedef int32 MouseButton;
00181 
00182 typedef int32 KeyButton;
00183 
00184 enum KeyEvent {
00185     KEY_PRESSED,
00186     KEY_DOWN,
00187     KEY_RELEASED,
00188     KEY_REPEATED
00189 };
00190 
00199 enum MouseDragType {
00200     DRAG_DEADBAND, // Have not yet started an actual drag
00201     DRAG_START,
00202     DRAG_DRAG,
00203     DRAG_END
00204 };
00205 
00206 enum WindowEventType {
00207     WindowShown,
00208     WindowHidden,
00209     WindowExposed,
00210     WindowMoved,
00211     WindowResized,
00212     WindowMinimized,
00213     WindowMaximized,
00214     WindowRestored,
00215     WindowMouseEnter,
00216     WindowMouseLeave,
00217     WindowFocusGained,
00218     WindowFocusLost,
00219     WindowQuit
00220 };
00221 
00222 class SIRIKATA_OGRE_EXPORT InputDevice {
00223 protected:
00224     std::string mName;
00225     InputManager *mManager;
00226 
00227     struct ButtonState {
00228         Modifier mod;
00229         Time initialTime;
00230         Time lastTime;
00231     };
00232     typedef std::tr1::unordered_map<unsigned int, ButtonState> ButtonSet;
00233     typedef std::vector<AxisValue> AxisVector;
00234 
00235     ButtonSet buttonState;
00236     AxisVector axisState;
00237 
00238     bool changeButton(unsigned int button, bool newState, Modifier &mod);
00239     bool changeAxis(unsigned int axis, AxisValue newValue);
00240 
00241 public:
00242     const std::string &getName() const {
00243         return mName;
00244     }
00245     void setName(const std::string &newName) {
00246         mName = newName;
00247     }
00248     InputManager *getInputManager() {
00249         return mManager;
00250     }
00251     void setInputManager(InputManager *man) {
00252         mManager = man;
00253     }
00254 
00255     InputDevice() : mManager(0) {}
00256     virtual ~InputDevice() {}
00257 
00258     virtual std::string getButtonName(unsigned int button) const = 0;
00259     virtual int getNumButtons() const = 0;
00260 
00261     virtual std::string getAxisName(unsigned int axis) const = 0;
00262     virtual unsigned int getNumAxes() const = 0;
00263 
00264     virtual bool isKeyboard() { return false; }
00265 
00266     bool fireButton(const InputDevicePtr &thisptr,
00267                     unsigned int button, bool newState, Modifier mod = 0);
00268     bool fireAxis(const InputDevicePtr &thisptr,
00269                   unsigned int axis, AxisValue newState);
00270 
00271     inline AxisValue getAxis(unsigned int axis) const {
00272         if (axisState.size() <= axis) {
00273             return AxisValue::null();
00274         }
00275         return axisState[axis];
00276     }
00277     inline bool getButton(unsigned int button, Modifier mod) const {
00278         ButtonSet::const_iterator iter = buttonState.find(button);
00279         if (iter != buttonState.end()) {
00280             return (*iter).second.mod == mod;
00281         } else {
00282             return false;
00283         }
00284     }
00285     inline const Modifier *getButton(unsigned int button) const {
00286         ButtonSet::const_iterator iter = buttonState.find(button);
00287         if (iter != buttonState.end()) {
00288             return &((*iter).second.mod);
00289         } else {
00290             return NULL;
00291         }
00292     }
00293 };
00294 
00295 
00296 class SIRIKATA_OGRE_EXPORT PointerDevice : public InputDevice {
00297     struct DragInfo {
00298         int mButton;
00299         bool mIsDragging;
00300         float mDragStartX;
00301         float mDragStartY;
00302         float mDragX;
00303         float mDragY;
00304         float mOffsetX;
00305         float mOffsetY;
00306     };
00307     typedef std::list<DragInfo> DragMap;
00308     DragMap mDragInfo;
00309 protected:
00310     float mDeadband;
00311     unsigned int mRelativeMode;
00312 
00313     virtual void setRelativeMode(bool enabled) = 0;
00314 
00315 public:
00316     PointerDevice() : mDeadband(0.0), mRelativeMode(0) {
00317     }
00318     void setDragDeadband(float deadband) {
00319         mDeadband = deadband;
00320     }
00321 
00322     void pushRelativeMode() {
00323         if (mRelativeMode++ == 0) {
00324             setRelativeMode(true);
00325         }
00326     }
00327 
00328     void popRelativeMode() {
00329         if (mRelativeMode > 0) {
00330             if (--mRelativeMode == 0) {
00331                 setRelativeMode(false);
00332             }
00333         }
00334     }
00335     bool getRelativeMode() const {
00336         return mRelativeMode ? true : false;
00337     }
00338 
00339     void firePointerMotion(const PointerDevicePtr &thisptr,
00340                     float xPixel,
00341                     float yPixel,
00342                     int cursorType,
00343                     int pressure, int pressmin, int pressmax);
00344     void firePointerClick(const PointerDevicePtr &thisptr,
00345                     float xPixel,
00346                     float yPixel,
00347                     int cursor,
00348                     int button,
00349                     bool state);
00350 };
00351 
00352 }
00353 }
00354 
00355 #endif