2
0

actionMap.cpp 84 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 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 "sim/actionMap.h"
  23. #include "console/console.h"
  24. #include "platform/platform.h"
  25. #include "platform/platformInput.h"
  26. #include "platform/platformAssert.h"
  27. #include "core/stream/fileStream.h"
  28. #include "math/mMathFn.h"
  29. #include "console/engineAPI.h"
  30. #include "math/mQuat.h"
  31. #include "math/mAngAxis.h"
  32. #define CONST_E 2.7182818284590452353602874f
  33. IMPLEMENT_CONOBJECT(ActionMap);
  34. ConsoleDocClass( ActionMap,
  35. "@brief ActionMaps assign platform input events to console commands.\n\n"
  36. "Any platform input event can be bound in a single, generic way. In theory, the game doesn't need to know if the event came from the keyboard, mouse, joystick "
  37. "or some other input device. This allows users of the game to map keys and actions according to their own preferences. "
  38. "Game action maps are arranged in a stack for processing so individual parts of the game can define specific "
  39. "actions. For example, when the player jumps into a vehicle it could push a vehicle action map and pop the default player action map.\n\n"
  40. "@section ActionMap_creation Creating an ActionMap\n"
  41. "The input system allows for the creation of multiple ActionMaps, so long as they have unique names and do not already exist. It's a simple "
  42. "three step process.\n\n"
  43. "1. Check to see if the ActionMap exists\n"
  44. "2. Delete it if it exists\n"
  45. "3. Instantiate the ActionMap\n\n"
  46. "The following is an example of how to create a new ActionMap:\n"
  47. "@tsexample\n"
  48. "if ( isObject( moveMap ) )\n"
  49. " moveMap.delete();\n"
  50. "new ActionMap(moveMap);"
  51. "@endtsexample\n\n\n"
  52. "@section ActionMap_binding Binding Functions\n"
  53. "Once you have created an ActionMap, you can start binding functionality to events. Currently, Torque 3D supports the following devices out of the box\n\n"
  54. "* Mouse\n\n"
  55. "* Keyboard\n\n"
  56. "* Joystick/Gamepad\n\n"
  57. "* Xbox 360 Controller\n\n"
  58. "The two most commonly used binding methods are bind() and bindCmd(). Both are similar in that they will bind functionality to a device and event, "
  59. "but different in how the event is interpreted. With bind(), "
  60. "you specify a device, action to bind, then a function to be called when the event happens.\n\n"
  61. "@tsexample\n"
  62. "// Simple function that prints to console\n"
  63. "// %val - Sent by the device letting the user know\n"
  64. "// if an input was pressed (true) or released (false)\n"
  65. "function testInput(%val)\n"
  66. "{\n"
  67. " if(%val)\n"
  68. " echo(\"Key is down\");\n"
  69. " else\n"
  70. " echo(\"Key was released\");\n"
  71. "}\n\n"
  72. "// Bind the \'K\' key to the testInput function\n"
  73. "moveMap.bind(keyboard, \"k\", testInput);\n\n"
  74. "@endtsexample\n\n\n"
  75. "bindCmd is an alternative method for binding commands. This function is similar to bind(), "
  76. "except two functions are set to be called when the event is processed.\n\n"
  77. "One will be called when the event is activated (input down), while the other is activated when the event is broken (input release). "
  78. "When using bindCmd(), pass the functions as strings rather than the function names.\n\n"
  79. "@tsexample\n"
  80. "// Print to the console when the spacebar is pressed\n"
  81. "function onSpaceDown()\n"
  82. "{\n"
  83. " echo(\"Space bar down!\");\n"
  84. "}\n\n"
  85. "// Print to the console when the spacebar is released\n"
  86. "function onSpaceUp()\n"
  87. "{\n"
  88. " echo(\"Space bar up!\");\n"
  89. "}\n\n"
  90. "// Bind the commands onSpaceDown and onSpaceUp to spacebar events\n"
  91. "moveMap.bindCmd(keyboard, \"space\", \"onSpaceDown();\", \"onSpaceUp();\");\n"
  92. "@endtsexample\n\n"
  93. "@section ActionMap_switching Switching ActionMaps\n"
  94. "Let's say you want to have different ActionMaps activated based on game play situations. A classic example would be first person shooter controls and racing controls "
  95. "in the same game. On foot, spacebar may cause your player to jump. In a vehicle, it may cause some kind of \"turbo charge\". You simply need to push/pop the ActionMaps appropriately:\n\n"
  96. "First, create two separate ActionMaps:\n\n"
  97. "@tsexample\n"
  98. "// Create the two ActionMaps\n"
  99. "if ( isObject( moveMap ) )\n"
  100. " moveMap.delete();\n"
  101. "new ActionMap(moveMap);\n\n"
  102. "if ( isObject( carMap ) )\n"
  103. " carMap.delete();\n"
  104. "new ActionMap(carMap);\n\n"
  105. "@endtsexample\n\n"
  106. "Next, create the two separate functions. Both will be bound to spacebar, but not the same ActionMap:\n\n"
  107. "@tsexample\n"
  108. "// Print to the console the player is jumping\n"
  109. "function playerJump(%val)\n"
  110. "{\n"
  111. " if(%val)\n"
  112. " echo(\"Player jumping!\");\n"
  113. "}\n\n"
  114. "// Print to the console the vehicle is charging\n"
  115. "function turboCharge()\n"
  116. "{\n"
  117. " if(%val)\n"
  118. " echo(\"Vehicle turbo charging!\");\n"
  119. "}\n"
  120. "@endtsexample\n\n"
  121. "You are now ready to bind functions to your ActionMaps' devices:\n\n"
  122. "@tsexample\n"
  123. "// Bind the spacebar to the playerJump function\n"
  124. "// when moveMap is the active ActionMap\n"
  125. "moveMap.bind(keyboard, \"space\", playerJump);\n\n"
  126. "// Bind the spacebar to the turboCharge function\n"
  127. "// when carMap is the active ActionMap\n"
  128. "carMap.bind(keyboard, \"space\", turboCharge);\n"
  129. "@endtsexample\n"
  130. "Finally, you can use the push() and pop() commands on each ActionMap to toggle activation. To activate an ActionMap, use push():\n\n"
  131. "@tsexample\n"
  132. "// Make moveMap the active action map\n"
  133. "// You should now be able to activate playerJump with spacebar\n"
  134. "moveMap.push();\n"
  135. "@endtsexample\n\n"
  136. "To switch ActionMaps, first pop() the old one. Then you can push() the new one:\n\n"
  137. "@tsexample\n"
  138. "// Deactivate moveMap\n"
  139. "moveMap.pop();\n\n"
  140. "// Activate carMap\n"
  141. "carMap.push();\n\n"
  142. "@endtsexample\n\n\n"
  143. "@ingroup Input"
  144. );
  145. // This is used for determing keys that have ascii codes for the foreign keyboards. IsAlpha doesn't work on foreign keys.
  146. static inline bool dIsDecentChar(U8 c)
  147. {
  148. return ((U8(0xa0) <= c) || (( U8(0x21) <= c) && (c <= U8(0x7e))) || ((U8(0x91) <= c) && (c <= U8(0x92))));
  149. }
  150. struct AsciiMapping
  151. {
  152. const char* pDescription;
  153. U16 asciiCode;
  154. };
  155. extern AsciiMapping gAsciiMap[];
  156. //------------------------------------------------------------------------------
  157. //-------------------------------------- Action maps
  158. //
  159. Vector<ActionMap::BreakEntry> ActionMap::smBreakTable(__FILE__, __LINE__);
  160. //------------------------------------------------------------------------------
  161. ActionMap::ActionMap()
  162. {
  163. VECTOR_SET_ASSOCIATION(mDeviceMaps);
  164. }
  165. //------------------------------------------------------------------------------
  166. ActionMap::~ActionMap()
  167. {
  168. for (U32 i = 0; i < mDeviceMaps.size(); i++)
  169. delete mDeviceMaps[i];
  170. mDeviceMaps.clear();
  171. }
  172. //------------------------------------------------------------------------------
  173. ActionMap::DeviceMap::~DeviceMap()
  174. {
  175. for(U32 i = 0; i < nodeMap.size(); i++)
  176. {
  177. dFree(nodeMap[i].makeConsoleCommand);
  178. dFree(nodeMap[i].breakConsoleCommand);
  179. }
  180. }
  181. //------------------------------------------------------------------------------
  182. bool ActionMap::onAdd()
  183. {
  184. if (Parent::onAdd() == false)
  185. return false;
  186. Sim::getActionMapGroup()->addObject(this);
  187. return true;
  188. }
  189. //--------------------------------------------------------------------------
  190. void ActionMap::dumpActionMap(const char* fileName, const bool append) const
  191. {
  192. if (fileName != NULL) {
  193. // Dump the deletion, and creation script commands, followed by all the binds
  194. // to a script.
  195. FileStream *iostrm;
  196. if((iostrm = FileStream::createAndOpen( fileName, append ? Torque::FS::File::WriteAppend : Torque::FS::File::Write )) == NULL)
  197. {
  198. Con::errorf( "Unable to open file '%s' for writing.", fileName );
  199. return;
  200. }
  201. char lineBuffer[1024];
  202. if ( append )
  203. iostrm->setPosition( iostrm->getStreamSize() );
  204. else
  205. {
  206. // IMPORTANT -- do NOT change the following line, it identifies the file as an input map file
  207. dStrcpy( lineBuffer, "// Torque Input Map File\n", 1024 );
  208. iostrm->write( dStrlen( lineBuffer ), lineBuffer );
  209. }
  210. dSprintf(lineBuffer, 1024, "if (isObject(%s)) %s.delete();\n"
  211. "new ActionMap(%s);\n", getName(), getName(), getName());
  212. iostrm->write(dStrlen(lineBuffer), lineBuffer);
  213. // Dump all the binds to the console...
  214. for (S32 i = 0; i < mDeviceMaps.size(); i++) {
  215. const DeviceMap* pDevMap = mDeviceMaps[i];
  216. char devbuffer[32];
  217. getDeviceName(pDevMap->deviceType, pDevMap->deviceInst, devbuffer);
  218. for (S32 j = 0; j < pDevMap->nodeMap.size(); j++) {
  219. const Node& rNode = pDevMap->nodeMap[j];
  220. const char* pModifierString = getModifierString(rNode.modifiers);
  221. char objectbuffer[64];
  222. if (getKeyString(rNode.action, objectbuffer) == false)
  223. continue;
  224. const char* command;
  225. if (rNode.flags & Node::BindCmd)
  226. command = "bindCmd";
  227. else if (rNode.flags & Node::Held)
  228. command = "held";
  229. else
  230. command = "bind";
  231. dSprintf(lineBuffer, 1024, "%s.%s(%s, \"%s%s\"",
  232. getName(),
  233. command,
  234. devbuffer,
  235. pModifierString, objectbuffer);
  236. if (rNode.flags & (Node::HasScale|Node::HasDeadZone|Node::Ranged|Node::Inverted)) {
  237. char buff[10];
  238. U32 curr = 0;
  239. buff[curr++] = ',';
  240. buff[curr++] = ' ';
  241. if (rNode.flags & Node::HasScale)
  242. buff[curr++] = 'S';
  243. if (rNode.flags & Node::Ranged)
  244. buff[curr++] = 'R';
  245. if (rNode.flags & Node::HasDeadZone)
  246. buff[curr++] = 'D';
  247. if (rNode.flags & Node::Inverted)
  248. buff[curr++] = 'I';
  249. buff[curr] = '\0';
  250. dStrcat(lineBuffer, buff, 1024);
  251. }
  252. if (rNode.flags & Node::HasDeadZone) {
  253. char buff[64];
  254. dSprintf(buff, 63, ", \"%g %g\"", rNode.deadZoneBegin, rNode.deadZoneEnd);
  255. dStrcat(lineBuffer, buff, 1024);
  256. }
  257. if (rNode.flags & Node::HasScale) {
  258. char buff[64];
  259. dSprintf(buff, 63, ", %g", rNode.scaleFactor);
  260. dStrcat(lineBuffer, buff, 1024);
  261. }
  262. if (rNode.flags & Node::BindCmd) {
  263. if (rNode.makeConsoleCommand) {
  264. dStrcat(lineBuffer, ", \"", 1024);
  265. U32 pos = dStrlen(lineBuffer);
  266. expandEscape(lineBuffer + pos, rNode.makeConsoleCommand);
  267. dStrcat(lineBuffer, "\"", 1024);
  268. } else {
  269. dStrcat(lineBuffer, ", \"\"", 1024);
  270. }
  271. if (rNode.breakConsoleCommand) {
  272. dStrcat(lineBuffer, ", \"", 1024);
  273. U32 pos = dStrlen(lineBuffer);
  274. expandEscape(lineBuffer + pos, rNode.breakConsoleCommand);
  275. dStrcat(lineBuffer, "\"", 1024);
  276. }
  277. else
  278. dStrcat(lineBuffer, ", \"\"", 1024);
  279. }
  280. else if (rNode.flags & Node::Held)
  281. {
  282. dStrcat(lineBuffer, ", ", 1024);
  283. dStrcat(lineBuffer, rNode.consoleFunction, 1024);
  284. dStrcat(lineBuffer, ", ", 1024);
  285. dStrcat(lineBuffer, rNode.contextEvent->mConsoleFunctionHeld, 1024);
  286. }
  287. else {
  288. dStrcat(lineBuffer, ", ", 1024);
  289. dStrcat(lineBuffer, rNode.consoleFunction, 1024);
  290. }
  291. dStrcat(lineBuffer, ");\n", 1024);
  292. iostrm->write(dStrlen(lineBuffer), lineBuffer);
  293. }
  294. }
  295. delete iostrm;
  296. }
  297. else {
  298. // Dump all the binds to the console...
  299. for (S32 i = 0; i < mDeviceMaps.size(); i++) {
  300. const DeviceMap* pDevMap = mDeviceMaps[i];
  301. char devbuffer[32];
  302. getDeviceName(pDevMap->deviceType, pDevMap->deviceInst, devbuffer);
  303. for (S32 j = 0; j < pDevMap->nodeMap.size(); j++) {
  304. const Node& rNode = pDevMap->nodeMap[j];
  305. const char* pModifierString = getModifierString(rNode.modifiers);
  306. char keybuffer[64];
  307. if (getKeyString(rNode.action, keybuffer) == false)
  308. continue;
  309. const char* command;
  310. if (rNode.flags & Node::BindCmd)
  311. command = "bindCmd";
  312. else if (rNode.flags & Node::Held)
  313. command = "held";
  314. else
  315. command = "bind";
  316. char finalBuffer[1024];
  317. dSprintf(finalBuffer, 1024, "%s.%s(%s, \"%s%s\"",
  318. getName(),
  319. command,
  320. devbuffer,
  321. pModifierString, keybuffer);
  322. if (rNode.flags & (Node::HasScale|Node::HasDeadZone|Node::Ranged|Node::Inverted)) {
  323. char buff[10];
  324. U32 curr = 0;
  325. buff[curr++] = ',';
  326. buff[curr++] = ' ';
  327. if (rNode.flags & Node::HasScale)
  328. buff[curr++] = 'S';
  329. if (rNode.flags & Node::Ranged)
  330. buff[curr++] = 'R';
  331. if (rNode.flags & Node::HasDeadZone)
  332. buff[curr++] = 'D';
  333. if (rNode.flags & Node::Inverted)
  334. buff[curr++] = 'I';
  335. buff[curr] = '\0';
  336. dStrcat(finalBuffer, buff, 1024);
  337. }
  338. if (rNode.flags & Node::HasDeadZone) {
  339. char buff[64];
  340. dSprintf(buff, 63, ", \"%g %g\"", rNode.deadZoneBegin, rNode.deadZoneEnd);
  341. dStrcat(finalBuffer, buff, 1024);
  342. }
  343. if (rNode.flags & Node::HasScale) {
  344. char buff[64];
  345. dSprintf(buff, 63, ", %g", rNode.scaleFactor);
  346. dStrcat(finalBuffer, buff, 1024);
  347. }
  348. if (rNode.flags & Node::BindCmd) {
  349. if (rNode.makeConsoleCommand) {
  350. dStrcat(finalBuffer, ", \"", 1024);
  351. dStrcat(finalBuffer, rNode.makeConsoleCommand, 1024);
  352. dStrcat(finalBuffer, "\"", 1024);
  353. } else {
  354. dStrcat(finalBuffer, ", \"\"", 1024);
  355. }
  356. if (rNode.breakConsoleCommand) {
  357. dStrcat(finalBuffer, ", \"", 1024);
  358. dStrcat(finalBuffer, rNode.breakConsoleCommand, 1024);
  359. dStrcat(finalBuffer, "\"", 1024);
  360. }
  361. else
  362. dStrcat(finalBuffer, ", \"\"", 1024);
  363. }
  364. else if (rNode.flags & Node::Held)
  365. {
  366. dStrcat(finalBuffer, ", ", 1024);
  367. dStrcat(finalBuffer, rNode.consoleFunction, 1024);
  368. dStrcat(finalBuffer, ", ", 1024);
  369. dStrcat(finalBuffer, rNode.contextEvent->mConsoleFunctionHeld, 1024);
  370. }
  371. else {
  372. dStrcat(finalBuffer, ", ", 1024);
  373. dStrcat(finalBuffer, rNode.consoleFunction, 1024);
  374. }
  375. dStrcat(finalBuffer, ");", 1024);
  376. Con::printf(finalBuffer);
  377. }
  378. }
  379. }
  380. }
  381. //--------------------------------------------------------------------------
  382. bool ActionMap::createEventDescriptor(const char* pEventString, EventDescriptor* pDescriptor)
  383. {
  384. char copyBuffer[256];
  385. dStrcpy(copyBuffer, pEventString, 256);
  386. // Do we have modifiers?
  387. char* pSpace = dStrchr(copyBuffer, ' ');
  388. char* pObjectString;
  389. if (pSpace != NULL) {
  390. // Yes. Parse them out...
  391. //
  392. pDescriptor->flags = 0;
  393. pObjectString = pSpace + 1;
  394. pSpace[0] = '\0';
  395. char* pModifier = dStrtok(copyBuffer, "-");
  396. while (pModifier != NULL) {
  397. if (dStricmp(pModifier, "shift") == 0) {
  398. pDescriptor->flags |= SI_SHIFT;
  399. } else if (dStricmp(pModifier, "ctrl") == 0) {
  400. pDescriptor->flags |= SI_CTRL;
  401. } else if (dStricmp(pModifier, "alt") == 0) {
  402. pDescriptor->flags |= SI_ALT;
  403. } else if (dStricmp(pModifier, "cmd") == 0) {
  404. pDescriptor->flags |= SI_ALT;
  405. } else if (dStricmp(pModifier, "opt") == 0) {
  406. pDescriptor->flags |= SI_MAC_OPT;
  407. }
  408. pModifier = dStrtok(NULL, "-");
  409. }
  410. } else {
  411. // No.
  412. pDescriptor->flags = 0;
  413. pObjectString = copyBuffer;
  414. }
  415. // Now we need to map the key string to the proper KEY code from event.h
  416. //
  417. AssertFatal(dStrlen(pObjectString) != 0, "Error, no key was specified!");
  418. if (dStrlen(pObjectString) == 1)
  419. {
  420. if (dIsDecentChar(*pObjectString)) // includes foreign chars
  421. {
  422. U16 asciiCode = (*pObjectString);
  423. // clear out the FF in upper 8bits for foreign keys??
  424. asciiCode &= 0xFF;
  425. U16 keyCode = Input::getKeyCode(asciiCode);
  426. if ( keyCode >= KEY_0 )
  427. {
  428. pDescriptor->eventType = SI_KEY;
  429. pDescriptor->eventCode = keyCode;
  430. return true;
  431. }
  432. else if (dIsalpha(*pObjectString) == true)
  433. {
  434. pDescriptor->eventType = SI_KEY;
  435. pDescriptor->eventCode = KEY_A+dTolower(*pObjectString)-'a';
  436. return true;
  437. }
  438. else if (dIsdigit(*pObjectString) == true)
  439. {
  440. pDescriptor->eventType = SI_KEY;
  441. pDescriptor->eventCode = KEY_0+(*pObjectString)-'0';
  442. return true;
  443. }
  444. }
  445. return false;
  446. }
  447. else
  448. {
  449. pDescriptor->eventCode = 0;
  450. // Gotta search through the Ascii table...
  451. for (U16 i = 0; gAsciiMap[i].asciiCode != 0xFFFF; i++)
  452. {
  453. if (dStricmp(pObjectString, gAsciiMap[i].pDescription) == 0)
  454. {
  455. U16 asciiCode = gAsciiMap[i].asciiCode;
  456. U16 keyCode = Input::getKeyCode(asciiCode);
  457. if ( keyCode >= KEY_0 )
  458. {
  459. pDescriptor->eventType = SI_KEY;
  460. pDescriptor->eventCode = keyCode;
  461. return(true);
  462. }
  463. else
  464. {
  465. break;
  466. }
  467. }
  468. }
  469. // Didn't find an ascii match. Check the virtual map table
  470. //for (U32 j = 0; gVirtualMap[j].code != 0xFFFFFFFF; j++)
  471. //{
  472. // if (dStricmp(pObjectString, gVirtualMap[j].pDescription) == 0)
  473. // {
  474. // pDescriptor->eventType = gVirtualMap[j].type;
  475. // pDescriptor->eventCode = gVirtualMap[j].code;
  476. // return true;
  477. // }
  478. //}
  479. InputEventManager::VirtualMapData* data = INPUTMGR->findVirtualMap(pObjectString);
  480. if(data)
  481. {
  482. pDescriptor->eventType = data->type;
  483. pDescriptor->eventCode = data->code;
  484. return true;
  485. }
  486. }
  487. return false;
  488. }
  489. //------------------------------------------------------------------------------
  490. ActionMap::Node* ActionMap::getNode(const U32 inDeviceType, const U32 inDeviceInst,
  491. const U32 inModifiers, const U32 inAction,SimObject* object /*= NULL*/)
  492. {
  493. // DMMTODO - Slow INITIAL implementation. Replace with a faster version...
  494. //
  495. DeviceMap* pDeviceMap = NULL;
  496. U32 i;
  497. for (i = 0; i < mDeviceMaps.size(); i++)
  498. {
  499. if (mDeviceMaps[i]->deviceType == inDeviceType &&
  500. mDeviceMaps[i]->deviceInst == inDeviceInst) {
  501. pDeviceMap = mDeviceMaps[i];
  502. break;
  503. }
  504. }
  505. if (pDeviceMap == NULL)
  506. {
  507. mDeviceMaps.increment();
  508. mDeviceMaps.last() = new DeviceMap;
  509. pDeviceMap = mDeviceMaps.last();
  510. pDeviceMap->deviceInst = inDeviceInst;
  511. pDeviceMap->deviceType = inDeviceType;
  512. }
  513. for (i = 0; i < pDeviceMap->nodeMap.size(); i++)
  514. {
  515. if (pDeviceMap->nodeMap[i].modifiers == inModifiers &&
  516. pDeviceMap->nodeMap[i].action == inAction &&
  517. ( (object != NULL) ? object == pDeviceMap->nodeMap[i].object : true )) // Check for an object match if the object exists
  518. {
  519. return &pDeviceMap->nodeMap[i];
  520. }
  521. }
  522. // If we're here, the node doesn't exist. create it.
  523. pDeviceMap->nodeMap.increment();
  524. Node* pRetNode = &pDeviceMap->nodeMap.last();
  525. pRetNode->modifiers = inModifiers;
  526. pRetNode->action = inAction;
  527. pRetNode->flags = 0;
  528. pRetNode->deadZoneBegin = 0.0;
  529. pRetNode->deadZoneEnd = 0.0;
  530. pRetNode->scaleFactor = 1.0;
  531. pRetNode->consoleFunction = NULL;
  532. pRetNode->makeConsoleCommand = NULL;
  533. pRetNode->breakConsoleCommand = NULL;
  534. //[neob, 5/7/2007 - #2975]
  535. pRetNode->object = 0;
  536. return pRetNode;
  537. }
  538. //------------------------------------------------------------------------------
  539. void ActionMap::removeNode(const U32 inDeviceType, const U32 inDeviceInst, const U32 inModifiers, const U32 inAction, SimObject* object /*= NULL*/)
  540. {
  541. // DMMTODO - Slow INITIAL implementation. Replace with a faster version...
  542. //
  543. DeviceMap* pDeviceMap = NULL;
  544. U32 i;
  545. for (i = 0; i < mDeviceMaps.size(); i++) {
  546. if (mDeviceMaps[i]->deviceType == inDeviceType &&
  547. mDeviceMaps[i]->deviceInst == inDeviceInst) {
  548. pDeviceMap = mDeviceMaps[i];
  549. break;
  550. }
  551. }
  552. if (pDeviceMap == NULL)
  553. return;
  554. U32 realMods = inModifiers;
  555. if (realMods & SI_SHIFT)
  556. realMods |= SI_SHIFT;
  557. if (realMods & SI_CTRL)
  558. realMods |= SI_CTRL;
  559. if (realMods & SI_ALT)
  560. realMods |= SI_ALT;
  561. if (realMods & SI_MAC_OPT)
  562. realMods |= SI_MAC_OPT;
  563. for (i = 0; i < pDeviceMap->nodeMap.size(); i++) {
  564. if (pDeviceMap->nodeMap[i].modifiers == realMods &&
  565. pDeviceMap->nodeMap[i].action == inAction &&
  566. ( (object != NULL) ? object == pDeviceMap->nodeMap[i].object : true ))
  567. {
  568. dFree(pDeviceMap->nodeMap[i].makeConsoleCommand);
  569. dFree(pDeviceMap->nodeMap[i].breakConsoleCommand);
  570. pDeviceMap->nodeMap.erase(i);
  571. }
  572. }
  573. }
  574. //------------------------------------------------------------------------------
  575. const ActionMap::Node* ActionMap::findNode(const U32 inDeviceType, const U32 inDeviceInst,
  576. const U32 inModifiers, const U32 inAction)
  577. {
  578. // DMMTODO - Slow INITIAL implementation. Replace with a faster version...
  579. //
  580. DeviceMap* pDeviceMap = NULL;
  581. U32 i;
  582. for (i = 0; i < mDeviceMaps.size(); i++)
  583. {
  584. if (mDeviceMaps[i]->deviceType == inDeviceType && mDeviceMaps[i]->deviceInst == inDeviceInst)
  585. {
  586. pDeviceMap = mDeviceMaps[i];
  587. break;
  588. }
  589. }
  590. if (pDeviceMap == NULL)
  591. return NULL;
  592. U32 realMods = inModifiers;
  593. if (realMods & SI_SHIFT)
  594. realMods |= SI_SHIFT;
  595. if (realMods & SI_CTRL)
  596. realMods |= SI_CTRL;
  597. if (realMods & SI_ALT)
  598. realMods |= SI_ALT;
  599. if (realMods & SI_MAC_OPT)
  600. realMods |= SI_MAC_OPT;
  601. for (i = 0; i < pDeviceMap->nodeMap.size(); i++)
  602. {
  603. // Special case for an ANYKEY bind...
  604. if (pDeviceMap->nodeMap[i].action == KEY_ANYKEY
  605. && pDeviceMap->nodeMap[i].modifiers == realMods
  606. && dIsDecentChar(inAction)
  607. && inAction <= U8_MAX)
  608. return &pDeviceMap->nodeMap[i];
  609. if (pDeviceMap->nodeMap[i].modifiers == realMods
  610. && pDeviceMap->nodeMap[i].action == inAction)
  611. return &pDeviceMap->nodeMap[i];
  612. }
  613. return NULL;
  614. }
  615. //------------------------------------------------------------------------------
  616. bool ActionMap::findBoundNode( const char* function, U32 &devMapIndex, U32 &nodeIndex )
  617. {
  618. devMapIndex = 0;
  619. nodeIndex = 0;
  620. return nextBoundNode( function, devMapIndex, nodeIndex );
  621. }
  622. bool ActionMap::nextBoundNode( const char* function, U32 &devMapIndex, U32 &nodeIndex )
  623. {
  624. // Loop through all of the existing nodes to find the one mapped to the
  625. // given function:
  626. for ( U32 i = devMapIndex; i < mDeviceMaps.size(); i++ )
  627. {
  628. const DeviceMap* dvcMap = mDeviceMaps[i];
  629. for ( U32 j = nodeIndex; j < dvcMap->nodeMap.size(); j++ )
  630. {
  631. const Node* node = &dvcMap->nodeMap[j];
  632. if ( !( node->flags & Node::BindCmd ) && ( dStricmp( function, node->consoleFunction ) == 0 ) )
  633. {
  634. devMapIndex = i;
  635. nodeIndex = j;
  636. return( true );
  637. }
  638. }
  639. nodeIndex = 0;
  640. }
  641. return( false );
  642. }
  643. //------------------------------------------------------------------------------
  644. bool ActionMap::processUnbind(const char *device, const char *action, SimObject* object /*= NULL*/)
  645. {
  646. U32 deviceType;
  647. U32 deviceInst;
  648. if(!getDeviceTypeAndInstance(device, deviceType, deviceInst))
  649. return false;
  650. EventDescriptor eventDescriptor;
  651. if (!createEventDescriptor(action, &eventDescriptor))
  652. return false;
  653. removeNode(deviceType, deviceInst, eventDescriptor.flags,eventDescriptor.eventCode, object);
  654. return true;
  655. }
  656. //------------------------------------------------------------------------------
  657. // This function is for the use of the control remapper.
  658. // It will only check against the console function (since all remappable commands are
  659. // bound using bind and not bindCmd).
  660. //
  661. const char* ActionMap::getBinding( const char* command )
  662. {
  663. char* returnString = Con::getReturnBuffer( 1024 );
  664. returnString[0] = 0;
  665. char buffer[256];
  666. char deviceBuffer[32];
  667. char keyBuffer[64];
  668. U32 devMapIndex = 0, nodeIndex = 0;
  669. while ( nextBoundNode( command, devMapIndex, nodeIndex ) )
  670. {
  671. const DeviceMap* deviceMap = mDeviceMaps[devMapIndex];
  672. if ( getDeviceName( deviceMap->deviceType, deviceMap->deviceInst, deviceBuffer ) )
  673. {
  674. const Node* node = &deviceMap->nodeMap[nodeIndex];
  675. const char* modifierString = getModifierString( node->modifiers );
  676. if ( getKeyString( node->action, keyBuffer ) )
  677. {
  678. dSprintf( buffer, sizeof( buffer ), "%s\t%s%s", deviceBuffer, modifierString, keyBuffer );
  679. if ( returnString[0] )
  680. dStrcat( returnString, "\t", 1024 );
  681. dStrcat( returnString, buffer, 1024 );
  682. }
  683. }
  684. ++nodeIndex;
  685. }
  686. return returnString;
  687. }
  688. //------------------------------------------------------------------------------
  689. // This function is for the use of the control remapper.
  690. // The intent of this function is to determine if the given event descriptor is already
  691. // bound in this action map. If so, this function returns the command it is bound to.
  692. // If not, it returns NULL.
  693. //
  694. const char* ActionMap::getCommand( const char* device, const char* action )
  695. {
  696. U32 deviceType;
  697. U32 deviceInst;
  698. if ( getDeviceTypeAndInstance( device, deviceType, deviceInst ) )
  699. {
  700. EventDescriptor eventDescriptor;
  701. if ( createEventDescriptor( action, &eventDescriptor ) )
  702. {
  703. const ActionMap::Node* mapNode = findNode( deviceType, deviceInst, eventDescriptor.flags, eventDescriptor.eventCode );
  704. if ( mapNode )
  705. {
  706. if ( mapNode->flags & Node::BindCmd )
  707. {
  708. S32 bufferLen = dStrlen( mapNode->makeConsoleCommand ) + dStrlen( mapNode->breakConsoleCommand ) + 2;
  709. char* returnString = Con::getReturnBuffer( bufferLen );
  710. dSprintf( returnString, bufferLen, "%s\t%s",
  711. ( mapNode->makeConsoleCommand ? mapNode->makeConsoleCommand : "" ),
  712. ( mapNode->breakConsoleCommand ? mapNode->breakConsoleCommand : "" ) );
  713. return( returnString );
  714. }
  715. if (mapNode->flags & Node::Held)
  716. {
  717. S32 bufferLen = dStrlen(mapNode->consoleFunction) + dStrlen(mapNode->contextEvent->mConsoleFunctionHeld) + 2;
  718. char* returnString = Con::getReturnBuffer(bufferLen);
  719. dSprintf(returnString, bufferLen, "%st%s",
  720. (mapNode->consoleFunction ? mapNode->consoleFunction : ""),
  721. (mapNode->contextEvent->mConsoleFunctionHeld ? mapNode->contextEvent->mConsoleFunctionHeld : ""));
  722. return(returnString);
  723. }
  724. else
  725. return( mapNode->consoleFunction );
  726. }
  727. }
  728. }
  729. return( "" );
  730. }
  731. //------------------------------------------------------------------------------
  732. // This function returns whether or not the mapping specified is inverted.
  733. // Obviously, this should only be used for axes.
  734. bool ActionMap::isInverted( const char* device, const char* action )
  735. {
  736. U32 deviceType;
  737. U32 deviceInst;
  738. if ( getDeviceTypeAndInstance( device, deviceType, deviceInst ) )
  739. {
  740. EventDescriptor eventDescriptor;
  741. if ( createEventDescriptor( action, &eventDescriptor ) )
  742. {
  743. const ActionMap::Node* mapNode = findNode( deviceType, deviceInst, eventDescriptor.flags, eventDescriptor.eventCode );
  744. if ( mapNode )
  745. return( mapNode->flags & Node::Inverted );
  746. }
  747. }
  748. Con::errorf( "The input event specified by %s %s is not in this action map!", device, action );
  749. return( false );
  750. }
  751. //------------------------------------------------------------------------------
  752. F32 ActionMap::getScale( const char* device, const char* action )
  753. {
  754. U32 deviceType;
  755. U32 deviceInst;
  756. if ( getDeviceTypeAndInstance( device, deviceType, deviceInst ) )
  757. {
  758. EventDescriptor eventDescriptor;
  759. if ( createEventDescriptor( action, &eventDescriptor ) )
  760. {
  761. const ActionMap::Node* mapNode = findNode( deviceType, deviceInst, eventDescriptor.flags, eventDescriptor.eventCode );
  762. if ( mapNode )
  763. {
  764. if ( mapNode->flags & Node::HasScale )
  765. return( mapNode->scaleFactor );
  766. else
  767. return( 1.0f );
  768. }
  769. }
  770. }
  771. Con::errorf( "The input event specified by %s %s is not in this action map!", device, action );
  772. return( 1.0f );
  773. }
  774. //------------------------------------------------------------------------------
  775. const char* ActionMap::getDeadZone( const char* device, const char* action )
  776. {
  777. U32 deviceType;
  778. U32 deviceInst;
  779. if ( getDeviceTypeAndInstance( device, deviceType, deviceInst ) )
  780. {
  781. EventDescriptor eventDescriptor;
  782. if ( createEventDescriptor( action, &eventDescriptor ) )
  783. {
  784. const ActionMap::Node* mapNode = findNode( deviceType, deviceInst, eventDescriptor.flags, eventDescriptor.eventCode );
  785. if ( mapNode )
  786. {
  787. if ( mapNode->flags & Node::HasDeadZone )
  788. {
  789. char buf[64];
  790. dSprintf( buf, sizeof( buf ), "%g %g", mapNode->deadZoneBegin, mapNode->deadZoneEnd );
  791. dsize_t returnLen = dStrlen(buf) + 1;
  792. char* returnString = Con::getReturnBuffer( returnLen );
  793. dStrcpy( returnString, buf, returnLen );
  794. return( returnString );
  795. }
  796. else
  797. return( "0 0" );
  798. }
  799. }
  800. }
  801. Con::errorf( "The input event specified by %s %s is not in this action map!", device, action );
  802. return( "" );
  803. }
  804. //------------------------------------------------------------------------------
  805. const char* ActionMap::buildActionString( const InputEventInfo* event )
  806. {
  807. const char* modifierString = getModifierString( event->modifier );
  808. char objectBuffer[64];
  809. if ( !getKeyString( event->objInst, objectBuffer ) )
  810. return( "" );
  811. U32 returnLen = dStrlen( modifierString ) + dStrlen( objectBuffer ) + 2;
  812. char* returnString = Con::getReturnBuffer( returnLen );
  813. dSprintf( returnString, returnLen - 1, "%s%s", modifierString, objectBuffer );
  814. return( returnString );
  815. }
  816. //------------------------------------------------------------------------------
  817. bool ActionMap::getDeviceTypeAndInstance(const char *pDeviceName, U32 &deviceType, U32 &deviceInstance)
  818. {
  819. U32 offset = 0;
  820. U32 inputMgrDeviceType = 0;
  821. if (dStrnicmp(pDeviceName, "keyboard", dStrlen("keyboard")) == 0)
  822. {
  823. deviceType = KeyboardDeviceType;
  824. offset = dStrlen("keyboard");
  825. }
  826. else if (dStrnicmp(pDeviceName, "mouse", dStrlen("mouse")) == 0)
  827. {
  828. deviceType = MouseDeviceType;
  829. offset = dStrlen("mouse");
  830. }
  831. else if (dStrnicmp(pDeviceName, "joystick", dStrlen("joystick")) == 0)
  832. {
  833. deviceType = JoystickDeviceType;
  834. offset = dStrlen("joystick");
  835. }
  836. else if (dStrnicmp(pDeviceName, "gamepad", dStrlen("gamepad")) == 0)
  837. {
  838. deviceType = GamepadDeviceType;
  839. offset = dStrlen("gamepad");
  840. }
  841. else if(INPUTMGR->isRegisteredDeviceWithAttributes(pDeviceName, inputMgrDeviceType, offset))
  842. {
  843. deviceType = inputMgrDeviceType;
  844. }
  845. else
  846. {
  847. return false;
  848. }
  849. if (dStrlen(pDeviceName) > offset)
  850. {
  851. const char* pInst = pDeviceName + offset;
  852. S32 instNum = dAtoi(pInst);
  853. if (instNum < 0)
  854. deviceInstance = 0;
  855. else
  856. deviceInstance = instNum;
  857. }
  858. else
  859. {
  860. deviceInstance = 0;
  861. }
  862. return true;
  863. }
  864. //------------------------------------------------------------------------------
  865. bool ActionMap::getDeviceName(const U32 deviceType, const U32 deviceInstance, char* buffer)
  866. {
  867. switch (deviceType) {
  868. case KeyboardDeviceType:
  869. dStrcpy(buffer, "keyboard", 16);
  870. break;
  871. case MouseDeviceType:
  872. dSprintf(buffer, 16, "mouse%d", deviceInstance);
  873. break;
  874. case JoystickDeviceType:
  875. dSprintf(buffer, 16, "joystick%d", deviceInstance);
  876. break;
  877. case GamepadDeviceType:
  878. dSprintf(buffer, 16, "gamepad%d", deviceInstance);
  879. break;
  880. default:
  881. {
  882. const char* name = INPUTMGR->getRegisteredDeviceName(deviceType);
  883. if(!name)
  884. {
  885. Con::errorf( "ActionMap::getDeviceName: unknown device type specified, %d (inst: %d)", deviceType, deviceInstance);
  886. return false;
  887. }
  888. dSprintf(buffer, 16, "%s%d", name, deviceInstance);
  889. break;
  890. }
  891. }
  892. return true;
  893. }
  894. //------------------------------------------------------------------------------
  895. const char* ActionMap::getModifierString(const U32 modifiers)
  896. {
  897. U32 realModifiers = modifiers;
  898. if ( modifiers & SI_LSHIFT || modifiers & SI_RSHIFT )
  899. realModifiers |= SI_SHIFT;
  900. if ( modifiers & SI_LCTRL || modifiers & SI_RCTRL )
  901. realModifiers |= SI_CTRL;
  902. if ( modifiers & SI_LALT || modifiers & SI_RALT )
  903. realModifiers |= SI_ALT;
  904. if ( modifiers & SI_MAC_LOPT || modifiers & SI_MAC_ROPT )
  905. realModifiers |= SI_MAC_OPT;
  906. switch (realModifiers & (SI_SHIFT|SI_CTRL|SI_ALT|SI_MAC_OPT))
  907. {
  908. #if defined(TORQUE_OS_MAC)
  909. // optional code, to output alt as cmd on mac.
  910. // interpreter sees them as the same...
  911. case (SI_SHIFT|SI_CTRL|SI_ALT):
  912. return "cmd-shift-ctrl ";
  913. case (SI_SHIFT|SI_ALT):
  914. return "cmd-shift ";
  915. case (SI_CTRL|SI_ALT):
  916. return "cmd-ctrl ";
  917. case (SI_ALT):
  918. return "cmd ";
  919. #else
  920. case (SI_SHIFT|SI_CTRL|SI_ALT):
  921. return "shift-ctrl-alt ";
  922. case (SI_SHIFT|SI_ALT):
  923. return "shift-alt ";
  924. case (SI_CTRL|SI_ALT):
  925. return "ctrl-alt ";
  926. case (SI_ALT):
  927. return "alt ";
  928. #endif
  929. case (SI_SHIFT|SI_CTRL):
  930. return "shift-ctrl ";
  931. case (SI_SHIFT):
  932. return "shift ";
  933. case (SI_CTRL):
  934. return "ctrl ";
  935. // plus new mac cases:
  936. case (SI_ALT|SI_SHIFT|SI_CTRL|SI_MAC_OPT):
  937. return "cmd-shift-ctrl-opt ";
  938. case (SI_ALT|SI_SHIFT|SI_MAC_OPT):
  939. return "cmd-shift-opt ";
  940. case (SI_ALT|SI_CTRL|SI_MAC_OPT):
  941. return "cmd-ctrl-opt ";
  942. case (SI_ALT|SI_MAC_OPT):
  943. return "cmd-opt ";
  944. case (SI_SHIFT|SI_CTRL|SI_MAC_OPT):
  945. return "shift-ctrl-opt ";
  946. case (SI_SHIFT|SI_MAC_OPT):
  947. return "shift-opt ";
  948. case (SI_CTRL|SI_MAC_OPT):
  949. return "ctrl-opt ";
  950. case (SI_MAC_OPT):
  951. return "opt ";
  952. case 0:
  953. return "";
  954. default:
  955. AssertFatal(false, "Error, should never reach the default case in getModifierString");
  956. return "";
  957. }
  958. }
  959. //------------------------------------------------------------------------------
  960. bool ActionMap::getKeyString(const U32 action, char* buffer)
  961. {
  962. U16 asciiCode = 0;
  963. // This is a special case.... numpad keys do have ascii values
  964. // but for the purposes of this method we want to return the
  965. // description from the gVirtualMap.
  966. if ( !( KEY_NUMPAD0 <= action && action <= KEY_NUMPAD9 ) )
  967. asciiCode = Input::getAscii( action, STATE_LOWER );
  968. // if (action >= KEY_A && action <= KEY_Z) {
  969. // buffer[0] = char(action - KEY_A + 'a');
  970. // buffer[1] = '\0';
  971. // return true;
  972. // } else if (action >= KEY_0 && action <= KEY_9) {
  973. // buffer[0] = char(action - KEY_0 + '0');
  974. // buffer[1] = '\0';
  975. if ( (asciiCode != 0) && dIsDecentChar((char)asciiCode))
  976. {
  977. for (U32 i = 0; gAsciiMap[i].asciiCode != 0xFFFF; i++) {
  978. if (gAsciiMap[i].asciiCode == asciiCode)
  979. {
  980. dStrcpy(buffer, gAsciiMap[i].pDescription, 16);
  981. return true;
  982. }
  983. }
  984. // Must not have found a string for that ascii code just record the char
  985. buffer[0] = char(asciiCode);
  986. buffer[1] = '\0';
  987. return true;
  988. }
  989. else
  990. {
  991. if (action >= KEY_A && action <= KEY_Z)
  992. {
  993. buffer[0] = char(action - KEY_A + 'a');
  994. buffer[1] = '\0';
  995. return true;
  996. }
  997. else if (action >= KEY_0 && action <= KEY_9) {
  998. buffer[0] = char(action - KEY_0 + '0');
  999. buffer[1] = '\0';
  1000. return true;
  1001. }
  1002. //for (U32 i = 0; gVirtualMap[i].code != 0xFFFFFFFF; i++) {
  1003. // if (gVirtualMap[i].code == action) {
  1004. // dStrcpy(buffer, gVirtualMap[i].pDescription, 16);
  1005. // return true;
  1006. // }
  1007. //}
  1008. const char* desc = INPUTMGR->findVirtualMapDescFromCode(action);
  1009. if(desc)
  1010. {
  1011. dStrcpy(buffer, desc, 16);
  1012. return true;
  1013. }
  1014. }
  1015. Con::errorf( "ActionMap::getKeyString: no string for action %d", action );
  1016. return false;
  1017. }
  1018. //--------------------------------------------------------------------------
  1019. bool ActionMap::processBindCmd(const char *device, const char *action, const char *makeCmd, const char *breakCmd)
  1020. {
  1021. U32 deviceType;
  1022. U32 deviceInst;
  1023. if(!getDeviceTypeAndInstance(device, deviceType, deviceInst))
  1024. {
  1025. Con::printf("processBindCmd: unknown device: %s", device);
  1026. return false;
  1027. }
  1028. // Ok, we now have the deviceType and instance. Create an event descriptor
  1029. // for the bind...
  1030. //
  1031. EventDescriptor eventDescriptor;
  1032. if (createEventDescriptor(action, &eventDescriptor) == false) {
  1033. Con::printf("Could not create a description for binding: %s", action);
  1034. return false;
  1035. }
  1036. // SI_POV == SI_MOVE, and the POV works fine with bindCmd, so we have to add these manually.
  1037. if( ( eventDescriptor.eventCode == SI_XAXIS ) ||
  1038. ( eventDescriptor.eventCode == SI_YAXIS ) ||
  1039. ( eventDescriptor.eventCode == SI_ZAXIS ) ||
  1040. ( eventDescriptor.eventCode == SI_RXAXIS ) ||
  1041. ( eventDescriptor.eventCode == SI_RYAXIS ) ||
  1042. ( eventDescriptor.eventCode == SI_RZAXIS ) ||
  1043. ( eventDescriptor.eventCode == SI_SLIDER ) ||
  1044. ( eventDescriptor.eventCode == SI_XPOV ) ||
  1045. ( eventDescriptor.eventCode == SI_YPOV ) ||
  1046. ( eventDescriptor.eventCode == SI_XPOV2 ) ||
  1047. ( eventDescriptor.eventCode == SI_YPOV2 ) )
  1048. {
  1049. Con::warnf( "ActionMap::processBindCmd - Cannot use 'bindCmd' with a move event type. Use 'bind' instead." );
  1050. return false;
  1051. }
  1052. // Create the full bind entry, and place it in the map
  1053. //
  1054. // DMMTODO
  1055. Node* pBindNode = getNode(deviceType, deviceInst,
  1056. eventDescriptor.flags,
  1057. eventDescriptor.eventCode);
  1058. pBindNode->flags = Node::BindCmd;
  1059. pBindNode->deadZoneBegin = 0;
  1060. pBindNode->deadZoneEnd = 0;
  1061. pBindNode->scaleFactor = 1;
  1062. if( pBindNode->makeConsoleCommand )
  1063. dFree( pBindNode->makeConsoleCommand );
  1064. if( pBindNode->breakConsoleCommand )
  1065. dFree( pBindNode->breakConsoleCommand );
  1066. if(makeCmd[0])
  1067. pBindNode->makeConsoleCommand = dStrdup(makeCmd);
  1068. else
  1069. pBindNode->makeConsoleCommand = dStrdup("");
  1070. if(breakCmd[0])
  1071. pBindNode->breakConsoleCommand = dStrdup(breakCmd);
  1072. else
  1073. pBindNode->breakConsoleCommand = dStrdup("");
  1074. return true;
  1075. }
  1076. //------------------------------------------------------------------------------
  1077. bool ActionMap::processBind(const U32 argc, const char** argv, SimObject* object)
  1078. {
  1079. // Ok, the bind will come in the following format:
  1080. // [device] [key or button] <[param spec] [param] ...> [fnName]
  1081. //
  1082. const char* pDeviceName = argv[0];
  1083. const char* pEvent = argv[1];
  1084. const char* pFnName = argv[argc - 1];
  1085. // Determine the device
  1086. U32 deviceType;
  1087. U32 deviceInst;
  1088. if(!getDeviceTypeAndInstance(argv[0], deviceType, deviceInst))
  1089. {
  1090. Con::printf("processBind: unknown device: %s", pDeviceName);
  1091. return false;
  1092. }
  1093. // Ok, we now have the deviceType and instance. Create an event descriptor
  1094. // for the bind...
  1095. //
  1096. EventDescriptor eventDescriptor;
  1097. if (createEventDescriptor(pEvent, &eventDescriptor) == false)
  1098. {
  1099. Con::printf("Could not create a description for binding: %s", pEvent);
  1100. return false;
  1101. }
  1102. // Event has now been described, and device determined. we need now to extract
  1103. // any modifiers that the action map will apply to incoming events before
  1104. // calling the bound function...
  1105. //
  1106. // DMMTODO
  1107. U32 assignedFlags = 0;
  1108. F32 deadZoneBegin = 0.0f;
  1109. F32 deadZoneEnd = 0.0f;
  1110. F32 scaleFactor = 1.0f;
  1111. if (argc != 3) {
  1112. // We have the following: "[DSIR]" [deadZone] [scale]
  1113. //
  1114. const char* pSpec = argv[2];
  1115. for (U32 i = 0; pSpec[i] != '\0'; i++) {
  1116. switch (pSpec[i]) {
  1117. case 'r': case 'R':
  1118. assignedFlags |= Node::Ranged;
  1119. break;
  1120. case 's': case 'S':
  1121. assignedFlags |= Node::HasScale;
  1122. break;
  1123. case 'd': case 'D':
  1124. assignedFlags |= Node::HasDeadZone;
  1125. break;
  1126. case 'i': case 'I':
  1127. assignedFlags |= Node::Inverted;
  1128. break;
  1129. case 'n': case 'N':
  1130. assignedFlags |= Node::NonLinear;
  1131. break;
  1132. default:
  1133. AssertFatal(false, avar("Misunderstood specifier in bind (spec string: %s)",
  1134. pSpec));
  1135. }
  1136. }
  1137. // Ok, we have the flags. Scan the dead zone and scale, if any.
  1138. //
  1139. U32 curArg = 3;
  1140. if (assignedFlags & Node::HasDeadZone) {
  1141. dSscanf(argv[curArg], "%g %g", &deadZoneBegin, &deadZoneEnd);
  1142. curArg++;
  1143. }
  1144. if (assignedFlags & Node::HasScale) {
  1145. scaleFactor = dAtof(argv[curArg]);
  1146. curArg++;
  1147. }
  1148. if (curArg != (argc - 1)) {
  1149. AssertFatal(curArg == (argc - 1), "error in bind spec somewhere...");
  1150. Con::printf("Improperly specified bind for key: %s", argv[2]);
  1151. return false;
  1152. }
  1153. }
  1154. // Ensure that the console function is properly specified?
  1155. //
  1156. // DMMTODO
  1157. // Create the full bind entry, and place it in the map
  1158. //
  1159. // DMMTODO
  1160. Node* pBindNode = getNode(deviceType, deviceInst,
  1161. eventDescriptor.flags,
  1162. eventDescriptor.eventCode, object);
  1163. pBindNode->flags = assignedFlags;
  1164. pBindNode->deadZoneBegin = deadZoneBegin;
  1165. pBindNode->deadZoneEnd = deadZoneEnd;
  1166. pBindNode->scaleFactor = scaleFactor;
  1167. pBindNode->object = object;
  1168. pBindNode->consoleFunction = StringTable->insert(pFnName);
  1169. return true;
  1170. }
  1171. //------------------------------------------------------------------------------
  1172. bool ActionMap::processHoldBind(const char *device, const char *action, const char *holdFunc, const char *tapFunc, const U32 holdTime, const bool holdOnly, const bool retHoldTime)
  1173. {
  1174. U32 deviceType;
  1175. U32 deviceInst;
  1176. if (!getDeviceTypeAndInstance(device, deviceType, deviceInst))
  1177. {
  1178. Con::printf("processBindCmd: unknown device: %s", device);
  1179. return false;
  1180. }
  1181. // Ok, we now have the deviceType and instance. Create an event descriptor
  1182. // for the bind...
  1183. //
  1184. EventDescriptor eventDescriptor;
  1185. if (createEventDescriptor(action, &eventDescriptor) == false) {
  1186. Con::printf("Could not create a description for binding: %s", action);
  1187. return false;
  1188. }
  1189. // SI_POV == SI_MOVE, and the POV works fine with bindCmd, so we have to add these manually.
  1190. if ((eventDescriptor.eventCode == SI_XAXIS) ||
  1191. (eventDescriptor.eventCode == SI_YAXIS) ||
  1192. (eventDescriptor.eventCode == SI_ZAXIS) ||
  1193. (eventDescriptor.eventCode == SI_RXAXIS) ||
  1194. (eventDescriptor.eventCode == SI_RYAXIS) ||
  1195. (eventDescriptor.eventCode == SI_RZAXIS) ||
  1196. (eventDescriptor.eventCode == SI_SLIDER) ||
  1197. (eventDescriptor.eventCode == SI_XPOV) ||
  1198. (eventDescriptor.eventCode == SI_YPOV) ||
  1199. (eventDescriptor.eventCode == SI_XPOV2) ||
  1200. (eventDescriptor.eventCode == SI_YPOV2))
  1201. {
  1202. Con::warnf("ActionMap::processBindCmd - Cannot use 'bindCmd' with a move event type. Use 'bind' instead.");
  1203. return false;
  1204. }
  1205. // Event has now been described, and device determined. we need now to extract
  1206. // any modifiers that the action map will apply to incoming events before
  1207. // calling the bound function...
  1208. //
  1209. // DMMTODO
  1210. F32 deadZoneBegin = 0.0f;
  1211. F32 deadZoneEnd = 0.0f;
  1212. F32 scaleFactor = 1.0f;
  1213. // Ensure that the console function is properly specified?
  1214. //
  1215. // DMMTODO
  1216. // Create the full bind entry, and place it in the map
  1217. //
  1218. // DMMTODO
  1219. Node* pBindNode = getNode(deviceType, deviceInst,
  1220. eventDescriptor.flags,
  1221. eventDescriptor.eventCode);
  1222. pBindNode->flags = Node::Held;
  1223. pBindNode->deadZoneBegin = deadZoneBegin;
  1224. pBindNode->deadZoneEnd = deadZoneEnd;
  1225. pBindNode->scaleFactor = scaleFactor;
  1226. pBindNode->consoleFunction = StringTable->insert(dStrdup(tapFunc));
  1227. pBindNode->contextEvent = new ContextAction(StringTable->insert(dStrdup(holdFunc)), holdTime, pBindNode, holdOnly);
  1228. pBindNode->contextEvent->mReturnHoldTime = retHoldTime;
  1229. return true;
  1230. }
  1231. //------------------------------------------------------------------------------
  1232. bool ActionMap::processAction(const InputEventInfo* pEvent)
  1233. {
  1234. // Suppress excluded input events, like alt-tab.
  1235. if(Platform::checkKeyboardInputExclusion(pEvent))
  1236. return false;
  1237. static const char *argv[5];
  1238. if (pEvent->action == SI_MAKE) {
  1239. const Node* pNode = findNode(pEvent->deviceType, pEvent->deviceInst,
  1240. pEvent->modifier, pEvent->objInst);
  1241. if( pNode == NULL )
  1242. return false;
  1243. // Enter the break into the table if this is a make event...
  1244. // Do this now rather than after command is processed because
  1245. // command might add a binding which can move the vector of nodes.
  1246. // Filter to prevent Hold buttons from being eaten
  1247. if (!(pNode->flags & Node::Held))
  1248. enterBreakEvent(pEvent, pNode);
  1249. // Whadda ya know, we have this bound. Set up, and call the console
  1250. // function associated with it...
  1251. //
  1252. F32 value = pEvent->fValue;
  1253. if (pNode->flags & Node::Ranged) {
  1254. value = (value * 2.0f) - 1.0f;
  1255. if (pNode->flags & Node::Inverted)
  1256. value *= -1.0f;
  1257. } else {
  1258. if (pNode->flags & Node::Inverted)
  1259. value = 1.0f - value;
  1260. }
  1261. if (pNode->flags & Node::HasScale)
  1262. value *= pNode->scaleFactor;
  1263. if ( pNode->flags & Node::HasDeadZone )
  1264. {
  1265. if ( value >= pNode->deadZoneBegin && value <= pNode->deadZoneEnd )
  1266. value = 0.0f;
  1267. else
  1268. {
  1269. if( value > 0 )
  1270. value = ( value - pNode->deadZoneBegin ) * ( 1.f / ( 1.f - pNode->deadZoneBegin ) );
  1271. else
  1272. value = ( value + pNode->deadZoneBegin ) * ( 1.f / ( 1.f - pNode->deadZoneBegin ) );
  1273. }
  1274. }
  1275. if( pNode->flags & Node::NonLinear )
  1276. value = ( value < 0.f ? -1.f : 1.f ) * mPow( mFabs( value ), CONST_E );
  1277. // Ok, we're all set up, call the function.
  1278. if(pNode->flags & Node::BindCmd)
  1279. {
  1280. // it's a bind command
  1281. if(pNode->makeConsoleCommand)
  1282. Con::evaluate(pNode->makeConsoleCommand);
  1283. }
  1284. else if (pNode->flags & Node::Held)
  1285. {
  1286. //check if we're already holding, if not, start our timer
  1287. if (!pNode->contextEvent->mActive) {
  1288. pNode->contextEvent->mActive = true;
  1289. pNode->contextEvent->mStartTime = Sim::getCurrentTime();
  1290. pNode->contextEvent->mEventValue = value;
  1291. }
  1292. }
  1293. else if ( pNode->consoleFunction[0] )
  1294. {
  1295. argv[0] = pNode->consoleFunction;
  1296. argv[1] = Con::getFloatArg(value);
  1297. if (pNode->object)
  1298. Con::executef(pNode->object, argv[0], argv[1]);
  1299. else
  1300. Con::execute(2, argv);
  1301. }
  1302. return true;
  1303. } else if (pEvent->action == SI_MOVE) {
  1304. if (pEvent->deviceType == MouseDeviceType) {
  1305. const Node* pNode = findNode(pEvent->deviceType, pEvent->deviceInst,
  1306. pEvent->modifier, pEvent->objInst);
  1307. if( pNode == NULL )
  1308. return false;
  1309. // "Do nothing" bind:
  1310. if ( !pNode->consoleFunction[0] )
  1311. return( true );
  1312. // Whadda ya know, we have this bound. Set up, and call the console
  1313. // function associated with it. Mouse events ignore range and dead
  1314. // zone params.
  1315. //
  1316. F32 value = pEvent->fValue;
  1317. if (pNode->flags & Node::Inverted)
  1318. value *= -1.0f;
  1319. if (pNode->flags & Node::HasScale)
  1320. value *= pNode->scaleFactor;
  1321. // Ok, we're all set up, call the function.
  1322. argv[0] = pNode->consoleFunction;
  1323. argv[1] = Con::getFloatArg(value);
  1324. if (pNode->object)
  1325. Con::executef(pNode->object, argv[0], argv[1]);
  1326. else
  1327. Con::execute(2, argv);
  1328. return true;
  1329. }
  1330. else if ( (pEvent->objType == SI_POS || pEvent->objType == SI_FLOAT || pEvent->objType == SI_ROT || pEvent->objType == SI_INT)
  1331. && INPUTMGR->isRegisteredDevice(pEvent->deviceType)
  1332. )
  1333. {
  1334. const Node* pNode = findNode(pEvent->deviceType, pEvent->deviceInst,
  1335. pEvent->modifier, pEvent->objInst);
  1336. if( pNode == NULL )
  1337. return false;
  1338. // Ok, we're all set up, call the function.
  1339. argv[0] = pNode->consoleFunction;
  1340. S32 argc = 1;
  1341. if (pEvent->objType == SI_INT)
  1342. {
  1343. // Handle the integer as some sort of motion such as a
  1344. // single component to an absolute position
  1345. argv[1] = Con::getIntArg( pEvent->iValue );
  1346. argc += 1;
  1347. }
  1348. else if (pEvent->objType == SI_FLOAT)
  1349. {
  1350. // Handle float as some sort of motion such as a
  1351. // single component to an absolute position
  1352. argv[1] = Con::getFloatArg( pEvent->fValue );
  1353. argc += 1;
  1354. }
  1355. else if (pEvent->objType == SI_POS)
  1356. {
  1357. // Handle Point3F type position
  1358. argv[1] = Con::getFloatArg( pEvent->fValue );
  1359. argv[2] = Con::getFloatArg( pEvent->fValue2 );
  1360. argv[3] = Con::getFloatArg( pEvent->fValue3 );
  1361. argc += 3;
  1362. }
  1363. else
  1364. {
  1365. // Handle rotation (AngAxisF)
  1366. AngAxisF aa(Point3F(pEvent->fValue, pEvent->fValue2, pEvent->fValue3), pEvent->fValue4);
  1367. aa.axis.normalize();
  1368. argv[1] = Con::getFloatArg( aa.axis.x );
  1369. argv[2] = Con::getFloatArg( aa.axis.y );
  1370. argv[3] = Con::getFloatArg( aa.axis.z );
  1371. argv[4] = Con::getFloatArg( mRadToDeg(aa.angle) );
  1372. argc += 4;
  1373. }
  1374. if (pNode->object)
  1375. {
  1376. Con::execute(pNode->object, argc, argv);
  1377. }
  1378. else
  1379. {
  1380. Con::execute(argc, argv);
  1381. }
  1382. return true;
  1383. }
  1384. else if ( pEvent->deviceType == JoystickDeviceType
  1385. || pEvent->deviceType == GamepadDeviceType
  1386. || INPUTMGR->isRegisteredDevice(pEvent->deviceType)
  1387. )
  1388. {
  1389. // Joystick events...
  1390. const Node* pNode = findNode( pEvent->deviceType, pEvent->deviceInst,
  1391. pEvent->modifier, pEvent->objInst );
  1392. if( pNode == NULL )
  1393. return false;
  1394. // "Do nothing" bind:
  1395. if ( !pNode->consoleFunction[0] )
  1396. return( true );
  1397. // Whadda ya know, we have this bound. Set up, and call the console
  1398. // function associated with it. Joystick move events are the same as mouse
  1399. // move events except that they don't ignore dead zone.
  1400. //
  1401. F32 value = pEvent->fValue;
  1402. if ( pNode->flags & Node::Inverted )
  1403. value *= -1.0f;
  1404. if ( pNode->flags & Node::HasScale )
  1405. value *= pNode->scaleFactor;
  1406. if ( pNode->flags & Node::HasDeadZone )
  1407. {
  1408. if ( value >= pNode->deadZoneBegin &&
  1409. value <= pNode->deadZoneEnd )
  1410. value = 0.0f;
  1411. else
  1412. {
  1413. if( value > 0 )
  1414. value = ( value - pNode->deadZoneEnd ) * ( 1.f / ( 1.f - pNode->deadZoneEnd ) );
  1415. else
  1416. value = ( value - pNode->deadZoneBegin ) * ( 1.f / ( 1.f + pNode->deadZoneBegin ) );
  1417. }
  1418. }
  1419. if( pNode->flags & Node::NonLinear )
  1420. value = ( value < 0.f ? -1.f : 1.f ) * mPow( mFabs( value ), CONST_E );
  1421. // Ok, we're all set up, call the function.
  1422. argv[0] = pNode->consoleFunction;
  1423. argv[1] = Con::getFloatArg( value );
  1424. if (pNode->object)
  1425. Con::executef(pNode->object, argv[0], argv[1]);
  1426. else
  1427. Con::execute(2, argv);
  1428. return true;
  1429. }
  1430. }
  1431. else if (pEvent->action == SI_BREAK)
  1432. {
  1433. const Node* button = findNode(pEvent->deviceType, pEvent->deviceInst,
  1434. pEvent->modifier, pEvent->objInst);
  1435. if (button != NULL)
  1436. {
  1437. if (button->flags == Node::Held)
  1438. {
  1439. if (!button->contextEvent->mBreakEvent)
  1440. button->contextEvent->mBreakEvent = true;
  1441. return true;
  1442. }
  1443. }
  1444. return checkBreakTable(pEvent);
  1445. }
  1446. else if (pEvent->action == SI_VALUE)
  1447. {
  1448. if ( (pEvent->objType == SI_FLOAT || pEvent->objType == SI_INT)
  1449. && INPUTMGR->isRegisteredDevice(pEvent->deviceType)
  1450. )
  1451. {
  1452. const Node* pNode = findNode(pEvent->deviceType, pEvent->deviceInst,
  1453. pEvent->modifier, pEvent->objInst);
  1454. if( pNode == NULL )
  1455. return false;
  1456. // Ok, we're all set up, call the function.
  1457. argv[0] = pNode->consoleFunction;
  1458. S32 argc = 1;
  1459. if (pEvent->objType == SI_INT)
  1460. {
  1461. // Handle the integer as some sort of motion such as a
  1462. // single component to an absolute position
  1463. argv[1] = Con::getIntArg( pEvent->iValue );
  1464. argc += 1;
  1465. }
  1466. else if (pEvent->objType == SI_FLOAT)
  1467. {
  1468. // Handle float as some sort of motion such as a
  1469. // single component to an absolute position
  1470. argv[1] = Con::getFloatArg( pEvent->fValue );
  1471. argc += 1;
  1472. }
  1473. if (pNode->object)
  1474. {
  1475. Con::execute(pNode->object, argc, argv);
  1476. }
  1477. else
  1478. {
  1479. Con::execute(argc, argv);
  1480. }
  1481. return true;
  1482. }
  1483. }
  1484. return false;
  1485. }
  1486. //------------------------------------------------------------------------------
  1487. bool ActionMap::isAction( U32 deviceType, U32 deviceInst, U32 modifiers, U32 action )
  1488. {
  1489. return ( findNode( deviceType, deviceInst, modifiers, action ) != NULL );
  1490. }
  1491. //------------------------------------------------------------------------------
  1492. ActionMap* ActionMap::getGlobalMap()
  1493. {
  1494. SimSet* pActionMapSet = Sim::getActiveActionMapSet();
  1495. AssertFatal( pActionMapSet && pActionMapSet->size() != 0,
  1496. "error, no ActiveMapSet or no global action map...");
  1497. return ( ( ActionMap* ) pActionMapSet->first() );
  1498. }
  1499. //------------------------------------------------------------------------------
  1500. void ActionMap::enterBreakEvent(const InputEventInfo* pEvent, const Node* pNode)
  1501. {
  1502. // There aren't likely to be many breaks outstanding at any one given time,
  1503. // so a simple linear search is probably sufficient. Note that the break table
  1504. // is static to the class, all breaks are directed to the action map that received
  1505. // the make.
  1506. //
  1507. S32 entry = -1;
  1508. for (U32 i = 0; i < smBreakTable.size(); i++) {
  1509. if (smBreakTable[i].deviceType == U32(pEvent->deviceType) &&
  1510. smBreakTable[i].deviceInst == U32(pEvent->deviceInst) &&
  1511. smBreakTable[i].objInst == U32(pEvent->objInst)) {
  1512. // Match.
  1513. entry = i;
  1514. break;
  1515. }
  1516. }
  1517. if (entry == -1) {
  1518. smBreakTable.increment();
  1519. entry = smBreakTable.size() - 1;
  1520. smBreakTable[entry].deviceType = pEvent->deviceType;
  1521. smBreakTable[entry].deviceInst = pEvent->deviceInst;
  1522. smBreakTable[entry].objInst = pEvent->objInst;
  1523. }
  1524. // Ok, we now have the entry, and know that the device desc. and the objInst match.
  1525. // Copy out the node information...
  1526. //
  1527. smBreakTable[entry].object = pNode->object;
  1528. smBreakTable[entry].consoleFunction = pNode->consoleFunction;
  1529. if(pNode->breakConsoleCommand)
  1530. smBreakTable[entry].breakConsoleCommand = dStrdup(pNode->breakConsoleCommand);
  1531. else
  1532. smBreakTable[entry].breakConsoleCommand = NULL;
  1533. smBreakTable[entry].flags = pNode->flags;
  1534. smBreakTable[entry].deadZoneBegin = pNode->deadZoneBegin;
  1535. smBreakTable[entry].deadZoneEnd = pNode->deadZoneEnd;
  1536. smBreakTable[entry].scaleFactor = pNode->scaleFactor;
  1537. }
  1538. //------------------------------------------------------------------------------
  1539. bool ActionMap::checkBreakTable(const InputEventInfo* pEvent)
  1540. {
  1541. for (U32 i = 0; i < smBreakTable.size(); i++)
  1542. {
  1543. if (smBreakTable[i].deviceType == U32(pEvent->deviceType) &&
  1544. smBreakTable[i].deviceInst == U32(pEvent->deviceInst) &&
  1545. smBreakTable[i].objInst == U32(pEvent->objInst))
  1546. {
  1547. fireBreakEvent(i, pEvent->fValue);
  1548. return true;
  1549. }
  1550. }
  1551. return false;
  1552. }
  1553. //------------------------------------------------------------------------------
  1554. bool ActionMap::handleEvent(const InputEventInfo* pEvent)
  1555. {
  1556. // Interate through the ActionMapSet until we get a map that
  1557. // handles the event or we run out of maps...
  1558. //
  1559. SimSet* pActionMapSet = Sim::getActiveActionMapSet();
  1560. AssertFatal(pActionMapSet && pActionMapSet->size() != 0,
  1561. "error, no ActiveMapSet or no global action map...");
  1562. for (SimSet::iterator itr = pActionMapSet->end() - 1;
  1563. itr > pActionMapSet->begin(); itr--) {
  1564. ActionMap* pMap = static_cast<ActionMap*>(*itr);
  1565. if (pMap->processAction(pEvent) == true)
  1566. return true;
  1567. }
  1568. // Found no matching action. Try with the modifiers stripped.
  1569. InputEventInfo eventNoModifiers = *pEvent;
  1570. eventNoModifiers.modifier = ( InputModifiers ) 0;
  1571. for (SimSet::iterator itr = pActionMapSet->end() - 1;
  1572. itr > pActionMapSet->begin(); itr--) {
  1573. ActionMap* pMap = static_cast<ActionMap*>(*itr);
  1574. if( pMap->processAction( &eventNoModifiers ) )
  1575. return true;
  1576. }
  1577. return false;
  1578. }
  1579. //------------------------------------------------------------------------------
  1580. bool ActionMap::handleEventGlobal(const InputEventInfo* pEvent)
  1581. {
  1582. return getGlobalMap()->processAction( pEvent );
  1583. }
  1584. //------------------------------------------------------------------------------
  1585. bool ActionMap::checkAsciiGlobal( U16 key, U32 modifiers )
  1586. {
  1587. // Does this ascii map to a key?
  1588. U16 keyCode = Input::getKeyCode(key);
  1589. if(keyCode == 0)
  1590. return false;
  1591. // Grab the action map set.
  1592. SimSet* pActionMapSet = Sim::getActiveActionMapSet();
  1593. AssertFatal(pActionMapSet && pActionMapSet->size() != 0,
  1594. "error, no ActiveMapSet or no global action map...");
  1595. // Grab the device maps for the first ActionMap.
  1596. Vector<DeviceMap*> &maps = ((ActionMap*)pActionMapSet->first())->mDeviceMaps;
  1597. // Find the keyboard.
  1598. DeviceMap *keyMap = NULL;
  1599. for(S32 i=0; i<maps.size(); i++)
  1600. {
  1601. // CodeReview Doesn't deal with multiple keyboards [bjg, 5/16/07]
  1602. if(maps[i]->deviceType == KeyboardDeviceType)
  1603. {
  1604. keyMap = maps[i];
  1605. break;
  1606. }
  1607. }
  1608. if(!keyMap)
  1609. return false;
  1610. // Normalize modifiers.
  1611. U32 realMods = modifiers;
  1612. if (realMods & SI_SHIFT)
  1613. realMods |= SI_SHIFT;
  1614. if (realMods & SI_CTRL)
  1615. realMods |= SI_CTRL;
  1616. if (realMods & SI_ALT)
  1617. realMods |= SI_ALT;
  1618. if (realMods & SI_MAC_OPT)
  1619. realMods |= SI_MAC_OPT;
  1620. // Now find a matching node, if there is one.
  1621. for(S32 i=0; i<keyMap->nodeMap.size(); i++)
  1622. {
  1623. Node &n = keyMap->nodeMap[i];
  1624. if(n.action == keyCode && (n.modifiers == modifiers))
  1625. return true;
  1626. }
  1627. return false;
  1628. }
  1629. void ActionMap::clearAllBreaks()
  1630. {
  1631. while(smBreakTable.size())
  1632. fireBreakEvent(smBreakTable.size()-1);
  1633. }
  1634. void ActionMap::fireBreakEvent( U32 i, F32 fValue )
  1635. {
  1636. // Match. Issue the break event...
  1637. //
  1638. F32 value = fValue;
  1639. if (smBreakTable[i].flags & Node::Ranged) {
  1640. value = (value * 2.0f) - 1.0f;
  1641. if (smBreakTable[i].flags & Node::Inverted)
  1642. value *= -1.0f;
  1643. } else {
  1644. if (smBreakTable[i].flags & Node::Inverted)
  1645. value = 1.0f - value;
  1646. }
  1647. if (smBreakTable[i].flags & Node::HasScale)
  1648. value *= smBreakTable[i].scaleFactor;
  1649. if (smBreakTable[i].flags & Node::HasDeadZone)
  1650. {
  1651. if (value >= smBreakTable[i].deadZoneBegin &&
  1652. value <= smBreakTable[i].deadZoneEnd)
  1653. value = 0.0f;
  1654. else
  1655. {
  1656. if( value > 0 )
  1657. value = ( value - smBreakTable[i].deadZoneBegin ) * ( 1.f / ( 1.f - smBreakTable[i].deadZoneBegin ) );
  1658. else
  1659. value = ( value + smBreakTable[i].deadZoneBegin ) * ( 1.f / ( 1.f - smBreakTable[i].deadZoneBegin ) );
  1660. }
  1661. }
  1662. if( smBreakTable[i].flags & Node::NonLinear )
  1663. value = ( value < 0.f ? -1.f : 1.f ) * mPow( mFabs( value ), CONST_E );
  1664. // Ok, we're all set up, call the function.
  1665. if(smBreakTable[i].consoleFunction)
  1666. {
  1667. if ( smBreakTable[i].consoleFunction[0] )
  1668. {
  1669. static const char *argv[2];
  1670. argv[0] = smBreakTable[i].consoleFunction;
  1671. argv[1] = Con::getFloatArg(value);
  1672. if (smBreakTable[i].object)
  1673. Con::executef(smBreakTable[i].object, argv[0], argv[1]);
  1674. else
  1675. Con::execute(2, argv);
  1676. }
  1677. }
  1678. else if(smBreakTable[i].breakConsoleCommand)
  1679. {
  1680. Con::evaluate(smBreakTable[i].breakConsoleCommand);
  1681. dFree(smBreakTable[i].breakConsoleCommand);
  1682. }
  1683. smBreakTable.erase(i);
  1684. }
  1685. //------------------------------------------------------------------------------
  1686. //Context actions
  1687. ContextAction::ContextAction(StringTableEntry func, F32 minHoldTime, ActionMap::Node* button, bool holdOnly)
  1688. : mStartTime(0), mEventValue(1.0f), mBreakEvent(false), mDidHold(false), mActive(false), mReturnHoldTime(false)
  1689. {
  1690. mButton = button;
  1691. mMinHoldTime = minHoldTime;
  1692. mConsoleFunctionHeld = func;
  1693. mHoldOnly = holdOnly;
  1694. }
  1695. void ContextAction::processTick()
  1696. {
  1697. if (mActive)
  1698. {
  1699. F32 currTime = Sim::getCurrentTime();
  1700. static const char *argv[3];
  1701. //see if this key even is still active
  1702. if (!mBreakEvent)
  1703. {
  1704. //are we only checking if it's holding?
  1705. if (mHoldOnly)
  1706. {
  1707. //yes, we are, and since it's held, we fire off our function
  1708. if (mReturnHoldTime)
  1709. {
  1710. argv[0] = mConsoleFunctionHeld;
  1711. argv[1] = Con::getFloatArg(mEventValue);
  1712. argv[2] = Con::getFloatArg((currTime - mStartTime));
  1713. Con::execute(3, argv);
  1714. }
  1715. else
  1716. {
  1717. argv[0] = mConsoleFunctionHeld;
  1718. argv[1] = Con::getFloatArg(mEventValue);
  1719. Con::execute(2, argv);
  1720. }
  1721. }
  1722. //if we don't care if we're just holding, check our time
  1723. //have we passed our min limit?
  1724. else if ((currTime - mStartTime) >= mMinHoldTime)
  1725. {
  1726. //holy crap, we have, fire off our hold function
  1727. mDidHold = true;
  1728. argv[0] = mConsoleFunctionHeld;
  1729. argv[1] = Con::getFloatArg(mEventValue);
  1730. Con::execute(2, argv);
  1731. }
  1732. //otherwise we haven't yet, so keep our active status
  1733. return;
  1734. }
  1735. //hmm, apparently not, so see if we tapped the key instead
  1736. else
  1737. {
  1738. if (!mHoldOnly && !mDidHold)
  1739. {
  1740. //yes, we tapped and we care, so fire off the tap function.
  1741. argv[0] = mButton->consoleFunction;
  1742. argv[1] = Con::getFloatArg(mEventValue);
  1743. Con::execute(2, argv);
  1744. }
  1745. //otherwise we don't care and we're done, so reset everything
  1746. mActive = false;
  1747. mStartTime = 0;
  1748. mBreakEvent = false;
  1749. mDidHold = false;
  1750. }
  1751. }
  1752. }
  1753. //------------------------------------------------------------------------------
  1754. // Console interop version.
  1755. static ConsoleDocFragment _ActionMapbind1(
  1756. "@brief Associates a function to an input event.\n\n"
  1757. "When the input event is raised, the specified function will be called.\n\n"
  1758. "@param device The input device, such as mouse or keyboard.\n"
  1759. "@param action The input event, such as space, button0, etc.\n"
  1760. "@param command The function to bind to the action. Function must have a single boolean argument.\n"
  1761. "@return True if the binding was successful, false if the device was unknown or description failed.\n\n"
  1762. "@tsexample\n"
  1763. "// Simple function that prints to console\n"
  1764. "// %val - Sent by the device letting the user know\n"
  1765. "// if an input was pressed (true) or released (false)\n"
  1766. "function testInput(%val)\n"
  1767. "{\n"
  1768. " if(%val)\n"
  1769. " echo(\"Key is down\");\n"
  1770. " else\n"
  1771. " echo(\"Key was released\");\n"
  1772. "}\n\n"
  1773. "// Bind the \'K\' key to the testInput function\n"
  1774. "moveMap.bind(keyboard, k, testInput);\n\n"
  1775. "@endtsexample\n\n\n",
  1776. "ActionMap",
  1777. "bool bind( string device, string action, string command );");
  1778. static ConsoleDocFragment _ActionMapbind2(
  1779. "@brief Associates a function and input parameters to an input event.\n\n"
  1780. "When the input event is raised, the specified function will be called. Modifier flags may be specified to process "
  1781. "dead zones, input inversion, and more.\n\n"
  1782. "Valid modifier flags:\n\n"
  1783. " - R - Input is Ranged.\n"
  1784. " - S - Input is Scaled.\n"
  1785. " - I - Input is inverted.\n"
  1786. " - D - Dead zone is present.\n"
  1787. " - N - Input should be re-fit to a non-linear scale.\n\n"
  1788. "@param device The input device, such as mouse or keyboard.\n"
  1789. "@param action The input event, such as space, button0, etc.\n"
  1790. "@param flag Modifier flag assigned during binding, letting event know there are additional parameters to consider. \n"
  1791. "@param deadZone Restricted region in which device motion will not be acknowledged.\n"
  1792. "@param scale Modifies the deadZone region.\n"
  1793. "@param command The function bound to the action. Must take in a single argument.\n"
  1794. "@return True if the binding was successful, false if the device was unknown or description failed.\n\n"
  1795. "@tsexample\n"
  1796. "// Simple function that adjusts the pitch of the camera based on the "
  1797. "mouse's movement along the X axis.\n"
  1798. "function testPitch(%val)\n"
  1799. "{\n"
  1800. " %pitchAdj = getMouseAdjustAmount(%val);\n"
  1801. " $mvPitch += %pitchAdj;\n"
  1802. "}\n\n"
  1803. "// Bind the mouse's X axis to the testPitch function\n"
  1804. "// DI is flagged, meaning input is inverted and has a deadzone\n"
  1805. "%this.bind( mouse, \"xaxis\", \"DI\", \"-0.23 0.23\", testPitch );\n"
  1806. "@endtsexample\n\n\n",
  1807. "ActionMap",
  1808. "bool bind( string device, string action, string flag, string deadZone, string scale, string command );");
  1809. DefineEngineStringlyVariadicMethod( ActionMap, bind, bool, 5, 10, "actionMap.bind( device, action, [modifier, spec, mod...], command )"
  1810. "@hide")
  1811. {
  1812. ConsoleValueToStringArrayWrapper args(argc - 2, argv + 2);
  1813. return object->processBind( args.count(), args, NULL );
  1814. }
  1815. static ConsoleDocFragment _ActionMapbindObj1(
  1816. "@brief Associates a function to an input event for a specified class or object.\n\n"
  1817. "You must specify a device, the action to bind, a function, and an object to be called when the event happens. "
  1818. "The function specified must be set to receive a single boolean value passed.\n\n"
  1819. "@param device The input device, such as mouse or keyboard.\n"
  1820. "@param action The input event, such as space, button0, etc.\n"
  1821. "@param command The function bound to the action.\n"
  1822. "@param object The object or class bound to the action.\n"
  1823. "@return True if the binding was successful, false if the device was unknown or description failed.\n\n"
  1824. "@tsexample\n"
  1825. "moveMap.bindObj(keyboard, \"numpad1\", \"rangeChange\", %player);"
  1826. "@endtsexample\n\n",
  1827. "ActionMap",
  1828. "bool bindObj( string device, string action, string command, SimObjectID object );");
  1829. static ConsoleDocFragment _ActionMapbindObj2(
  1830. "@brief Associates a function to an input event for a specified class or object.\n\n"
  1831. "You must specify a device, the action to bind, a function, and an object to be called when the event happens. "
  1832. "The function specified must be set to receive a single boolean value passed. Modifier flags may be specified to process "
  1833. "dead zones, input inversion, and more.\n\n"
  1834. "Valid modifier flags:\n\n"
  1835. " - R - Input is Ranged.\n"
  1836. " - S - Input is Scaled.\n"
  1837. " - I - Input is inverted.\n"
  1838. " - D - Dead zone is present.\n"
  1839. " - N - Input should be re-fit to a non-linear scale.\n\n"
  1840. "@param device The input device, such as mouse or keyboard.\n"
  1841. "@param action The input event, such as space, button0, etc.\n"
  1842. "@param flag Modifier flag assigned during binding, letting event know there are additional parameters to consider.\n"
  1843. "@param deadZone [Required only when flag is set] Restricted region in which device motion will not be acknowledged.\n"
  1844. "@param scale [Required only when flag is set] Modifies the deadZone region.\n"
  1845. "@param command The function bound to the action.\n"
  1846. "@param object The object or class bound to the action.\n"
  1847. "@return True if the binding was successful, false if the device was unknown or description failed.\n\n"
  1848. "@tsexample\n"
  1849. "// Bind the mouse's movement along the x-axis to the testInput function of the Player class\n"
  1850. "// DSI is flagged, meaning input is inverted, has scale and has a deadzone\n"
  1851. "%this.bindObj( mouse, \"xaxis\", \"DSI\", %deadZone, %scale, \"testInput\", %player );\n"
  1852. "@endtsexample\n\n\n",
  1853. "ActionMap",
  1854. "bool bindObj( string device, string action, string flag, string deadZone, string scale, string command, SimObjectID object );");
  1855. DefineEngineStringlyVariadicMethod( ActionMap, bindObj, bool, 6, 11, "(device, action, [modifier, spec, mod...], command, object)"
  1856. "@hide")
  1857. {
  1858. SimObject* simObject = Sim::findObject(argv[argc - 1]);
  1859. if ( simObject == NULL )
  1860. {
  1861. Con::warnf("ActionMap::bindObj() - Cannot bind, specified object was not found!");
  1862. return false;
  1863. }
  1864. ConsoleValueToStringArrayWrapper args(argc - 3, argv + 2);
  1865. return object->processBind( args.count(), args, simObject );
  1866. }
  1867. //------------------------------------------------------------------------------
  1868. DefineEngineMethod( ActionMap, bindCmd, bool, ( const char* device, const char* action, const char* makeCmd, const char* breakCmd ), ( "" ),
  1869. "@brief Associates a make command and optional break command to a specified input device action.\n\n"
  1870. "Must include parenthesis and semicolon in the make and break command strings.\n\n"
  1871. "@param device The device to bind to. Can be a keyboard, mouse, joystick or gamepad.\n"
  1872. "@param action The device action to bind to. The action is dependant upon the device. Specify a key for keyboards.\n"
  1873. "@param makeCmd The command to execute when the device/action is made.\n"
  1874. "@param breakCmd [optional] The command to execute when the device or action is unmade.\n"
  1875. "@return True the bind was successful, false if the device was unknown or description failed.\n"
  1876. "@tsexample\n"
  1877. "// Print to the console when the spacebar is pressed\n"
  1878. "function onSpaceDown()\n"
  1879. "{\n"
  1880. " echo(\"Space bar down!\");\n"
  1881. "}\n\n"
  1882. "// Print to the console when the spacebar is released\n"
  1883. "function onSpaceUp()\n"
  1884. "{\n"
  1885. " echo(\"Space bar up!\");\n"
  1886. "}\n\n"
  1887. "// Bind the commands onSpaceDown() and onSpaceUp() to spacebar events\n\n"
  1888. "moveMap.bindCmd(keyboard, \"space\", \"onSpaceDown();\", \"onSpaceUp();\");\n"
  1889. "@endtsexample\n\n")
  1890. {
  1891. return object->processBindCmd( device, action, makeCmd, breakCmd );
  1892. }
  1893. DefineEngineMethod(ActionMap, bindContext, void, (const char* device, const char* action, const char* holdFunction, const char* tapFunction, U32 holdTime),
  1894. ("", "", "", "", 0), "actionMap.bindCmd( device, action, holdFunction, tapFunction, holdTime)")
  1895. {
  1896. object->processHoldBind(device, action, holdFunction, tapFunction, holdTime, false);
  1897. }
  1898. DefineEngineMethod(ActionMap, bindHold, void, (const char* device, const char* action, const char* holdFunction, bool returnHoldTime),
  1899. ("", "", "", false), "actionMap.bindCmd( device, action, holdFunction, returnHoldTime)")
  1900. {
  1901. object->processHoldBind(device, action, holdFunction, "", 0, true, returnHoldTime);
  1902. }
  1903. DefineEngineMethod( ActionMap, unbind, bool, ( const char* device, const char* action ),,
  1904. "@brief Removes the binding on an input device and action.\n"
  1905. "@param device The device to unbind from. Can be a keyboard, mouse, joystick or a gamepad.\n"
  1906. "@param action The device action to unbind from. The action is dependant upon the device. Specify a key for keyboards.\n"
  1907. "@return True if the unbind was successful, false if the device was unknown or description failed.\n\n"
  1908. "@tsexample\n"
  1909. "moveMap.unbind(\"keyboard\", \"space\");\n"
  1910. "@endtsexample\n\n")
  1911. {
  1912. return object->processUnbind( device, action );
  1913. }
  1914. DefineEngineMethod( ActionMap, unbindObj, bool, ( const char* device, const char* action, const char* obj ),,
  1915. "@brief Remove any object-binding on an input device and action.\n"
  1916. "@param device The device to bind to. Can be keyboard, mouse, joystick or gamepad.\n"
  1917. "@param action The device action to unbind from. The action is dependant upon the device. Specify a key for keyboards.\n"
  1918. "@param obj The object to perform unbind against.\n"
  1919. "@return True if the unbind was successful, false if the device was unknown or description failed.\n"
  1920. "@tsexample\n"
  1921. "moveMap.unbindObj(\"keyboard\", \"numpad1\", \"rangeChange\", %player);"
  1922. "@endtsexample\n\n\n")
  1923. {
  1924. SimObject* simObject = Sim::findObject(obj);
  1925. if ( simObject == NULL )
  1926. {
  1927. Con::warnf("ActionMap::unbindObj() - Cannot unbind, specified object was not found!");
  1928. return false;
  1929. }
  1930. return object->processUnbind( device, action, simObject );
  1931. }
  1932. DefineEngineMethod( ActionMap, save, void, ( const char* fileName, bool append ), ( nullAsType<const char*>(), false ),
  1933. "@brief Saves the ActionMap to a file or dumps it to the console.\n\n"
  1934. "@param fileName The file path to save the ActionMap to. If a filename is not specified "
  1935. " the ActionMap will be dumped to the console.\n"
  1936. "@param append Whether to write the ActionMap at the end of the file or overwrite it.\n"
  1937. "@tsexample\n"
  1938. "// Write out the actionmap into the config." TORQUE_SCRIPT_EXTENSION " file\n"
  1939. "moveMap.save( \"scripts/client/config." TORQUE_SCRIPT_EXTENSION "\" );"
  1940. "@endtsexample\n\n")
  1941. {
  1942. char buffer[1024];
  1943. if(fileName)
  1944. {
  1945. if(Con::expandScriptFilename(buffer, sizeof(buffer), fileName))
  1946. fileName = buffer;
  1947. }
  1948. object->dumpActionMap( fileName, append );
  1949. }
  1950. DefineEngineFunction( getCurrentActionMap, ActionMap*, (),,
  1951. "@brief Returns the current %ActionMap.\n"
  1952. "@see ActionMap"
  1953. "@ingroup Input")
  1954. {
  1955. SimSet* pActionMapSet = Sim::getActiveActionMapSet();
  1956. return dynamic_cast< ActionMap* >( pActionMapSet->last() );
  1957. }
  1958. DefineEngineMethod( ActionMap, push, void, (),,
  1959. "@brief Push the ActionMap onto the %ActionMap stack.\n\n"
  1960. "Activates an ActionMap and placees it at the top of the ActionMap stack.\n\n"
  1961. "@tsexample\n"
  1962. "// Make moveMap the active action map\n"
  1963. "moveMap.push();\n"
  1964. "@endtsexample\n\n"
  1965. "@see ActionMap")
  1966. {
  1967. SimSet* pActionMapSet = Sim::getActiveActionMapSet();
  1968. pActionMapSet->pushObject( object );
  1969. }
  1970. DefineEngineMethod( ActionMap, pop, void, (),,
  1971. "@brief Pop the ActionMap off the %ActionMap stack.\n\n"
  1972. "Deactivates an %ActionMap and removes it from the @ActionMap stack.\n"
  1973. "@tsexample\n"
  1974. "// Deactivate moveMap\n"
  1975. "moveMap.pop();\n"
  1976. "@endtsexample\n\n"
  1977. "@see ActionMap")
  1978. {
  1979. SimSet* pActionMapSet = Sim::getActiveActionMapSet();
  1980. pActionMapSet->removeObject( object );
  1981. }
  1982. DefineEngineMethod( ActionMap, getBinding, const char*, ( const char* command ),,
  1983. "@brief Gets the ActionMap binding for the specified command.\n\n"
  1984. "Use getField() on the return value to get the device and action of the binding.\n"
  1985. "@param command The function to search bindings for.\n"
  1986. "@return The binding against the specified command. Returns an empty string(\"\") "
  1987. "if a binding wasn't found.\n"
  1988. "@tsexample\n"
  1989. "// Find what the function \"jump()\" is bound to in moveMap\n"
  1990. "%bind = moveMap.getBinding( \"jump\" );\n\n"
  1991. "if ( %bind !$= \"\" )\n"
  1992. "{\n"
  1993. "// Find out what device is used in the binding\n"
  1994. " %device = getField( %bind, 0 );\n\n"
  1995. "// Find out what action (such as a key) is used in the binding\n"
  1996. " %action = getField( %bind, 1 );\n"
  1997. "}\n"
  1998. "@endtsexample\n\n"
  1999. "@see getField")
  2000. {
  2001. return object->getBinding( command );
  2002. }
  2003. DefineEngineMethod( ActionMap, getCommand, const char*, ( const char* device, const char* action ),,
  2004. "@brief Gets ActionMap command for the device and action.\n\n"
  2005. "@param device The device that was bound. Can be a keyboard, mouse, joystick or a gamepad.\n"
  2006. "@param action The device action that was bound. The action is dependant upon the device. Specify a key for keyboards.\n"
  2007. "@return The command against the specified device and action.\n"
  2008. "@tsexample\n"
  2009. "// Find what function is bound to a device\'s action\n"
  2010. "// In this example, \"jump()\" was assigned to the space key in another script\n"
  2011. "%command = moveMap.getCommand(\"keyboard\", \"space\");\n\n"
  2012. "// Should print \"jump\" in the console\n"
  2013. "echo(%command)\n"
  2014. "@endtsexample\n\n")
  2015. {
  2016. return object->getCommand( device, action );
  2017. }
  2018. DefineEngineMethod( ActionMap, isInverted, bool, ( const char* device, const char* action ),,
  2019. "@brief Determines if the specified device and action is inverted.\n\n"
  2020. "Should only be used for scrolling devices or gamepad/joystick axes."
  2021. "@param device The device that was bound. Can be a keyboard, mouse, joystick or a gamepad.\n"
  2022. "@param action The device action that was bound. The action is dependant upon the device. Specify a key for keyboards.\n"
  2023. "@return True if the specified device and action is inverted.\n"
  2024. "@tsexample\n"
  2025. "%if ( moveMap.isInverted( \"mouse\", \"xaxis\"))\n"
  2026. " echo(\"Mouse's xAxis is inverted\");"
  2027. "@endtsexample\n\n")
  2028. {
  2029. return object->isInverted( device, action );
  2030. }
  2031. DefineEngineMethod( ActionMap, getScale, F32, ( const char* device, const char* action ),,
  2032. "@brief Get any scaling on the specified device and action.\n\n"
  2033. "@param device The device that was bound. Can be keyboard, mouse, joystick or gamepad.\n"
  2034. "@param action The device action that was bound. The action is dependant upon the device. Specify a key for keyboards.\n"
  2035. "@return Any scaling applied to the specified device and action.\n"
  2036. "@tsexample\n"
  2037. "%scale = %moveMap.getScale( \"gamepad\", \"thumbrx\");\n"
  2038. "@endtsexample\n\n")
  2039. {
  2040. return object->getScale( device, action );
  2041. }
  2042. DefineEngineMethod( ActionMap, getDeadZone, const char*, ( const char* device, const char* action ),,
  2043. "@brief Gets the Dead zone for the specified device and action.\n\n"
  2044. "@param device The device that was bound. Can be a keyboard, mouse, joystick or a gamepad.\n"
  2045. "@param action The device action that was bound. The action is dependant upon the device. Specify a key for keyboards.\n"
  2046. "@return The dead zone for the specified device and action. Returns \"0 0\" if there is no dead zone "
  2047. "or an empty string(\"\") if the mapping was not found.\n"
  2048. "@tsexample\n"
  2049. "%deadZone = moveMap.getDeadZone( \"gamepad\", \"thumbrx\");\n"
  2050. "@endtsexample\n\n")
  2051. {
  2052. return object->getDeadZone( device, action );
  2053. }
  2054. //------------------------------------------------------------------------------
  2055. AsciiMapping gAsciiMap[] =
  2056. {
  2057. //--- KEYBOARD EVENTS
  2058. //
  2059. { "space", 0x0020 },
  2060. //{ "exclamation", 0x0021 },
  2061. { "doublequote", 0x0022 },
  2062. //{ "pound", 0x0023 },
  2063. //{ "ampersand", 0x0026 },
  2064. { "apostrophe", 0x0027 },
  2065. //{ "lparen", 0x0028 },
  2066. //{ "rparen", 0x0029 },
  2067. { "comma", 0x002c },
  2068. { "minus", 0x002d },
  2069. { "period", 0x002e },
  2070. //{ "slash", 0x002f },
  2071. //{ "colon", 0x003a },
  2072. //{ "semicolon", 0x003b },
  2073. //{ "lessthan", 0x003c },
  2074. //{ "equals", 0x003d },
  2075. //{ "morethan", 0x003e },
  2076. //{ "lbracket", 0x005b },
  2077. { "backslash", 0x005c },
  2078. //{ "rbracket", 0x005d },
  2079. //{ "circumflex", 0x005e },
  2080. //{ "underscore", 0x005f },
  2081. { "grave", 0x0060 },
  2082. //{ "tilde", 0x007e },
  2083. //{ "vertbar", 0x007c },
  2084. //{ "exclamdown", 0x00a1 },
  2085. //{ "cent", 0x00a2 },
  2086. //{ "sterling", 0x00a3 },
  2087. //{ "currency", 0x00a4 },
  2088. //{ "brokenbar", 0x00a6 },
  2089. //{ "ring", 0x00b0 },
  2090. //{ "plusminus", 0x00b1 },
  2091. { "super2", 0x00b2 },
  2092. { "super3", 0x00b3 },
  2093. { "acute", 0x00b4 },
  2094. //{ "mu", 0x00b5 },
  2095. //{ "ordmasculine", 0x00ba },
  2096. //{ "questiondown", 0x00bf },
  2097. //{ "gemandbls", 0x00df },
  2098. //{ "agrave", 0x00e0 },
  2099. //{ "aacute", 0x00e1 },
  2100. //{ "acircumflex", 0x00e2 },
  2101. //{ "atilde", 0x00e3 },
  2102. //{ "adieresis", 0x00e4 },
  2103. //{ "aring", 0x00e5 },
  2104. //{ "ae", 0x00e6 },
  2105. //{ "ccedille", 0x00e7 },
  2106. //{ "egrave", 0x00e8 },
  2107. //{ "eacute", 0x00e9 },
  2108. //{ "ecircumflex", 0x00ea },
  2109. //{ "edieresis", 0x00eb },
  2110. //{ "igrave", 0x00ec },
  2111. //{ "iacute", 0x00ed },
  2112. //{ "icircumflex", 0x00ee },
  2113. //{ "idieresis", 0x00ef },
  2114. //{ "ntilde", 0x00f1 },
  2115. //{ "ograve", 0x00f2 },
  2116. //{ "oacute", 0x00f3 },
  2117. //{ "ocircumflex", 0x00f4 },
  2118. //{ "otilde", 0x00f5 },
  2119. //{ "odieresis", 0x00f6 },
  2120. //{ "divide", 0x00f7 },
  2121. //{ "oslash", 0x00f8 },
  2122. //{ "ugrave", 0x00f9 },
  2123. //{ "uacute", 0x00fa },
  2124. //{ "ucircumflex", 0x00fb },
  2125. //{ "udieresis", 0x00fc },
  2126. //{ "ygrave", 0x00fd },
  2127. //{ "thorn", 0x00fe },
  2128. //{ "ydieresis", 0x00ff },
  2129. { "nomatch", 0xFFFF }
  2130. };