00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "gamepad-type.h"
00036
00037 #include "common/wave_ex.h"
00038 #include "datahash/datahash_util.h"
00039 #include "datahash/datahash_text.h"
00040 #include "perf/perf.h"
00041 #include "util/file.h"
00042
00043
00044 namespace gamepad {
00045
00046
00047
00048 Type::~Type(void) throw() { }
00049
00050
00051 const char * s_extension = "gamepad";
00052
00053
00054 struct input_entry_t {
00055 eInputType type;
00056 const char * name;
00057 const char * key;
00058 };
00059
00060
00061 static const input_entry_t s_inputTypes[] = {
00062
00063
00064 { eInput_Button, "button", "button" },
00065 { eInput_Joystick, "joystick", "joystick" },
00066 { eInput_Pot, "potentiometer", "pot" },
00067 { eInput_Dpad, "directionalPad", "dpad" },
00068
00069
00070 { eInput_Invalid, NULL, NULL }
00071 };
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087 class GType : public Type {
00088 public:
00089
00090 GType(void) throw();
00091 ~GType(void) throw();
00092
00093
00094 void initialize(IN nstream::Stream * stream);
00095
00096
00097 const char * getId(void) const throw() { return m_id.c_str(); }
00098 const char * getName(void) const throw() { return m_name.c_str(); }
00099 int getInputCount(IN eInputType type) const throw();
00100 const char * getLogicalName(IN eInputType type,
00101 IN int idx) const throw();
00102 void getAllInputs(OUT VecString& names) const;
00103 eInputType getInputTypes(IN const char * logicalName) const throw();
00104 int getLogicalIndex(IN const char * logicalName,
00105 IN eInputType type) throw();
00106 const char * getMainButton(void) const throw();
00107 smart_ptr<nstream::Stream> getVgfx(void);
00108 void dump(void) const throw();
00109
00110 private:
00111
00112 typedef std::map<eInputType, smart_ptr<VecString> > type_names_t;
00113
00114 struct type_rec_t {
00115 type_rec_t(void) throw() { this->clear(); }
00116 void clear(void) throw() {
00117 types = eInput_Invalid;
00118 buttonIndex = joyIndex = potIndex = dpadIndex = -1;
00119 }
00120
00121
00122 eInputType types;
00123 int buttonIndex;
00124 int joyIndex;
00125 int potIndex;
00126 int dpadIndex;
00127 };
00128
00129 typedef std::map<std::string, type_rec_t> type_map_t;
00130
00131
00132 void addInputs(IN eInputType type,
00133 IN const VecString& names);
00134 int getIndex(IN eInputType type,
00135 IN const char * name);
00136
00137
00138 std::string m_id;
00139 std::string m_name;
00140 std::string m_mainButton;
00141 type_names_t m_names;
00142 type_map_t m_types;
00143 smart_ptr<nstream::File> m_vgfxFile;
00144 };
00145
00146
00147
00148 GType::GType(void)
00149 throw()
00150 {
00151 }
00152
00153
00154
00155 GType::~GType(void)
00156 throw()
00157 {
00158 }
00159
00160
00161
00162 void
00163 GType::initialize
00164 (
00165 IN nstream::Stream * stream
00166 )
00167 {
00168 ASSERT(stream, "null");
00169 ASSERT_THROW(stream->good(), "bad stream");
00170
00171
00172 std::istream& in = stream->getStream();
00173 ASSERT_THROW(in.good(), "bad stream?");
00174
00175 smart_ptr<Datahash> logical = readHashFromStream("(root)", in);
00176 ASSERT(logical, "null");
00177
00178
00179
00180 m_id = getString(logical, "id");
00181
00182
00183
00184 m_name = getString(logical, "name");
00185
00186
00187
00188 m_mainButton = getString(logical, "mainButton");
00189
00190
00191
00192 ASSERT(!m_vgfxFile, "already have vgfx file?");
00193 const char * vgfxFile = getOptionalString(logical, "vgfx", NULL);
00194 if (vgfxFile) {
00195 smart_ptr<nstream::File> file = stream->getFile();
00196 ASSERT(file, "null");
00197 const char * thisFile = file->getName();
00198
00199 std::string relPath = getPathRelativeTo(thisFile, vgfxFile);
00200
00201 smart_ptr<nstream::Manager> mgr = file->getManager();
00202 ASSERT(mgr, "null");
00203 m_vgfxFile = mgr->getEntry(relPath.c_str());
00204 }
00205
00206
00207 for (const input_entry_t * p = s_inputTypes; p->key; ++p) {
00208 smart_ptr<VecString> vec = new VecString;
00209 ASSERT(vec, "out of memory");
00210
00211
00212 if (!logical->count(p->key))
00213 continue;
00214
00215
00216 getStringValues(logical, p->key, *vec);
00217
00218
00219 m_names[p->type] = vec;
00220
00221
00222 this->addInputs(p->type, *vec);
00223 }
00224 }
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234 int
00235 GType::getInputCount
00236 (
00237 IN eInputType type
00238 )
00239 const
00240 throw()
00241 {
00242 type_names_t::const_iterator i = m_names.find(type);
00243 if (m_names.end() == i) {
00244 return 0;
00245 }
00246 ASSERT(i->second, "null vector in map");
00247 return i->second->size();
00248 }
00249
00250
00251
00252 const char *
00253 GType::getLogicalName
00254 (
00255 IN eInputType type,
00256 IN int idx
00257 )
00258 const
00259 throw()
00260 {
00261 ASSERT(idx >= 0, "Bad index: %d", idx);
00262
00263 type_names_t::const_iterator i = m_names.find(type);
00264 if (m_names.end() == i) {
00265 DPRINTF("cannot get logical name: no such type!");
00266 return NULL;
00267 }
00268 ASSERT(i->second, "null vector in map");
00269 ASSERT(idx < (int) i->second->size(),
00270 "Input index is too large: %d", idx);
00271
00272 return i->second->operator[](idx).c_str();
00273 }
00274
00275
00276
00277 void
00278 GType::getAllInputs
00279 (
00280 OUT VecString& logicalNames
00281 )
00282 const
00283 {
00284 logicalNames.clear();
00285
00286 for (type_map_t::const_iterator i = m_types.begin(); i != m_types.end();
00287 ++i) {
00288 logicalNames.push_back(i->first);
00289 }
00290 }
00291
00292
00293
00294 eInputType
00295 GType::getInputTypes
00296 (
00297 IN const char * logicalName
00298 )
00299 const
00300 throw()
00301 {
00302 ASSERT(logicalName, "null");
00303
00304 type_map_t::const_iterator i = m_types.find(logicalName);
00305 if (m_types.end() == i) {
00306
00307 return eInput_Invalid;
00308 }
00309 const type_rec_t& tr = i->second;
00310 ASSERT(eInput_Invalid != tr.types, "should be valid type");
00311
00312 return tr.types;
00313 }
00314
00315
00316
00317 int
00318 GType::getLogicalIndex
00319 (
00320 IN const char * logicalName,
00321 IN eInputType type
00322 )
00323 throw()
00324 {
00325 ASSERT(logicalName, "null");
00326
00327 type_map_t::iterator i = m_types.find(logicalName);
00328 if (m_types.end() == i) {
00329
00330 return -1;
00331 }
00332
00333 type_rec_t& tr = i->second;
00334 if (!(type & tr.types)) {
00335 DPRINTF("Logical name is not of correct type");
00336 return -1;
00337 }
00338
00339
00340 switch (type) {
00341 case eInput_Button:
00342 if (-1 == tr.buttonIndex) {
00343 tr.buttonIndex = getIndex(eInput_Button, logicalName);
00344 }
00345 return tr.buttonIndex;
00346
00347 case eInput_Joystick:
00348 if (-1 == tr.joyIndex) {
00349 tr.joyIndex = getIndex(eInput_Joystick, logicalName);
00350 }
00351 return tr.joyIndex;
00352
00353 case eInput_Pot:
00354 if (-1 == tr.potIndex) {
00355 tr.potIndex = getIndex(eInput_Pot, logicalName);
00356 }
00357 return tr.potIndex;
00358
00359 case eInput_Dpad:
00360 if (-1 == tr.dpadIndex) {
00361 tr.dpadIndex = getIndex(eInput_Dpad, logicalName);
00362 }
00363 return tr.dpadIndex;
00364
00365 default:
00366 ASSERT(false, "bad type: %d", type);
00367 }
00368
00369 ASSERT(false, "bad type: %d", type);
00370 return -1;
00371 }
00372
00373
00374
00375 const char *
00376 GType::getMainButton
00377 (
00378 void
00379 )
00380 const
00381 throw()
00382 {
00383 return m_mainButton.c_str();
00384 }
00385
00386
00387
00388 smart_ptr<nstream::Stream>
00389 GType::getVgfx
00390 (
00391 void
00392 )
00393 {
00394 if (!m_vgfxFile) {
00395 DPRINTF("Gamepad has no vector graphics file");
00396 return NULL;
00397 }
00398
00399
00400 smart_ptr<nstream::Stream> stream = m_vgfxFile->openStream();
00401 ASSERT(stream, "null");
00402 ASSERT_THROW(stream->good(), "bad stream?");
00403 return stream;
00404 }
00405
00406
00407
00408 void
00409 GType::dump
00410 (
00411 void
00412 )
00413 const
00414 throw()
00415 {
00416 DPRINTF("Gamepad type: %s", this->getName());
00417 DPRINTF(" Contains %d logical inputs", (int) m_types.size());
00418
00419 for (type_map_t::const_iterator i = m_types.begin(); i != m_types.end();
00420 ++i) {
00421 std::string out = i->first;
00422 out += ":";
00423 const type_rec_t& tr = i->second;
00424 for (const input_entry_t * p = s_inputTypes; p->key; ++p) {
00425 if (tr.types & p->type) {
00426 out += " ";
00427 out += p->name;
00428 }
00429 }
00430 DPRINTF(" %s", out.c_str());
00431 }
00432 }
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442 void
00443 GType::addInputs
00444 (
00445 IN eInputType type,
00446 IN const VecString& names
00447 )
00448 {
00449
00450 for (VecString::const_iterator i = names.begin(); i != names.end();
00451 ++i) {
00452 const char * name = i->c_str();
00453 type_map_t::iterator k = m_types.find(name);
00454 if (m_types.end() == k) {
00455
00456 type_rec_t tr;
00457 tr.types = type;
00458 m_types[name] = tr;
00459 } else {
00460
00461 type_rec_t& tr = k->second;
00462 tr.types = (eInputType) (tr.types | type);
00463 }
00464 }
00465 }
00466
00467
00468
00469 int
00470 GType::getIndex
00471 (
00472 IN eInputType type,
00473 IN const char * logicalName
00474 )
00475 {
00476 ASSERT(eInput_Invalid != type, "invalid type");
00477 ASSERT(logicalName, "null");
00478
00479 type_names_t::iterator i = m_names.find(type);
00480 ASSERT_THROW(m_names.end() != i, "bad type: " << type);
00481
00482 const VecString * names = i->second;
00483 ASSERT(names, "null");
00484 int nNames = names->size();
00485 for (int j = 0; j < nNames; ++j) {
00486 const char * name = names->operator[](j).c_str();
00487 if (!strcmp(name, logicalName)) {
00488 return j;
00489 }
00490 }
00491
00492
00493 ASSERT(false, "logical name not in type list");
00494 return -1;
00495 }
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505 smart_ptr<Type>
00506 readType
00507 (
00508 IN nstream::Stream * stream
00509 )
00510 {
00511 ASSERT(stream, "null");
00512
00513
00514 smart_ptr<GType> local = new GType;
00515 ASSERT(local, "out of memory");
00516 local->initialize(stream);
00517
00518
00519 return local;
00520 }
00521
00522
00523
00524 void
00525 addGamepadTypesInFolderToMap
00526 (
00527 IO nstream::Folder * folder,
00528 IO gamepad_type_map_t& map
00529 )
00530 {
00531 ASSERT(folder, "null");
00532
00533
00534 folder->resetIteration();
00535 for (;;) {
00536 smart_ptr<nstream::Entry> entry = folder->getNextChild();
00537 if (!entry)
00538 break;
00539
00540
00541 smart_ptr<nstream::File> file = entry;
00542 if (!file)
00543 continue;
00544
00545
00546 if (!hasExtension(file->getName(), s_extension))
00547 continue;
00548
00549
00550 smart_ptr<nstream::Stream> stream = file->openStream();
00551
00552 try {
00553 THROW(stream, "failed to open stream");
00554 THROW(stream->good(), "bad stream");
00555
00556 smart_ptr<Type> gt = readType(stream);
00557 THROW(gt, "null gamepad type object returned");
00558 map[gt->getName()] = gt;
00559
00560 } catch (std::exception& e) {
00561 WAVE_EX(wex);
00562 wex << "Failed to read gamepad stream: '";
00563 wex << file->getName() << "' in folder '";
00564 wex << folder->getName() << "'\n";
00565 wex << e.what();
00566 }
00567 }
00568 }
00569
00570
00571
00572 };
00573