gamepad-map.cpp

Go to the documentation of this file.
00001 /*
00002  * gamepad-map.cpp
00003  *
00004  * Copyright (C) 2009,2010  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  * Gamepad mapping routines.
00032  */
00033 
00034 // includes --------------------------------------------------------------------
00035 #include "gamepad-map.h"                // always include our own header first
00036 
00037 #include "datahash/datahash_util.h"
00038 #include "util/parsing.h"
00039 
00040 
00041 namespace gamepad {
00042 
00043 // interface destructors
00044 Map::~Map(void) throw() { }
00045 
00046 
00047 ////////////////////////////////////////////////////////////////////////////////
00048 //
00049 //      static helper methods
00050 //
00051 ////////////////////////////////////////////////////////////////////////////////
00052 
00053 ////////////////////////////////////////////////////////////////////////////////
00054 //
00055 //      Mapping - class that implements the gamepad::Map interface
00056 //
00057 ////////////////////////////////////////////////////////////////////////////////
00058 
00059 class Mapping : public Map {
00060 public:
00061         // constructor, destructor ---------------------------------------------
00062         ~Mapping(void) throw() { }
00063 
00064         // public class methods ------------------------------------------------
00065         void initialize(IN const Datahash * hash);
00066 
00067         // gamepad::Map class interface methods --------------------------------
00068         const char * getId(void) const throw() { return m_id.c_str(); }
00069         const char * getTypeId(void) const throw() { return m_typeId.c_str(); }
00070         const char * getName(void) const throw() { return m_name.c_str(); }
00071         const VecString& getDeviceNames(void) const throw() { return m_devices; }
00072         const button_map_t * getButtonMapping(IN const char * logicalName) const throw();
00073         const joystick_map_t * getJoystickMapping(IN const char * logicalName) const throw();
00074         const pot_map_t * getPotMapping(IN const char * logicalName) const throw();
00075         const dpad_map_t * getDpadMapping(IN const char * logicalName) const throw();
00076 
00077 private:
00078         // private helper methods ----------------------------------------------
00079         typedef std::map<std::string, button_map_t> buttons_t;
00080         typedef std::map<std::string, joystick_map_t> joysticks_t;
00081         typedef std::map<std::string, pot_map_t> pots_t;
00082         typedef std::map<std::string, dpad_map_t> dpads_t;
00083 
00084         // private member data -------------------------------------------------
00085         std::string             m_id;
00086         std::string             m_typeId;
00087         std::string             m_name;
00088         VecString               m_devices;
00089         buttons_t               m_buttons;
00090         joysticks_t             m_joysticks;
00091         pots_t                  m_pots;
00092         dpads_t                 m_dpads;
00093 };
00094 
00095 
00096 
00097 void
00098 Mapping::initialize
00099 (
00100 IN const Datahash * in_hash
00101 )
00102 {
00103         ASSERT(in_hash, "null");
00104 
00105         //DPRINTF("Reading gamepad mapping...");
00106 
00107         // get the "map" subhash
00108         const Datahash * hash = getSubhash(in_hash, "map");
00109         ASSERT_THROW(hash, "gamepad map hash does not contain 'map' section?");
00110 
00111         m_id = getString(hash, "id");
00112         //DPRINTF("  id: '%s'", m_id.c_str());
00113         m_typeId = getString(hash, "typeId");
00114         //DPRINTF("  type id: '%s'", m_typeId.c_str());
00115         m_name = getString(hash, "name");
00116         //DPRINTF("  name: %s", m_name.c_str());
00117 
00118         // get the list of device names supported (can be empty!)
00119         m_devices.clear();
00120         Datahash::iterator_t i;
00121         hash->getIterator("deviceName", i);
00122         while (const hash_value_t * phv = hash->getNextElementUnsafe(i)) {
00123                 if (eHashDataType_String != phv->type)
00124                         continue;
00125                 m_devices.push_back(phv->text);
00126         }
00127         //DPRINTF("  Mapping supports %d known devices", (int) m_devices.size());
00128 
00129         // read all buttons
00130         hash->getIterator("button", i);
00131         while (const hash_value_t * phv = hash->getNextElementUnsafe(i)) {
00132                 if (eHashDataType_Hash != phv->type)
00133                         continue;       // skip
00134 
00135                 const Datahash * btn = phv->hash;
00136                 ASSERT(btn, "null hash in vector?");
00137 
00138                 button_map_t bmap;
00139                 const char * logical = getString(btn, "logical");
00140                 const char * index = getString(btn, "button");
00141                 bmap.index = atoi(index);
00142                 //bmap.dump(logical);
00143                 ASSERT_THROW(bmap.isValid(),
00144                     "Gamepad mapping for '" << logical << "' is not valid");
00145                 m_buttons[logical] = bmap;
00146         }
00147         //DPRINTF("  Read %d button mappings", (int) m_buttons.size());
00148 
00149         // read all joysticks
00150         hash->getIterator("joystick", i);
00151         while (const hash_value_t * phv = hash->getNextElementUnsafe(i)) {
00152                 if (eHashDataType_Hash != phv->type)
00153                         continue;
00154                 const Datahash * joy = phv->hash;
00155                 ASSERT(joy, "null hash in vector?");
00156 
00157                 joystick_map_t jmap;
00158                 const char * logical = getString(joy, "logical");
00159                 jmap.xIndex = getInt(joy, "xAxis");
00160                 jmap.yIndex = getInt(joy, "yAxis");
00161 
00162                 //jmap.dump(logical);
00163                 ASSERT_THROW(jmap.isValid(),
00164                     "Gamepad mapping for '" << logical << "' is not valid");
00165                 m_joysticks[logical] = jmap;
00166         }
00167         //DPRINTF("  Read %d joystick mappings", (int) m_joysticks.size());
00168 
00169         // read all potentiometers
00170         hash->getIterator("pot", i);
00171         while (const hash_value_t * phv = hash->getNextElementUnsafe(i)) {
00172                 if (eHashDataType_Hash != phv->type)
00173                         continue;
00174                 const Datahash * pot = phv->hash;
00175                 ASSERT(pot, "null hash in vector?");
00176 
00177                 pot_map_t pmap;
00178                 const char * logical = getString(pot, "logical");
00179                 pmap.index = getInt(pot, "index");
00180 
00181                 //pmap.dump(logical);
00182                 ASSERT_THROW(pmap.isValid(),
00183                     "Gamepad mapping for '" << logical << "' is not valid");
00184                 m_pots[logical] = pmap;
00185         }
00186         //DPRINTF("  Read %d potentiometer mappings", (int) m_pots.size());
00187 
00188         // read all directional pads (dpads)
00189         hash->getIterator("dpad", i);
00190         while (const hash_value_t * phv = hash->getNextElementUnsafe(i)) {
00191                 if (eHashDataType_Hash != phv->type)
00192                         continue;
00193                 const Datahash * dpad = phv->hash;
00194                 ASSERT(dpad, "null hash in vector?");
00195 
00196                 dpad_map_t dmap;
00197                 const char * logical = getString(dpad, "logical");
00198                 const char * type = getString(dpad, "type");
00199                 if (!strcmp("pot", type)) {
00200                 } else if (!strcmp("button", type)) {
00201                         dmap.type = dpad_map_t::eType_Button;
00202                 } else {
00203                         ASSERT_THROW(false, "Invalid dpad type: " << type);
00204                 }
00205                 dmap.index[dpad_map_t::eUp] = getByte(dpad, "up");
00206                 dmap.index[dpad_map_t::eDown] = getByte(dpad, "down");
00207                 dmap.index[dpad_map_t::eLeft] = getByte(dpad, "left");
00208                 dmap.index[dpad_map_t::eRight] = getByte(dpad, "right");
00209 
00210                 // if we have a blank type, determine 2 or 4 potentiometer
00211                 if (dpad_map_t::eType_Invalid == dmap.type) {
00212                         if (dmap.index[dpad_map_t::eUp] == dmap.index[dpad_map_t::eDown]) {
00213                                 dmap.type = dpad_map_t::eType_2Pot;
00214                         } else {
00215                                 dmap.type = dpad_map_t::eType_4Pot;
00216                         }
00217                 }
00218 
00219                 // flip any axes?
00220                 const char * flipX = getOptionalString(dpad, "flipX", "");
00221                 const char * flipY = getOptionalString(dpad, "flipY", "");
00222                 dmap.flipX = getBooleanFromString(flipX);
00223                 dmap.flipY = getBooleanFromString(flipY);
00224 
00225                 //dmap.dump(logical);
00226                 ASSERT_THROW(dmap.isValid(),
00227                     "Gamepad mapping for '" << logical << "' is not valid");
00228                 m_dpads[logical] = dmap;
00229         }
00230         //DPRINTF("  Read %d directional pad (dpad) mappings",
00231         //    (int) m_dpads.size());
00232 }
00233 
00234 
00235 
00236 ////////////////////////////////////////////////////////////////////////////////
00237 //
00238 //      Mapping -- gamepad::Map class interface methods
00239 //
00240 ////////////////////////////////////////////////////////////////////////////////
00241 
00242 const button_map_t *
00243 Mapping::getButtonMapping
00244 (
00245 IN const char * logicalName
00246 )
00247 const
00248 throw()
00249 {
00250         ASSERT(logicalName, "null");
00251 
00252         buttons_t::const_iterator i = m_buttons.find(logicalName);
00253         if (m_buttons.end() == i)
00254                 return NULL;    // name not found
00255 
00256         return &i->second;
00257 }
00258 
00259 
00260 
00261 const joystick_map_t *
00262 Mapping::getJoystickMapping
00263 (
00264 IN const char * logicalName
00265 )
00266 const
00267 throw()
00268 {
00269         ASSERT(logicalName, "null");
00270 
00271         joysticks_t::const_iterator i = m_joysticks.find(logicalName);
00272         if (m_joysticks.end() == i)
00273                 return NULL;    // joystick of that name not found
00274         return &i->second;
00275 }
00276 
00277 
00278 
00279 const pot_map_t *
00280 Mapping::getPotMapping
00281 (
00282 IN const char * logicalName
00283 )
00284 const
00285 throw()
00286 {
00287         ASSERT(logicalName, "null");
00288 
00289         pots_t::const_iterator i = m_pots.find(logicalName);
00290         if (m_pots.end() == i)
00291                 return NULL;    // potentiometer of that name not found
00292         return &i->second;
00293 }
00294 
00295 
00296 
00297 const dpad_map_t *
00298 Mapping::getDpadMapping
00299 (
00300 IN const char * logicalName
00301 )
00302 const
00303 throw()
00304 {
00305         ASSERT(logicalName, "null");
00306 
00307         dpads_t::const_iterator i = m_dpads.find(logicalName);
00308         if (m_dpads.end() == i)
00309                 return NULL;    // dpad of that name not found
00310         return &i->second;
00311 }
00312 
00313 
00314 
00315 ////////////////////////////////////////////////////////////////////////////////
00316 //
00317 //      public API
00318 //
00319 ////////////////////////////////////////////////////////////////////////////////
00320 
00321 smart_ptr<Map>
00322 readMap
00323 (
00324 IN const Datahash * hash
00325 )
00326 {
00327         ASSERT(hash, "null");
00328 
00329         smart_ptr<Mapping> local = new Mapping;
00330         ASSERT(local, "out of memory");
00331 
00332         local->initialize(hash);
00333 
00334         return local;
00335 }
00336 
00337 
00338 
00339 };      // gamepad namespace
00340