manager.cpp

Go to the documentation of this file.
00001 /*
00002  * manager.cpp
00003  *
00004  * Copyright (C) 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 manager implementation.  See manager.h
00032  */
00033 
00034 // includes --------------------------------------------------------------------
00035 #include "manager.h"            // always include our own header first
00036 
00037 #ifdef WIN32
00038         // windows: use direct input device factory
00039 #include "direct-input/direct-input.h"
00040 #else   // WIN32
00041         // linux: use linux input device factory
00042 #include "linux-joystick/linux-joystick.h"
00043 #endif  // WIN32
00044 
00045 #include "datahash/datahash_text.h"
00046 #include "perf/perf.h"
00047 #include "resources/resources-internal.h"
00048 #include "util/file.h"
00049 
00050 
00051 namespace gamepad {
00052 
00053 // interface destructors
00054 Gamepad::~Gamepad(void) throw() { }
00055 Manager::~Manager(void) throw() { }
00056 
00057 
00058 // what percentage must pot be pushed for button to count as "pressed"?
00059 static const float s_buttonRatio                = 0.2;
00060 
00061 static const float s_4potRatio                  = 0.08;
00062 
00063 
00064 static const char * s_gamepadExtension          = "gamepad";
00065 static const char * s_mappingExtension          = "map";
00066 
00067 
00068 ////////////////////////////////////////////////////////////////////////////////
00069 //
00070 //      static helper methods
00071 //
00072 ////////////////////////////////////////////////////////////////////////////////
00073 
00074 static smart_ptr<Map>
00075 readMapFromString
00076 (
00077 IN const char * val
00078 )
00079 {
00080         ASSERT(val, "null");
00081 
00082         smart_ptr<Datahash> hash = readHashFromString(val);
00083         ASSERT(hash, "null");
00084 
00085         smart_ptr<Map> map = readMap(hash);
00086         ASSERT(map, "null");
00087 
00088         return map;
00089 }
00090 
00091 
00092 
00093 static int
00094 getDpadFromPot
00095 (
00096 IN SourceDevice * device,
00097 IN int idx
00098 )
00099 {
00100         ASSERT(device, "null");
00101         ASSERT(idx >= 0, "Bad pot index: %d", idx);
00102 
00103         const pot_value_t& pv = device->getPotValue(idx);
00104 
00105         int iThreshold = s_buttonRatio * (pv.maxSeen - pv.minSeen);
00106         if ((pv.value - pv.minSeen) <= iThreshold)
00107                 return -1;
00108         if ((pv.maxSeen - pv.value) <= iThreshold)
00109                 return +1;
00110         return 0;
00111 }
00112 
00113 
00114 
00115 static bool
00116 potMoved
00117 (
00118 IN SourceDevice * device,
00119 IN int idx
00120 )
00121 {
00122         ASSERT(device, "null");
00123         ASSERT(idx >= 0, "bad index: %d", idx);
00124 
00125         const pot_value_t& pv = device->getPotValue(idx);
00126 
00127         int iThreshold = s_4potRatio * (pv.maxSeen - pv.minSeen);
00128         if ((pv.value - pv.minSeen) >= iThreshold)
00129                 return true;
00130         return false;
00131 }
00132 
00133 
00134 
00135 static nstream::eIterationFlag
00136 loadFilesCallback
00137 (
00138 IN nstream::Entry * entry,
00139 IN void * context
00140 )
00141 {
00142         ASSERT(entry, "null");
00143         Manager * mgr = (Manager *) context;
00144         ASSERT(mgr, "null context");
00145 
00146         // only care about Files, not Folders
00147         nstream::File * file = dynamic_cast<nstream::File *>(entry);
00148         if (!file)
00149                 return nstream::eIterate_Continue;      // skip folders
00150 
00151         // get the extension of the name (.gamepad or .map, for instance)
00152         const char * filename = file->getName();
00153         const char * ext = GetExtension(filename);
00154         //DPRINTF("Load Files: extension='%s'", ext);
00155         if (!strcmp(s_gamepadExtension, ext)) {
00156                 // this is a gamepad file!  Load it
00157                 //DPRINTF("  Attempting to load type at '%s'", filename);
00158                 smart_ptr<nstream::Stream> stream = file->openStream();
00159                 ASSERT(stream, "null");
00160                 if (stream->good()) {
00161                         smart_ptr<Type> type = readType(stream);
00162                         ASSERT(type, "null");
00163                         //DPRINTF("    Adding type: '%s'", type->getName());
00164                         mgr->addType(type);
00165                 } else {
00166                         DPRINTF("File is bad: '%s'", filename);
00167                 }
00168         } else if (!strcmp(s_mappingExtension, ext)) {
00169                 // this is a gamepad mapping file!  Load it
00170                 //DPRINTF("  Attempting to load mapping at '%s'", filename);
00171                 smart_ptr<nstream::Stream> stream = file->openStream();
00172                 ASSERT(stream, "null");
00173                 std::istream& in = stream->getStream();
00174                 if (in.good()) {
00175                         smart_ptr<Datahash> hash =
00176                             readHashFromStream("map", in);
00177                         ASSERT(hash, "null");
00178                         smart_ptr<Map> map = readMap(hash);
00179                         ASSERT(map, "null");
00180                         //DPRINTF("    Adding mapping: '%s'", map->getName());
00181                         mgr->addMapping(map);
00182                 } else {
00183                         DPRINTF("File is bad: '%s'", filename);
00184                 }
00185         }
00186 
00187         // okay, next...
00188         return nstream::eIterate_Continue;
00189 }
00190 
00191 
00192 
00193 static bool
00194 sourceAndMapInUse
00195 (
00196 IN Manager * mgr,
00197 IN const char * deviceId,
00198 IN const char * mappingId
00199 )
00200 {
00201         ASSERT(mgr, "null");
00202         ASSERT(deviceId, "null");
00203         ASSERT(mappingId, "null");
00204 
00205         // loop through all gamepads and see if any are using this combo
00206         int nGamepads = mgr->getGamepadCount();
00207         for (int i = 0; i < nGamepads; ++i) {
00208                 smart_ptr<Gamepad> gp = mgr->getGamepad(i);
00209                 if (!gp) {
00210                         DPRINTF("Gamepad %d has disappeared", i);
00211                         continue;
00212                 }
00213 
00214                 if (!strcmp(deviceId, gp->getSourceDeviceId()) &&
00215                     !strcmp(mappingId, gp->getMappingId())) {
00216                         // gamepad i uses the same source + mapping!
00217                         return true;
00218                 }
00219         }
00220 
00221         // no gamepads used this device + mapping
00222         return false;
00223 }
00224 
00225 
00226 
00227 ////////////////////////////////////////////////////////////////////////////////
00228 //
00229 //      GPad -- class that implements the gamepad::Gamepad interface
00230 //
00231 ////////////////////////////////////////////////////////////////////////////////
00232 
00233 class GPad : public Gamepad {
00234 public:
00235         // constructor, destructor ---------------------------------------------
00236         ~GPad(void) throw() { }
00237 
00238         // public class methods ------------------------------------------------
00239         void initialize(IN Type * type,
00240                                 IN smart_ptr<SourceDevice>& device,
00241                                 IN smart_ptr<Map>& mapping);
00242 
00243         // gamepad::Gamepad class interface methods ----------------------------
00244         Type * getType(void) const throw();
00245         const char * getId(void) throw();
00246         const char * getSourceDeviceId(void) throw();
00247         const char * getMappingId(void) throw();
00248         eDeviceState getState(void) throw();
00249         buttons_t getButtons(void) throw();
00250         eButton getButton(IN int idx) throw();
00251         void getJoystick(IN int idx,
00252                                 OUT joystick_t& joy) throw();
00253         void getPot(IN int idx,
00254                                 OUT pot_value_t& pv) throw();
00255         eDpad getDpad(IN int idx) throw();
00256 
00257 private:
00258         // private typedefs ----------------------------------------------------
00259         typedef std::vector<button_map_t> btn_vec_t;
00260         typedef std::vector<dpad_map_t> dpad_vec_t;
00261         typedef std::vector<joystick_map_t> joy_vec_t;
00262         typedef std::vector<pot_map_t> pot_vec_t;
00263 
00264         // private helper functions --------------------------------------------
00265         // private member data -------------------------------------------------
00266         Type *                  m_type; // weak reference
00267         smart_ptr<SourceDevice> m_device;// our source device
00268         std::string             m_mappingId; // GUID of mapping
00269         std::string             m_id; // id of gamepad
00270 //      smart_ptr<Map>          m_mapping;// mapping from device -> gamepad
00271         btn_vec_t               m_button; // button mappings
00272         dpad_vec_t              m_dpad; // dpad mappings
00273         pot_vec_t               m_pot;  // potentiometer mappings
00274         joy_vec_t               m_joystick; // joystick mappings
00275 };
00276 
00277 
00278 
00279 void
00280 GPad::initialize
00281 (
00282 IN Type * type,
00283 IN smart_ptr<SourceDevice>& device,
00284 IN smart_ptr<Map>& mapping
00285 )
00286 {
00287         ASSERT(type, "null");
00288         ASSERT(device, "null");
00289         ASSERT(mapping, "null");
00290 
00291         //DPRINTF("Creating gamepad of type '%s'", type->getName());
00292 
00293         m_type = type;
00294         m_device = device;
00295 //      m_mapping = mapping;
00296         m_mappingId = mapping->getId();
00297 
00298         // construct ID
00299         m_id = device->getUniqueId();
00300         m_id += ":";
00301         m_id += mapping->getId();
00302 
00303         DPRINTF("Gamepad id: '%s'", m_id.c_str());
00304 
00305         // determine button mappings
00306         int nButtons = type->getInputCount(eInput_Button);
00307         //DPRINTF("  Contains %d buttons", nButtons);
00308         m_button.reserve(nButtons);
00309         for (int i = 0; i < nButtons; ++i) {
00310                 const char * name = type->getLogicalName(eInput_Button, i);
00311                 //DPRINTF("  Button %d: '%s'", i, name);
00312                 const button_map_t * bmap = mapping->getButtonMapping(name);
00313         //      if (bmap)
00314         //              bmap->dump(name);
00315                 ASSERT_THROW(bmap && bmap->isValid(),
00316                     "Missing or invalid mapping found for button: '" << name
00317                     << "', gamepad type: '" << type->getName() <<
00318                     "', mapping name: '" << mapping->getName() << "'");
00319 
00320                 m_button.push_back(*bmap);
00321         }
00322         //DPRINTF("Have %d buttons", (int) m_button.size());
00323         ASSERT(nButtons == (int) m_button.size(), "should match");
00324 
00325         // determine joystick mappings
00326         int nJoys = type->getInputCount(eInput_Joystick);
00327         //DPRINTF("  Contains %d joysticks", nJoys);
00328         m_joystick.reserve(nJoys);
00329         for (int i = 0; i < nJoys; ++i) {
00330                 const char * name = type->getLogicalName(eInput_Joystick, i);
00331                 //DPRINTF("  Joystick %d: '%s'", i, name);
00332                 const joystick_map_t * jmap = mapping->getJoystickMapping(name);
00333         //      if (jmap)
00334         //              jmap->dump(name);
00335                 ASSERT_THROW(jmap && jmap->isValid(),
00336                     "Missing or invalid mapping found for joystick: '" << name
00337                     << "', gamepad type: '" << type->getName() << 
00338                     "', mapping name: '" << mapping->getName() << "'");
00339 
00340                 m_joystick.push_back(*jmap);
00341         }
00342 
00343         // determine dpad mappings
00344         int nDpads = type->getInputCount(eInput_Dpad);
00345         //DPRINTF("  Contains %d dpads", nDpads);
00346         m_dpad.reserve(nDpads);
00347         for (int i = 0; i < nDpads; ++i) {
00348                 const char * name = type->getLogicalName(eInput_Dpad, i);
00349                 //DPRINTF("  Dpad %d: '%s'", i, name);
00350                 const dpad_map_t * dmap = mapping->getDpadMapping(name);
00351         //      if (dmap)
00352         //              dmap->dump(name);
00353                 ASSERT_THROW(dmap && dmap->isValid(),
00354                     "Missing or invalid mapping found for dpad: '" << name
00355                     << "', gamepad type: '" << type->getName() <<
00356                     "', mapping name: '" << mapping->getName() << "'");
00357 
00358                 m_dpad.push_back(*dmap);
00359         }
00360         //DPRINTF("Have %d dpads", (int) m_dpad.size());
00361         ASSERT(nDpads == (int) m_dpad.size(), "should match");
00362 
00363         // determine potentiometer mappings
00364         int nPots = type->getInputCount(eInput_Pot);
00365         //DPRINTF("  Contains %d potentiometers", nPots);
00366         m_pot.reserve(nPots);
00367         for (int i = 0; i < nPots; ++i) {
00368                 const char * name = type->getLogicalName(eInput_Pot, i);
00369                 //DPRINTF("  Pot %d: '%s'", i, name);
00370                 const pot_map_t * pmap = mapping->getPotMapping(name);
00371                 if (pmap) {
00372                         // have an explicitly-defined mapping
00373         //              pmap->dump(name);
00374                         m_pot.push_back(*pmap);
00375                 } else {
00376                         ASSERT_THROW(false,
00377                             "Missing or invalid mapping found for potentiometer: '" <<
00378                             name << "', gamepad type: '" << type->getName() <<
00379                             "', mapping name: '" << mapping->getName() << "'");
00380                 }
00381         }
00382         //DPRINTF("Have %d potentiometers", (int) m_pot.size());
00383         ASSERT(nPots == (int) m_pot.size(), "should match");
00384 }
00385 
00386 
00387 
00388 ////////////////////////////////////////////////////////////////////////////////
00389 //
00390 //      GPad -- gamepad::Gamepad class interface methods
00391 //
00392 ////////////////////////////////////////////////////////////////////////////////
00393 
00394 Type *
00395 GPad::getType
00396 (
00397 void
00398 )
00399 const
00400 throw()
00401 {
00402         return m_type;
00403 }
00404 
00405 
00406 
00407 const char *
00408 GPad::getId
00409 (
00410 void
00411 )
00412 throw()
00413 {
00414         return m_id.c_str();
00415 }
00416 
00417 
00418 
00419 const char *
00420 GPad::getSourceDeviceId
00421 (
00422 void
00423 )
00424 throw()
00425 {
00426         ASSERT(m_device, "null");
00427 
00428         return m_device->getUniqueId();
00429 }
00430 
00431 
00432 
00433 const char *
00434 GPad::getMappingId
00435 (
00436 void
00437 )
00438 throw()
00439 {
00440         return m_mappingId.c_str();
00441 }
00442 
00443 
00444 
00445 eDeviceState
00446 GPad::getState
00447 (
00448 void
00449 )
00450 throw()
00451 {
00452         ASSERT(m_device, "null");
00453         return m_device->getState();
00454 }
00455 
00456 
00457 
00458 buttons_t
00459 GPad::getButtons
00460 (
00461 void
00462 )
00463 throw()
00464 {
00465         ASSERT(m_device, "null");
00466         buttons_t retval = 0;
00467 
00468         int bit = 1;
00469         for (btn_vec_t::iterator i = m_button.begin(); i != m_button.end();
00470              ++i, bit = 2 * bit) {
00471                 const button_map_t& bmap = *i;
00472                 eButton val = m_device->getButtonValue(bmap.index);
00473                 //DPRINTF("  Button[0x%08x] (binary): %d", bit, val);
00474                 if (val) {
00475                         retval |= bit;
00476                 }
00477         }
00478         return retval;
00479 }
00480 
00481 
00482 
00483 eButton
00484 GPad::getButton
00485 (
00486 IN int idx
00487 )
00488 throw()
00489 {
00490         ASSERT(idx >= 0 && idx < (int) m_button.size(), "Bad index: %d", idx);
00491 
00492         const button_map_t& bmap = m_button[idx];
00493         return m_device->getButtonValue(bmap.index);
00494 }
00495 
00496 
00497 
00498 void
00499 GPad::getJoystick
00500 (
00501 IN int idx,
00502 OUT joystick_t& joy
00503 )
00504 throw()
00505 {
00506         ASSERT(idx >= 0, "Bad joystick index: %d", idx);
00507         ASSERT(idx < (int) m_joystick.size(), "Bad joystick index: %d", idx);
00508         ASSERT(m_device, "NULL");
00509         joy.clear();
00510 
00511         const joystick_map_t& jmap = m_joystick[idx];
00512         joy.x = m_device->getPotValue(jmap.xIndex);
00513         joy.y = m_device->getPotValue(jmap.yIndex);
00514 }
00515 
00516 
00517 
00518 void
00519 GPad::getPot
00520 (
00521 IN int idx,
00522 OUT pot_value_t& pv
00523 )
00524 throw()
00525 {
00526         ASSERT(idx >= 0, "Bad pot index: %d", idx);
00527         ASSERT(idx < (int) m_pot.size(), "Bad pot index: %d", idx);
00528         ASSERT(m_device, "null");
00529 
00530         const pot_map_t& pmap = m_pot[idx];
00531         pv = m_device->getPotValue(pmap.index);
00532 }
00533 
00534 
00535 
00536 eDpad
00537 GPad::getDpad
00538 (
00539 IN int idx
00540 )
00541 throw()
00542 {
00543         ASSERT(idx >= 0, "Bad dpad index: %d", idx);
00544         ASSERT(idx < (int) m_dpad.size(), "Bad dpad index: %d", idx);
00545         ASSERT(m_device, "null");
00546 
00547         const dpad_map_t& dmap = m_dpad[idx];
00548 
00549         int xPos = 0;
00550         int yPos = 0;
00551         // is this a potentiometer-based dpad, or button-based?
00552         if (dpad_map_t::eType_2Pot == dmap.type) {
00553                 // this is a dpad with two pots
00554                 xPos = getDpadFromPot(m_device, dmap.index[dpad_map_t::eLeft]);
00555                 yPos = getDpadFromPot(m_device, dmap.index[dpad_map_t::eUp]);
00556         } else if (dpad_map_t::eType_4Pot == dmap.type) {
00557                 // this is a dpad with four pots
00558                 if (potMoved(m_device, dmap.index[dpad_map_t::eLeft]))
00559                         xPos = -1;
00560                 if (potMoved(m_device, dmap.index[dpad_map_t::eRight]))
00561                         xPos = +1;
00562                 if (potMoved(m_device, dmap.index[dpad_map_t::eUp]))
00563                         yPos = -1;
00564                 if (potMoved(m_device, dmap.index[dpad_map_t::eDown]))
00565                         yPos = +1;
00566         } else {
00567                 // button-based dpad
00568                 if (eButtonDown & m_device->getButtonValue(dmap.index[dpad_map_t::eLeft]))
00569                         xPos = -1;
00570                 if (eButtonDown & m_device->getButtonValue(dmap.index[dpad_map_t::eRight]))
00571                         xPos = +1;
00572                 if (eButtonDown & m_device->getButtonValue(dmap.index[dpad_map_t::eUp]))
00573                         yPos = -1;
00574                 if (eButtonDown & m_device->getButtonValue(dmap.index[dpad_map_t::eDown]))
00575                         yPos = +1;
00576                 //DPRINTF("  xpos=%d  ypos=%d", xPos, yPos);
00577         }
00578 
00579         // flip axes?
00580         if (dmap.flipX)
00581                 xPos = -xPos;
00582         if (dmap.flipY)
00583                 yPos = -yPos;
00584 
00585         // okay, based on x/y, determine dpad state
00586         int retval = eDpad_Centered;
00587         if (xPos < 0)
00588                 retval = eDpad_Left;
00589         else if (xPos > 0)
00590                 retval = eDpad_Right;
00591         
00592         if (yPos < 0)
00593                 retval |= eDpad_Up;
00594         else if (yPos > 0)
00595                 retval |= eDpad_Down;
00596 
00597         return (eDpad) retval;
00598 }
00599 
00600 
00601 
00602 ////////////////////////////////////////////////////////////////////////////////
00603 //
00604 //      Mgr -- class that implements the gamepad::Manager interface
00605 //
00606 ////////////////////////////////////////////////////////////////////////////////
00607 
00608 class Mgr : public Manager {
00609 public:
00610         // constructor, destructor ---------------------------------------------
00611         ~Mgr(void) throw() { }
00612 
00613         // public class methods ------------------------------------------------
00614         void initialize(IN smart_ptr<nstream::Folder>& dataDir);
00615 
00616         // gamepad::Manager class interface methods ----------------------------
00617         nstream::Folder * getDataDirectory(void);
00618         bool rediscover(void);
00619         int getSourceDeviceCount(void) { return m_devices.size(); }
00620         smart_ptr<SourceDevice> getSourceDevice(IN int index);
00621         smart_ptr<SourceDevice> getSourceDeviceById(IN const char * id);
00622         int getTypeCount(void);
00623         smart_ptr<Type> getType(IN int index);
00624         smart_ptr<Type> getType(IN const char * id);
00625         void addType(IN smart_ptr<Type>& type);
00626         int getMappingCount(void);
00627         smart_ptr<Map> getMapping(IN int index);
00628         smart_ptr<Map> getMapping(IN const char * id);
00629         void addMapping(IN smart_ptr<Map>& map);
00630         eResult createGamepad(IN smart_ptr<SourceDevice>& device,
00631                                 IN smart_ptr<Map>& map,
00632                                 OUT smart_ptr<Gamepad>& gamepad);
00633         int getGamepadCount(void);
00634         smart_ptr<Gamepad> getGamepad(IN int index);
00635         smart_ptr<Gamepad> getGamepad(IN const char * id);
00636         bool deleteGamepad(IN const char * id);
00637         void update(void);
00638 
00639 private:
00640         // private typedefs ----------------------------------------------------
00641         typedef std::vector<smart_ptr<SourceDeviceFactory> > vec_factory_t;
00642         typedef std::map<std::string, smart_ptr<SourceDevice> > device_map_t;
00643         typedef std::map<std::string, smart_ptr<Type> > map_type_t;
00644         typedef std::map<std::string, smart_ptr<Map> > map_map_t;
00645         typedef std::map<std::string, smart_ptr<Gamepad> > gamepad_map_t;
00646 
00647         // private member data -------------------------------------------------
00648         smart_ptr<nstream::Folder> m_folder;    // our data directory
00649         vec_factory_t           m_factories;
00650         device_map_t            m_devices;
00651         map_type_t              m_types;
00652         map_map_t               m_mappings;
00653         gamepad_map_t           m_gamepads;
00654 };
00655 
00656 
00657 
00658 ////////////////////////////////////////////////////////////////////////////////
00659 //
00660 //      Mgr -- public class methods
00661 //
00662 ////////////////////////////////////////////////////////////////////////////////
00663 
00664 nstream::Folder *
00665 Mgr::getDataDirectory
00666 (
00667 void
00668 )
00669 {
00670         ASSERT(m_folder, "null");
00671 
00672         return m_folder;
00673 }
00674 
00675 
00676 
00677 void
00678 Mgr::initialize
00679 (
00680 IN smart_ptr<nstream::Folder>& folder
00681 )
00682 {
00683         ASSERT(folder, "null");
00684 
00685         // recursively walk folder for interesting gamepad data files
00686         m_folder = folder;      // save data directory
00687         void * context = (Manager *) this;
00688         nstream::walkChildFolders(folder, loadFilesCallback, context);
00689 
00690         // populate factory objects
00691 #if WIN32
00692         // win32 setup here
00693         smart_ptr<SourceDeviceFactory> factory =
00694            getDirectInputSourceDeviceFactory();
00695         ASSERT(factory, "failed to create direct input source device factory");
00696         m_factories.push_back(factory);
00697 
00698 #else   // WIN32
00699         // assume linux!
00700         smart_ptr<SourceDeviceFactory> factory =
00701             getLinuxJoystickSourceDeviceFactory();
00702         ASSERT(factory, "failed to create linux joystick source device factory");
00703         m_factories.push_back(factory);
00704 
00705 #endif  // WIN32
00706 
00707         DPRINTF("Have %d factory objects", (int) m_factories.size());
00708 }
00709 
00710 
00711 
00712 ////////////////////////////////////////////////////////////////////////////////
00713 //
00714 //      Mgr -- gamepad::Manager class interface methods
00715 //
00716 ////////////////////////////////////////////////////////////////////////////////
00717 
00718 bool
00719 Mgr::rediscover
00720 (
00721 void
00722 )
00723 {
00724         perf::Timer timer("gamepad::Manager::rediscover");
00725 
00726         bool changes = false;
00727 
00728         // clear out any bad devices
00729         VecString badIds;
00730         for (device_map_t::iterator i = m_devices.begin(); i != m_devices.end();
00731              ++i) {
00732                 const char * id = i->first.c_str();
00733                 SourceDevice * sd = i->second;
00734                 ASSERT(sd, "null device in map");
00735 
00736                 //DPRINTF("Checking device '%s'...", id);
00737 
00738                 if (eDevice_Detached == sd->getState()) {
00739                         badIds.push_back(id);
00740                         changes = true;
00741                 }
00742         }
00743         //DPRINTF("Found %d devices that need to be nuked", badIds.size());
00744 
00745         for (VecString::const_iterator i = badIds.begin(); i != badIds.end();
00746              ++i) {
00747                 const char * id = i->c_str();
00748                 device_map_t::iterator bad = m_devices.find(id);
00749                 if (m_devices.end() == bad) {
00750                         DPRINTF("ERROR: bad id not in map?  '%s'", id);
00751                         continue;
00752                 }
00753                 m_devices.erase(bad);
00754         }
00755         //DPRINTF("%d devices remain in map after cleaning", m_devices.size());
00756 
00757         // walk through factories and update map
00758         for (vec_factory_t::iterator i = m_factories.begin();
00759              i != m_factories.end(); ++i) {
00760                 SourceDeviceFactory * factory = *i;
00761                 ASSERT(factory, "null factory in map");
00762 
00763                 int N = factory->getCount();
00764                 //DPRINTF("%d devices from '%s'", N, factory->getName());
00765 
00766                 for (int j = 0; j < N; ++j) {
00767                         smart_ptr<SourceDevice> device =
00768                             factory->getSourceDevice(j);
00769                         if (!device) {
00770                                 DPRINTF("Device %d was null", j);
00771                                 continue;
00772                         }
00773 
00774                         const char * id = device->getUniqueId();
00775                         //DPRINTF("Device %d has ID '%s'", j, id);
00776 
00777                         device_map_t::iterator existing = m_devices.find(id);
00778                         if (m_devices.end() != existing) {
00779                                 //DPRINTF("  ...already in map");
00780                                 continue;
00781                         }
00782 
00783                         // new device!
00784                         changes = true;
00785                         m_devices[id] = device;
00786                 }
00787         }
00788 
00789         // walk through and remove any gamepads no longer supported by devices
00790         VecString badGamepadIds;
00791         int nGamepads = this->getGamepadCount();
00792         for (int i = 0; i < nGamepads; ++i) {
00793                 smart_ptr<gamepad::Gamepad> gp = this->getGamepad(i);
00794                 if (!gp)
00795                         continue;
00796 
00797                 const char * deviceId = gp->getSourceDeviceId();
00798                 if (!deviceId || !this->getSourceDeviceById(deviceId)) {
00799                         DPRINTF("Gamepad is gone");
00800                         badGamepadIds.push_back(gp->getId());
00801                 }
00802         }
00803 
00804         int nBadIds = badGamepadIds.size();
00805         for (int i = 0; i < nBadIds; ++i) {
00806                 const char * badId = badGamepadIds[i].c_str();
00807                 this->deleteGamepad(badId);
00808         }
00809 
00810         // all done!
00811         return changes;
00812 }
00813 
00814 
00815 
00816 smart_ptr<SourceDevice>
00817 Mgr::getSourceDevice
00818 (
00819 IN int index
00820 )
00821 {
00822         ASSERT(index >= 0, "Bad index: %d", index);
00823 
00824         // we don't do anything clever here, just walk the map...
00825         for (device_map_t::iterator i = m_devices.begin();
00826              i != m_devices.end(); ++i, --index) {
00827                 if (!index) {
00828                         // this must be it
00829                         return i->second;
00830                 }
00831         }
00832 
00833         // got here?  ran out of entries
00834         return NULL;
00835 }
00836 
00837 
00838 
00839 smart_ptr<SourceDevice>
00840 Mgr::getSourceDeviceById
00841 (
00842 IN const char * id
00843 )
00844 {
00845         ASSERT(id, "null");
00846 
00847         // again, no indexing.  Just walk the map
00848         for (device_map_t::iterator i = m_devices.begin();
00849              i != m_devices.end(); ++i) {
00850                 smart_ptr<SourceDevice> device = i->second;
00851                 if (device &&
00852                     !strcmp(id, device->getUniqueId())) {
00853                         return device;
00854                 }
00855         }
00856 
00857         // got here?  ran out of entries
00858         return NULL;
00859 }
00860 
00861 
00862 
00863 int
00864 Mgr::getTypeCount
00865 (
00866 void
00867 )
00868 {
00869         return m_types.size();
00870 }
00871 
00872 
00873 
00874 smart_ptr<Type>
00875 Mgr::getType
00876 (
00877 IN int index
00878 )
00879 {
00880         ASSERT(index >= 0, "Bad index: %d", index);
00881 
00882         for (map_type_t::iterator i = m_types.begin();
00883              i != m_types.end(), index >= 0; ++i, --index) {
00884                 if (!index) {
00885                         return i->second;
00886                 }
00887         }
00888 
00889         // not found?
00890         return NULL;
00891 }
00892 
00893 
00894 
00895 smart_ptr<Type>
00896 Mgr::getType
00897 (
00898 IN const char * id
00899 )
00900 {
00901         ASSERT(id, "null");
00902 
00903         map_type_t::iterator i = m_types.find(id);
00904         if (m_types.end() == i) {
00905                 return NULL;            // ID not found
00906         }
00907         return i->second;
00908 }
00909 
00910 
00911 
00912 void
00913 Mgr::addType
00914 (
00915 IN smart_ptr<Type>& type
00916 )
00917 {
00918         ASSERT(type, "null");
00919 
00920         const char * id = type->getId();
00921         ASSERT(id, "null id from type");
00922 
00923         // don't check for collisions--IDs should be unique!
00924         m_types[id] = type;
00925 }
00926 
00927 
00928 
00929 int
00930 Mgr::getMappingCount
00931 (
00932 void
00933 )
00934 {
00935         return m_mappings.size();
00936 }
00937 
00938 
00939 
00940 smart_ptr<Map>
00941 Mgr::getMapping
00942 (
00943 IN int index
00944 )
00945 {
00946         ASSERT(index >= 0, "Bad index: %d", index);
00947 
00948         for (map_map_t::iterator i = m_mappings.begin();
00949              i != m_mappings.end(), index >= 0; ++i, --index) {
00950                 if (!index) {
00951                         return i->second;
00952                 }
00953         }
00954 
00955         // not found
00956         return NULL;
00957 }
00958 
00959 
00960 
00961 smart_ptr<Map>
00962 Mgr::getMapping
00963 (
00964 IN const char * id
00965 )
00966 {
00967         ASSERT(id, "null");
00968 
00969         map_map_t::iterator i = m_mappings.find(id);
00970         if (m_mappings.end() == i) {
00971                 return NULL;            // not found
00972         }
00973         return i->second;
00974 }
00975 
00976 
00977 
00978 void
00979 Mgr::addMapping
00980 (
00981 IN smart_ptr<Map>& map
00982 )
00983 {
00984         ASSERT(map, "null");
00985 
00986         const char * id = map->getId();
00987         ASSERT(id, "null id for gamepad mapping");
00988 
00989         // don't check for collisions -- IDs should be unique
00990         m_mappings[id] = map;
00991 }
00992 
00993 
00994 
00995 Manager::eResult
00996 Mgr::createGamepad
00997 (
00998 IN smart_ptr<SourceDevice>& device,
00999 IN smart_ptr<Map>& map,
01000 OUT smart_ptr<Gamepad>& gamepad
01001 )
01002 {
01003         ASSERT(device, "null");
01004         ASSERT(map, "null");
01005         gamepad = NULL;         // initialize output
01006 
01007         // verify we recognize this type
01008         const char * typeId = map->getTypeId();
01009         DPRINTF("Creating gamepad from mapping with type=%s", typeId);
01010         ASSERT(typeId, "bad type id");
01011 
01012         map_type_t::iterator i = m_types.find(typeId);
01013         ASSERT_THROW(m_types.end() != i,
01014             "Cannot create gamepad since type specified in mapping is not "
01015             "recognized.  Mapping name: '" << map->getName() << "', type id: '"
01016             << typeId << "'");
01017         Type * type = i->second;
01018 ASSERT(type, "null type object in type map?");
01019 
01020         // do any gamepads already use this source + mapping?
01021         if (sourceAndMapInUse(this, device->getUniqueId(), map->getId())) {
01022                 DPRINTF("  Cannot create gamepad: source and map already used");
01023                 return Manager::eResult_SourceInUse;
01024         }
01025 
01026         // okay, create gamepad of this type, with device and mapping
01027         smart_ptr<GPad> gpad = new GPad;
01028         ASSERT(gpad, "out of memory");
01029         gpad->initialize(type, device, map);
01030 
01031         // hand over (and downcast)
01032         gamepad = gpad;
01033 
01034         // store ourselves
01035         m_gamepads[gamepad->getId()] = gamepad;
01036 
01037         return Manager::eResult_Success;
01038 }
01039 
01040 
01041 
01042 int
01043 Mgr::getGamepadCount
01044 (
01045 void
01046 )
01047 {
01048         return m_gamepads.size();
01049 }
01050 
01051 
01052 
01053 smart_ptr<Gamepad>
01054 Mgr::getGamepad
01055 (
01056 IN int index
01057 )
01058 {
01059         ASSERT(index >= 0, "invalid gamepad index: %d", index);
01060 
01061         for (gamepad_map_t::iterator i = m_gamepads.begin();
01062              index >= 0 && i != m_gamepads.end(); ++i, --index) {
01063                 if (!index)
01064                         return i->second;
01065         }
01066 
01067         // not found
01068         return NULL;
01069 }
01070 
01071 
01072 
01073 smart_ptr<Gamepad>
01074 Mgr::getGamepad
01075 (
01076 IN const char * id
01077 )
01078 {
01079         ASSERT(id, "null");
01080 
01081         gamepad_map_t::iterator i = m_gamepads.find(id);
01082         if (m_gamepads.end() == i) {
01083                 DPRINTF("Gamepad not found, id='%s'", id);
01084                 return NULL;
01085         }
01086 
01087         return i->second;
01088 }
01089 
01090 
01091 
01092 bool
01093 Mgr::deleteGamepad
01094 (
01095 IN const char * id
01096 )
01097 {
01098         ASSERT(id, "null");
01099 
01100         gamepad_map_t::iterator i = m_gamepads.find(id);
01101         if (m_gamepads.end() == i) {
01102                 DPRINTF("Gamepad not found, id='%s'", id);
01103                 return false;
01104         }
01105 
01106         m_gamepads.erase(i);
01107         return true;
01108 }
01109 
01110 
01111 
01112 void
01113 Mgr::update
01114 (
01115 void
01116 )
01117 {
01118         for (device_map_t::iterator i = m_devices.begin(); i != m_devices.end();
01119              ++i) {
01120                 SourceDevice * device = i->second;
01121                 ASSERT(device, "null");
01122 
01123                 device->poll();
01124         }
01125 }
01126 
01127 
01128 
01129 ////////////////////////////////////////////////////////////////////////////////
01130 //
01131 //      public API
01132 //
01133 ////////////////////////////////////////////////////////////////////////////////
01134 
01135 smart_ptr<Manager>
01136 Manager::create
01137 (
01138 IN smart_ptr<nstream::Folder>& dataDirectory
01139 )
01140 {
01141         ASSERT(dataDirectory, "null");
01142 
01143         smart_ptr<Mgr> local = new Mgr;
01144         ASSERT(local, "out of memory");
01145 
01146         local->initialize(dataDirectory);
01147 
01148         return local;
01149 }
01150 
01151 
01152 
01153 void
01154 getRecommendedMappings
01155 (
01156 IN Manager * mgr,
01157 IN SourceDevice * device,
01158 OUT VecString& mapNames
01159 )
01160 {
01161         ASSERT(mgr, "null");
01162         ASSERT(device, "null");
01163         mapNames.clear();
01164 
01165         // what is the public name?
01166         const char * devName = device->getPublicName();
01167         ASSERT(devName, "null");
01168 //      DPRINTF("Determining recommended mappings for device: '%s'", devName);
01169 
01170         // loop through all mappings
01171         int nMaps = mgr->getMappingCount();
01172         for (int i = 0; i < nMaps; ++i) {
01173                 smart_ptr<Map> mapping = mgr->getMapping(i);
01174                 ASSERT(mapping, "null");
01175 
01176                 // get the list of devices supported by this mapping
01177                 const VecString& mapDevNames = mapping->getDeviceNames();
01178                 for (VecString::const_iterator j = mapDevNames.begin();
01179                      j != mapDevNames.end(); ++j) {
01180                         if (*j == devName) {
01181                                 // mapping claims to support this device!
01182                                 const char * id = mapping->getId();
01183                                 ASSERT(id, "null");
01184                                 mapNames.push_back(id);
01185                         }
01186                 }
01187         }
01188 //      DPRINTF("  Found %d mappings that support device",
01189 //          (int) mapNames.size());
01190 }
01191 
01192 
01193 
01194 void
01195 autoconfigureGamepads
01196 (
01197 IN Manager * mgr
01198 )
01199 {
01200         ASSERT(mgr, "null");
01201 
01202         DPRINTF("Attempting to autoconfigure gamepads...");
01203 
01204         // loop through all discovered source devices
01205         int nDevices = mgr->getSourceDeviceCount();
01206         for (int i = 0; i < nDevices; ++i) {
01207                 smart_ptr<SourceDevice> device = mgr->getSourceDevice(i);
01208                 if (!device) {
01209                         DPRINTF("Source device %d is no longer available", i);
01210                         continue;
01211                 }
01212 
01213                 VecString names;
01214                 getRecommendedMappings(mgr, device, names);
01215 
01216                 DPRINTF("  Seeing if I can autoconfigure device: '%s'",
01217                     device->getPublicName());
01218                 int nMappings = names.size();
01219                 DPRINTF("    %d recommended mappings found", nMappings);
01220                 if (nMappings < 1) {
01221                         continue;       // no recommendations for this one
01222                 }
01223                 if (nMappings > 1) {
01224                         DPRINTF("    Found %d recommended mappings.",
01225                             nMappings);
01226                         DPRINTF("    I'll use the first one that works.");
01227                 }
01228                 smart_ptr<Map> map;
01229                 for (int j = 0; j < nMappings; ++j) {
01230                         const char * mapName = names[j].c_str();
01231                         DPRINTF("    Trying mapping: %d='%s'", j, mapName);
01232                         map = mgr->getMapping(mapName);
01233                         if (map)
01234                                 break;
01235 
01236                         DPRINTF("      ...could not generate mapping");
01237                 }
01238                 if (!map) {
01239                         DPRINTF("    No mappings worked!  Skipping device.");
01240                         continue;
01241                 }
01242 
01243                 // attempt to create!
01244                 smart_ptr<Gamepad> gamepad;
01245                 Manager::eResult result =
01246                     mgr->createGamepad(device, map, gamepad);
01247                 if (Manager::eResult_Success == result) {
01248                         DPRINTF("    Autoconfigured gamepad!");
01249                 } else if (Manager::eResult_SourceInUse == result) {
01250                         DPRINTF("    (this gamepad is already configured)");
01251                 } else {
01252                         DPRINTF("    Autoconfig failed, reason: %d", result);
01253                 }
01254         }
01255 }
01256 
01257 
01258 
01259 };      // gamepad namespace
01260