123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "sim/actionMap.h"
- #include "console/console.h"
- #include "platform/platform.h"
- #include "platform/platformInput.h"
- #include "platform/platformAssert.h"
- #include "core/stream/fileStream.h"
- #include "math/mMathFn.h"
- #include "console/engineAPI.h"
- #include "math/mQuat.h"
- #include "math/mAngAxis.h"
- #define CONST_E 2.7182818284590452353602874f
- IMPLEMENT_CONOBJECT(ActionMap);
- ConsoleDocClass( ActionMap,
- "@brief ActionMaps assign platform input events to console commands.\n\n"
- "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 "
- "or some other input device. This allows users of the game to map keys and actions according to their own preferences. "
- "Game action maps are arranged in a stack for processing so individual parts of the game can define specific "
- "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"
- "@section ActionMap_creation Creating an ActionMap\n"
- "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 "
- "three step process.\n\n"
- "1. Check to see if the ActionMap exists\n"
- "2. Delete it if it exists\n"
- "3. Instantiate the ActionMap\n\n"
- "The following is an example of how to create a new ActionMap:\n"
- "@tsexample\n"
- "if ( isObject( moveMap ) )\n"
- " moveMap.delete();\n"
- "new ActionMap(moveMap);"
- "@endtsexample\n\n\n"
-
- "@section ActionMap_binding Binding Functions\n"
- "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"
- "* Mouse\n\n"
- "* Keyboard\n\n"
- "* Joystick/Gamepad\n\n"
- "* Xbox 360 Controller\n\n"
- "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, "
- "but different in how the event is interpreted. With bind(), "
- "you specify a device, action to bind, then a function to be called when the event happens.\n\n"
- "@tsexample\n"
- "// Simple function that prints to console\n"
- "// %val - Sent by the device letting the user know\n"
- "// if an input was pressed (true) or released (false)\n"
- "function testInput(%val)\n"
- "{\n"
- " if(%val)\n"
- " echo(\"Key is down\");\n"
- " else\n"
- " echo(\"Key was released\");\n"
- "}\n\n"
- "// Bind the \'K\' key to the testInput function\n"
- "moveMap.bind(keyboard, \"k\", testInput);\n\n"
- "@endtsexample\n\n\n"
- "bindCmd is an alternative method for binding commands. This function is similar to bind(), "
- "except two functions are set to be called when the event is processed.\n\n"
- "One will be called when the event is activated (input down), while the other is activated when the event is broken (input release). "
- "When using bindCmd(), pass the functions as strings rather than the function names.\n\n"
- "@tsexample\n"
- "// Print to the console when the spacebar is pressed\n"
- "function onSpaceDown()\n"
- "{\n"
- " echo(\"Space bar down!\");\n"
- "}\n\n"
- "// Print to the console when the spacebar is released\n"
- "function onSpaceUp()\n"
- "{\n"
- " echo(\"Space bar up!\");\n"
- "}\n\n"
- "// Bind the commands onSpaceDown and onSpaceUp to spacebar events\n"
- "moveMap.bindCmd(keyboard, \"space\", \"onSpaceDown();\", \"onSpaceUp();\");\n"
- "@endtsexample\n\n"
-
- "@section ActionMap_switching Switching ActionMaps\n"
- "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 "
- "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"
- "First, create two separate ActionMaps:\n\n"
- "@tsexample\n"
- "// Create the two ActionMaps\n"
- "if ( isObject( moveMap ) )\n"
- " moveMap.delete();\n"
- "new ActionMap(moveMap);\n\n"
- "if ( isObject( carMap ) )\n"
- " carMap.delete();\n"
- "new ActionMap(carMap);\n\n"
- "@endtsexample\n\n"
- "Next, create the two separate functions. Both will be bound to spacebar, but not the same ActionMap:\n\n"
- "@tsexample\n"
- "// Print to the console the player is jumping\n"
- "function playerJump(%val)\n"
- "{\n"
- " if(%val)\n"
- " echo(\"Player jumping!\");\n"
- "}\n\n"
- "// Print to the console the vehicle is charging\n"
- "function turboCharge()\n"
- "{\n"
- " if(%val)\n"
- " echo(\"Vehicle turbo charging!\");\n"
- "}\n"
- "@endtsexample\n\n"
-
- "You are now ready to bind functions to your ActionMaps' devices:\n\n"
- "@tsexample\n"
- "// Bind the spacebar to the playerJump function\n"
- "// when moveMap is the active ActionMap\n"
- "moveMap.bind(keyboard, \"space\", playerJump);\n\n"
- "// Bind the spacebar to the turboCharge function\n"
- "// when carMap is the active ActionMap\n"
- "carMap.bind(keyboard, \"space\", turboCharge);\n"
- "@endtsexample\n"
- "Finally, you can use the push() and pop() commands on each ActionMap to toggle activation. To activate an ActionMap, use push():\n\n"
- "@tsexample\n"
- "// Make moveMap the active action map\n"
- "// You should now be able to activate playerJump with spacebar\n"
- "moveMap.push();\n"
- "@endtsexample\n\n"
- "To switch ActionMaps, first pop() the old one. Then you can push() the new one:\n\n"
- "@tsexample\n"
- "// Deactivate moveMap\n"
- "moveMap.pop();\n\n"
- "// Activate carMap\n"
- "carMap.push();\n\n"
- "@endtsexample\n\n\n"
- "@ingroup Input"
-
- );
- // This is used for determing keys that have ascii codes for the foreign keyboards. IsAlpha doesn't work on foreign keys.
- static inline bool dIsDecentChar(U8 c)
- {
- return ((U8(0xa0) <= c) || (( U8(0x21) <= c) && (c <= U8(0x7e))) || ((U8(0x91) <= c) && (c <= U8(0x92))));
- }
- struct AsciiMapping
- {
- const char* pDescription;
- U16 asciiCode;
- };
- extern AsciiMapping gAsciiMap[];
- //------------------------------------------------------------------------------
- //-------------------------------------- Action maps
- //
- Vector<ActionMap::BreakEntry> ActionMap::smBreakTable(__FILE__, __LINE__);
- //------------------------------------------------------------------------------
- ActionMap::ActionMap()
- {
- VECTOR_SET_ASSOCIATION(mDeviceMaps);
- }
- //------------------------------------------------------------------------------
- ActionMap::~ActionMap()
- {
- for (U32 i = 0; i < mDeviceMaps.size(); i++)
- delete mDeviceMaps[i];
- mDeviceMaps.clear();
- }
- //------------------------------------------------------------------------------
- ActionMap::DeviceMap::~DeviceMap()
- {
- for(U32 i = 0; i < nodeMap.size(); i++)
- {
- dFree(nodeMap[i].makeConsoleCommand);
- dFree(nodeMap[i].breakConsoleCommand);
- }
- }
- //------------------------------------------------------------------------------
- bool ActionMap::onAdd()
- {
- if (Parent::onAdd() == false)
- return false;
- Sim::getActionMapGroup()->addObject(this);
- return true;
- }
- //--------------------------------------------------------------------------
- void ActionMap::dumpActionMap(const char* fileName, const bool append) const
- {
- if (fileName != NULL) {
- // Dump the deletion, and creation script commands, followed by all the binds
- // to a script.
- FileStream *iostrm;
- if((iostrm = FileStream::createAndOpen( fileName, append ? Torque::FS::File::WriteAppend : Torque::FS::File::Write )) == NULL)
- {
- Con::errorf( "Unable to open file '%s' for writing.", fileName );
- return;
- }
- char lineBuffer[1024];
- if ( append )
- iostrm->setPosition( iostrm->getStreamSize() );
- else
- {
- // IMPORTANT -- do NOT change the following line, it identifies the file as an input map file
- dStrcpy( lineBuffer, "// Torque Input Map File\n", 1024 );
- iostrm->write( dStrlen( lineBuffer ), lineBuffer );
- }
- dSprintf(lineBuffer, 1024, "if (isObject(%s)) %s.delete();\n"
- "new ActionMap(%s);\n", getName(), getName(), getName());
- iostrm->write(dStrlen(lineBuffer), lineBuffer);
- // Dump all the binds to the console...
- for (S32 i = 0; i < mDeviceMaps.size(); i++) {
- const DeviceMap* pDevMap = mDeviceMaps[i];
- char devbuffer[32];
- getDeviceName(pDevMap->deviceType, pDevMap->deviceInst, devbuffer);
- for (S32 j = 0; j < pDevMap->nodeMap.size(); j++) {
- const Node& rNode = pDevMap->nodeMap[j];
- const char* pModifierString = getModifierString(rNode.modifiers);
- char objectbuffer[64];
- if (getKeyString(rNode.action, objectbuffer) == false)
- continue;
- const char* command;
- if (rNode.flags & Node::BindCmd)
- command = "bindCmd";
- else if (rNode.flags & Node::Held)
- command = "held";
- else
- command = "bind";
- dSprintf(lineBuffer, 1024, "%s.%s(%s, \"%s%s\"",
- getName(),
- command,
- devbuffer,
- pModifierString, objectbuffer);
- if (rNode.flags & (Node::HasScale|Node::HasDeadZone|Node::Ranged|Node::Inverted)) {
- char buff[10];
- U32 curr = 0;
- buff[curr++] = ',';
- buff[curr++] = ' ';
- if (rNode.flags & Node::HasScale)
- buff[curr++] = 'S';
- if (rNode.flags & Node::Ranged)
- buff[curr++] = 'R';
- if (rNode.flags & Node::HasDeadZone)
- buff[curr++] = 'D';
- if (rNode.flags & Node::Inverted)
- buff[curr++] = 'I';
- buff[curr] = '\0';
- dStrcat(lineBuffer, buff, 1024);
- }
- if (rNode.flags & Node::HasDeadZone) {
- char buff[64];
- dSprintf(buff, 63, ", \"%g %g\"", rNode.deadZoneBegin, rNode.deadZoneEnd);
- dStrcat(lineBuffer, buff, 1024);
- }
- if (rNode.flags & Node::HasScale) {
- char buff[64];
- dSprintf(buff, 63, ", %g", rNode.scaleFactor);
- dStrcat(lineBuffer, buff, 1024);
- }
- if (rNode.flags & Node::BindCmd) {
- if (rNode.makeConsoleCommand) {
- dStrcat(lineBuffer, ", \"", 1024);
- U32 pos = dStrlen(lineBuffer);
- expandEscape(lineBuffer + pos, rNode.makeConsoleCommand);
- dStrcat(lineBuffer, "\"", 1024);
- } else {
- dStrcat(lineBuffer, ", \"\"", 1024);
- }
- if (rNode.breakConsoleCommand) {
- dStrcat(lineBuffer, ", \"", 1024);
- U32 pos = dStrlen(lineBuffer);
- expandEscape(lineBuffer + pos, rNode.breakConsoleCommand);
- dStrcat(lineBuffer, "\"", 1024);
- }
- else
- dStrcat(lineBuffer, ", \"\"", 1024);
- }
- else if (rNode.flags & Node::Held)
- {
- dStrcat(lineBuffer, ", ", 1024);
- dStrcat(lineBuffer, rNode.consoleFunction, 1024);
- dStrcat(lineBuffer, ", ", 1024);
- dStrcat(lineBuffer, rNode.contextEvent->mConsoleFunctionHeld, 1024);
- }
- else {
- dStrcat(lineBuffer, ", ", 1024);
- dStrcat(lineBuffer, rNode.consoleFunction, 1024);
- }
- dStrcat(lineBuffer, ");\n", 1024);
- iostrm->write(dStrlen(lineBuffer), lineBuffer);
- }
- }
- delete iostrm;
- }
- else {
- // Dump all the binds to the console...
- for (S32 i = 0; i < mDeviceMaps.size(); i++) {
- const DeviceMap* pDevMap = mDeviceMaps[i];
- char devbuffer[32];
- getDeviceName(pDevMap->deviceType, pDevMap->deviceInst, devbuffer);
- for (S32 j = 0; j < pDevMap->nodeMap.size(); j++) {
- const Node& rNode = pDevMap->nodeMap[j];
- const char* pModifierString = getModifierString(rNode.modifiers);
- char keybuffer[64];
- if (getKeyString(rNode.action, keybuffer) == false)
- continue;
- const char* command;
- if (rNode.flags & Node::BindCmd)
- command = "bindCmd";
- else if (rNode.flags & Node::Held)
- command = "held";
- else
- command = "bind";
- char finalBuffer[1024];
- dSprintf(finalBuffer, 1024, "%s.%s(%s, \"%s%s\"",
- getName(),
- command,
- devbuffer,
- pModifierString, keybuffer);
- if (rNode.flags & (Node::HasScale|Node::HasDeadZone|Node::Ranged|Node::Inverted)) {
- char buff[10];
- U32 curr = 0;
- buff[curr++] = ',';
- buff[curr++] = ' ';
- if (rNode.flags & Node::HasScale)
- buff[curr++] = 'S';
- if (rNode.flags & Node::Ranged)
- buff[curr++] = 'R';
- if (rNode.flags & Node::HasDeadZone)
- buff[curr++] = 'D';
- if (rNode.flags & Node::Inverted)
- buff[curr++] = 'I';
- buff[curr] = '\0';
- dStrcat(finalBuffer, buff, 1024);
- }
- if (rNode.flags & Node::HasDeadZone) {
- char buff[64];
- dSprintf(buff, 63, ", \"%g %g\"", rNode.deadZoneBegin, rNode.deadZoneEnd);
- dStrcat(finalBuffer, buff, 1024);
- }
- if (rNode.flags & Node::HasScale) {
- char buff[64];
- dSprintf(buff, 63, ", %g", rNode.scaleFactor);
- dStrcat(finalBuffer, buff, 1024);
- }
- if (rNode.flags & Node::BindCmd) {
- if (rNode.makeConsoleCommand) {
- dStrcat(finalBuffer, ", \"", 1024);
- dStrcat(finalBuffer, rNode.makeConsoleCommand, 1024);
- dStrcat(finalBuffer, "\"", 1024);
- } else {
- dStrcat(finalBuffer, ", \"\"", 1024);
- }
- if (rNode.breakConsoleCommand) {
- dStrcat(finalBuffer, ", \"", 1024);
- dStrcat(finalBuffer, rNode.breakConsoleCommand, 1024);
- dStrcat(finalBuffer, "\"", 1024);
- }
- else
- dStrcat(finalBuffer, ", \"\"", 1024);
- }
- else if (rNode.flags & Node::Held)
- {
- dStrcat(finalBuffer, ", ", 1024);
- dStrcat(finalBuffer, rNode.consoleFunction, 1024);
- dStrcat(finalBuffer, ", ", 1024);
- dStrcat(finalBuffer, rNode.contextEvent->mConsoleFunctionHeld, 1024);
- }
- else {
- dStrcat(finalBuffer, ", ", 1024);
- dStrcat(finalBuffer, rNode.consoleFunction, 1024);
- }
- dStrcat(finalBuffer, ");", 1024);
- Con::printf(finalBuffer);
- }
- }
- }
- }
- //--------------------------------------------------------------------------
- bool ActionMap::createEventDescriptor(const char* pEventString, EventDescriptor* pDescriptor)
- {
- char copyBuffer[256];
- dStrcpy(copyBuffer, pEventString, 256);
- // Do we have modifiers?
- char* pSpace = dStrchr(copyBuffer, ' ');
- char* pObjectString;
- if (pSpace != NULL) {
- // Yes. Parse them out...
- //
- pDescriptor->flags = 0;
- pObjectString = pSpace + 1;
- pSpace[0] = '\0';
- char* pModifier = dStrtok(copyBuffer, "-");
- while (pModifier != NULL) {
- if (dStricmp(pModifier, "shift") == 0) {
- pDescriptor->flags |= SI_SHIFT;
- } else if (dStricmp(pModifier, "ctrl") == 0) {
- pDescriptor->flags |= SI_CTRL;
- } else if (dStricmp(pModifier, "alt") == 0) {
- pDescriptor->flags |= SI_ALT;
- } else if (dStricmp(pModifier, "cmd") == 0) {
- pDescriptor->flags |= SI_ALT;
- } else if (dStricmp(pModifier, "opt") == 0) {
- pDescriptor->flags |= SI_MAC_OPT;
- }
- pModifier = dStrtok(NULL, "-");
- }
- } else {
- // No.
- pDescriptor->flags = 0;
- pObjectString = copyBuffer;
- }
- // Now we need to map the key string to the proper KEY code from event.h
- //
- AssertFatal(dStrlen(pObjectString) != 0, "Error, no key was specified!");
- if (dStrlen(pObjectString) == 1)
- {
- if (dIsDecentChar(*pObjectString)) // includes foreign chars
- {
- U16 asciiCode = (*pObjectString);
- // clear out the FF in upper 8bits for foreign keys??
- asciiCode &= 0xFF;
- U16 keyCode = Input::getKeyCode(asciiCode);
- if ( keyCode >= KEY_0 )
- {
- pDescriptor->eventType = SI_KEY;
- pDescriptor->eventCode = keyCode;
- return true;
- }
- else if (dIsalpha(*pObjectString) == true)
- {
- pDescriptor->eventType = SI_KEY;
- pDescriptor->eventCode = KEY_A+dTolower(*pObjectString)-'a';
- return true;
- }
- else if (dIsdigit(*pObjectString) == true)
- {
- pDescriptor->eventType = SI_KEY;
- pDescriptor->eventCode = KEY_0+(*pObjectString)-'0';
- return true;
- }
- }
- return false;
- }
- else
- {
- pDescriptor->eventCode = 0;
- // Gotta search through the Ascii table...
- for (U16 i = 0; gAsciiMap[i].asciiCode != 0xFFFF; i++)
- {
- if (dStricmp(pObjectString, gAsciiMap[i].pDescription) == 0)
- {
- U16 asciiCode = gAsciiMap[i].asciiCode;
- U16 keyCode = Input::getKeyCode(asciiCode);
- if ( keyCode >= KEY_0 )
- {
- pDescriptor->eventType = SI_KEY;
- pDescriptor->eventCode = keyCode;
- return(true);
- }
- else
- {
- break;
- }
- }
- }
- // Didn't find an ascii match. Check the virtual map table
- //for (U32 j = 0; gVirtualMap[j].code != 0xFFFFFFFF; j++)
- //{
- // if (dStricmp(pObjectString, gVirtualMap[j].pDescription) == 0)
- // {
- // pDescriptor->eventType = gVirtualMap[j].type;
- // pDescriptor->eventCode = gVirtualMap[j].code;
- // return true;
- // }
- //}
- InputEventManager::VirtualMapData* data = INPUTMGR->findVirtualMap(pObjectString);
- if(data)
- {
- pDescriptor->eventType = data->type;
- pDescriptor->eventCode = data->code;
- return true;
- }
- }
- return false;
- }
- //------------------------------------------------------------------------------
- ActionMap::Node* ActionMap::getNode(const U32 inDeviceType, const U32 inDeviceInst,
- const U32 inModifiers, const U32 inAction,SimObject* object /*= NULL*/)
- {
- // DMMTODO - Slow INITIAL implementation. Replace with a faster version...
- //
- DeviceMap* pDeviceMap = NULL;
- U32 i;
- for (i = 0; i < mDeviceMaps.size(); i++)
- {
- if (mDeviceMaps[i]->deviceType == inDeviceType &&
- mDeviceMaps[i]->deviceInst == inDeviceInst) {
- pDeviceMap = mDeviceMaps[i];
- break;
- }
- }
- if (pDeviceMap == NULL)
- {
- mDeviceMaps.increment();
- mDeviceMaps.last() = new DeviceMap;
- pDeviceMap = mDeviceMaps.last();
- pDeviceMap->deviceInst = inDeviceInst;
- pDeviceMap->deviceType = inDeviceType;
- }
- for (i = 0; i < pDeviceMap->nodeMap.size(); i++)
- {
- if (pDeviceMap->nodeMap[i].modifiers == inModifiers &&
- pDeviceMap->nodeMap[i].action == inAction &&
- ( (object != NULL) ? object == pDeviceMap->nodeMap[i].object : true )) // Check for an object match if the object exists
- {
- return &pDeviceMap->nodeMap[i];
- }
- }
- // If we're here, the node doesn't exist. create it.
- pDeviceMap->nodeMap.increment();
- Node* pRetNode = &pDeviceMap->nodeMap.last();
- pRetNode->modifiers = inModifiers;
- pRetNode->action = inAction;
- pRetNode->flags = 0;
- pRetNode->deadZoneBegin = 0.0;
- pRetNode->deadZoneEnd = 0.0;
- pRetNode->scaleFactor = 1.0;
- pRetNode->consoleFunction = NULL;
- pRetNode->makeConsoleCommand = NULL;
- pRetNode->breakConsoleCommand = NULL;
- //[neob, 5/7/2007 - #2975]
- pRetNode->object = 0;
- return pRetNode;
- }
- //------------------------------------------------------------------------------
- void ActionMap::removeNode(const U32 inDeviceType, const U32 inDeviceInst, const U32 inModifiers, const U32 inAction, SimObject* object /*= NULL*/)
- {
- // DMMTODO - Slow INITIAL implementation. Replace with a faster version...
- //
- DeviceMap* pDeviceMap = NULL;
- U32 i;
- for (i = 0; i < mDeviceMaps.size(); i++) {
- if (mDeviceMaps[i]->deviceType == inDeviceType &&
- mDeviceMaps[i]->deviceInst == inDeviceInst) {
- pDeviceMap = mDeviceMaps[i];
- break;
- }
- }
- if (pDeviceMap == NULL)
- return;
- U32 realMods = inModifiers;
- if (realMods & SI_SHIFT)
- realMods |= SI_SHIFT;
- if (realMods & SI_CTRL)
- realMods |= SI_CTRL;
- if (realMods & SI_ALT)
- realMods |= SI_ALT;
- if (realMods & SI_MAC_OPT)
- realMods |= SI_MAC_OPT;
- for (i = 0; i < pDeviceMap->nodeMap.size(); i++) {
- if (pDeviceMap->nodeMap[i].modifiers == realMods &&
- pDeviceMap->nodeMap[i].action == inAction &&
- ( (object != NULL) ? object == pDeviceMap->nodeMap[i].object : true ))
- {
- dFree(pDeviceMap->nodeMap[i].makeConsoleCommand);
- dFree(pDeviceMap->nodeMap[i].breakConsoleCommand);
- pDeviceMap->nodeMap.erase(i);
- }
- }
- }
- //------------------------------------------------------------------------------
- const ActionMap::Node* ActionMap::findNode(const U32 inDeviceType, const U32 inDeviceInst,
- const U32 inModifiers, const U32 inAction)
- {
- // DMMTODO - Slow INITIAL implementation. Replace with a faster version...
- //
- DeviceMap* pDeviceMap = NULL;
- U32 i;
- for (i = 0; i < mDeviceMaps.size(); i++)
- {
- if (mDeviceMaps[i]->deviceType == inDeviceType && mDeviceMaps[i]->deviceInst == inDeviceInst)
- {
- pDeviceMap = mDeviceMaps[i];
- break;
- }
- }
- if (pDeviceMap == NULL)
- return NULL;
- U32 realMods = inModifiers;
- if (realMods & SI_SHIFT)
- realMods |= SI_SHIFT;
- if (realMods & SI_CTRL)
- realMods |= SI_CTRL;
- if (realMods & SI_ALT)
- realMods |= SI_ALT;
- if (realMods & SI_MAC_OPT)
- realMods |= SI_MAC_OPT;
- for (i = 0; i < pDeviceMap->nodeMap.size(); i++)
- {
- // Special case for an ANYKEY bind...
- if (pDeviceMap->nodeMap[i].action == KEY_ANYKEY
- && pDeviceMap->nodeMap[i].modifiers == realMods
- && dIsDecentChar(inAction)
- && inAction <= U8_MAX)
- return &pDeviceMap->nodeMap[i];
- if (pDeviceMap->nodeMap[i].modifiers == realMods
- && pDeviceMap->nodeMap[i].action == inAction)
- return &pDeviceMap->nodeMap[i];
- }
- return NULL;
- }
- //------------------------------------------------------------------------------
- bool ActionMap::findBoundNode( const char* function, U32 &devMapIndex, U32 &nodeIndex )
- {
- devMapIndex = 0;
- nodeIndex = 0;
- return nextBoundNode( function, devMapIndex, nodeIndex );
- }
- bool ActionMap::nextBoundNode( const char* function, U32 &devMapIndex, U32 &nodeIndex )
- {
- // Loop through all of the existing nodes to find the one mapped to the
- // given function:
- for ( U32 i = devMapIndex; i < mDeviceMaps.size(); i++ )
- {
- const DeviceMap* dvcMap = mDeviceMaps[i];
- for ( U32 j = nodeIndex; j < dvcMap->nodeMap.size(); j++ )
- {
- const Node* node = &dvcMap->nodeMap[j];
- if ( !( node->flags & Node::BindCmd ) && ( dStricmp( function, node->consoleFunction ) == 0 ) )
- {
- devMapIndex = i;
- nodeIndex = j;
- return( true );
- }
- }
- nodeIndex = 0;
- }
- return( false );
- }
- //------------------------------------------------------------------------------
- bool ActionMap::processUnbind(const char *device, const char *action, SimObject* object /*= NULL*/)
- {
- U32 deviceType;
- U32 deviceInst;
- if(!getDeviceTypeAndInstance(device, deviceType, deviceInst))
- return false;
- EventDescriptor eventDescriptor;
- if (!createEventDescriptor(action, &eventDescriptor))
- return false;
- removeNode(deviceType, deviceInst, eventDescriptor.flags,eventDescriptor.eventCode, object);
- return true;
- }
- //------------------------------------------------------------------------------
- // This function is for the use of the control remapper.
- // It will only check against the console function (since all remappable commands are
- // bound using bind and not bindCmd).
- //
- const char* ActionMap::getBinding( const char* command )
- {
- char* returnString = Con::getReturnBuffer( 1024 );
- returnString[0] = 0;
- char buffer[256];
- char deviceBuffer[32];
- char keyBuffer[64];
-
- U32 devMapIndex = 0, nodeIndex = 0;
- while ( nextBoundNode( command, devMapIndex, nodeIndex ) )
- {
- const DeviceMap* deviceMap = mDeviceMaps[devMapIndex];
- if ( getDeviceName( deviceMap->deviceType, deviceMap->deviceInst, deviceBuffer ) )
- {
- const Node* node = &deviceMap->nodeMap[nodeIndex];
- const char* modifierString = getModifierString( node->modifiers );
- if ( getKeyString( node->action, keyBuffer ) )
- {
- dSprintf( buffer, sizeof( buffer ), "%s\t%s%s", deviceBuffer, modifierString, keyBuffer );
- if ( returnString[0] )
- dStrcat( returnString, "\t", 1024 );
- dStrcat( returnString, buffer, 1024 );
- }
- }
- ++nodeIndex;
- }
- return returnString;
- }
- //------------------------------------------------------------------------------
- // This function is for the use of the control remapper.
- // The intent of this function is to determine if the given event descriptor is already
- // bound in this action map. If so, this function returns the command it is bound to.
- // If not, it returns NULL.
- //
- const char* ActionMap::getCommand( const char* device, const char* action )
- {
- U32 deviceType;
- U32 deviceInst;
- if ( getDeviceTypeAndInstance( device, deviceType, deviceInst ) )
- {
- EventDescriptor eventDescriptor;
- if ( createEventDescriptor( action, &eventDescriptor ) )
- {
- const ActionMap::Node* mapNode = findNode( deviceType, deviceInst, eventDescriptor.flags, eventDescriptor.eventCode );
- if ( mapNode )
- {
- if ( mapNode->flags & Node::BindCmd )
- {
- S32 bufferLen = dStrlen( mapNode->makeConsoleCommand ) + dStrlen( mapNode->breakConsoleCommand ) + 2;
- char* returnString = Con::getReturnBuffer( bufferLen );
- dSprintf( returnString, bufferLen, "%s\t%s",
- ( mapNode->makeConsoleCommand ? mapNode->makeConsoleCommand : "" ),
- ( mapNode->breakConsoleCommand ? mapNode->breakConsoleCommand : "" ) );
- return( returnString );
- }
- if (mapNode->flags & Node::Held)
- {
- S32 bufferLen = dStrlen(mapNode->consoleFunction) + dStrlen(mapNode->contextEvent->mConsoleFunctionHeld) + 2;
- char* returnString = Con::getReturnBuffer(bufferLen);
- dSprintf(returnString, bufferLen, "%st%s",
- (mapNode->consoleFunction ? mapNode->consoleFunction : ""),
- (mapNode->contextEvent->mConsoleFunctionHeld ? mapNode->contextEvent->mConsoleFunctionHeld : ""));
- return(returnString);
- }
- else
- return( mapNode->consoleFunction );
- }
- }
- }
- return( "" );
- }
- //------------------------------------------------------------------------------
- // This function returns whether or not the mapping specified is inverted.
- // Obviously, this should only be used for axes.
- bool ActionMap::isInverted( const char* device, const char* action )
- {
- U32 deviceType;
- U32 deviceInst;
- if ( getDeviceTypeAndInstance( device, deviceType, deviceInst ) )
- {
- EventDescriptor eventDescriptor;
- if ( createEventDescriptor( action, &eventDescriptor ) )
- {
- const ActionMap::Node* mapNode = findNode( deviceType, deviceInst, eventDescriptor.flags, eventDescriptor.eventCode );
- if ( mapNode )
- return( mapNode->flags & Node::Inverted );
- }
- }
- Con::errorf( "The input event specified by %s %s is not in this action map!", device, action );
- return( false );
- }
- //------------------------------------------------------------------------------
- F32 ActionMap::getScale( const char* device, const char* action )
- {
- U32 deviceType;
- U32 deviceInst;
- if ( getDeviceTypeAndInstance( device, deviceType, deviceInst ) )
- {
- EventDescriptor eventDescriptor;
- if ( createEventDescriptor( action, &eventDescriptor ) )
- {
- const ActionMap::Node* mapNode = findNode( deviceType, deviceInst, eventDescriptor.flags, eventDescriptor.eventCode );
- if ( mapNode )
- {
- if ( mapNode->flags & Node::HasScale )
- return( mapNode->scaleFactor );
- else
- return( 1.0f );
- }
- }
- }
- Con::errorf( "The input event specified by %s %s is not in this action map!", device, action );
- return( 1.0f );
- }
- //------------------------------------------------------------------------------
- const char* ActionMap::getDeadZone( const char* device, const char* action )
- {
- U32 deviceType;
- U32 deviceInst;
- if ( getDeviceTypeAndInstance( device, deviceType, deviceInst ) )
- {
- EventDescriptor eventDescriptor;
- if ( createEventDescriptor( action, &eventDescriptor ) )
- {
- const ActionMap::Node* mapNode = findNode( deviceType, deviceInst, eventDescriptor.flags, eventDescriptor.eventCode );
- if ( mapNode )
- {
- if ( mapNode->flags & Node::HasDeadZone )
- {
- char buf[64];
- dSprintf( buf, sizeof( buf ), "%g %g", mapNode->deadZoneBegin, mapNode->deadZoneEnd );
- dsize_t returnLen = dStrlen(buf) + 1;
- char* returnString = Con::getReturnBuffer( returnLen );
- dStrcpy( returnString, buf, returnLen );
- return( returnString );
- }
- else
- return( "0 0" );
- }
- }
- }
- Con::errorf( "The input event specified by %s %s is not in this action map!", device, action );
- return( "" );
- }
- //------------------------------------------------------------------------------
- const char* ActionMap::buildActionString( const InputEventInfo* event )
- {
- const char* modifierString = getModifierString( event->modifier );
- char objectBuffer[64];
- if ( !getKeyString( event->objInst, objectBuffer ) )
- return( "" );
- U32 returnLen = dStrlen( modifierString ) + dStrlen( objectBuffer ) + 2;
- char* returnString = Con::getReturnBuffer( returnLen );
- dSprintf( returnString, returnLen - 1, "%s%s", modifierString, objectBuffer );
- return( returnString );
- }
- //------------------------------------------------------------------------------
- bool ActionMap::getDeviceTypeAndInstance(const char *pDeviceName, U32 &deviceType, U32 &deviceInstance)
- {
- U32 offset = 0;
- U32 inputMgrDeviceType = 0;
- if (dStrnicmp(pDeviceName, "keyboard", dStrlen("keyboard")) == 0)
- {
- deviceType = KeyboardDeviceType;
- offset = dStrlen("keyboard");
- }
- else if (dStrnicmp(pDeviceName, "mouse", dStrlen("mouse")) == 0)
- {
- deviceType = MouseDeviceType;
- offset = dStrlen("mouse");
- }
- else if (dStrnicmp(pDeviceName, "joystick", dStrlen("joystick")) == 0)
- {
- deviceType = JoystickDeviceType;
- offset = dStrlen("joystick");
- }
- else if (dStrnicmp(pDeviceName, "gamepad", dStrlen("gamepad")) == 0)
- {
- deviceType = GamepadDeviceType;
- offset = dStrlen("gamepad");
- }
- else if(INPUTMGR->isRegisteredDeviceWithAttributes(pDeviceName, inputMgrDeviceType, offset))
- {
- deviceType = inputMgrDeviceType;
- }
- else
- {
- return false;
- }
- if (dStrlen(pDeviceName) > offset)
- {
- const char* pInst = pDeviceName + offset;
- S32 instNum = dAtoi(pInst);
-
- if (instNum < 0)
- deviceInstance = 0;
- else
- deviceInstance = instNum;
- }
- else
- {
- deviceInstance = 0;
- }
- return true;
- }
- //------------------------------------------------------------------------------
- bool ActionMap::getDeviceName(const U32 deviceType, const U32 deviceInstance, char* buffer)
- {
- switch (deviceType) {
- case KeyboardDeviceType:
- dStrcpy(buffer, "keyboard", 16);
- break;
- case MouseDeviceType:
- dSprintf(buffer, 16, "mouse%d", deviceInstance);
- break;
- case JoystickDeviceType:
- dSprintf(buffer, 16, "joystick%d", deviceInstance);
- break;
- case GamepadDeviceType:
- dSprintf(buffer, 16, "gamepad%d", deviceInstance);
- break;
- default:
- {
- const char* name = INPUTMGR->getRegisteredDeviceName(deviceType);
- if(!name)
- {
- Con::errorf( "ActionMap::getDeviceName: unknown device type specified, %d (inst: %d)", deviceType, deviceInstance);
- return false;
- }
- dSprintf(buffer, 16, "%s%d", name, deviceInstance);
- break;
- }
- }
- return true;
- }
- //------------------------------------------------------------------------------
- const char* ActionMap::getModifierString(const U32 modifiers)
- {
- U32 realModifiers = modifiers;
- if ( modifiers & SI_LSHIFT || modifiers & SI_RSHIFT )
- realModifiers |= SI_SHIFT;
- if ( modifiers & SI_LCTRL || modifiers & SI_RCTRL )
- realModifiers |= SI_CTRL;
- if ( modifiers & SI_LALT || modifiers & SI_RALT )
- realModifiers |= SI_ALT;
- if ( modifiers & SI_MAC_LOPT || modifiers & SI_MAC_ROPT )
- realModifiers |= SI_MAC_OPT;
- switch (realModifiers & (SI_SHIFT|SI_CTRL|SI_ALT|SI_MAC_OPT))
- {
- #if defined(TORQUE_OS_MAC)
- // optional code, to output alt as cmd on mac.
- // interpreter sees them as the same...
- case (SI_SHIFT|SI_CTRL|SI_ALT):
- return "cmd-shift-ctrl ";
- case (SI_SHIFT|SI_ALT):
- return "cmd-shift ";
- case (SI_CTRL|SI_ALT):
- return "cmd-ctrl ";
- case (SI_ALT):
- return "cmd ";
- #else
- case (SI_SHIFT|SI_CTRL|SI_ALT):
- return "shift-ctrl-alt ";
- case (SI_SHIFT|SI_ALT):
- return "shift-alt ";
- case (SI_CTRL|SI_ALT):
- return "ctrl-alt ";
- case (SI_ALT):
- return "alt ";
- #endif
- case (SI_SHIFT|SI_CTRL):
- return "shift-ctrl ";
- case (SI_SHIFT):
- return "shift ";
- case (SI_CTRL):
- return "ctrl ";
- // plus new mac cases:
- case (SI_ALT|SI_SHIFT|SI_CTRL|SI_MAC_OPT):
- return "cmd-shift-ctrl-opt ";
- case (SI_ALT|SI_SHIFT|SI_MAC_OPT):
- return "cmd-shift-opt ";
- case (SI_ALT|SI_CTRL|SI_MAC_OPT):
- return "cmd-ctrl-opt ";
- case (SI_ALT|SI_MAC_OPT):
- return "cmd-opt ";
- case (SI_SHIFT|SI_CTRL|SI_MAC_OPT):
- return "shift-ctrl-opt ";
- case (SI_SHIFT|SI_MAC_OPT):
- return "shift-opt ";
- case (SI_CTRL|SI_MAC_OPT):
- return "ctrl-opt ";
- case (SI_MAC_OPT):
- return "opt ";
-
- case 0:
- return "";
- default:
- AssertFatal(false, "Error, should never reach the default case in getModifierString");
- return "";
- }
- }
- //------------------------------------------------------------------------------
- bool ActionMap::getKeyString(const U32 action, char* buffer)
- {
- U16 asciiCode = 0;
- // This is a special case.... numpad keys do have ascii values
- // but for the purposes of this method we want to return the
- // description from the gVirtualMap.
- if ( !( KEY_NUMPAD0 <= action && action <= KEY_NUMPAD9 ) )
- asciiCode = Input::getAscii( action, STATE_LOWER );
- // if (action >= KEY_A && action <= KEY_Z) {
- // buffer[0] = char(action - KEY_A + 'a');
- // buffer[1] = '\0';
- // return true;
- // } else if (action >= KEY_0 && action <= KEY_9) {
- // buffer[0] = char(action - KEY_0 + '0');
- // buffer[1] = '\0';
- if ( (asciiCode != 0) && dIsDecentChar((char)asciiCode))
- {
- for (U32 i = 0; gAsciiMap[i].asciiCode != 0xFFFF; i++) {
- if (gAsciiMap[i].asciiCode == asciiCode)
- {
- dStrcpy(buffer, gAsciiMap[i].pDescription, 16);
- return true;
- }
- }
- // Must not have found a string for that ascii code just record the char
- buffer[0] = char(asciiCode);
- buffer[1] = '\0';
- return true;
- }
- else
- {
- if (action >= KEY_A && action <= KEY_Z)
- {
- buffer[0] = char(action - KEY_A + 'a');
- buffer[1] = '\0';
- return true;
- }
- else if (action >= KEY_0 && action <= KEY_9) {
- buffer[0] = char(action - KEY_0 + '0');
- buffer[1] = '\0';
- return true;
- }
- //for (U32 i = 0; gVirtualMap[i].code != 0xFFFFFFFF; i++) {
- // if (gVirtualMap[i].code == action) {
- // dStrcpy(buffer, gVirtualMap[i].pDescription, 16);
- // return true;
- // }
- //}
- const char* desc = INPUTMGR->findVirtualMapDescFromCode(action);
- if(desc)
- {
- dStrcpy(buffer, desc, 16);
- return true;
- }
- }
- Con::errorf( "ActionMap::getKeyString: no string for action %d", action );
- return false;
- }
- //--------------------------------------------------------------------------
- bool ActionMap::processBindCmd(const char *device, const char *action, const char *makeCmd, const char *breakCmd)
- {
- U32 deviceType;
- U32 deviceInst;
- if(!getDeviceTypeAndInstance(device, deviceType, deviceInst))
- {
- Con::printf("processBindCmd: unknown device: %s", device);
- return false;
- }
- // Ok, we now have the deviceType and instance. Create an event descriptor
- // for the bind...
- //
- EventDescriptor eventDescriptor;
- if (createEventDescriptor(action, &eventDescriptor) == false) {
- Con::printf("Could not create a description for binding: %s", action);
- return false;
- }
- // SI_POV == SI_MOVE, and the POV works fine with bindCmd, so we have to add these manually.
- if( ( eventDescriptor.eventCode == SI_XAXIS ) ||
- ( eventDescriptor.eventCode == SI_YAXIS ) ||
- ( eventDescriptor.eventCode == SI_ZAXIS ) ||
- ( eventDescriptor.eventCode == SI_RXAXIS ) ||
- ( eventDescriptor.eventCode == SI_RYAXIS ) ||
- ( eventDescriptor.eventCode == SI_RZAXIS ) ||
- ( eventDescriptor.eventCode == SI_SLIDER ) ||
- ( eventDescriptor.eventCode == SI_XPOV ) ||
- ( eventDescriptor.eventCode == SI_YPOV ) ||
- ( eventDescriptor.eventCode == SI_XPOV2 ) ||
- ( eventDescriptor.eventCode == SI_YPOV2 ) )
- {
- Con::warnf( "ActionMap::processBindCmd - Cannot use 'bindCmd' with a move event type. Use 'bind' instead." );
- return false;
- }
- // Create the full bind entry, and place it in the map
- //
- // DMMTODO
- Node* pBindNode = getNode(deviceType, deviceInst,
- eventDescriptor.flags,
- eventDescriptor.eventCode);
- pBindNode->flags = Node::BindCmd;
- pBindNode->deadZoneBegin = 0;
- pBindNode->deadZoneEnd = 0;
- pBindNode->scaleFactor = 1;
- if( pBindNode->makeConsoleCommand )
- dFree( pBindNode->makeConsoleCommand );
- if( pBindNode->breakConsoleCommand )
- dFree( pBindNode->breakConsoleCommand );
- if(makeCmd[0])
- pBindNode->makeConsoleCommand = dStrdup(makeCmd);
- else
- pBindNode->makeConsoleCommand = dStrdup("");
- if(breakCmd[0])
- pBindNode->breakConsoleCommand = dStrdup(breakCmd);
- else
- pBindNode->breakConsoleCommand = dStrdup("");
- return true;
- }
- //------------------------------------------------------------------------------
- bool ActionMap::processBind(const U32 argc, const char** argv, SimObject* object)
- {
- // Ok, the bind will come in the following format:
- // [device] [key or button] <[param spec] [param] ...> [fnName]
- //
- const char* pDeviceName = argv[0];
- const char* pEvent = argv[1];
- const char* pFnName = argv[argc - 1];
- // Determine the device
- U32 deviceType;
- U32 deviceInst;
- if(!getDeviceTypeAndInstance(argv[0], deviceType, deviceInst))
- {
- Con::printf("processBind: unknown device: %s", pDeviceName);
- return false;
- }
- // Ok, we now have the deviceType and instance. Create an event descriptor
- // for the bind...
- //
- EventDescriptor eventDescriptor;
- if (createEventDescriptor(pEvent, &eventDescriptor) == false)
- {
- Con::printf("Could not create a description for binding: %s", pEvent);
- return false;
- }
- // Event has now been described, and device determined. we need now to extract
- // any modifiers that the action map will apply to incoming events before
- // calling the bound function...
- //
- // DMMTODO
- U32 assignedFlags = 0;
- F32 deadZoneBegin = 0.0f;
- F32 deadZoneEnd = 0.0f;
- F32 scaleFactor = 1.0f;
- if (argc != 3) {
- // We have the following: "[DSIR]" [deadZone] [scale]
- //
- const char* pSpec = argv[2];
- for (U32 i = 0; pSpec[i] != '\0'; i++) {
- switch (pSpec[i]) {
- case 'r': case 'R':
- assignedFlags |= Node::Ranged;
- break;
- case 's': case 'S':
- assignedFlags |= Node::HasScale;
- break;
- case 'd': case 'D':
- assignedFlags |= Node::HasDeadZone;
- break;
- case 'i': case 'I':
- assignedFlags |= Node::Inverted;
- break;
- case 'n': case 'N':
- assignedFlags |= Node::NonLinear;
- break;
- default:
- AssertFatal(false, avar("Misunderstood specifier in bind (spec string: %s)",
- pSpec));
- }
- }
- // Ok, we have the flags. Scan the dead zone and scale, if any.
- //
- U32 curArg = 3;
- if (assignedFlags & Node::HasDeadZone) {
- dSscanf(argv[curArg], "%g %g", &deadZoneBegin, &deadZoneEnd);
- curArg++;
- }
- if (assignedFlags & Node::HasScale) {
- scaleFactor = dAtof(argv[curArg]);
- curArg++;
- }
- if (curArg != (argc - 1)) {
- AssertFatal(curArg == (argc - 1), "error in bind spec somewhere...");
- Con::printf("Improperly specified bind for key: %s", argv[2]);
- return false;
- }
- }
- // Ensure that the console function is properly specified?
- //
- // DMMTODO
- // Create the full bind entry, and place it in the map
- //
- // DMMTODO
- Node* pBindNode = getNode(deviceType, deviceInst,
- eventDescriptor.flags,
- eventDescriptor.eventCode, object);
- pBindNode->flags = assignedFlags;
- pBindNode->deadZoneBegin = deadZoneBegin;
- pBindNode->deadZoneEnd = deadZoneEnd;
- pBindNode->scaleFactor = scaleFactor;
- pBindNode->object = object;
- pBindNode->consoleFunction = StringTable->insert(pFnName);
- return true;
- }
- //------------------------------------------------------------------------------
- bool ActionMap::processHoldBind(const char *device, const char *action, const char *holdFunc, const char *tapFunc, const U32 holdTime, const bool holdOnly, const bool retHoldTime)
- {
- U32 deviceType;
- U32 deviceInst;
- if (!getDeviceTypeAndInstance(device, deviceType, deviceInst))
- {
- Con::printf("processBindCmd: unknown device: %s", device);
- return false;
- }
- // Ok, we now have the deviceType and instance. Create an event descriptor
- // for the bind...
- //
- EventDescriptor eventDescriptor;
- if (createEventDescriptor(action, &eventDescriptor) == false) {
- Con::printf("Could not create a description for binding: %s", action);
- return false;
- }
- // SI_POV == SI_MOVE, and the POV works fine with bindCmd, so we have to add these manually.
- if ((eventDescriptor.eventCode == SI_XAXIS) ||
- (eventDescriptor.eventCode == SI_YAXIS) ||
- (eventDescriptor.eventCode == SI_ZAXIS) ||
- (eventDescriptor.eventCode == SI_RXAXIS) ||
- (eventDescriptor.eventCode == SI_RYAXIS) ||
- (eventDescriptor.eventCode == SI_RZAXIS) ||
- (eventDescriptor.eventCode == SI_SLIDER) ||
- (eventDescriptor.eventCode == SI_XPOV) ||
- (eventDescriptor.eventCode == SI_YPOV) ||
- (eventDescriptor.eventCode == SI_XPOV2) ||
- (eventDescriptor.eventCode == SI_YPOV2))
- {
- Con::warnf("ActionMap::processBindCmd - Cannot use 'bindCmd' with a move event type. Use 'bind' instead.");
- return false;
- }
- // Event has now been described, and device determined. we need now to extract
- // any modifiers that the action map will apply to incoming events before
- // calling the bound function...
- //
- // DMMTODO
- F32 deadZoneBegin = 0.0f;
- F32 deadZoneEnd = 0.0f;
- F32 scaleFactor = 1.0f;
- // Ensure that the console function is properly specified?
- //
- // DMMTODO
- // Create the full bind entry, and place it in the map
- //
- // DMMTODO
- Node* pBindNode = getNode(deviceType, deviceInst,
- eventDescriptor.flags,
- eventDescriptor.eventCode);
- pBindNode->flags = Node::Held;
- pBindNode->deadZoneBegin = deadZoneBegin;
- pBindNode->deadZoneEnd = deadZoneEnd;
- pBindNode->scaleFactor = scaleFactor;
- pBindNode->consoleFunction = StringTable->insert(dStrdup(tapFunc));
- pBindNode->contextEvent = new ContextAction(StringTable->insert(dStrdup(holdFunc)), holdTime, pBindNode, holdOnly);
- pBindNode->contextEvent->mReturnHoldTime = retHoldTime;
- return true;
- }
- //------------------------------------------------------------------------------
- bool ActionMap::processAction(const InputEventInfo* pEvent)
- {
- // Suppress excluded input events, like alt-tab.
- if(Platform::checkKeyboardInputExclusion(pEvent))
- return false;
- static const char *argv[5];
- if (pEvent->action == SI_MAKE) {
- const Node* pNode = findNode(pEvent->deviceType, pEvent->deviceInst,
- pEvent->modifier, pEvent->objInst);
- if( pNode == NULL )
- return false;
- // Enter the break into the table if this is a make event...
- // Do this now rather than after command is processed because
- // command might add a binding which can move the vector of nodes.
- // Filter to prevent Hold buttons from being eaten
- if (!(pNode->flags & Node::Held))
- enterBreakEvent(pEvent, pNode);
- // Whadda ya know, we have this bound. Set up, and call the console
- // function associated with it...
- //
- F32 value = pEvent->fValue;
- if (pNode->flags & Node::Ranged) {
- value = (value * 2.0f) - 1.0f;
- if (pNode->flags & Node::Inverted)
- value *= -1.0f;
- } else {
- if (pNode->flags & Node::Inverted)
- value = 1.0f - value;
- }
- if (pNode->flags & Node::HasScale)
- value *= pNode->scaleFactor;
- if ( pNode->flags & Node::HasDeadZone )
- {
- if ( value >= pNode->deadZoneBegin && value <= pNode->deadZoneEnd )
- value = 0.0f;
- else
- {
- if( value > 0 )
- value = ( value - pNode->deadZoneBegin ) * ( 1.f / ( 1.f - pNode->deadZoneBegin ) );
- else
- value = ( value + pNode->deadZoneBegin ) * ( 1.f / ( 1.f - pNode->deadZoneBegin ) );
- }
- }
- if( pNode->flags & Node::NonLinear )
- value = ( value < 0.f ? -1.f : 1.f ) * mPow( mFabs( value ), CONST_E );
- // Ok, we're all set up, call the function.
- if(pNode->flags & Node::BindCmd)
- {
- // it's a bind command
- if(pNode->makeConsoleCommand)
- Con::evaluate(pNode->makeConsoleCommand);
- }
- else if (pNode->flags & Node::Held)
- {
- //check if we're already holding, if not, start our timer
- if (!pNode->contextEvent->mActive) {
- pNode->contextEvent->mActive = true;
- pNode->contextEvent->mStartTime = Sim::getCurrentTime();
- pNode->contextEvent->mEventValue = value;
- }
- }
- else if ( pNode->consoleFunction[0] )
- {
- argv[0] = pNode->consoleFunction;
- argv[1] = Con::getFloatArg(value);
- if (pNode->object)
- Con::executef(pNode->object, argv[0], argv[1]);
- else
- Con::execute(2, argv);
- }
- return true;
- } else if (pEvent->action == SI_MOVE) {
- if (pEvent->deviceType == MouseDeviceType) {
- const Node* pNode = findNode(pEvent->deviceType, pEvent->deviceInst,
- pEvent->modifier, pEvent->objInst);
- if( pNode == NULL )
- return false;
- // "Do nothing" bind:
- if ( !pNode->consoleFunction[0] )
- return( true );
- // Whadda ya know, we have this bound. Set up, and call the console
- // function associated with it. Mouse events ignore range and dead
- // zone params.
- //
- F32 value = pEvent->fValue;
- if (pNode->flags & Node::Inverted)
- value *= -1.0f;
- if (pNode->flags & Node::HasScale)
- value *= pNode->scaleFactor;
- // Ok, we're all set up, call the function.
- argv[0] = pNode->consoleFunction;
- argv[1] = Con::getFloatArg(value);
- if (pNode->object)
- Con::executef(pNode->object, argv[0], argv[1]);
- else
- Con::execute(2, argv);
- return true;
- }
- else if ( (pEvent->objType == SI_POS || pEvent->objType == SI_FLOAT || pEvent->objType == SI_ROT || pEvent->objType == SI_INT)
- && INPUTMGR->isRegisteredDevice(pEvent->deviceType)
- )
- {
- const Node* pNode = findNode(pEvent->deviceType, pEvent->deviceInst,
- pEvent->modifier, pEvent->objInst);
- if( pNode == NULL )
- return false;
- // Ok, we're all set up, call the function.
- argv[0] = pNode->consoleFunction;
- S32 argc = 1;
- if (pEvent->objType == SI_INT)
- {
- // Handle the integer as some sort of motion such as a
- // single component to an absolute position
- argv[1] = Con::getIntArg( pEvent->iValue );
- argc += 1;
- }
- else if (pEvent->objType == SI_FLOAT)
- {
- // Handle float as some sort of motion such as a
- // single component to an absolute position
- argv[1] = Con::getFloatArg( pEvent->fValue );
- argc += 1;
- }
- else if (pEvent->objType == SI_POS)
- {
- // Handle Point3F type position
- argv[1] = Con::getFloatArg( pEvent->fValue );
- argv[2] = Con::getFloatArg( pEvent->fValue2 );
- argv[3] = Con::getFloatArg( pEvent->fValue3 );
- argc += 3;
- }
- else
- {
- // Handle rotation (AngAxisF)
- AngAxisF aa(Point3F(pEvent->fValue, pEvent->fValue2, pEvent->fValue3), pEvent->fValue4);
- aa.axis.normalize();
- argv[1] = Con::getFloatArg( aa.axis.x );
- argv[2] = Con::getFloatArg( aa.axis.y );
- argv[3] = Con::getFloatArg( aa.axis.z );
- argv[4] = Con::getFloatArg( mRadToDeg(aa.angle) );
- argc += 4;
- }
- if (pNode->object)
- {
- Con::execute(pNode->object, argc, argv);
- }
- else
- {
- Con::execute(argc, argv);
- }
- return true;
- }
- else if ( pEvent->deviceType == JoystickDeviceType
- || pEvent->deviceType == GamepadDeviceType
- || INPUTMGR->isRegisteredDevice(pEvent->deviceType)
- )
- {
- // Joystick events...
- const Node* pNode = findNode( pEvent->deviceType, pEvent->deviceInst,
- pEvent->modifier, pEvent->objInst );
- if( pNode == NULL )
- return false;
- // "Do nothing" bind:
- if ( !pNode->consoleFunction[0] )
- return( true );
- // Whadda ya know, we have this bound. Set up, and call the console
- // function associated with it. Joystick move events are the same as mouse
- // move events except that they don't ignore dead zone.
- //
- F32 value = pEvent->fValue;
- if ( pNode->flags & Node::Inverted )
- value *= -1.0f;
- if ( pNode->flags & Node::HasScale )
- value *= pNode->scaleFactor;
- if ( pNode->flags & Node::HasDeadZone )
- {
- if ( value >= pNode->deadZoneBegin &&
- value <= pNode->deadZoneEnd )
- value = 0.0f;
- else
- {
- if( value > 0 )
- value = ( value - pNode->deadZoneEnd ) * ( 1.f / ( 1.f - pNode->deadZoneEnd ) );
- else
- value = ( value - pNode->deadZoneBegin ) * ( 1.f / ( 1.f + pNode->deadZoneBegin ) );
- }
- }
- if( pNode->flags & Node::NonLinear )
- value = ( value < 0.f ? -1.f : 1.f ) * mPow( mFabs( value ), CONST_E );
- // Ok, we're all set up, call the function.
- argv[0] = pNode->consoleFunction;
- argv[1] = Con::getFloatArg( value );
- if (pNode->object)
- Con::executef(pNode->object, argv[0], argv[1]);
- else
- Con::execute(2, argv);
- return true;
- }
- }
- else if (pEvent->action == SI_BREAK)
- {
- const Node* button = findNode(pEvent->deviceType, pEvent->deviceInst,
- pEvent->modifier, pEvent->objInst);
- if (button != NULL)
- {
- if (button->flags == Node::Held)
- {
- if (!button->contextEvent->mBreakEvent)
- button->contextEvent->mBreakEvent = true;
- return true;
- }
- }
- return checkBreakTable(pEvent);
- }
- else if (pEvent->action == SI_VALUE)
- {
- if ( (pEvent->objType == SI_FLOAT || pEvent->objType == SI_INT)
- && INPUTMGR->isRegisteredDevice(pEvent->deviceType)
- )
- {
- const Node* pNode = findNode(pEvent->deviceType, pEvent->deviceInst,
- pEvent->modifier, pEvent->objInst);
- if( pNode == NULL )
- return false;
- // Ok, we're all set up, call the function.
- argv[0] = pNode->consoleFunction;
- S32 argc = 1;
- if (pEvent->objType == SI_INT)
- {
- // Handle the integer as some sort of motion such as a
- // single component to an absolute position
- argv[1] = Con::getIntArg( pEvent->iValue );
- argc += 1;
- }
- else if (pEvent->objType == SI_FLOAT)
- {
- // Handle float as some sort of motion such as a
- // single component to an absolute position
- argv[1] = Con::getFloatArg( pEvent->fValue );
- argc += 1;
- }
- if (pNode->object)
- {
- Con::execute(pNode->object, argc, argv);
- }
- else
- {
- Con::execute(argc, argv);
- }
- return true;
- }
- }
- return false;
- }
- //------------------------------------------------------------------------------
- bool ActionMap::isAction( U32 deviceType, U32 deviceInst, U32 modifiers, U32 action )
- {
- return ( findNode( deviceType, deviceInst, modifiers, action ) != NULL );
- }
- //------------------------------------------------------------------------------
- ActionMap* ActionMap::getGlobalMap()
- {
- SimSet* pActionMapSet = Sim::getActiveActionMapSet();
- AssertFatal( pActionMapSet && pActionMapSet->size() != 0,
- "error, no ActiveMapSet or no global action map...");
- return ( ( ActionMap* ) pActionMapSet->first() );
- }
- //------------------------------------------------------------------------------
- void ActionMap::enterBreakEvent(const InputEventInfo* pEvent, const Node* pNode)
- {
- // There aren't likely to be many breaks outstanding at any one given time,
- // so a simple linear search is probably sufficient. Note that the break table
- // is static to the class, all breaks are directed to the action map that received
- // the make.
- //
- S32 entry = -1;
- for (U32 i = 0; i < smBreakTable.size(); i++) {
- if (smBreakTable[i].deviceType == U32(pEvent->deviceType) &&
- smBreakTable[i].deviceInst == U32(pEvent->deviceInst) &&
- smBreakTable[i].objInst == U32(pEvent->objInst)) {
- // Match.
- entry = i;
- break;
- }
- }
- if (entry == -1) {
- smBreakTable.increment();
- entry = smBreakTable.size() - 1;
- smBreakTable[entry].deviceType = pEvent->deviceType;
- smBreakTable[entry].deviceInst = pEvent->deviceInst;
- smBreakTable[entry].objInst = pEvent->objInst;
- }
- // Ok, we now have the entry, and know that the device desc. and the objInst match.
- // Copy out the node information...
- //
- smBreakTable[entry].object = pNode->object;
- smBreakTable[entry].consoleFunction = pNode->consoleFunction;
- if(pNode->breakConsoleCommand)
- smBreakTable[entry].breakConsoleCommand = dStrdup(pNode->breakConsoleCommand);
- else
- smBreakTable[entry].breakConsoleCommand = NULL;
- smBreakTable[entry].flags = pNode->flags;
- smBreakTable[entry].deadZoneBegin = pNode->deadZoneBegin;
- smBreakTable[entry].deadZoneEnd = pNode->deadZoneEnd;
- smBreakTable[entry].scaleFactor = pNode->scaleFactor;
- }
- //------------------------------------------------------------------------------
- bool ActionMap::checkBreakTable(const InputEventInfo* pEvent)
- {
- for (U32 i = 0; i < smBreakTable.size(); i++)
- {
- if (smBreakTable[i].deviceType == U32(pEvent->deviceType) &&
- smBreakTable[i].deviceInst == U32(pEvent->deviceInst) &&
- smBreakTable[i].objInst == U32(pEvent->objInst))
- {
- fireBreakEvent(i, pEvent->fValue);
- return true;
- }
- }
- return false;
- }
- //------------------------------------------------------------------------------
- bool ActionMap::handleEvent(const InputEventInfo* pEvent)
- {
- // Interate through the ActionMapSet until we get a map that
- // handles the event or we run out of maps...
- //
- SimSet* pActionMapSet = Sim::getActiveActionMapSet();
- AssertFatal(pActionMapSet && pActionMapSet->size() != 0,
- "error, no ActiveMapSet or no global action map...");
-
- for (SimSet::iterator itr = pActionMapSet->end() - 1;
- itr > pActionMapSet->begin(); itr--) {
- ActionMap* pMap = static_cast<ActionMap*>(*itr);
- if (pMap->processAction(pEvent) == true)
- return true;
- }
-
- // Found no matching action. Try with the modifiers stripped.
- InputEventInfo eventNoModifiers = *pEvent;
- eventNoModifiers.modifier = ( InputModifiers ) 0;
-
- for (SimSet::iterator itr = pActionMapSet->end() - 1;
- itr > pActionMapSet->begin(); itr--) {
- ActionMap* pMap = static_cast<ActionMap*>(*itr);
- if( pMap->processAction( &eventNoModifiers ) )
- return true;
- }
- return false;
- }
- //------------------------------------------------------------------------------
- bool ActionMap::handleEventGlobal(const InputEventInfo* pEvent)
- {
- return getGlobalMap()->processAction( pEvent );
- }
- //------------------------------------------------------------------------------
- bool ActionMap::checkAsciiGlobal( U16 key, U32 modifiers )
- {
- // Does this ascii map to a key?
- U16 keyCode = Input::getKeyCode(key);
- if(keyCode == 0)
- return false;
- // Grab the action map set.
- SimSet* pActionMapSet = Sim::getActiveActionMapSet();
- AssertFatal(pActionMapSet && pActionMapSet->size() != 0,
- "error, no ActiveMapSet or no global action map...");
- // Grab the device maps for the first ActionMap.
- Vector<DeviceMap*> &maps = ((ActionMap*)pActionMapSet->first())->mDeviceMaps;
- // Find the keyboard.
- DeviceMap *keyMap = NULL;
- for(S32 i=0; i<maps.size(); i++)
- {
- // CodeReview Doesn't deal with multiple keyboards [bjg, 5/16/07]
- if(maps[i]->deviceType == KeyboardDeviceType)
- {
- keyMap = maps[i];
- break;
- }
- }
- if(!keyMap)
- return false;
- // Normalize modifiers.
- U32 realMods = modifiers;
- if (realMods & SI_SHIFT)
- realMods |= SI_SHIFT;
- if (realMods & SI_CTRL)
- realMods |= SI_CTRL;
- if (realMods & SI_ALT)
- realMods |= SI_ALT;
- if (realMods & SI_MAC_OPT)
- realMods |= SI_MAC_OPT;
- // Now find a matching node, if there is one.
- for(S32 i=0; i<keyMap->nodeMap.size(); i++)
- {
- Node &n = keyMap->nodeMap[i];
- if(n.action == keyCode && (n.modifiers == modifiers))
- return true;
- }
- return false;
- }
- void ActionMap::clearAllBreaks()
- {
- while(smBreakTable.size())
- fireBreakEvent(smBreakTable.size()-1);
- }
- void ActionMap::fireBreakEvent( U32 i, F32 fValue )
- {
- // Match. Issue the break event...
- //
- F32 value = fValue;
- if (smBreakTable[i].flags & Node::Ranged) {
- value = (value * 2.0f) - 1.0f;
- if (smBreakTable[i].flags & Node::Inverted)
- value *= -1.0f;
- } else {
- if (smBreakTable[i].flags & Node::Inverted)
- value = 1.0f - value;
- }
- if (smBreakTable[i].flags & Node::HasScale)
- value *= smBreakTable[i].scaleFactor;
- if (smBreakTable[i].flags & Node::HasDeadZone)
- {
- if (value >= smBreakTable[i].deadZoneBegin &&
- value <= smBreakTable[i].deadZoneEnd)
- value = 0.0f;
- else
- {
- if( value > 0 )
- value = ( value - smBreakTable[i].deadZoneBegin ) * ( 1.f / ( 1.f - smBreakTable[i].deadZoneBegin ) );
- else
- value = ( value + smBreakTable[i].deadZoneBegin ) * ( 1.f / ( 1.f - smBreakTable[i].deadZoneBegin ) );
- }
- }
- if( smBreakTable[i].flags & Node::NonLinear )
- value = ( value < 0.f ? -1.f : 1.f ) * mPow( mFabs( value ), CONST_E );
- // Ok, we're all set up, call the function.
- if(smBreakTable[i].consoleFunction)
- {
- if ( smBreakTable[i].consoleFunction[0] )
- {
- static const char *argv[2];
- argv[0] = smBreakTable[i].consoleFunction;
- argv[1] = Con::getFloatArg(value);
- if (smBreakTable[i].object)
- Con::executef(smBreakTable[i].object, argv[0], argv[1]);
- else
- Con::execute(2, argv);
- }
- }
- else if(smBreakTable[i].breakConsoleCommand)
- {
- Con::evaluate(smBreakTable[i].breakConsoleCommand);
- dFree(smBreakTable[i].breakConsoleCommand);
- }
- smBreakTable.erase(i);
- }
- //------------------------------------------------------------------------------
- //Context actions
- ContextAction::ContextAction(StringTableEntry func, F32 minHoldTime, ActionMap::Node* button, bool holdOnly)
- : mStartTime(0), mEventValue(1.0f), mBreakEvent(false), mDidHold(false), mActive(false), mReturnHoldTime(false)
- {
- mButton = button;
- mMinHoldTime = minHoldTime;
- mConsoleFunctionHeld = func;
- mHoldOnly = holdOnly;
- }
- void ContextAction::processTick()
- {
- if (mActive)
- {
- F32 currTime = Sim::getCurrentTime();
- static const char *argv[3];
- //see if this key even is still active
- if (!mBreakEvent)
- {
- //are we only checking if it's holding?
- if (mHoldOnly)
- {
- //yes, we are, and since it's held, we fire off our function
- if (mReturnHoldTime)
- {
- argv[0] = mConsoleFunctionHeld;
- argv[1] = Con::getFloatArg(mEventValue);
- argv[2] = Con::getFloatArg((currTime - mStartTime));
- Con::execute(3, argv);
- }
- else
- {
- argv[0] = mConsoleFunctionHeld;
- argv[1] = Con::getFloatArg(mEventValue);
- Con::execute(2, argv);
- }
- }
- //if we don't care if we're just holding, check our time
- //have we passed our min limit?
- else if ((currTime - mStartTime) >= mMinHoldTime)
- {
- //holy crap, we have, fire off our hold function
- mDidHold = true;
- argv[0] = mConsoleFunctionHeld;
- argv[1] = Con::getFloatArg(mEventValue);
- Con::execute(2, argv);
- }
- //otherwise we haven't yet, so keep our active status
- return;
- }
- //hmm, apparently not, so see if we tapped the key instead
- else
- {
- if (!mHoldOnly && !mDidHold)
- {
- //yes, we tapped and we care, so fire off the tap function.
- argv[0] = mButton->consoleFunction;
- argv[1] = Con::getFloatArg(mEventValue);
- Con::execute(2, argv);
- }
- //otherwise we don't care and we're done, so reset everything
- mActive = false;
- mStartTime = 0;
- mBreakEvent = false;
- mDidHold = false;
- }
- }
- }
- //------------------------------------------------------------------------------
- // Console interop version.
- static ConsoleDocFragment _ActionMapbind1(
- "@brief Associates a function to an input event.\n\n"
- "When the input event is raised, the specified function will be called.\n\n"
- "@param device The input device, such as mouse or keyboard.\n"
- "@param action The input event, such as space, button0, etc.\n"
- "@param command The function to bind to the action. Function must have a single boolean argument.\n"
- "@return True if the binding was successful, false if the device was unknown or description failed.\n\n"
- "@tsexample\n"
- "// Simple function that prints to console\n"
- "// %val - Sent by the device letting the user know\n"
- "// if an input was pressed (true) or released (false)\n"
- "function testInput(%val)\n"
- "{\n"
- " if(%val)\n"
- " echo(\"Key is down\");\n"
- " else\n"
- " echo(\"Key was released\");\n"
- "}\n\n"
- "// Bind the \'K\' key to the testInput function\n"
- "moveMap.bind(keyboard, k, testInput);\n\n"
- "@endtsexample\n\n\n",
- "ActionMap",
- "bool bind( string device, string action, string command );");
- static ConsoleDocFragment _ActionMapbind2(
- "@brief Associates a function and input parameters to an input event.\n\n"
- "When the input event is raised, the specified function will be called. Modifier flags may be specified to process "
- "dead zones, input inversion, and more.\n\n"
- "Valid modifier flags:\n\n"
- " - R - Input is Ranged.\n"
- " - S - Input is Scaled.\n"
- " - I - Input is inverted.\n"
- " - D - Dead zone is present.\n"
- " - N - Input should be re-fit to a non-linear scale.\n\n"
- "@param device The input device, such as mouse or keyboard.\n"
- "@param action The input event, such as space, button0, etc.\n"
- "@param flag Modifier flag assigned during binding, letting event know there are additional parameters to consider. \n"
- "@param deadZone Restricted region in which device motion will not be acknowledged.\n"
- "@param scale Modifies the deadZone region.\n"
- "@param command The function bound to the action. Must take in a single argument.\n"
- "@return True if the binding was successful, false if the device was unknown or description failed.\n\n"
- "@tsexample\n"
- "// Simple function that adjusts the pitch of the camera based on the "
- "mouse's movement along the X axis.\n"
- "function testPitch(%val)\n"
- "{\n"
- " %pitchAdj = getMouseAdjustAmount(%val);\n"
- " $mvPitch += %pitchAdj;\n"
- "}\n\n"
- "// Bind the mouse's X axis to the testPitch function\n"
- "// DI is flagged, meaning input is inverted and has a deadzone\n"
- "%this.bind( mouse, \"xaxis\", \"DI\", \"-0.23 0.23\", testPitch );\n"
- "@endtsexample\n\n\n",
- "ActionMap",
- "bool bind( string device, string action, string flag, string deadZone, string scale, string command );");
- DefineEngineStringlyVariadicMethod( ActionMap, bind, bool, 5, 10, "actionMap.bind( device, action, [modifier, spec, mod...], command )"
- "@hide")
- {
- ConsoleValueToStringArrayWrapper args(argc - 2, argv + 2);
- return object->processBind( args.count(), args, NULL );
- }
- static ConsoleDocFragment _ActionMapbindObj1(
- "@brief Associates a function to an input event for a specified class or object.\n\n"
- "You must specify a device, the action to bind, a function, and an object to be called when the event happens. "
- "The function specified must be set to receive a single boolean value passed.\n\n"
- "@param device The input device, such as mouse or keyboard.\n"
- "@param action The input event, such as space, button0, etc.\n"
- "@param command The function bound to the action.\n"
- "@param object The object or class bound to the action.\n"
- "@return True if the binding was successful, false if the device was unknown or description failed.\n\n"
- "@tsexample\n"
- "moveMap.bindObj(keyboard, \"numpad1\", \"rangeChange\", %player);"
- "@endtsexample\n\n",
- "ActionMap",
- "bool bindObj( string device, string action, string command, SimObjectID object );");
- static ConsoleDocFragment _ActionMapbindObj2(
- "@brief Associates a function to an input event for a specified class or object.\n\n"
- "You must specify a device, the action to bind, a function, and an object to be called when the event happens. "
- "The function specified must be set to receive a single boolean value passed. Modifier flags may be specified to process "
- "dead zones, input inversion, and more.\n\n"
- "Valid modifier flags:\n\n"
- " - R - Input is Ranged.\n"
- " - S - Input is Scaled.\n"
- " - I - Input is inverted.\n"
- " - D - Dead zone is present.\n"
- " - N - Input should be re-fit to a non-linear scale.\n\n"
- "@param device The input device, such as mouse or keyboard.\n"
- "@param action The input event, such as space, button0, etc.\n"
- "@param flag Modifier flag assigned during binding, letting event know there are additional parameters to consider.\n"
- "@param deadZone [Required only when flag is set] Restricted region in which device motion will not be acknowledged.\n"
- "@param scale [Required only when flag is set] Modifies the deadZone region.\n"
- "@param command The function bound to the action.\n"
- "@param object The object or class bound to the action.\n"
- "@return True if the binding was successful, false if the device was unknown or description failed.\n\n"
- "@tsexample\n"
- "// Bind the mouse's movement along the x-axis to the testInput function of the Player class\n"
- "// DSI is flagged, meaning input is inverted, has scale and has a deadzone\n"
- "%this.bindObj( mouse, \"xaxis\", \"DSI\", %deadZone, %scale, \"testInput\", %player );\n"
- "@endtsexample\n\n\n",
- "ActionMap",
- "bool bindObj( string device, string action, string flag, string deadZone, string scale, string command, SimObjectID object );");
- DefineEngineStringlyVariadicMethod( ActionMap, bindObj, bool, 6, 11, "(device, action, [modifier, spec, mod...], command, object)"
- "@hide")
- {
- SimObject* simObject = Sim::findObject(argv[argc - 1]);
- if ( simObject == NULL )
- {
- Con::warnf("ActionMap::bindObj() - Cannot bind, specified object was not found!");
- return false;
- }
- ConsoleValueToStringArrayWrapper args(argc - 3, argv + 2);
- return object->processBind( args.count(), args, simObject );
- }
- //------------------------------------------------------------------------------
- DefineEngineMethod( ActionMap, bindCmd, bool, ( const char* device, const char* action, const char* makeCmd, const char* breakCmd ), ( "" ),
- "@brief Associates a make command and optional break command to a specified input device action.\n\n"
- "Must include parenthesis and semicolon in the make and break command strings.\n\n"
- "@param device The device to bind to. Can be a keyboard, mouse, joystick or gamepad.\n"
- "@param action The device action to bind to. The action is dependant upon the device. Specify a key for keyboards.\n"
- "@param makeCmd The command to execute when the device/action is made.\n"
- "@param breakCmd [optional] The command to execute when the device or action is unmade.\n"
- "@return True the bind was successful, false if the device was unknown or description failed.\n"
- "@tsexample\n"
- "// Print to the console when the spacebar is pressed\n"
- "function onSpaceDown()\n"
- "{\n"
- " echo(\"Space bar down!\");\n"
- "}\n\n"
- "// Print to the console when the spacebar is released\n"
- "function onSpaceUp()\n"
- "{\n"
- " echo(\"Space bar up!\");\n"
- "}\n\n"
- "// Bind the commands onSpaceDown() and onSpaceUp() to spacebar events\n\n"
- "moveMap.bindCmd(keyboard, \"space\", \"onSpaceDown();\", \"onSpaceUp();\");\n"
- "@endtsexample\n\n")
- {
- return object->processBindCmd( device, action, makeCmd, breakCmd );
- }
- DefineEngineMethod(ActionMap, bindContext, void, (const char* device, const char* action, const char* holdFunction, const char* tapFunction, U32 holdTime),
- ("", "", "", "", 0), "actionMap.bindCmd( device, action, holdFunction, tapFunction, holdTime)")
- {
- object->processHoldBind(device, action, holdFunction, tapFunction, holdTime, false);
- }
- DefineEngineMethod(ActionMap, bindHold, void, (const char* device, const char* action, const char* holdFunction, bool returnHoldTime),
- ("", "", "", false), "actionMap.bindCmd( device, action, holdFunction, returnHoldTime)")
- {
- object->processHoldBind(device, action, holdFunction, "", 0, true, returnHoldTime);
- }
- DefineEngineMethod( ActionMap, unbind, bool, ( const char* device, const char* action ),,
- "@brief Removes the binding on an input device and action.\n"
- "@param device The device to unbind from. Can be a keyboard, mouse, joystick or a gamepad.\n"
- "@param action The device action to unbind from. The action is dependant upon the device. Specify a key for keyboards.\n"
- "@return True if the unbind was successful, false if the device was unknown or description failed.\n\n"
- "@tsexample\n"
- "moveMap.unbind(\"keyboard\", \"space\");\n"
- "@endtsexample\n\n")
- {
- return object->processUnbind( device, action );
- }
- DefineEngineMethod( ActionMap, unbindObj, bool, ( const char* device, const char* action, const char* obj ),,
- "@brief Remove any object-binding on an input device and action.\n"
- "@param device The device to bind to. Can be keyboard, mouse, joystick or gamepad.\n"
- "@param action The device action to unbind from. The action is dependant upon the device. Specify a key for keyboards.\n"
- "@param obj The object to perform unbind against.\n"
- "@return True if the unbind was successful, false if the device was unknown or description failed.\n"
- "@tsexample\n"
- "moveMap.unbindObj(\"keyboard\", \"numpad1\", \"rangeChange\", %player);"
- "@endtsexample\n\n\n")
- {
- SimObject* simObject = Sim::findObject(obj);
- if ( simObject == NULL )
- {
- Con::warnf("ActionMap::unbindObj() - Cannot unbind, specified object was not found!");
- return false;
- }
- return object->processUnbind( device, action, simObject );
- }
- DefineEngineMethod( ActionMap, save, void, ( const char* fileName, bool append ), ( nullAsType<const char*>(), false ),
- "@brief Saves the ActionMap to a file or dumps it to the console.\n\n"
- "@param fileName The file path to save the ActionMap to. If a filename is not specified "
- " the ActionMap will be dumped to the console.\n"
- "@param append Whether to write the ActionMap at the end of the file or overwrite it.\n"
- "@tsexample\n"
- "// Write out the actionmap into the config." TORQUE_SCRIPT_EXTENSION " file\n"
- "moveMap.save( \"scripts/client/config." TORQUE_SCRIPT_EXTENSION "\" );"
- "@endtsexample\n\n")
- {
- char buffer[1024];
- if(fileName)
- {
- if(Con::expandScriptFilename(buffer, sizeof(buffer), fileName))
- fileName = buffer;
- }
- object->dumpActionMap( fileName, append );
- }
- DefineEngineFunction( getCurrentActionMap, ActionMap*, (),,
- "@brief Returns the current %ActionMap.\n"
- "@see ActionMap"
- "@ingroup Input")
- {
- SimSet* pActionMapSet = Sim::getActiveActionMapSet();
- return dynamic_cast< ActionMap* >( pActionMapSet->last() );
- }
- DefineEngineMethod( ActionMap, push, void, (),,
- "@brief Push the ActionMap onto the %ActionMap stack.\n\n"
- "Activates an ActionMap and placees it at the top of the ActionMap stack.\n\n"
- "@tsexample\n"
- "// Make moveMap the active action map\n"
- "moveMap.push();\n"
- "@endtsexample\n\n"
- "@see ActionMap")
- {
- SimSet* pActionMapSet = Sim::getActiveActionMapSet();
- pActionMapSet->pushObject( object );
- }
- DefineEngineMethod( ActionMap, pop, void, (),,
- "@brief Pop the ActionMap off the %ActionMap stack.\n\n"
- "Deactivates an %ActionMap and removes it from the @ActionMap stack.\n"
- "@tsexample\n"
- "// Deactivate moveMap\n"
- "moveMap.pop();\n"
- "@endtsexample\n\n"
- "@see ActionMap")
- {
- SimSet* pActionMapSet = Sim::getActiveActionMapSet();
- pActionMapSet->removeObject( object );
- }
- DefineEngineMethod( ActionMap, getBinding, const char*, ( const char* command ),,
- "@brief Gets the ActionMap binding for the specified command.\n\n"
- "Use getField() on the return value to get the device and action of the binding.\n"
- "@param command The function to search bindings for.\n"
- "@return The binding against the specified command. Returns an empty string(\"\") "
- "if a binding wasn't found.\n"
- "@tsexample\n"
- "// Find what the function \"jump()\" is bound to in moveMap\n"
- "%bind = moveMap.getBinding( \"jump\" );\n\n"
- "if ( %bind !$= \"\" )\n"
- "{\n"
- "// Find out what device is used in the binding\n"
- " %device = getField( %bind, 0 );\n\n"
- "// Find out what action (such as a key) is used in the binding\n"
- " %action = getField( %bind, 1 );\n"
- "}\n"
- "@endtsexample\n\n"
- "@see getField")
- {
- return object->getBinding( command );
- }
- DefineEngineMethod( ActionMap, getCommand, const char*, ( const char* device, const char* action ),,
- "@brief Gets ActionMap command for the device and action.\n\n"
- "@param device The device that was bound. Can be a keyboard, mouse, joystick or a gamepad.\n"
- "@param action The device action that was bound. The action is dependant upon the device. Specify a key for keyboards.\n"
- "@return The command against the specified device and action.\n"
- "@tsexample\n"
- "// Find what function is bound to a device\'s action\n"
- "// In this example, \"jump()\" was assigned to the space key in another script\n"
- "%command = moveMap.getCommand(\"keyboard\", \"space\");\n\n"
- "// Should print \"jump\" in the console\n"
- "echo(%command)\n"
- "@endtsexample\n\n")
- {
- return object->getCommand( device, action );
- }
- DefineEngineMethod( ActionMap, isInverted, bool, ( const char* device, const char* action ),,
- "@brief Determines if the specified device and action is inverted.\n\n"
- "Should only be used for scrolling devices or gamepad/joystick axes."
- "@param device The device that was bound. Can be a keyboard, mouse, joystick or a gamepad.\n"
- "@param action The device action that was bound. The action is dependant upon the device. Specify a key for keyboards.\n"
- "@return True if the specified device and action is inverted.\n"
- "@tsexample\n"
- "%if ( moveMap.isInverted( \"mouse\", \"xaxis\"))\n"
- " echo(\"Mouse's xAxis is inverted\");"
- "@endtsexample\n\n")
- {
- return object->isInverted( device, action );
- }
- DefineEngineMethod( ActionMap, getScale, F32, ( const char* device, const char* action ),,
- "@brief Get any scaling on the specified device and action.\n\n"
- "@param device The device that was bound. Can be keyboard, mouse, joystick or gamepad.\n"
- "@param action The device action that was bound. The action is dependant upon the device. Specify a key for keyboards.\n"
- "@return Any scaling applied to the specified device and action.\n"
- "@tsexample\n"
- "%scale = %moveMap.getScale( \"gamepad\", \"thumbrx\");\n"
- "@endtsexample\n\n")
- {
- return object->getScale( device, action );
- }
- DefineEngineMethod( ActionMap, getDeadZone, const char*, ( const char* device, const char* action ),,
- "@brief Gets the Dead zone for the specified device and action.\n\n"
- "@param device The device that was bound. Can be a keyboard, mouse, joystick or a gamepad.\n"
- "@param action The device action that was bound. The action is dependant upon the device. Specify a key for keyboards.\n"
- "@return The dead zone for the specified device and action. Returns \"0 0\" if there is no dead zone "
- "or an empty string(\"\") if the mapping was not found.\n"
- "@tsexample\n"
- "%deadZone = moveMap.getDeadZone( \"gamepad\", \"thumbrx\");\n"
- "@endtsexample\n\n")
- {
- return object->getDeadZone( device, action );
- }
- //------------------------------------------------------------------------------
- AsciiMapping gAsciiMap[] =
- {
- //--- KEYBOARD EVENTS
- //
- { "space", 0x0020 },
- //{ "exclamation", 0x0021 },
- { "doublequote", 0x0022 },
- //{ "pound", 0x0023 },
- //{ "ampersand", 0x0026 },
- { "apostrophe", 0x0027 },
- //{ "lparen", 0x0028 },
- //{ "rparen", 0x0029 },
- { "comma", 0x002c },
- { "minus", 0x002d },
- { "period", 0x002e },
- //{ "slash", 0x002f },
- //{ "colon", 0x003a },
- //{ "semicolon", 0x003b },
- //{ "lessthan", 0x003c },
- //{ "equals", 0x003d },
- //{ "morethan", 0x003e },
- //{ "lbracket", 0x005b },
- { "backslash", 0x005c },
- //{ "rbracket", 0x005d },
- //{ "circumflex", 0x005e },
- //{ "underscore", 0x005f },
- { "grave", 0x0060 },
- //{ "tilde", 0x007e },
- //{ "vertbar", 0x007c },
- //{ "exclamdown", 0x00a1 },
- //{ "cent", 0x00a2 },
- //{ "sterling", 0x00a3 },
- //{ "currency", 0x00a4 },
- //{ "brokenbar", 0x00a6 },
- //{ "ring", 0x00b0 },
- //{ "plusminus", 0x00b1 },
- { "super2", 0x00b2 },
- { "super3", 0x00b3 },
- { "acute", 0x00b4 },
- //{ "mu", 0x00b5 },
- //{ "ordmasculine", 0x00ba },
- //{ "questiondown", 0x00bf },
- //{ "gemandbls", 0x00df },
- //{ "agrave", 0x00e0 },
- //{ "aacute", 0x00e1 },
- //{ "acircumflex", 0x00e2 },
- //{ "atilde", 0x00e3 },
- //{ "adieresis", 0x00e4 },
- //{ "aring", 0x00e5 },
- //{ "ae", 0x00e6 },
- //{ "ccedille", 0x00e7 },
- //{ "egrave", 0x00e8 },
- //{ "eacute", 0x00e9 },
- //{ "ecircumflex", 0x00ea },
- //{ "edieresis", 0x00eb },
- //{ "igrave", 0x00ec },
- //{ "iacute", 0x00ed },
- //{ "icircumflex", 0x00ee },
- //{ "idieresis", 0x00ef },
- //{ "ntilde", 0x00f1 },
- //{ "ograve", 0x00f2 },
- //{ "oacute", 0x00f3 },
- //{ "ocircumflex", 0x00f4 },
- //{ "otilde", 0x00f5 },
- //{ "odieresis", 0x00f6 },
- //{ "divide", 0x00f7 },
- //{ "oslash", 0x00f8 },
- //{ "ugrave", 0x00f9 },
- //{ "uacute", 0x00fa },
- //{ "ucircumflex", 0x00fb },
- //{ "udieresis", 0x00fc },
- //{ "ygrave", 0x00fd },
- //{ "thorn", 0x00fe },
- //{ "ydieresis", 0x00ff },
- { "nomatch", 0xFFFF }
- };
|