source-device.h

Go to the documentation of this file.
00001 /*
00002  * source-device.h
00003  *
00004  * Copyright (C) 2009-2011  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are 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 the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  *
00031  * Abstraction for a device that can act as the source of gamepad events.  This
00032  * is often a wrapper around a particular USB adapter, for instance
00033  */
00034 
00035 #ifndef GAMEPAD_SOURCE_DEVICE_H__
00036 #define GAMEPAD_SOURCE_DEVICE_H__
00037 
00038 // includes --------------------------------------------------------------------
00039 #include "common/common.h"
00040 #include "threadsafe/smart_ptr.h"
00041 
00042 
00043 namespace gamepad {
00044 
00045 
00046 /// \ingroup gamepad_api
00047 /// \defgroup source_device Source Device Interface
00048 ///
00049 /// This library exists to abstract the gamepad library from physical input
00050 /// sources.  You can use the gamepad library to map any input to a gamepad,
00051 /// so long as you supply an object that supports this interface.
00052 ///
00053 /// See linux_input for an example of a SourceDevice implemented on top of the
00054 /// linux input event model.
00055 /*@{*/
00056 
00057 
00058 /// button state enum.  Note that button state is somewhat tricky!  Many (or
00059 ///     most) source devices will give a full event history, so that every
00060 ///     single button press will be recorded.  But this interface uses polling
00061 ///     rather than events, and therefore multiple button press events could
00062 ///     be compressed into a single "button is down" result.
00063 /// If your game requires full eventing (capture every single button press
00064 ///     regardless of polling interval)
00065 ///     then you probably need to use raw input APIs directly.  For most
00066 ///     uses the eButtonWasPushed/eButtonWasReleased flags should be sufficient.
00067 enum eButton {
00068         // current state
00069         eButtonDown             = 0x01, ///< button is pushed down right now
00070         eButtonUp               = 0x00, ///< button is not pushed down now
00071 
00072         // recent state
00073         eButtonWasPushed        = 0x10, ///< button was pushed at one point
00074         eButtonWasReleased      = 0x20, ///< button was released at one point
00075 
00076         // handy masks
00077         eButtonWasOrIsDown      = 0x11, ///< button was or is pushed down
00078 
00079         // keep this last!
00080         eButtonInvalid          = 0x80
00081 };
00082 
00083 
00084 
00085 /// device state enum.  At the moment these are exclusive values, but other
00086 ///     device flags may be supported in the future, so I recommend performing
00087 ///     bit-check operations rather than checking for equality.
00088 /// "Attached" means that the device is capable of sending events, even if it
00089 ///     isn't physically attached.  For instance, a wireless or
00090 ///     bluetooth device is considered attached if it is communicating
00091 ///     with the local host.  "Detached" means that the device has been
00092 ///     physically disconnected and/or turned off so no more events can
00093 ///     be retrieved.
00094 enum eDeviceState {
00095 
00096         // attached state.  These are exclusive values.
00097         eDevice_Attached = 0x0001, ///< device is properly attached
00098         eDevice_Detached = 0x0002, ///< device is definitely not attached
00099         eDevice_Unknown  = 0x0004, ///< may or may not be attached--common!
00100 
00101         // keep this last
00102         eDevice_Invalid = 0
00103 };
00104 
00105 
00106 
00107 /// what you get back when you read the value of a particular potentiometer
00108 struct pot_value_t {
00109         enum eConstants {
00110                 eStartMin       = (+1000) * (1000),
00111                 eStartMax       = (-1000) * (1000)
00112         };
00113 
00114         // constructor, manipulators
00115         pot_value_t(void) throw() { this->clear(); }
00116         void clear(void) throw() {
00117                         minSeen = eStartMin;
00118                         maxSeen = eStartMax;
00119                         value = 0;
00120                 }
00121         void dump(IN const char * title) const throw() {
00122                         DPRINTF("%s  val=%d  [%d - %d]",
00123                             title, value, minSeen, maxSeen);
00124                 }
00125         bool isValid(void) const throw() {
00126                         return (minSeen < maxSeen &&
00127                                 value >= minSeen &&
00128                                 value <= maxSeen);
00129                 }
00130         void update(IN int newValue) throw() {
00131                         value = newValue;
00132                         if (value < minSeen)
00133                                 minSeen = value;
00134                         if (value > maxSeen)
00135                                 maxSeen = value;
00136                 }
00137 
00138         // data fields
00139         int     minSeen;        ///< minimum value seen
00140         int     maxSeen;        ///< maximum value seen
00141         int     value;          ///< current (most recent) value
00142 };
00143 
00144 
00145 
00146 /// helper method to update a button value.  Given an input set of eButton
00147 ///     bit flags, and the current button state (up or down), returns a new
00148 ///     set of button bit flags.
00149 byte_t updateButton(IN byte_t oldBitFlags, IN bool isButtonDown) throw();
00150 
00151 
00152 
00153 /// An object that supplies gamepad input.  Often this is a USB device, for
00154 /// instance, that may support multiple different types of gamepads plugged in
00155 /// at once.  Regardless of how many gamepads are plugged in, a SourceDevice
00156 /// is supposed to represent a physical or logical device (USB device or the
00157 /// bluetooth subsystem as respective examples) that supports polling
00158 /// independent of other SourceDevice objects.
00159 ///
00160 /// Force feedback support is purposely limited for now.  If you want rich
00161 /// force feedback support, you should probably work closer to the native
00162 /// drivers.
00163 class SourceDevice {
00164 public:
00165         // virtual destructor --------------------------------------------------
00166         virtual ~SourceDevice(void) throw();
00167 
00168         // gamepad::SourceDevice class interface methods -----------------------
00169 
00170         /// a "pretty" name, often the manufacturer and model, for instance.
00171         ///  note that this is recommended for debugging but not necessarily
00172         ///  for display to the end gamer (string may not be meaningful, and
00173         ///  almost certainly isn't localized).
00174         /// \b NOTE: this should come directly from the hardware itself, and
00175         ///  not be modified by any code.  This gives developers a chance to
00176         ///  identify hardware by name.
00177         /// \b WARNING: despite what I just said, be careful about identifying
00178         ///  hardware by public name.  In testing, I've found many USB adaptors
00179         ///  have the same hardware-specified information, even though they
00180         ///  behave quite differently.  So only use the public name for
00181         ///  devices you know will have consistent behavior.  In practice, this
00182         ///  will tend to be gamepads that directly attach via USB and not
00183         ///  adaptors (for instance, XBox 360 and Playstation3 controllers).
00184         virtual const char * getPublicName(void) throw() = 0;
00185 
00186         /// each source device MUST supply a unique ID.  The ID must be unique
00187         ///     to that physical device, not just the manufacturer and model!
00188         ///     So for instance if a gamer plugged in two identical USB
00189         ///     adapters, the unique ID would still be different for each.
00190         ///     Sometimes (rarely) manufacturers make the serial number of their
00191         ///     adapters/joysticks available.  Barring that, anyone who
00192         ///     implements this interface has to ensure the IDs are unique.
00193         /// These IDs should be unique for the lifetime of the device (this
00194         ///     process) but are not generally valid across process lifetimes,
00195         ///     and so should not be persisted.
00196         virtual const char * getUniqueId(void) throw() = 0;
00197 
00198         /// returns the current state of the source device.  Note that many
00199         ///     sources aren't capable of determining whether or not they are
00200         ///     attached!  This is annoying but reflects either poor standards
00201         ///     or the physical realities of the device in question.
00202         /// If someone disconnects a gamepad (or turns it off in the case of
00203         ///     wireless gamepads) you'll stop receiving events and the poll()
00204         ///     call won't actually do anything.
00205         /// Call this method occasionally so you can detect when a player has
00206         ///     disconnected a device.
00207         virtual eDeviceState getState(void) throw() = 0;
00208 
00209         /// the source must say how many pots (potentiometers) are exposed.  A
00210         ///     "pot" is any input that allows the user to continuously vary it
00211         ///     through a range of values.  An example is the X or Y axis of a
00212         ///     joystick, or a single axis in the case of steering wheels.
00213         ///     See http://en.wikipedia.org/wiki/Potentiometer
00214         /// This is the total number of pots supported by the source device, NOT
00215         ///     the number of pots per gamepad (the two numbers will often be
00216         ///     the same for single-gamepad devices).
00217         virtual int getNumPots(void) throw() = 0;
00218 
00219         /// the source must say how many buttons are exposed.  This is the total
00220         ///     number of buttons for the source device, NOT the number of
00221         ///     buttons per gamepad (again, some source devices may support
00222         ///     multiple gamepads).
00223         virtual int getNumButtons(void) throw() = 0;
00224 
00225 /*
00226         // Jan 2011: removing all force feedback support for now
00227         /// the source must say how many force feedback rumble objects are
00228         ///     supported.  Typically there are one per gamepad, for instance.
00229         //virtual int getNumRumblers(void) throw() = 0;
00230  */
00231 
00232         /// the source will be asked to poll all of its inputs.  This is so
00233         ///     that later calls to getPotValue() or getButtonValue() will
00234         ///     return the current value.
00235         virtual void poll(void) throw() = 0;
00236 
00237         /// retrieves the value of a particular potentiometer. 
00238         virtual const pot_value_t& getPotValue(IN int potIndex) = 0;
00239 
00240         /// retrieves the state of a particular button.  Typically this is
00241         ///     eButtonDown or eButtonUp, maybe OR'd with eButtonWasPushed
00242         ///     if the button was ever pushed between this and the previous
00243         ///     poll interval.  See the eButton enum.
00244         virtual eButton getButtonValue(IN int buttonIndex) = 0;
00245 
00246 /*
00247         // Jan 2011: removing all force feedback support for now
00248         /// plays the given rumbler effect.  Returns false on failure
00249         virtual bool playRumble(IN int rumbleIndex,
00250                                 IN uint16_t highFreqMagnitude,
00251                                 IN uint16_t lowFreqMagnitude,
00252                                 IN int durationMilliseconds) = 0;
00253 */
00254 };
00255 
00256 
00257 
00258 /// objects supporting this interface can create gamepad::SourceDevice
00259 ///     instances.
00260 /// Note to implementers (and users): objects supporting this interface are
00261 ///     intended to be long-lived.  So if you write an object that supports this 
00262 ///     interface, it should re-poll (or do whatever discovery is necessary) on
00263 ///     every API call, and not rely on one-time discovery during object
00264 ///     initialization.  In particular, it is expected that
00265 ///     SourceDeviceFactory::getCount() will be expensive to call.
00266 class SourceDeviceFactory {
00267 public:
00268         // virtual destructor --------------------------------------------------
00269         virtual ~SourceDeviceFactory(void) throw();
00270 
00271         // gamepad::SourceDeviceFactory class interface methods ----------------
00272         virtual const char * getName(void) const throw() = 0;
00273         virtual int getCount(void) = 0;
00274         virtual smart_ptr<SourceDevice> getSourceDevice(IN int index) = 0;
00275 };
00276 
00277 
00278 
00279 /// state snapshot of a source device.  Used by configuration tools only
00280 struct device_state_t {
00281         // enums
00282         enum eConstants {
00283                 eMaxButtons     = 256,
00284                 eMaxPots        = 256
00285         };
00286 
00287         // constructor, manipulators
00288         device_state_t(void) throw() { this->clear(); }
00289         void clear(void) throw() {
00290                         nPots = nButtons = 0;
00291                 }
00292         void dump(IN const char * title) const throw() {
00293                         DPRINTF("%s (source device state snapshot)", title);
00294                         DPRINTF("  Number of potentiometers: %d", nPots);
00295                         DPRINTF("  Number of buttons: %d", nButtons);
00296                 }
00297 
00298         // data fields
00299         int             nPots;
00300         int             nButtons;
00301         int             button[eMaxButtons];
00302         pot_value_t     pot[eMaxPots];
00303 };
00304 
00305 
00306 
00307 /// take a state snapshot
00308 void snapshotState(IN SourceDevice * device,
00309                         OUT device_state_t& state);
00310 
00311 
00312 /// is a single button down?
00313 int buttonDown(IN const device_state_t& state);
00314 
00315 
00316 /// was a button released?
00317 int buttonReleased(IN const device_state_t& state);
00318 
00319 
00320 /// compare new and old states: did a single button change state?
00321 int buttonChanged(IN const device_state_t& oldState,
00322                         IN const device_state_t& newState);
00323 
00324 
00325 /// compare new and old states: are all potentiometers calibrated?
00326 bool potsCalibrated(IN const device_state_t& oldState,
00327                         IN const device_state_t& newState);
00328 
00329 
00330 /// get pot at largest value--specify threshold: 0 (min) to 1 (max).
00331 ///     pots with values under the threshold will be ignored.
00332 int maxPotValue(IN const device_state_t& state,
00333                         IN float threshold);
00334 
00335 
00336 /// compare new and old states: which potentiometer has changed most?
00337 int maxPotChanged(IN const device_state_t& oldState,
00338                         IN const device_state_t& newState);
00339 
00340 
00341 };      // gamepad namespace
00342 
00343 #endif  // GAMEPAD_SOURCE_DEVICE_H__
00344