actionMap.cc 78 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "input/actionMap.h"
  23. #include "platform/event.h"
  24. #include "console/console.h"
  25. #include "platform/platform.h"
  26. #include "platform/platformInput.h"
  27. #include "platform/platformAssert.h"
  28. #include "io/fileStream.h"
  29. #include "io/resource/resourceManager.h"
  30. IMPLEMENT_CONOBJECT(ActionMap);
  31. // This is used for determing keys that have ascii codes for the foreign keyboards. IsAlpha doesn't work on foreign keys.
  32. #define dIsDecentChar(c) (((char(0xa0) <= (c)) && ((c) <= char(0xff))) || (( char(0x21) <= (c)) && ((c) <= char(0x7e))) || (( char(0x91) <= (c)) && ((c) <= char(0x92))))
  33. struct CodeMapping
  34. {
  35. const char* pDescription;
  36. U8 type;
  37. U32 code;
  38. };
  39. struct AsciiMapping
  40. {
  41. const char* pDescription;
  42. U16 asciiCode;
  43. };
  44. extern CodeMapping gVirtualMap[];
  45. extern AsciiMapping gAsciiMap[];
  46. //------------------------------------------------------------------------------
  47. //-------------------------------------- Action maps
  48. //
  49. Vector<ActionMap::BreakEntry> ActionMap::smBreakTable(__FILE__, __LINE__);
  50. //------------------------------------------------------------------------------
  51. ActionMap::ActionMap()
  52. {
  53. VECTOR_SET_ASSOCIATION(mDeviceMaps);
  54. }
  55. //------------------------------------------------------------------------------
  56. ActionMap::~ActionMap()
  57. {
  58. for (U32 i = 0; i < (U32)mDeviceMaps.size(); i++)
  59. delete mDeviceMaps[i];
  60. mDeviceMaps.clear();
  61. }
  62. //------------------------------------------------------------------------------
  63. ActionMap::DeviceMap::~DeviceMap()
  64. {
  65. for(U32 i = 0; i < (U32)nodeMap.size(); i++)
  66. {
  67. dFree(nodeMap[i].makeConsoleCommand);
  68. dFree(nodeMap[i].breakConsoleCommand);
  69. }
  70. }
  71. //------------------------------------------------------------------------------
  72. bool ActionMap::onAdd()
  73. {
  74. if (Parent::onAdd() == false)
  75. return false;
  76. Sim::getActionMapGroup()->addObject(this);
  77. return true;
  78. }
  79. //--------------------------------------------------------------------------
  80. void ActionMap::dumpActionMap(const char* fileName, const bool append) const
  81. {
  82. if (fileName != NULL) {
  83. // Dump the deletion, and creation script commands, followed by all the binds
  84. // to a script.
  85. FileStream iostrm;
  86. if ( !ResourceManager->openFileForWrite( iostrm, fileName, append ? FileStream::WriteAppend : FileStream::Write ) )
  87. {
  88. Con::errorf( "Unable to open file '%s' for writing.", fileName );
  89. return;
  90. }
  91. char lineBuffer[1024];
  92. if ( append )
  93. iostrm.setPosition( iostrm.getStreamSize() );
  94. else
  95. {
  96. // IMPORTANT -- do NOT change the following line, it identifies the file as an input map file
  97. dStrcpy( lineBuffer, "// Torque Input Map File\n" );
  98. iostrm.write( dStrlen( lineBuffer ), lineBuffer );
  99. }
  100. dSprintf(lineBuffer, 1023, "if (isObject(%s)) %s.delete();\n"
  101. "new ActionMap(%s);\n", getName(), getName(), getName());
  102. iostrm.write(dStrlen(lineBuffer), lineBuffer);
  103. // Dump all the binds to the console...
  104. for (S32 i = 0; i < mDeviceMaps.size(); i++) {
  105. const DeviceMap* pDevMap = mDeviceMaps[i];
  106. char devbuffer[32];
  107. getDeviceName(pDevMap->deviceType, pDevMap->deviceInst, devbuffer);
  108. for (S32 j = 0; j < pDevMap->nodeMap.size(); j++) {
  109. const Node& rNode = pDevMap->nodeMap[j];
  110. const char* pModifierString = getModifierString(rNode.modifiers);
  111. char objectbuffer[64];
  112. if (getKeyString(rNode.action, objectbuffer) == false)
  113. continue;
  114. const char* command = (rNode.flags & Node::BindCmd) ? "bindCmd" : "bind";
  115. dSprintf(lineBuffer, 1023, "%s.%s(%s, \"%s%s\"",
  116. getName(),
  117. command,
  118. devbuffer,
  119. pModifierString, objectbuffer);
  120. if (rNode.flags & (Node::HasScale|Node::HasDeadZone|Node::Ranged|Node::Inverted)) {
  121. char buff[10];
  122. U32 curr = 0;
  123. buff[curr++] = ',';
  124. buff[curr++] = ' ';
  125. if (rNode.flags & Node::HasScale)
  126. buff[curr++] = 'S';
  127. if (rNode.flags & Node::Ranged)
  128. buff[curr++] = 'R';
  129. if (rNode.flags & Node::HasDeadZone)
  130. buff[curr++] = 'D';
  131. if (rNode.flags & Node::Inverted)
  132. buff[curr++] = 'I';
  133. buff[curr] = '\0';
  134. dStrcat(lineBuffer, buff);
  135. }
  136. if (rNode.flags & Node::HasDeadZone) {
  137. char buff[64];
  138. dSprintf(buff, 63, ", \"%g %g\"", rNode.deadZoneBegin, rNode.deadZoneEnd);
  139. dStrcat(lineBuffer, buff);
  140. }
  141. if (rNode.flags & Node::HasScale) {
  142. char buff[64];
  143. dSprintf(buff, 63, ", %g", rNode.scaleFactor);
  144. dStrcat(lineBuffer, buff);
  145. }
  146. if (rNode.flags & Node::BindCmd) {
  147. if (rNode.makeConsoleCommand) {
  148. dStrcat(lineBuffer, ", \"");
  149. U32 pos = dStrlen(lineBuffer);
  150. expandEscape(lineBuffer + pos, rNode.makeConsoleCommand);
  151. dStrcat(lineBuffer, "\"");
  152. } else {
  153. dStrcat(lineBuffer, ", \"\"");
  154. }
  155. if (rNode.breakConsoleCommand) {
  156. dStrcat(lineBuffer, ", \"");
  157. U32 pos = dStrlen(lineBuffer);
  158. expandEscape(lineBuffer + pos, rNode.breakConsoleCommand);
  159. dStrcat(lineBuffer, "\"");
  160. }
  161. else
  162. dStrcat(lineBuffer, ", \"\"");
  163. } else {
  164. dStrcat(lineBuffer, ", ");
  165. dStrcat(lineBuffer, rNode.consoleFunction);
  166. }
  167. dStrcat(lineBuffer, ");\n");
  168. iostrm.write(dStrlen(lineBuffer), lineBuffer);
  169. }
  170. }
  171. iostrm.close();
  172. }
  173. else {
  174. // Dump all the binds to the console...
  175. for (S32 i = 0; i < mDeviceMaps.size(); i++) {
  176. const DeviceMap* pDevMap = mDeviceMaps[i];
  177. char devbuffer[32];
  178. getDeviceName(pDevMap->deviceType, pDevMap->deviceInst, devbuffer);
  179. for (S32 j = 0; j < pDevMap->nodeMap.size(); j++) {
  180. const Node& rNode = pDevMap->nodeMap[j];
  181. const char* pModifierString = getModifierString(rNode.modifiers);
  182. char keybuffer[64];
  183. if (getKeyString(rNode.action, keybuffer) == false)
  184. continue;
  185. const char* command = (rNode.flags & Node::BindCmd) ? "bindCmd" : "bind";
  186. char finalBuffer[1024];
  187. dSprintf(finalBuffer, 1023, "%s.%s(%s, \"%s%s\"",
  188. getName(),
  189. command,
  190. devbuffer,
  191. pModifierString, keybuffer);
  192. if (rNode.flags & (Node::HasScale|Node::HasDeadZone|Node::Ranged|Node::Inverted)) {
  193. char buff[10];
  194. U32 curr = 0;
  195. buff[curr++] = ',';
  196. buff[curr++] = ' ';
  197. if (rNode.flags & Node::HasScale)
  198. buff[curr++] = 'S';
  199. if (rNode.flags & Node::Ranged)
  200. buff[curr++] = 'R';
  201. if (rNode.flags & Node::HasDeadZone)
  202. buff[curr++] = 'D';
  203. if (rNode.flags & Node::Inverted)
  204. buff[curr++] = 'I';
  205. buff[curr] = '\0';
  206. dStrcat(finalBuffer, buff);
  207. }
  208. if (rNode.flags & Node::HasDeadZone) {
  209. char buff[64];
  210. dSprintf(buff, 63, ", \"%g %g\"", rNode.deadZoneBegin, rNode.deadZoneEnd);
  211. dStrcat(finalBuffer, buff);
  212. }
  213. if (rNode.flags & Node::HasScale) {
  214. char buff[64];
  215. dSprintf(buff, 63, ", %g", rNode.scaleFactor);
  216. dStrcat(finalBuffer, buff);
  217. }
  218. if (rNode.flags & Node::BindCmd) {
  219. if (rNode.makeConsoleCommand) {
  220. dStrcat(finalBuffer, ", \"");
  221. dStrcat(finalBuffer, rNode.makeConsoleCommand);
  222. dStrcat(finalBuffer, "\"");
  223. } else {
  224. dStrcat(finalBuffer, ", \"\"");
  225. }
  226. if (rNode.breakConsoleCommand) {
  227. dStrcat(finalBuffer, ", \"");
  228. dStrcat(finalBuffer, rNode.breakConsoleCommand);
  229. dStrcat(finalBuffer, "\"");
  230. }
  231. else
  232. dStrcat(finalBuffer, ", \"\"");
  233. } else {
  234. dStrcat(finalBuffer, ", ");
  235. dStrcat(finalBuffer, rNode.consoleFunction);
  236. }
  237. dStrcat(finalBuffer, ");");
  238. Con::printf(finalBuffer);
  239. }
  240. }
  241. }
  242. }
  243. //--------------------------------------------------------------------------
  244. bool ActionMap::createEventDescriptor(const char* pEventString, EventDescriptor* pDescriptor)
  245. {
  246. char copyBuffer[256];
  247. dStrcpy(copyBuffer, pEventString);
  248. // Do we have modifiers?
  249. char* pSpace = dStrchr(copyBuffer, ' ');
  250. char* pObjectString;
  251. if (pSpace != NULL) {
  252. // Yes. Parse them out...
  253. //
  254. pDescriptor->flags = 0;
  255. pObjectString = pSpace + 1;
  256. pSpace[0] = '\0';
  257. char* pModifier = dStrtok(copyBuffer, "-");
  258. while (pModifier != NULL) {
  259. if (dStricmp(pModifier, "shift") == 0) {
  260. pDescriptor->flags |= SI_SHIFT;
  261. } else if (dStricmp(pModifier, "ctrl") == 0) {
  262. pDescriptor->flags |= SI_CTRL;
  263. } else if (dStricmp(pModifier, "alt") == 0) {
  264. pDescriptor->flags |= SI_ALT;
  265. } else if (dStricmp(pModifier, "cmd") == 0) {
  266. pDescriptor->flags |= SI_ALT;
  267. } else if (dStricmp(pModifier, "opt") == 0) {
  268. pDescriptor->flags |= SI_MAC_OPT;
  269. }
  270. pModifier = dStrtok(NULL, "-");
  271. }
  272. } else {
  273. // No.
  274. pDescriptor->flags = 0;
  275. pObjectString = copyBuffer;
  276. }
  277. // Now we need to map the key string to the proper KEY code from event.h
  278. //
  279. AssertFatal(dStrlen(pObjectString) != 0, "Error, no key was specified!");
  280. if (dStrlen(pObjectString) == 1)
  281. {
  282. if (dIsDecentChar(*pObjectString)) // includes foreign chars
  283. {
  284. U16 asciiCode = (*pObjectString);
  285. // clear out the FF in upper 8bits for foreign keys??
  286. asciiCode &= 0xFF;
  287. U16 keyCode = Input::getKeyCode(asciiCode);
  288. if ( keyCode >= KEY_0 )
  289. {
  290. pDescriptor->eventType = SI_KEY;
  291. pDescriptor->eventCode = keyCode;
  292. return true;
  293. }
  294. else if (dIsalpha(*pObjectString) == true)
  295. {
  296. pDescriptor->eventType = SI_KEY;
  297. pDescriptor->eventCode = KEY_A+dTolower(*pObjectString)-'a';
  298. return true;
  299. }
  300. else if (dIsdigit(*pObjectString) == true)
  301. {
  302. pDescriptor->eventType = SI_KEY;
  303. pDescriptor->eventCode = KEY_0+(*pObjectString)-'0';
  304. return true;
  305. }
  306. }
  307. return false;
  308. }
  309. else
  310. {
  311. pDescriptor->eventCode = 0;
  312. // Gotta search through the Ascii table...
  313. for (U16 i = 0; gAsciiMap[i].asciiCode != 0xFFFF; i++)
  314. {
  315. if (dStricmp(pObjectString, gAsciiMap[i].pDescription) == 0)
  316. {
  317. U16 asciiCode = gAsciiMap[i].asciiCode;
  318. U16 keyCode = Input::getKeyCode(asciiCode);
  319. if ( keyCode >= KEY_0 )
  320. {
  321. pDescriptor->eventType = SI_KEY;
  322. pDescriptor->eventCode = keyCode;
  323. return(true);
  324. }
  325. else
  326. {
  327. break;
  328. }
  329. }
  330. }
  331. // Didn't find an ascii match. Check the virtual map table
  332. for (U32 j = 0; gVirtualMap[j].code != 0xFFFFFFFF; j++)
  333. {
  334. if (dStricmp(pObjectString, gVirtualMap[j].pDescription) == 0)
  335. {
  336. pDescriptor->eventType = gVirtualMap[j].type;
  337. pDescriptor->eventCode = gVirtualMap[j].code;
  338. return true;
  339. }
  340. }
  341. }
  342. return false;
  343. }
  344. //------------------------------------------------------------------------------
  345. ActionMap::Node* ActionMap::getNode(const U32 inDeviceType, const U32 inDeviceInst,
  346. const U32 inModifiers, const U32 inAction,SimObject* object /*= NULL*/)
  347. {
  348. // DMMTODO - Slow INITIAL implementation. Replace with a faster version...
  349. //
  350. DeviceMap* pDeviceMap = NULL;
  351. U32 i;
  352. for (i = 0; i < (U32)mDeviceMaps.size(); i++)
  353. {
  354. if (mDeviceMaps[i]->deviceType == inDeviceType &&
  355. mDeviceMaps[i]->deviceInst == inDeviceInst) {
  356. pDeviceMap = mDeviceMaps[i];
  357. break;
  358. }
  359. }
  360. if (pDeviceMap == NULL)
  361. {
  362. mDeviceMaps.increment();
  363. mDeviceMaps.last() = new DeviceMap;
  364. pDeviceMap = mDeviceMaps.last();
  365. pDeviceMap->deviceInst = inDeviceInst;
  366. pDeviceMap->deviceType = inDeviceType;
  367. }
  368. for (i = 0; i < (U32)pDeviceMap->nodeMap.size(); i++)
  369. {
  370. if (pDeviceMap->nodeMap[i].modifiers == inModifiers &&
  371. pDeviceMap->nodeMap[i].action == inAction &&
  372. ( (object != NULL) ? object == pDeviceMap->nodeMap[i].object : true )) // Check for an object match if the object exists
  373. {
  374. return &pDeviceMap->nodeMap[i];
  375. }
  376. }
  377. // If we're here, the node doesn't exist. create it.
  378. pDeviceMap->nodeMap.increment();
  379. Node* pRetNode = &pDeviceMap->nodeMap.last();
  380. pRetNode->modifiers = inModifiers;
  381. pRetNode->action = inAction;
  382. pRetNode->flags = 0;
  383. pRetNode->deadZoneBegin = 0.0;
  384. pRetNode->deadZoneEnd = 0.0;
  385. pRetNode->scaleFactor = 1.0;
  386. pRetNode->consoleFunction = NULL;
  387. pRetNode->makeConsoleCommand = NULL;
  388. pRetNode->breakConsoleCommand = NULL;
  389. //[neob, 5/7/2007 - #2975]
  390. pRetNode->object = 0;
  391. return pRetNode;
  392. }
  393. //------------------------------------------------------------------------------
  394. void ActionMap::removeNode(const U32 inDeviceType, const U32 inDeviceInst, const U32 inModifiers, const U32 inAction, SimObject* object /*= NULL*/)
  395. {
  396. // DMMTODO - Slow INITIAL implementation. Replace with a faster version...
  397. //
  398. DeviceMap* pDeviceMap = NULL;
  399. U32 i;
  400. for (i = 0; i < (U32)mDeviceMaps.size(); i++) {
  401. if (mDeviceMaps[i]->deviceType == inDeviceType &&
  402. mDeviceMaps[i]->deviceInst == inDeviceInst) {
  403. pDeviceMap = mDeviceMaps[i];
  404. break;
  405. }
  406. }
  407. if (pDeviceMap == NULL)
  408. return;
  409. U32 realMods = inModifiers;
  410. if (realMods & SI_SHIFT)
  411. realMods |= SI_SHIFT;
  412. if (realMods & SI_CTRL)
  413. realMods |= SI_CTRL;
  414. if (realMods & SI_ALT)
  415. realMods |= SI_ALT;
  416. if (realMods & SI_MAC_OPT)
  417. realMods |= SI_MAC_OPT;
  418. for (i = 0; i < (U32)pDeviceMap->nodeMap.size(); i++) {
  419. if (pDeviceMap->nodeMap[i].modifiers == realMods &&
  420. pDeviceMap->nodeMap[i].action == inAction &&
  421. ( (object != NULL) ? object == pDeviceMap->nodeMap[i].object : true ))
  422. {
  423. dFree(pDeviceMap->nodeMap[i].makeConsoleCommand);
  424. dFree(pDeviceMap->nodeMap[i].breakConsoleCommand);
  425. pDeviceMap->nodeMap.erase(i);
  426. }
  427. }
  428. }
  429. //------------------------------------------------------------------------------
  430. const ActionMap::Node* ActionMap::findNode(const U32 inDeviceType, const U32 inDeviceInst,
  431. const U32 inModifiers, const U32 inAction)
  432. {
  433. // DMMTODO - Slow INITIAL implementation. Replace with a faster version...
  434. //
  435. DeviceMap* pDeviceMap = NULL;
  436. U32 i;
  437. for (i = 0; i < (U32)mDeviceMaps.size(); i++)
  438. {
  439. if (mDeviceMaps[i]->deviceType == inDeviceType && mDeviceMaps[i]->deviceInst == inDeviceInst)
  440. {
  441. pDeviceMap = mDeviceMaps[i];
  442. break;
  443. }
  444. }
  445. if (pDeviceMap == NULL)
  446. return NULL;
  447. U32 realMods = inModifiers;
  448. if (realMods & SI_SHIFT)
  449. realMods |= SI_SHIFT;
  450. if (realMods & SI_CTRL)
  451. realMods |= SI_CTRL;
  452. if (realMods & SI_ALT)
  453. realMods |= SI_ALT;
  454. if (realMods & SI_MAC_OPT)
  455. realMods |= SI_MAC_OPT;
  456. for (i = 0; i < (U32)pDeviceMap->nodeMap.size(); i++)
  457. {
  458. if (pDeviceMap->nodeMap[i].action == KEY_ANYKEY && pDeviceMap->nodeMap[i].modifiers == realMods && dIsDecentChar(inAction))
  459. return &pDeviceMap->nodeMap[i];
  460. else if (pDeviceMap->nodeMap[i].modifiers == realMods && pDeviceMap->nodeMap[i].action == inAction)
  461. return &pDeviceMap->nodeMap[i];
  462. }
  463. return NULL;
  464. }
  465. //------------------------------------------------------------------------------
  466. bool ActionMap::findBoundNode( const char* function, U32 &devMapIndex, U32 &nodeIndex )
  467. {
  468. devMapIndex = 0;
  469. nodeIndex = 0;
  470. return nextBoundNode( function, devMapIndex, nodeIndex );
  471. }
  472. bool ActionMap::nextBoundNode( const char* function, U32 &devMapIndex, U32 &nodeIndex )
  473. {
  474. // Loop through all of the existing nodes to find the one mapped to the
  475. // given function:
  476. for ( U32 i = devMapIndex; i < (U32)mDeviceMaps.size(); i++ )
  477. {
  478. const DeviceMap* dvcMap = mDeviceMaps[i];
  479. for ( U32 j = nodeIndex; j < (U32)dvcMap->nodeMap.size(); j++ )
  480. {
  481. const Node* node = &dvcMap->nodeMap[j];
  482. if ( !( node->flags & Node::BindCmd ) && ( dStricmp( function, node->consoleFunction ) == 0 ) )
  483. {
  484. devMapIndex = i;
  485. nodeIndex = j;
  486. return( true );
  487. }
  488. }
  489. nodeIndex = 0;
  490. }
  491. return( false );
  492. }
  493. //------------------------------------------------------------------------------
  494. bool ActionMap::processUnbind(const char *device, const char *action, SimObject* object /*= NULL*/)
  495. {
  496. U32 deviceType;
  497. U32 deviceInst;
  498. if(!getDeviceTypeAndInstance(device, deviceType, deviceInst))
  499. return false;
  500. EventDescriptor eventDescriptor;
  501. if (!createEventDescriptor(action, &eventDescriptor))
  502. return false;
  503. removeNode(deviceType, deviceInst, eventDescriptor.flags,eventDescriptor.eventCode, object);
  504. return true;
  505. }
  506. //------------------------------------------------------------------------------
  507. // This function is for the use of the control remapper.
  508. // It will only check against the console function (since all remappable commands are
  509. // bound using bind and not bindCmd).
  510. //
  511. const char* ActionMap::getBinding( const char* command )
  512. {
  513. char* returnString = Con::getReturnBuffer( 1024 );
  514. returnString[0] = 0;
  515. char buffer[256];
  516. char deviceBuffer[32];
  517. char keyBuffer[64];
  518. U32 devMapIndex = 0, nodeIndex = 0;
  519. while ( nextBoundNode( command, devMapIndex, nodeIndex ) )
  520. {
  521. const DeviceMap* deviceMap = mDeviceMaps[devMapIndex];
  522. if ( getDeviceName( deviceMap->deviceType, deviceMap->deviceInst, deviceBuffer ) )
  523. {
  524. const Node* node = &deviceMap->nodeMap[nodeIndex];
  525. const char* modifierString = getModifierString( node->modifiers );
  526. if ( getKeyString( node->action, keyBuffer ) )
  527. {
  528. dSprintf( buffer, sizeof( buffer ), "%s\t%s%s", deviceBuffer, modifierString, keyBuffer );
  529. if ( returnString[0] )
  530. dStrcat( returnString, "\t" );
  531. dStrcat( returnString, buffer );
  532. }
  533. }
  534. ++nodeIndex;
  535. }
  536. return returnString;
  537. }
  538. //------------------------------------------------------------------------------
  539. // This function is for the use of the control remapper.
  540. // The intent of this function is to determine if the given event descriptor is already
  541. // bound in this action map. If so, this function returns the command it is bound to.
  542. // If not, it returns NULL.
  543. //
  544. const char* ActionMap::getCommand( const char* device, const char* action )
  545. {
  546. U32 deviceType;
  547. U32 deviceInst;
  548. if ( getDeviceTypeAndInstance( device, deviceType, deviceInst ) )
  549. {
  550. EventDescriptor eventDescriptor;
  551. if ( createEventDescriptor( action, &eventDescriptor ) )
  552. {
  553. const ActionMap::Node* mapNode = findNode( deviceType, deviceInst, eventDescriptor.flags, eventDescriptor.eventCode );
  554. if ( mapNode )
  555. {
  556. if ( mapNode->flags & Node::BindCmd )
  557. {
  558. S32 bufferLen = dStrlen( mapNode->makeConsoleCommand ) + dStrlen( mapNode->breakConsoleCommand ) + 2;
  559. char* returnString = Con::getReturnBuffer( bufferLen );
  560. dSprintf( returnString, bufferLen, "%s\t%s",
  561. ( mapNode->makeConsoleCommand ? mapNode->makeConsoleCommand : "" ),
  562. ( mapNode->breakConsoleCommand ? mapNode->breakConsoleCommand : "" ) );
  563. return( returnString );
  564. }
  565. else
  566. return( mapNode->consoleFunction );
  567. }
  568. }
  569. }
  570. return( "" );
  571. }
  572. //------------------------------------------------------------------------------
  573. // This function returns whether or not the mapping specified is inverted.
  574. // Obviously, this should only be used for axes.
  575. bool ActionMap::isInverted( const char* device, const char* action )
  576. {
  577. U32 deviceType;
  578. U32 deviceInst;
  579. if ( getDeviceTypeAndInstance( device, deviceType, deviceInst ) )
  580. {
  581. EventDescriptor eventDescriptor;
  582. if ( createEventDescriptor( action, &eventDescriptor ) )
  583. {
  584. const ActionMap::Node* mapNode = findNode( deviceType, deviceInst, eventDescriptor.flags, eventDescriptor.eventCode );
  585. if ( mapNode )
  586. return( mapNode->flags & Node::Inverted );
  587. }
  588. }
  589. Con::errorf( "The input event specified by %s %s is not in this action map!", device, action );
  590. return( false );
  591. }
  592. //------------------------------------------------------------------------------
  593. F32 ActionMap::getScale( const char* device, const char* action )
  594. {
  595. U32 deviceType;
  596. U32 deviceInst;
  597. if ( getDeviceTypeAndInstance( device, deviceType, deviceInst ) )
  598. {
  599. EventDescriptor eventDescriptor;
  600. if ( createEventDescriptor( action, &eventDescriptor ) )
  601. {
  602. const ActionMap::Node* mapNode = findNode( deviceType, deviceInst, eventDescriptor.flags, eventDescriptor.eventCode );
  603. if ( mapNode )
  604. {
  605. if ( mapNode->flags & Node::HasScale )
  606. return( mapNode->scaleFactor );
  607. else
  608. return( 1.0f );
  609. }
  610. }
  611. }
  612. Con::errorf( "The input event specified by %s %s is not in this action map!", device, action );
  613. return( 1.0f );
  614. }
  615. //------------------------------------------------------------------------------
  616. const char* ActionMap::getDeadZone( const char* device, const char* action )
  617. {
  618. U32 deviceType;
  619. U32 deviceInst;
  620. if ( getDeviceTypeAndInstance( device, deviceType, deviceInst ) )
  621. {
  622. EventDescriptor eventDescriptor;
  623. if ( createEventDescriptor( action, &eventDescriptor ) )
  624. {
  625. const ActionMap::Node* mapNode = findNode( deviceType, deviceInst, eventDescriptor.flags, eventDescriptor.eventCode );
  626. if ( mapNode )
  627. {
  628. if ( mapNode->flags & Node::HasDeadZone )
  629. {
  630. char buf[64];
  631. dSprintf( buf, sizeof( buf ), "%g %g", mapNode->deadZoneBegin, mapNode->deadZoneEnd );
  632. char* returnString = Con::getReturnBuffer( dStrlen( buf ) + 1 );
  633. dStrcpy( returnString, buf );
  634. return( returnString );
  635. }
  636. else
  637. return( "0 0" );
  638. }
  639. }
  640. }
  641. Con::errorf( "The input event specified by %s %s is not in this action map!", device, action );
  642. return( "" );
  643. }
  644. //------------------------------------------------------------------------------
  645. const char* ActionMap::buildActionString( const InputEvent* event )
  646. {
  647. const char* modifierString = getModifierString( event->modifier );
  648. char objectBuffer[64];
  649. if ( !getKeyString( event->objInst, objectBuffer ) )
  650. return( "" );
  651. U32 returnLen = dStrlen( modifierString ) + dStrlen( objectBuffer ) + 2;
  652. char* returnString = Con::getReturnBuffer( returnLen );
  653. dSprintf( returnString, returnLen - 1, "%s%s", modifierString, objectBuffer );
  654. return( returnString );
  655. }
  656. //------------------------------------------------------------------------------
  657. bool ActionMap::getDeviceTypeAndInstance(const char *pDeviceName, U32 &deviceType, U32 &deviceInstance)
  658. {
  659. U32 offset = 0;
  660. if (dStrnicmp(pDeviceName, "keyboard", dStrlen("keyboard")) == 0)
  661. {
  662. deviceType = KeyboardDeviceType;
  663. offset = dStrlen("keyboard");
  664. }
  665. else if (dStrnicmp(pDeviceName, "mouse", dStrlen("mouse")) == 0)
  666. {
  667. deviceType = MouseDeviceType;
  668. offset = dStrlen("mouse");
  669. }
  670. else if (dStrnicmp(pDeviceName, "joystick", dStrlen("joystick")) == 0)
  671. {
  672. deviceType = JoystickDeviceType;
  673. offset = dStrlen("joystick");
  674. }
  675. else if (dStrnicmp(pDeviceName, "accelerometer", dStrlen("accelerometer")) == 0)
  676. {
  677. deviceType = AccelerometerDeviceType;
  678. offset = dStrlen("accelerometer");
  679. }
  680. else if (dStrnicmp(pDeviceName, "gyroscope", dStrlen("gyroscope")) == 0)
  681. {
  682. deviceType = GyroscopeDeviceType;
  683. offset = dStrlen("gyroscope");
  684. }
  685. else if (dStrnicmp(pDeviceName, "touchdevice", dStrlen("touchdevice")) == 0)
  686. {
  687. deviceType = ScreenTouchDeviceType;
  688. offset = dStrlen("touchdevice");
  689. }
  690. else
  691. return false;
  692. if (dStrlen(pDeviceName) > offset)
  693. {
  694. const char* pInst = pDeviceName + offset;
  695. S32 instNum = dAtoi(pInst);
  696. if (instNum < 0)
  697. deviceInstance = 0;
  698. else
  699. deviceInstance = instNum;
  700. }
  701. else
  702. deviceInstance = 0;
  703. return true;
  704. }
  705. //------------------------------------------------------------------------------
  706. bool ActionMap::getDeviceName(const U32 deviceType, const U32 deviceInstance, char* buffer)
  707. {
  708. switch (deviceType)
  709. {
  710. case KeyboardDeviceType:
  711. dStrcpy(buffer, "keyboard");
  712. break;
  713. case MouseDeviceType:
  714. dSprintf(buffer, 16, "mouse%d", deviceInstance);
  715. break;
  716. case JoystickDeviceType:
  717. dSprintf(buffer, 16, "joystick%d", deviceInstance);
  718. break;
  719. case AccelerometerDeviceType:
  720. dStrcpy(buffer, "accelerometer");
  721. break;
  722. case GyroscopeDeviceType:
  723. dStrcpy(buffer, "gyroscope");
  724. break;
  725. case ScreenTouchDeviceType:
  726. dStrcpy(buffer, "touchdevice");
  727. break;
  728. default:
  729. Con::errorf( "ActionMap::getDeviceName: unknown device type specified, %d (inst: %d)", deviceType, deviceInstance);
  730. return false;
  731. }
  732. return true;
  733. }
  734. //------------------------------------------------------------------------------
  735. const char* ActionMap::getModifierString(const U32 modifiers)
  736. {
  737. U32 realModifiers = modifiers;
  738. if ( modifiers & SI_LSHIFT || modifiers & SI_RSHIFT )
  739. realModifiers |= SI_SHIFT;
  740. if ( modifiers & SI_LCTRL || modifiers & SI_RCTRL )
  741. realModifiers |= SI_CTRL;
  742. if ( modifiers & SI_LALT || modifiers & SI_RALT )
  743. realModifiers |= SI_ALT;
  744. if ( modifiers & SI_MAC_LOPT || modifiers & SI_MAC_ROPT )
  745. realModifiers |= SI_MAC_OPT;
  746. switch (realModifiers & (SI_SHIFT|SI_CTRL|SI_ALT|SI_MAC_OPT)) {
  747. #if defined(TORQUE_OS_OSX)
  748. // optional code, to output alt as cmd on mac.
  749. // interpreter sees them as the same...
  750. case (SI_SHIFT|SI_CTRL|SI_ALT):
  751. return "cmd-shift-ctrl ";
  752. case (SI_SHIFT|SI_ALT):
  753. return "cmd-shift ";
  754. case (SI_CTRL|SI_ALT):
  755. return "cmd-ctrl ";
  756. case (SI_ALT):
  757. return "cmd ";
  758. #else
  759. case (SI_SHIFT|SI_CTRL|SI_ALT):
  760. return "shift-ctrl-alt ";
  761. case (SI_SHIFT|SI_ALT):
  762. return "shift-alt ";
  763. case (SI_CTRL|SI_ALT):
  764. return "ctrl-alt ";
  765. case (SI_ALT):
  766. return "alt ";
  767. #endif
  768. case (SI_SHIFT|SI_CTRL):
  769. return "shift-ctrl ";
  770. case (SI_SHIFT):
  771. return "shift ";
  772. case (SI_CTRL):
  773. return "ctrl ";
  774. // plus new mac cases:
  775. case (SI_ALT|SI_SHIFT|SI_CTRL|SI_MAC_OPT):
  776. return "cmd-shift-ctrl-opt ";
  777. case (SI_ALT|SI_SHIFT|SI_MAC_OPT):
  778. return "cmd-shift-opt ";
  779. case (SI_ALT|SI_CTRL|SI_MAC_OPT):
  780. return "cmd-ctrl-opt ";
  781. case (SI_ALT|SI_MAC_OPT):
  782. return "cmd-opt ";
  783. case (SI_SHIFT|SI_CTRL|SI_MAC_OPT):
  784. return "shift-ctrl-opt ";
  785. case (SI_SHIFT|SI_MAC_OPT):
  786. return "shift-opt ";
  787. case (SI_CTRL|SI_MAC_OPT):
  788. return "ctrl-opt ";
  789. case (SI_MAC_OPT):
  790. return "opt ";
  791. case 0:
  792. return "";
  793. default:
  794. AssertFatal(false, "Error, should never reach the default case in getModifierString");
  795. return "";
  796. }
  797. }
  798. //------------------------------------------------------------------------------
  799. bool ActionMap::getKeyString(const U32 action, char* buffer)
  800. {
  801. U16 asciiCode = Input::getAscii(action, STATE_LOWER);
  802. // if (action >= KEY_A && action <= KEY_Z) {
  803. // buffer[0] = char(action - KEY_A + 'a');
  804. // buffer[1] = '\0';
  805. // return true;
  806. // } else if (action >= KEY_0 && action <= KEY_9) {
  807. // buffer[0] = char(action - KEY_0 + '0');
  808. // buffer[1] = '\0';
  809. if ( (asciiCode != 0) && dIsDecentChar((char)asciiCode))
  810. {
  811. for (U32 i = 0; gAsciiMap[i].asciiCode != 0xFFFF; i++) {
  812. if (gAsciiMap[i].asciiCode == asciiCode)
  813. {
  814. dStrcpy(buffer, gAsciiMap[i].pDescription);
  815. return true;
  816. }
  817. }
  818. // Must not have found a string for that ascii code just record the char
  819. buffer[0] = char(asciiCode);
  820. buffer[1] = '\0';
  821. return true;
  822. }
  823. else
  824. {
  825. if (action >= KEY_A && action <= KEY_Z)
  826. {
  827. buffer[0] = char(action - KEY_A + 'a');
  828. buffer[1] = '\0';
  829. return true;
  830. }
  831. else if (action >= KEY_0 && action <= KEY_9) {
  832. buffer[0] = char(action - KEY_0 + '0');
  833. buffer[1] = '\0';
  834. return true;
  835. }
  836. for (U32 i = 0; gVirtualMap[i].code != 0xFFFFFFFF; i++) {
  837. if (gVirtualMap[i].code == action) {
  838. dStrcpy(buffer, gVirtualMap[i].pDescription);
  839. return true;
  840. }
  841. }
  842. }
  843. Con::errorf( "ActionMap::getKeyString: no string for action %d", action );
  844. return false;
  845. }
  846. //--------------------------------------------------------------------------
  847. bool ActionMap::processBindCmd(const char *device, const char *action, const char *makeCmd, const char *breakCmd)
  848. {
  849. U32 deviceType;
  850. U32 deviceInst;
  851. if(!getDeviceTypeAndInstance(device, deviceType, deviceInst))
  852. {
  853. Con::printf("processBindCmd: unknown device: %s", device);
  854. return false;
  855. }
  856. // Ok, we now have the deviceType and instance. Create an event descriptor
  857. // for the bind...
  858. //
  859. EventDescriptor eventDescriptor;
  860. if (createEventDescriptor(action, &eventDescriptor) == false) {
  861. Con::printf("Could not create a description for binding: %s", action);
  862. return false;
  863. }
  864. // SI_POV == SI_MOVE, and the POV works fine with bindCmd, so we have to add these manually.
  865. if( ( eventDescriptor.eventCode == SI_XAXIS ) ||
  866. ( eventDescriptor.eventCode == SI_YAXIS ) ||
  867. ( eventDescriptor.eventCode == SI_ZAXIS ) ||
  868. ( eventDescriptor.eventCode == SI_RXAXIS ) ||
  869. ( eventDescriptor.eventCode == SI_RYAXIS ) ||
  870. ( eventDescriptor.eventCode == SI_RZAXIS ) ||
  871. ( eventDescriptor.eventCode == SI_SLIDER ) ||
  872. ( eventDescriptor.eventCode == SI_XPOV ) ||
  873. ( eventDescriptor.eventCode == SI_YPOV ) ||
  874. ( eventDescriptor.eventCode == SI_XPOV2 ) ||
  875. ( eventDescriptor.eventCode == SI_YPOV2 ) ||
  876. ( eventDescriptor.eventCode == SI_ACCELX ) ||
  877. ( eventDescriptor.eventCode == SI_ACCELY ) ||
  878. ( eventDescriptor.eventCode == SI_ACCELZ ) ||
  879. ( eventDescriptor.eventCode == SI_GRAVX ) ||
  880. ( eventDescriptor.eventCode == SI_GRAVY ) ||
  881. ( eventDescriptor.eventCode == SI_GRAVZ ) ||
  882. ( eventDescriptor.eventCode == SI_GYROX ) ||
  883. ( eventDescriptor.eventCode == SI_GYROY ) ||
  884. ( eventDescriptor.eventCode == SI_GYROZ ) ||
  885. ( eventDescriptor.eventCode == SI_YAW ) ||
  886. ( eventDescriptor.eventCode == SI_PITCH ) ||
  887. ( eventDescriptor.eventCode == SI_ROLL ) )
  888. {
  889. Con::warnf( "ActionMap::processBindCmd - Cannot use 'bindCmd' with a move event type. Use 'bind' instead." );
  890. return false;
  891. }
  892. // Create the full bind entry, and place it in the map
  893. //
  894. // DMMTODO
  895. Node* pBindNode = getNode(deviceType, deviceInst,
  896. eventDescriptor.flags,
  897. eventDescriptor.eventCode);
  898. pBindNode->flags = Node::BindCmd;
  899. pBindNode->deadZoneBegin = 0;
  900. pBindNode->deadZoneEnd = 0;
  901. pBindNode->scaleFactor = 1;
  902. if(makeCmd[0])
  903. pBindNode->makeConsoleCommand = dStrdup(makeCmd);
  904. else
  905. pBindNode->makeConsoleCommand = dStrdup("");
  906. if(breakCmd[0])
  907. pBindNode->breakConsoleCommand = dStrdup(breakCmd);
  908. else
  909. pBindNode->breakConsoleCommand = dStrdup("");
  910. return true;
  911. }
  912. //------------------------------------------------------------------------------
  913. bool ActionMap::processBind(const U32 argc, const char** argv, SimObject* object)
  914. {
  915. // Ok, the bind will come in the following format:
  916. // [device] [key or button] <[param spec] [param] ...> [fnName]
  917. //
  918. const char* pDeviceName = argv[0];
  919. const char* pEvent = argv[1];
  920. const char* pFnName = argv[argc - 1];
  921. // Determine the device
  922. U32 deviceType;
  923. U32 deviceInst;
  924. if(!getDeviceTypeAndInstance(argv[0], deviceType, deviceInst))
  925. {
  926. Con::printf("processBind: unknown device: %s", pDeviceName);
  927. return false;
  928. }
  929. // Ok, we now have the deviceType and instance. Create an event descriptor
  930. // for the bind...
  931. //
  932. EventDescriptor eventDescriptor;
  933. if (createEventDescriptor(pEvent, &eventDescriptor) == false) {
  934. Con::printf("Could not create a description for binding: %s", pEvent);
  935. return false;
  936. }
  937. // Event has now been described, and device determined. we need now to extract
  938. // any modifiers that the action map will apply to incoming events before
  939. // calling the bound function...
  940. //
  941. // DMMTODO
  942. U32 assignedFlags = 0;
  943. F32 deadZoneBegin = 0.0f;
  944. F32 deadZoneEnd = 0.0f;
  945. F32 scaleFactor = 1.0f;
  946. if (argc != 3) {
  947. // We have the following: "[DSIR]" [deadZone] [scale]
  948. //
  949. const char* pSpec = argv[2];
  950. for (U32 i = 0; pSpec[i] != '\0'; i++) {
  951. switch (pSpec[i]) {
  952. case 'r': case 'R':
  953. assignedFlags |= Node::HasScale;
  954. break;
  955. case 's': case 'S':
  956. assignedFlags |= Node::HasScale;
  957. break;
  958. case 'd': case 'D':
  959. assignedFlags |= Node::HasDeadZone;
  960. break;
  961. case 'i': case 'I':
  962. assignedFlags |= Node::Inverted;
  963. break;
  964. default:
  965. AssertFatal(false, avar("Misunderstood specifier in bind (spec string: %s)",
  966. pSpec));
  967. }
  968. }
  969. // Ok, we have the flags. Scan the dead zone and scale, if any.
  970. //
  971. U32 curArg = 3;
  972. if (assignedFlags & Node::HasDeadZone) {
  973. dSscanf(argv[curArg], "%g %g", &deadZoneBegin, &deadZoneEnd);
  974. curArg++;
  975. }
  976. if (assignedFlags & Node::HasScale) {
  977. scaleFactor = dAtof(argv[curArg]);
  978. curArg++;
  979. }
  980. if (curArg != (argc - 1)) {
  981. AssertFatal(curArg == (argc - 1), "error in bind spec somewhere...");
  982. Con::printf("Improperly specified bind for key: %s", argv[2]);
  983. return false;
  984. }
  985. }
  986. // Ensure that the console function is properly specified?
  987. //
  988. // DMMTODO
  989. // Create the full bind entry, and place it in the map
  990. //
  991. // DMMTODO
  992. Node* pBindNode = getNode(deviceType, deviceInst,
  993. eventDescriptor.flags,
  994. eventDescriptor.eventCode, object);
  995. pBindNode->flags = assignedFlags;
  996. pBindNode->deadZoneBegin = deadZoneBegin;
  997. pBindNode->deadZoneEnd = deadZoneEnd;
  998. pBindNode->scaleFactor = scaleFactor;
  999. pBindNode->object = object;
  1000. pBindNode->consoleFunction = StringTable->insert(pFnName);
  1001. return true;
  1002. }
  1003. //------------------------------------------------------------------------------
  1004. bool ActionMap::processAction(const InputEvent* pEvent)
  1005. {
  1006. static const char *argv[4];
  1007. if (pEvent->action == SI_TOUCH) // Touches
  1008. {
  1009. static const char *args[4];
  1010. const Node* pNode = findNode(pEvent->deviceType, pEvent->deviceInst, pEvent->modifier, pEvent->objInst);
  1011. if (pNode == NULL)
  1012. {
  1013. // Check to see if we clear the modifiers, do we find an action?
  1014. if (pEvent->modifier != 0)
  1015. pNode = findNode(pEvent->deviceType, pEvent->deviceInst, 0, pEvent->objInst);
  1016. if (pNode == NULL)
  1017. return false;
  1018. }
  1019. // "Do nothing" bind:
  1020. if ( !pNode->consoleFunction[0] )
  1021. return( true );
  1022. // Ok, we're all set up, call the function.
  1023. args[0] = pNode->consoleFunction;
  1024. args[1] = pEvent->touchIDs; //Con::getReturnBuffer(pEvent->touchIDs);
  1025. args[2] = pEvent->touchesX; //Con::getReturnBuffer(pEvent->touchesX);
  1026. args[3] = pEvent->touchesY; //Con::getReturnBuffer(pEvent->touchesY);
  1027. if (pNode->object)
  1028. Con::executef(pNode->object, 2, args[0], args[1], args[2], args[3]);
  1029. else
  1030. Con::execute(4, args);
  1031. return true;
  1032. }
  1033. else if (pEvent->action == SI_MAKE) // KEYBOARD/BUTTON DOWN EVENT
  1034. {
  1035. const Node* pNode = findNode(pEvent->deviceType, pEvent->deviceInst, pEvent->modifier, pEvent->objInst);
  1036. if (pNode == NULL)
  1037. {
  1038. // Check to see if we clear the modifiers, do we find an action?
  1039. if (pEvent->modifier != 0)
  1040. pNode = findNode(pEvent->deviceType, pEvent->deviceInst, 0, pEvent->objInst);
  1041. if (pNode == NULL)
  1042. return false;
  1043. }
  1044. // Whadda ya know, we have this bound. Set up, and call the console
  1045. // function associated with it...
  1046. //
  1047. F32 value = pEvent->fValue;
  1048. if (pNode->flags & Node::Ranged)
  1049. {
  1050. value = (value * 2.0f) - 1.0f;
  1051. if (pNode->flags & Node::Inverted)
  1052. value *= -1.0f;
  1053. }
  1054. else
  1055. {
  1056. if (pNode->flags & Node::Inverted)
  1057. value = 1.0f - value;
  1058. }
  1059. if (pNode->flags & Node::HasScale)
  1060. value *= pNode->scaleFactor;
  1061. if (pNode->flags & Node::HasDeadZone)
  1062. if (value >= pNode->deadZoneBegin && value <= pNode->deadZoneEnd)
  1063. value = 0.0f;
  1064. // Ok, we're all set up, call the function.
  1065. if(pNode->flags & Node::BindCmd)
  1066. {
  1067. // it's a bind command
  1068. if(pNode->makeConsoleCommand)
  1069. Con::evaluate(pNode->makeConsoleCommand);
  1070. }
  1071. else if ( pNode->consoleFunction[0] )
  1072. {
  1073. argv[0] = pNode->consoleFunction;
  1074. argv[1] = Con::getFloatArg(value);
  1075. if (pNode->object)
  1076. Con::executef(pNode->object, 2, argv[0], argv[1]);
  1077. else
  1078. Con::execute(2, argv);
  1079. }
  1080. // [neo, 5/13/2007 - #3109]
  1081. // The execs/evaluate above could have called reentrant script code which made calls to
  1082. // bindCmd() etc, channging the node map underneath us. If enough nodes were added then
  1083. // the node map vector would realloc, with the result that pNode would then be pointing
  1084. // at garbage and cause a crash when passed to enterBreakEvent() below. So we just look
  1085. // it up again to be safe. This is not needed in the other cases below as we return right
  1086. // after the execs and don't use pNode again.
  1087. pNode = findNode( pEvent->deviceType, pEvent->deviceInst, pEvent->modifier, pEvent->objInst );
  1088. if( pNode == NULL )
  1089. return true; // We already called any bound methods/functions so our job is done
  1090. //
  1091. // And enter the break into the table if this is a make event...
  1092. enterBreakEvent(pEvent, pNode);
  1093. return true;
  1094. }
  1095. else if (pEvent->action == SI_MOVE) // MOUSE/JOYSTICK MOVE EVENT
  1096. {
  1097. if (pEvent->deviceType == MouseDeviceType)
  1098. {
  1099. const Node* pNode = findNode(pEvent->deviceType, pEvent->deviceInst, pEvent->modifier, pEvent->objType);
  1100. if (pNode == NULL)
  1101. {
  1102. // Check to see if we clear the modifiers, do we find an action?
  1103. if (pEvent->modifier != 0)
  1104. pNode = findNode(pEvent->deviceType, pEvent->deviceInst,
  1105. 0, pEvent->objType);
  1106. if (pNode == NULL)
  1107. return false;
  1108. }
  1109. // "Do nothing" bind:
  1110. if ( !pNode->consoleFunction[0] )
  1111. return( true );
  1112. // Whadda ya know, we have this bound. Set up, and call the console
  1113. // function associated with it. Mouse events ignore range and dead
  1114. // zone params.
  1115. //
  1116. F32 value = pEvent->fValue;
  1117. if (pNode->flags & Node::Inverted)
  1118. value *= -1.0f;
  1119. if (pNode->flags & Node::HasScale)
  1120. value *= pNode->scaleFactor;
  1121. // Ok, we're all set up, call the function.
  1122. argv[0] = pNode->consoleFunction;
  1123. argv[1] = Con::getFloatArg(value);
  1124. if (pNode->object)
  1125. Con::executef(pNode->object, 2, argv[0], argv[1]);
  1126. else
  1127. Con::execute(2, argv);
  1128. return true;
  1129. }
  1130. else
  1131. {
  1132. // Joystick events...
  1133. const Node* pNode = findNode( pEvent->deviceType, pEvent->deviceInst,
  1134. pEvent->modifier, pEvent->objType );
  1135. if ( pNode == NULL )
  1136. {
  1137. // Check to see if we clear the modifiers, do we find an action?
  1138. if (pEvent->modifier != 0)
  1139. pNode = findNode( pEvent->deviceType, pEvent->deviceInst, 0, pEvent->objType );
  1140. if ( pNode == NULL )
  1141. return false;
  1142. }
  1143. // "Do nothing" bind:
  1144. if ( !pNode->consoleFunction[0] )
  1145. return( true );
  1146. // Whadda ya know, we have this bound. Set up, and call the console
  1147. // function associated with it. Joystick move events are the same as mouse
  1148. // move events except that they don't ignore dead zone.
  1149. //
  1150. F32 value = pEvent->fValue;
  1151. if ( pNode->flags & Node::Inverted )
  1152. value *= -1.0f;
  1153. if ( pNode->flags & Node::HasScale )
  1154. value *= pNode->scaleFactor;
  1155. if ( pNode->flags & Node::HasDeadZone )
  1156. if ( value >= pNode->deadZoneBegin && value <= pNode->deadZoneEnd )
  1157. value = 0.0f;
  1158. // Ok, we're all set up, call the function.
  1159. argv[0] = pNode->consoleFunction;
  1160. argv[1] = Con::getFloatArg( value );
  1161. if (pNode->object)
  1162. Con::executef(pNode->object, 2, argv[0], argv[1]);
  1163. else
  1164. Con::execute(2, argv);
  1165. return true;
  1166. }
  1167. }
  1168. else if (pEvent->action == SI_MOTION) // iOS MOTION EVENT
  1169. {
  1170. // iOS Accelerometer, Gyroscope and DeviceMotion processing
  1171. // Currently, this is identical to the joystick handling.
  1172. // This was copied over into its own section because this will
  1173. // give us a dedicated section to tweak processing based on iOS specific
  1174. // devices. No point in trying to mangle joystick code any further
  1175. const Node* pNode = findNode( pEvent->deviceType, pEvent->deviceInst, pEvent->modifier, pEvent->objType );
  1176. if ( pNode == NULL )
  1177. {
  1178. // Check to see if we clear the modifiers, do we find an action?
  1179. if (pEvent->modifier != 0)
  1180. pNode = findNode( pEvent->deviceType, pEvent->deviceInst, 0, pEvent->objType );
  1181. if ( pNode == NULL )
  1182. return false;
  1183. }
  1184. // "Do nothing" bind:
  1185. if ( !pNode->consoleFunction[0] )
  1186. return( true );
  1187. F32 value = pEvent->fValue;
  1188. if ( pNode->flags & Node::Inverted )
  1189. value *= -1.0f;
  1190. if ( pNode->flags & Node::HasScale )
  1191. value *= pNode->scaleFactor;
  1192. if ( pNode->flags & Node::HasDeadZone )
  1193. if ( value >= pNode->deadZoneBegin && value <= pNode->deadZoneEnd )
  1194. value = 0.0f;
  1195. // Ok, we're all set up, call the function.
  1196. argv[0] = pNode->consoleFunction;
  1197. argv[1] = Con::getFloatArg( value );
  1198. if (pNode->object)
  1199. Con::executef(pNode->object, 2, argv[0], argv[1]);
  1200. else
  1201. Con::execute(2, argv);
  1202. return true;
  1203. }
  1204. else if (pEvent->action == SI_BREAK) // UP EVENT
  1205. {
  1206. return checkBreakTable(pEvent);
  1207. }
  1208. return false;
  1209. }
  1210. //------------------------------------------------------------------------------
  1211. void ActionMap::enterBreakEvent(const InputEvent* pEvent, const Node* pNode)
  1212. {
  1213. // There aren't likely to be many breaks outstanding at any one given time,
  1214. // so a simple linear search is probably sufficient. Note that the break table
  1215. // is static to the class, all breaks are directed to the action map that received
  1216. // the make.
  1217. //
  1218. S32 entry = -1;
  1219. for (U32 i = 0; i < (U32)smBreakTable.size(); i++) {
  1220. if (smBreakTable[i].deviceType == U32(pEvent->deviceType) &&
  1221. smBreakTable[i].deviceInst == U32(pEvent->deviceInst) &&
  1222. smBreakTable[i].objInst == U32(pEvent->objInst)) {
  1223. // Match.
  1224. entry = i;
  1225. break;
  1226. }
  1227. }
  1228. if (entry == -1) {
  1229. smBreakTable.increment();
  1230. entry = smBreakTable.size() - 1;
  1231. smBreakTable[entry].deviceType = pEvent->deviceType;
  1232. smBreakTable[entry].deviceInst = pEvent->deviceInst;
  1233. smBreakTable[entry].objInst = pEvent->objInst;
  1234. }
  1235. // Ok, we now have the entry, and know that the device desc. and the objInst match.
  1236. // Copy out the node information...
  1237. //
  1238. smBreakTable[entry].object = pNode->object;
  1239. // [neo, 5/7/2007 - #2975]
  1240. // object above can be deleted in between a make/break and so object will point
  1241. // to turfed memory and crash. To keep things simple we just store id as well so
  1242. // we can look it up to validate object ref.
  1243. smBreakTable[entry].objectId = pNode->object ? pNode->object->getId() : 0;
  1244. smBreakTable[entry].consoleFunction = pNode->consoleFunction;
  1245. if(pNode->breakConsoleCommand)
  1246. smBreakTable[entry].breakConsoleCommand = dStrdup(pNode->breakConsoleCommand);
  1247. else
  1248. smBreakTable[entry].breakConsoleCommand = NULL;
  1249. smBreakTable[entry].flags = pNode->flags;
  1250. smBreakTable[entry].deadZoneBegin = pNode->deadZoneBegin;
  1251. smBreakTable[entry].deadZoneEnd = pNode->deadZoneEnd;
  1252. smBreakTable[entry].scaleFactor = pNode->scaleFactor;
  1253. }
  1254. //------------------------------------------------------------------------------
  1255. bool ActionMap::checkBreakTable(const InputEvent* pEvent)
  1256. {
  1257. for (U32 i = 0; i < (U32)smBreakTable.size(); i++) {
  1258. if (smBreakTable[i].deviceType == U32(pEvent->deviceType) &&
  1259. smBreakTable[i].deviceInst == U32(pEvent->deviceInst) &&
  1260. smBreakTable[i].objInst == U32(pEvent->objInst)) {
  1261. // Match. Issue the break event...
  1262. //
  1263. F32 value = pEvent->fValue;
  1264. if (smBreakTable[i].flags & Node::Ranged) {
  1265. value = (value * 2.0f) - 1.0f;
  1266. if (smBreakTable[i].flags & Node::Inverted)
  1267. value *= -1.0f;
  1268. } else {
  1269. if (smBreakTable[i].flags & Node::Inverted)
  1270. value = 1.0f - value;
  1271. }
  1272. if (smBreakTable[i].flags & Node::HasScale)
  1273. value *= smBreakTable[i].scaleFactor;
  1274. if (smBreakTable[i].flags & Node::HasDeadZone)
  1275. if (value >= smBreakTable[i].deadZoneBegin &&
  1276. value <= smBreakTable[i].deadZoneEnd)
  1277. value = 0.0f;
  1278. // Ok, we're all set up, call the function.
  1279. if(smBreakTable[i].consoleFunction)
  1280. {
  1281. if ( smBreakTable[i].consoleFunction[0] )
  1282. {
  1283. static const char *argv[2];
  1284. argv[0] = smBreakTable[i].consoleFunction;
  1285. argv[1] = Con::getFloatArg(value);
  1286. if( smBreakTable[i].object )
  1287. {
  1288. // [neo, 5/7/2007 - #2975]
  1289. // object above can be deleted in between a make/break and so object will point
  1290. // to turfed memory and crash. To keep things simple we just store id as well so
  1291. // we can look it up to validate object ref.
  1292. if( smBreakTable[i].objectId > 0 && Sim::findObject( smBreakTable[i].objectId ) )
  1293. Con::executef(smBreakTable[i].object, 2, argv[0], argv[1]);
  1294. }
  1295. else
  1296. Con::execute(2, argv);
  1297. }
  1298. }
  1299. else if(smBreakTable[i].breakConsoleCommand)
  1300. {
  1301. Con::evaluate(smBreakTable[i].breakConsoleCommand);
  1302. dFree(smBreakTable[i].breakConsoleCommand);
  1303. }
  1304. smBreakTable.erase(i);
  1305. return true;
  1306. }
  1307. }
  1308. return false;
  1309. }
  1310. //------------------------------------------------------------------------------
  1311. bool ActionMap::handleEvent(const InputEvent* pEvent)
  1312. {
  1313. // Interate through the ActionMapSet until we get a map that
  1314. // handles the event or we run out of maps...
  1315. //
  1316. SimSet* pActionMapSet = Sim::getActiveActionMapSet();
  1317. AssertFatal(pActionMapSet && pActionMapSet->size() != 0,
  1318. "error, no ActiveMapSet or no global action map...");
  1319. for (SimSet::iterator itr = pActionMapSet->end() - 1;
  1320. itr > pActionMapSet->begin(); itr--) {
  1321. ActionMap* pMap = static_cast<ActionMap*>(*itr);
  1322. if (pMap->processAction(pEvent) == true)
  1323. return true;
  1324. }
  1325. return false;
  1326. }
  1327. //------------------------------------------------------------------------------
  1328. bool ActionMap::handleEventGlobal(const InputEvent* pEvent)
  1329. {
  1330. // Interate through the ActionMapSet until we get a map that
  1331. // handles the event or we run out of maps...
  1332. //
  1333. SimSet* pActionMapSet = Sim::getActiveActionMapSet();
  1334. AssertFatal(pActionMapSet && pActionMapSet->size() != 0,
  1335. "error, no ActiveMapSet or no global action map...");
  1336. return ((ActionMap*)pActionMapSet->first())->processAction(pEvent);
  1337. }
  1338. //------------------------------------------------------------------------------
  1339. //-------------------------------------- Console stuff
  1340. //------------------------------------------------------------------------------
  1341. ConsoleMethod( ActionMap, bind, void, 5, 10, "( device , action , [ modifier , mod... ] , command ) Use the bind method to associate a function to a keystroke or other device input.\n"
  1342. "The command bound via the bind function must be specified as a flat name with no elipses or semi-colon termination and will be called on make and break events (i.e. key press and release for a mapped key). Args: Warning: When a function is bound to a keystroke or other device input, and no other versions of the binding are provided, the function will be called even if a modifier key like CTRL, ALT, or SHIFT is also pressed.\n"
  1343. "@param device Name of the device to bind the command to.\n"
  1344. "@param action Name of the action to watch for.\n"
  1345. "@param modifier Special modifiers (mouse only), such as dead spot, etc.\n"
  1346. "@param command The function to be called on make and break.\n"
  1347. "@return No return value.\n"
  1348. "@sa bindCmd, getBinding, unbind")
  1349. {
  1350. object->processBind( argc - 2, argv + 2, NULL );
  1351. }
  1352. ConsoleMethod( ActionMap, bindObj, void, 6, 11, "(device, action, [modifier spec, mod...], command, object) Use the bindObj method to associate a function to a keystroke or other device input.\n"
  1353. "The command bound via the bind function must be specified as a flat name with no elipses or semi-colon termination and will be called on make and break events (i.e. key press and release for a mapped key). Args: Warning: When a function is bound to a keystroke or other device input, and no other versions of the binding are provided, the function will be called even if a modifier key like CTRL, ALT, or SHIFT is also pressed.\n"
  1354. "@param device Name of the device to bind the command to.\n"
  1355. "@param action Name of the action to watch for.\n"
  1356. "@param modifier Special modifiers (mouse only), such as dead spot, etc.\n"
  1357. "@param command The function to be called on make and break.\n"
  1358. "@param object The explicit object (it defaults to NULL when you call bind() )\n"
  1359. "@return No return value.\n"
  1360. "@sa bindCmd, getBinding, unbind")
  1361. {
  1362. SimObject* obj = Sim::findObject(argv[argc - 1]);
  1363. object->processBind( argc - 3, argv + 2, obj );
  1364. }
  1365. //------------------------------------------------------------------------------
  1366. ConsoleMethod( ActionMap, bindCmd, void, 6, 6, "( device , action , makeCmd , breakCmd ) Use the bindCmd method to associate up to two functions to a keystroke or other device input.\n"
  1367. "The makeCmd is bound to the make event and the breakCmd is bound to the break event and in both cases, the commands are specified as complete scripts, with all arguments, elipses, and the terminating semi-colon. Either of these commands may be non-specified (NULL strings). For clarification, see 'Bind Sample' example below.\n"
  1368. "@param device Name of the device to bind the command to (see 'Device Table' below).\n"
  1369. "@param action Name of the action to watch for(see 'Action Table' below).\n"
  1370. "@param makeCmd The function to be called on make event.\n"
  1371. "@param breakCmd The function to be called on break event.\n"
  1372. "@return No return value.\n"
  1373. "@sa bind, getBinding, unbind")
  1374. {
  1375. object->processBindCmd( argv[2], argv[3], argv[4], argv[5] );
  1376. }
  1377. //------------------------------------------------------------------------------
  1378. ConsoleMethod( ActionMap, unbind, void, 4, 4, "( device , action ) Use the unbind method to remove a previosly specified device + action pair from the action map.\n"
  1379. "@param device Name of the device to bound to a command (see 'Device Table' below).\n"
  1380. "@param action Name of the action to watch for (see 'Action Table' below).\n"
  1381. "@return No return value.\n"
  1382. "@sa bind, bindCmd")
  1383. {
  1384. object->processUnbind( argv[2], argv[3] );
  1385. }
  1386. ConsoleMethod( ActionMap, unbindObj, void, 5, 5, "(device, action, object) Use the unbind method to remove a previosly specified device + action pair from the action map.\n"
  1387. "@param device Name of the device to bound to a command (see 'Device Table' below).\n"
  1388. "@param action Name of the action to watch for (see 'Action Table' below).\n"
  1389. "@param object Explicit object (it defaults to NULL when you call unbind() )."
  1390. "@return No return value.\n"
  1391. "@sa bind, bindCmd")
  1392. {
  1393. SimObject* obj = Sim::findObject(argv[4]);
  1394. object->processUnbind( argv[2], argv[3], obj );
  1395. }
  1396. //------------------------------------------------------------------------------
  1397. ConsoleMethod( ActionMap, save, void, 2, 4, "( [ fileName ] [ , append ] ) Use the save method to save an entire action map specification to a file. If append is not specified, or specified as false, fileName will be overwritten, otherwise the action map will be appended to the file.\n"
  1398. "@param fileName Full path to file in which to store action map definition.\n"
  1399. "@param append If true, do not overwrite the file, else start from scratch.\n"
  1400. "@return No return value")
  1401. {
  1402. const char* fileName = argc > 2 ? argv[2] : NULL;
  1403. bool append = argc > 3 ? dAtob(argv[3]) : false;
  1404. char buffer[1024];
  1405. if(fileName)
  1406. {
  1407. if(Con::expandPath(buffer, sizeof(buffer), fileName))
  1408. fileName = buffer;
  1409. }
  1410. object->dumpActionMap( fileName, append );
  1411. }
  1412. //------------------------------------------------------------------------------
  1413. ConsoleMethod( ActionMap, push, void, 2, 2, "() Use the push method to activate an ActionMap and place it at the top of the non-global ActionMap stack.\n"
  1414. "@return No return value.\n"
  1415. "@sa pop")
  1416. {
  1417. SimSet* pActionMapSet = Sim::getActiveActionMapSet();
  1418. pActionMapSet->pushObject( object );
  1419. }
  1420. //------------------------------------------------------------------------------
  1421. ConsoleMethod( ActionMap, pop, void, 2, 2, "() Use the pop method to de-activate an ActionMap and remove it from non-global ActionMap stack.\n"
  1422. "@return No return value.\n"
  1423. "@sa push")
  1424. {
  1425. SimSet* pActionMapSet = Sim::getActiveActionMapSet();
  1426. pActionMapSet->removeObject( object );
  1427. }
  1428. //------------------------------------------------------------------------------
  1429. ConsoleMethod( ActionMap, getBinding, const char*, 3, 3, "( command ) Use the getBinding method to get the binding for a specified command.\n"
  1430. "@param command The function to seek a binding for.\n"
  1431. "@return Returns a string containing the binding as a field (TAB separated string), or a NULL string meaning 'no binding found'.\n"
  1432. "@sa bind, bindCmd")
  1433. {
  1434. return( object->getBinding( argv[2] ) );
  1435. }
  1436. //------------------------------------------------------------------------------
  1437. ConsoleMethod( ActionMap, getCommand, const char*, 4, 4, "( device , action ) Use the getCommand method to get the function associated with a specific device + action pair.\n"
  1438. "@param device Name of the device to bound to a command (see 'Device Table' below).\n"
  1439. "@param action Name of the action to watch for (see 'Action Table' below).\n"
  1440. "@return Returns the function name or specification associated with the specified device + action pair, or a NULL-string meaning 'no binding found'.\n"
  1441. "@sa bind, bindCmd, getBinding")
  1442. {
  1443. return( object->getCommand( argv[2], argv[3] ) );
  1444. }
  1445. //------------------------------------------------------------------------------
  1446. ConsoleMethod( ActionMap, isInverted, bool, 4, 4, "( device , action ) Use the Purpose method to determine if a specific device + action pair in inverted.\n"
  1447. "This only applies to scrolling devices.\n"
  1448. "@param device Name of the device to bound to a command (see 'Device Table' below).\n"
  1449. "@param action Name of the action to watch for (see 'Action Table' below).\n"
  1450. "@return Returns 1 if the mouse (or other scrolling device) is inverted, 0 otherwise.\n"
  1451. "@sa bind, bindCmd")
  1452. {
  1453. return( object->isInverted( argv[2], argv[3] ) );
  1454. }
  1455. //------------------------------------------------------------------------------
  1456. ConsoleMethod( ActionMap, getScale, F32, 4, 4, "( device , action ) Use the getScale method to get the scale associated with a specific device + action pair.\n"
  1457. "@param device Name of the device to bound to a command (see 'Device Table' below).\n"
  1458. "@param action Name of the action to watch for (see 'Action Table' below).\n"
  1459. "@return Returns 1 if no scale is associated with the specified device + action pair, or the mapping was not found.\n"
  1460. "@sa bind, bindCmd")
  1461. {
  1462. return( object->getScale( argv[2], argv[3] ) );
  1463. }
  1464. //------------------------------------------------------------------------------
  1465. ConsoleMethod( ActionMap, getDeadZone, const char*, 4, 4, "( device , action ) Use the getDeadZone method to get the dead-zone associated with a specific device + action pair.\n"
  1466. "@param device Name of the device to bound to a command (see 'Device Table' below).\n"
  1467. "@param action Name of the action to watch for (see 'Action Table' below).\n"
  1468. "@return Returns a dead-zone specification, or \"0 0\" meaning that there is no dead-zone, or a NULL string meaning the mapping was not found.\n"
  1469. "@sa bind, bindCmd")
  1470. {
  1471. return( object->getDeadZone( argv[2], argv[3] ) );
  1472. }
  1473. //------------------------------------------------------------------------------
  1474. //-------------------------------------- Key code to string mapping
  1475. // TODO: Add most obvious aliases...
  1476. //
  1477. CodeMapping gVirtualMap[] =
  1478. {
  1479. //-------------------------------------- KEYBOARD EVENTS
  1480. //
  1481. { "backspace", SI_KEY, KEY_BACKSPACE },
  1482. { "tab", SI_KEY, KEY_TAB },
  1483. { "return", SI_KEY, KEY_RETURN },
  1484. { "enter", SI_KEY, KEY_RETURN },
  1485. { "shift", SI_KEY, KEY_SHIFT },
  1486. { "ctrl", SI_KEY, KEY_CONTROL },
  1487. { "alt", SI_KEY, KEY_ALT },
  1488. { "pause", SI_KEY, KEY_PAUSE },
  1489. { "capslock", SI_KEY, KEY_CAPSLOCK },
  1490. { "escape", SI_KEY, KEY_ESCAPE },
  1491. { "space", SI_KEY, KEY_SPACE },
  1492. { "pagedown", SI_KEY, KEY_PAGE_DOWN },
  1493. { "pageup", SI_KEY, KEY_PAGE_UP },
  1494. { "end", SI_KEY, KEY_END },
  1495. { "home", SI_KEY, KEY_HOME },
  1496. { "left", SI_KEY, KEY_LEFT },
  1497. { "up", SI_KEY, KEY_UP },
  1498. { "right", SI_KEY, KEY_RIGHT },
  1499. { "down", SI_KEY, KEY_DOWN },
  1500. { "print", SI_KEY, KEY_PRINT },
  1501. { "insert", SI_KEY, KEY_INSERT },
  1502. { "delete", SI_KEY, KEY_DELETE },
  1503. { "help", SI_KEY, KEY_HELP },
  1504. { "win_lwindow", SI_KEY, KEY_WIN_LWINDOW },
  1505. { "win_rwindow", SI_KEY, KEY_WIN_RWINDOW },
  1506. { "win_apps", SI_KEY, KEY_WIN_APPS },
  1507. { "cmd", SI_KEY, KEY_ALT },
  1508. { "opt", SI_KEY, KEY_MAC_OPT },
  1509. { "lopt", SI_KEY, KEY_MAC_LOPT },
  1510. { "ropt", SI_KEY, KEY_MAC_ROPT },
  1511. { "numpad0", SI_KEY, KEY_NUMPAD0 },
  1512. { "numpad1", SI_KEY, KEY_NUMPAD1 },
  1513. { "numpad2", SI_KEY, KEY_NUMPAD2 },
  1514. { "numpad3", SI_KEY, KEY_NUMPAD3 },
  1515. { "numpad4", SI_KEY, KEY_NUMPAD4 },
  1516. { "numpad5", SI_KEY, KEY_NUMPAD5 },
  1517. { "numpad6", SI_KEY, KEY_NUMPAD6 },
  1518. { "numpad7", SI_KEY, KEY_NUMPAD7 },
  1519. { "numpad8", SI_KEY, KEY_NUMPAD8 },
  1520. { "numpad9", SI_KEY, KEY_NUMPAD9 },
  1521. { "numpadmult", SI_KEY, KEY_MULTIPLY },
  1522. { "numpadadd", SI_KEY, KEY_ADD },
  1523. { "numpadsep", SI_KEY, KEY_SEPARATOR },
  1524. { "numpadminus", SI_KEY, KEY_SUBTRACT },
  1525. { "numpaddecimal", SI_KEY, KEY_DECIMAL },
  1526. { "numpaddivide", SI_KEY, KEY_DIVIDE },
  1527. { "numpadenter", SI_KEY, KEY_NUMPADENTER },
  1528. { "f1", SI_KEY, KEY_F1 },
  1529. { "f2", SI_KEY, KEY_F2 },
  1530. { "f3", SI_KEY, KEY_F3 },
  1531. { "f4", SI_KEY, KEY_F4 },
  1532. { "f5", SI_KEY, KEY_F5 },
  1533. { "f6", SI_KEY, KEY_F6 },
  1534. { "f7", SI_KEY, KEY_F7 },
  1535. { "f8", SI_KEY, KEY_F8 },
  1536. { "f9", SI_KEY, KEY_F9 },
  1537. { "f10", SI_KEY, KEY_F10 },
  1538. { "f11", SI_KEY, KEY_F11 },
  1539. { "f12", SI_KEY, KEY_F12 },
  1540. { "f13", SI_KEY, KEY_F13 },
  1541. { "f14", SI_KEY, KEY_F14 },
  1542. { "f15", SI_KEY, KEY_F15 },
  1543. { "f16", SI_KEY, KEY_F16 },
  1544. { "f17", SI_KEY, KEY_F17 },
  1545. { "f18", SI_KEY, KEY_F18 },
  1546. { "f19", SI_KEY, KEY_F19 },
  1547. { "f20", SI_KEY, KEY_F20 },
  1548. { "f21", SI_KEY, KEY_F21 },
  1549. { "f22", SI_KEY, KEY_F22 },
  1550. { "f23", SI_KEY, KEY_F23 },
  1551. { "f24", SI_KEY, KEY_F24 },
  1552. { "numlock", SI_KEY, KEY_NUMLOCK },
  1553. { "scrolllock", SI_KEY, KEY_SCROLLLOCK },
  1554. { "lshift", SI_KEY, KEY_LSHIFT },
  1555. { "rshift", SI_KEY, KEY_RSHIFT },
  1556. { "lcontrol", SI_KEY, KEY_LCONTROL },
  1557. { "rcontrol", SI_KEY, KEY_RCONTROL },
  1558. { "lalt", SI_KEY, KEY_LALT },
  1559. { "ralt", SI_KEY, KEY_RALT },
  1560. { "tilde", SI_KEY, KEY_TILDE },
  1561. { "minus", SI_KEY, KEY_MINUS },
  1562. { "equals", SI_KEY, KEY_EQUALS },
  1563. { "lbracket", SI_KEY, KEY_LBRACKET },
  1564. { "rbracket", SI_KEY, KEY_RBRACKET },
  1565. { "backslash", SI_KEY, KEY_BACKSLASH },
  1566. { "semicolon", SI_KEY, KEY_SEMICOLON },
  1567. { "apostrophe", SI_KEY, KEY_APOSTROPHE },
  1568. { "comma", SI_KEY, KEY_COMMA },
  1569. { "period", SI_KEY, KEY_PERIOD },
  1570. { "slash", SI_KEY, KEY_SLASH },
  1571. { "lessthan", SI_KEY, KEY_OEM_102 },
  1572. //-------------------------------------- BUTTON EVENTS
  1573. // Joystick/Mouse buttons
  1574. { "button0", SI_BUTTON, KEY_BUTTON0 },
  1575. { "button1", SI_BUTTON, KEY_BUTTON1 },
  1576. { "button2", SI_BUTTON, KEY_BUTTON2 },
  1577. { "button3", SI_BUTTON, KEY_BUTTON3 },
  1578. { "button4", SI_BUTTON, KEY_BUTTON4 },
  1579. { "button5", SI_BUTTON, KEY_BUTTON5 },
  1580. { "button6", SI_BUTTON, KEY_BUTTON6 },
  1581. { "button7", SI_BUTTON, KEY_BUTTON7 },
  1582. { "button8", SI_BUTTON, KEY_BUTTON8 },
  1583. { "button9", SI_BUTTON, KEY_BUTTON9 },
  1584. { "button10", SI_BUTTON, KEY_BUTTON10 },
  1585. { "button11", SI_BUTTON, KEY_BUTTON11 },
  1586. { "button12", SI_BUTTON, KEY_BUTTON12 },
  1587. { "button13", SI_BUTTON, KEY_BUTTON13 },
  1588. { "button14", SI_BUTTON, KEY_BUTTON14 },
  1589. { "button15", SI_BUTTON, KEY_BUTTON15 },
  1590. { "button16", SI_BUTTON, KEY_BUTTON16 },
  1591. { "button17", SI_BUTTON, KEY_BUTTON17 },
  1592. { "button18", SI_BUTTON, KEY_BUTTON18 },
  1593. { "button19", SI_BUTTON, KEY_BUTTON19 },
  1594. { "button20", SI_BUTTON, KEY_BUTTON20 },
  1595. { "button21", SI_BUTTON, KEY_BUTTON21 },
  1596. { "button22", SI_BUTTON, KEY_BUTTON22 },
  1597. { "button23", SI_BUTTON, KEY_BUTTON23 },
  1598. { "button24", SI_BUTTON, KEY_BUTTON24 },
  1599. { "button25", SI_BUTTON, KEY_BUTTON25 },
  1600. { "button26", SI_BUTTON, KEY_BUTTON26 },
  1601. { "button27", SI_BUTTON, KEY_BUTTON27 },
  1602. { "button28", SI_BUTTON, KEY_BUTTON28 },
  1603. { "button29", SI_BUTTON, KEY_BUTTON29 },
  1604. { "button30", SI_BUTTON, KEY_BUTTON30 },
  1605. { "button31", SI_BUTTON, KEY_BUTTON31 },
  1606. //-------------------------------------- MOVE EVENTS
  1607. // Mouse/Joystick axes:
  1608. { "xaxis", SI_MOVE, SI_XAXIS },
  1609. { "yaxis", SI_MOVE, SI_YAXIS },
  1610. { "zaxis", SI_MOVE, SI_ZAXIS },
  1611. { "rxaxis", SI_MOVE, SI_RXAXIS },
  1612. { "ryaxis", SI_MOVE, SI_RYAXIS },
  1613. { "rzaxis", SI_MOVE, SI_RZAXIS },
  1614. { "slider", SI_MOVE, SI_SLIDER },
  1615. //-------------------------------------- POV EVENTS
  1616. // Joystick POV:
  1617. { "xpov", SI_POV, SI_XPOV },
  1618. { "ypov", SI_POV, SI_YPOV },
  1619. { "upov", SI_POV, SI_UPOV },
  1620. { "dpov", SI_POV, SI_DPOV },
  1621. { "lpov", SI_POV, SI_LPOV },
  1622. { "rpov", SI_POV, SI_RPOV },
  1623. { "xpov2", SI_POV, SI_XPOV2 },
  1624. { "ypov2", SI_POV, SI_YPOV2 },
  1625. { "upov2", SI_POV, SI_UPOV2 },
  1626. { "dpov2", SI_POV, SI_DPOV2 },
  1627. { "lpov2", SI_POV, SI_LPOV2 },
  1628. { "rpov2", SI_POV, SI_RPOV2 },
  1629. //-------------------------------------- MOTION EVENTS
  1630. // Accelerometer/Gyroscope axes:
  1631. { "accelx", SI_MOTION, SI_ACCELX },
  1632. { "accely", SI_MOTION, SI_ACCELY },
  1633. { "accelz", SI_MOTION, SI_ACCELZ },
  1634. { "gravityx", SI_MOTION, SI_GRAVX },
  1635. { "gravityy", SI_MOTION, SI_GRAVY },
  1636. { "gravityz", SI_MOTION, SI_GRAVZ },
  1637. { "gyrox", SI_MOTION, SI_GYROX },
  1638. { "gyroy", SI_MOTION, SI_GYROY },
  1639. { "gyroz", SI_MOTION, SI_GYROZ },
  1640. { "yaw", SI_MOTION, SI_YAW },
  1641. { "pitch", SI_MOTION, SI_PITCH },
  1642. { "roll", SI_MOTION, SI_ROLL },
  1643. { "touchdown", SI_TOUCH, SI_TOUCHDOWN },
  1644. { "touchup", SI_TOUCH, SI_TOUCHUP },
  1645. { "touchmove", SI_TOUCH, SI_TOUCHMOVE },
  1646. { "gesture", SI_TOUCH, SI_GESTURE },
  1647. //-------------------------------------- MISCELLANEOUS EVENTS
  1648. //
  1649. { "anykey", SI_KEY, KEY_ANYKEY },
  1650. { "nomatch", SI_UNKNOWN, 0xFFFFFFFF }
  1651. };
  1652. AsciiMapping gAsciiMap[] =
  1653. {
  1654. //--- KEYBOARD EVENTS
  1655. //
  1656. { "space", 0x0020 },
  1657. //{ "exclamation", 0x0021 },
  1658. { "doublequote", 0x0022 },
  1659. //{ "pound", 0x0023 },
  1660. //{ "ampersand", 0x0026 },
  1661. { "apostrophe", 0x0027 },
  1662. //{ "lparen", 0x0028 },
  1663. //{ "rparen", 0x0029 },
  1664. { "comma", 0x002c },
  1665. { "minus", 0x002d },
  1666. { "period", 0x002e },
  1667. //{ "slash", 0x002f },
  1668. //{ "colon", 0x003a },
  1669. //{ "semicolon", 0x003b },
  1670. //{ "lessthan", 0x003c },
  1671. //{ "equals", 0x003d },
  1672. //{ "morethan", 0x003e },
  1673. //{ "lbracket", 0x005b },
  1674. { "backslash", 0x005c },
  1675. //{ "rbracket", 0x005d },
  1676. //{ "circumflex", 0x005e },
  1677. //{ "underscore", 0x005f },
  1678. { "grave", 0x0060 },
  1679. //{ "tilde", 0x007e },
  1680. //{ "vertbar", 0x007c },
  1681. //{ "exclamdown", 0x00a1 },
  1682. //{ "cent", 0x00a2 },
  1683. //{ "sterling", 0x00a3 },
  1684. //{ "currency", 0x00a4 },
  1685. //{ "brokenbar", 0x00a6 },
  1686. //{ "ring", 0x00b0 },
  1687. //{ "plusminus", 0x00b1 },
  1688. { "super2", 0x00b2 },
  1689. { "super3", 0x00b3 },
  1690. { "acute", 0x00b4 },
  1691. //{ "mu", 0x00b5 },
  1692. //{ "ordmasculine", 0x00ba },
  1693. //{ "questiondown", 0x00bf },
  1694. //{ "gemandbls", 0x00df },
  1695. //{ "agrave", 0x00e0 },
  1696. //{ "aacute", 0x00e1 },
  1697. //{ "acircumflex", 0x00e2 },
  1698. //{ "atilde", 0x00e3 },
  1699. //{ "adieresis", 0x00e4 },
  1700. //{ "aring", 0x00e5 },
  1701. //{ "ae", 0x00e6 },
  1702. //{ "ccedille", 0x00e7 },
  1703. //{ "egrave", 0x00e8 },
  1704. //{ "eacute", 0x00e9 },
  1705. //{ "ecircumflex", 0x00ea },
  1706. //{ "edieresis", 0x00eb },
  1707. //{ "igrave", 0x00ec },
  1708. //{ "iacute", 0x00ed },
  1709. //{ "icircumflex", 0x00ee },
  1710. //{ "idieresis", 0x00ef },
  1711. //{ "ntilde", 0x00f1 },
  1712. //{ "ograve", 0x00f2 },
  1713. //{ "oacute", 0x00f3 },
  1714. //{ "ocircumflex", 0x00f4 },
  1715. //{ "otilde", 0x00f5 },
  1716. //{ "odieresis", 0x00f6 },
  1717. //{ "divide", 0x00f7 },
  1718. //{ "oslash", 0x00f8 },
  1719. //{ "ugrave", 0x00f9 },
  1720. //{ "uacute", 0x00fa },
  1721. //{ "ucircumflex", 0x00fb },
  1722. //{ "udieresis", 0x00fc },
  1723. //{ "ygrave", 0x00fd },
  1724. //{ "thorn", 0x00fe },
  1725. //{ "ydieresis", 0x00ff },
  1726. { "nomatch", 0xFFFF }
  1727. };
  1728. ////Device Event Types
  1729. //#define SI_UNKNOWN 0x01
  1730. //#define SI_BUTTON 0x02
  1731. //#define SI_POV 0x03
  1732. //#define SI_XPOV 0x04
  1733. //#define SI_YPOV 0x05
  1734. //#define SI_UPOV 0x06
  1735. //#define SI_DPOV 0x07
  1736. //#define SI_LPOV 0x08
  1737. //#define SI_RPOV 0x09
  1738. //#define SI_KEY 0x0A
  1739. //#define SI_XAXIS 0x0B
  1740. //#define SI_YAXIS 0x0C
  1741. //#define SI_ZAXIS 0x0D
  1742. //#define SI_RXAXIS 0x0E
  1743. //#define SI_RYAXIS 0x0F
  1744. //#define SI_RZAXIS 0x10
  1745. //#define SI_SLIDER 0x11