src/ui/uInput.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 *************************************************************************
00004 
00005 ArmageTron -- Just another Tron Lightcycle Game in 3D.
00006 Copyright (C) 2000  Manuel Moos (manuel@moosnet.de)
00007 
00008 **************************************************************************
00009 
00010 This program is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 as published by the Free Software Foundation; either version 2
00013 of the License, or (at your option) any later version.
00014 
00015 This program is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00023 
00024 ***************************************************************************
00025 
00026 */
00027 
00028 #include <stdarg.h>
00029 #include "uInput.h"
00030 #include "tMemManager.h"
00031 #include "rScreen.h"
00032 #include "tInitExit.h"
00033 #include "tConfiguration.h"
00034 #include "rConsole.h"
00035 #include "uMenu.h"
00036 #include "tSysTime.h"
00037 
00038 #include <vector>
00039 #include <map>
00040 
00041 bool su_mouseGrab = false;
00042 
00043 static uAction* su_allActions[uMAX_ACTIONS];
00044 static int     su_allActionsLen = 0;
00045 
00046 uAction::uAction(uAction *&anchor,const char* name,
00047                  int priority_,
00048                  uInputType t)
00049         :tListItem<uAction>(anchor),type(t),priority(priority_),internalName(name){
00050     globalID = localID = su_allActionsLen++;
00051 
00052     tASSERT(localID < uMAX_ACTIONS);
00053 
00054     su_allActions[localID] = this;
00055 
00056     tString descname;
00057     descname << "input_" << name << "_text";
00058     tToLower( descname );
00059 
00060     const_cast<tOutput&>(description).AddLocale(descname);
00061 
00062     tString helpname;
00063     helpname << "input_" << name << "_help";
00064     tToLower( helpname );
00065 
00066     const_cast<tOutput&>(helpText).AddLocale(helpname);
00067 }
00068 
00069 uAction::uAction(uAction *&anchor,const char* name,
00070                  const tOutput& desc,
00071                  const tOutput& help,
00072                  int priority_,
00073                  uInputType t)
00074         :tListItem<uAction>(anchor),type(t),priority(priority_),internalName(name), description(desc), helpText(help){
00075     globalID = localID = su_allActionsLen++;
00076 
00077     tASSERT(localID < uMAX_ACTIONS);
00078 
00079     su_allActions[localID] = this;
00080 }
00081 
00082 uAction::~uAction(){
00083     su_allActions[localID] = NULL;
00084 }
00085 
00086 uAction * uAction::Find( char const * name )
00087 {
00088     for (int i=su_allActionsLen-1;i>=0;i--)
00089         if (!strcmp(name,su_allActions[i]->internalName))
00090             return su_allActions[i];
00091 
00092     return 0;
00093 }
00094 
00095 // ****************************************
00096 // uInput
00097 // ****************************************
00098 
00099 typedef std::vector< uInput * > uInputs;
00100 uInputs su_inputs;
00101 std::map< std::string, uInput * > su_inputMap;
00102 
00103 uInput::uInput( tString const & persistentID, tString const & name )
00104         : persistentID_( persistentID ), name_( name )
00105         , pressed_( 0 )
00106 {
00107     ID_ = su_inputs.size();
00108     su_inputs.push_back( this );
00109     su_inputMap[ persistentID ] = this;
00110 }
00111 
00112 uInput::~uInput()
00113 {
00114     su_inputs[ID_] = 0;
00115     // su_inputMap.erase( su_inputMap.find( persistentID_ ) );
00116 }
00117 
00118 static uInput * su_GetInput( tString const & persistentID )
00119 {
00120     try
00121     {
00122         return su_inputMap[ persistentID ];
00123     }
00124     catch (...)
00125     {
00126         return NULL;
00127     }
00128 }
00129 
00130 // class that manages unknown input
00131 class uAutoDeleteInput
00132 {
00133 public:
00134     uAutoDeleteInput()
00135     {
00136     }
00137 
00138     ~uAutoDeleteInput()
00139     {
00140         for ( uInputs::iterator iter = unknowns.begin(); iter != unknowns.end(); ++iter )
00141         {
00142             delete(*iter);
00143             *iter = 0;
00144         }
00145     }
00146 
00147     uInput * Create( tString const & persistentID, tString const & name )
00148     {
00149         uInput * input = new uInput( persistentID, name );
00150         unknowns.push_back( input );
00151         return input;
00152     }
00153 
00154     // array of unknown inputs that should be deleted afterwards
00155     uInputs unknowns;
00156 };
00157 
00158 static uAutoDeleteInput & su_GetAutoDeleteInput()
00159 {
00160     static uAutoDeleteInput filler;
00161     return filler;
00162 }
00163 
00164 static uInput * su_NewInput( tString const & ID, tString const & name )
00165 {
00166     return su_GetAutoDeleteInput().Create( ID, name );
00167 }
00168 
00169 static uInput * su_NewInput( char const * ID, char const * name )
00170 {
00171     return su_GetAutoDeleteInput().Create( tString( ID ), tString( name ) );
00172 }
00173 
00174 // class that manages keyboard input
00175 class uKeyInput
00176 {
00177 public:
00178     uKeyInput()
00179     {
00180         for ( int i = 0; i <= SDLK_LAST; ++i )
00181         {
00182 #ifndef DEDICATED
00183             char const * ID_Raw = SDL_GetKeyName(static_cast< SDLKey >( i ) );
00184 #else
00185             char const * ID_Raw = "unknown key";
00186 #endif
00187             std::ostringstream id;
00188             id << "KEY_";
00189             if ( strcmp( ID_Raw, "unknown key" ) == 0 )
00190             {
00191                 id << "UNKNONW_" << i;
00192             }
00193             else
00194             {
00195                 for ( char const * c = ID_Raw; *c; ++c )
00196                 {
00197                     if ( isblank( *c ) )
00198                     {
00199                         id << "_";
00200                     }
00201                     else
00202                     {
00203                         id << char(toupper( *c ));
00204                     }
00205                 }
00206             }
00207 
00208             // store new input key
00209             sdl_keys[i] = su_NewInput( id.str(), tString(ID_Raw) );
00210 
00211             tASSERT( sdl_keys[i]->ID() == i );
00212         }
00213     }
00214 
00215     ~uKeyInput()
00216     {
00217     }
00218 
00219     uInput * sdl_keys[SDLK_LAST+1];
00220 };
00221 
00222 static uKeyInput const & su_GetKeyInput()
00223 {
00224     static uKeyInput filler;
00225     return filler;
00226 }
00227 
00228 # define MOUSE_BUTTONS 7
00229 
00230 // class that manages mouse inout
00231 class uMouseInput
00232 {
00233 public:
00234     uMouseInput()
00235     {
00236         x_plus = su_NewInput( "MOUSE_X_PLUS", "mouse right" );
00237         x_minus = su_NewInput( "MOUSE_X_MINUS", "mouse left" );
00238         y_plus = su_NewInput( "MOUSE_Y_PLUS", "mouse up" );
00239         y_minus = su_NewInput( "MOUSE_Y_MINUS", "mouse down" );
00240         z_plus = su_NewInput( "MOUSE_Z_PLUS", "mouse z up" );
00241         z_minus = su_NewInput( "MOUSE_Z_MINUS", "mouse z down" );
00242 
00243         for ( int i = 0; i < MOUSE_BUTTONS; ++i )
00244         {
00245             std::ostringstream id;
00246             id << "MOUSE_BUTTON_" << i+1;
00247             std::ostringstream name;
00248             name << "mouse button " << i+1;
00249             button[i] = su_NewInput( id.str(), name.str() );
00250         }
00251     }
00252 
00253     uInput * x_plus;
00254     uInput * x_minus;
00255     uInput * y_plus;
00256     uInput * y_minus;
00257     uInput * z_plus;
00258     uInput * z_minus;
00259     uInput * button[MOUSE_BUTTONS];
00260 };
00261 
00262 static uMouseInput const & su_GetMouseInput()
00263 {
00264     static uMouseInput filler;
00265     return filler;
00266 }
00267 
00268 void su_KeyInit()
00269 {
00270     su_GetKeyInput();
00271     su_GetMouseInput();
00272 }
00273 
00274 // ****************************************
00275 // a configuration class for keyboard binds
00276 // ****************************************
00277 
00278 class tConfItem_key:public tConfItemBase{
00279 public:
00280     tConfItem_key():tConfItemBase("KEYBOARD"){}
00281     ~tConfItem_key(){};
00282 
00283     // write the complete keymap
00284     virtual void WriteVal(std::ostream &s){
00285         int first=1;
00286         for ( uInputs::const_iterator i = su_inputs.begin(); i != su_inputs.end(); ++i )
00287         {
00288             if ( !(*i)->GetBind() )
00289                 continue;
00290 
00291             std::string const & id = (*i)->PersistentID();
00292 
00293             if (!first)
00294                 s << "\nKEYBOARD\t";
00295             else
00296                 first=0;
00297 
00298             s << id << '\t';
00299             (*i)->GetBind()->Write(s);
00300         }
00301         if (first)
00302             s << "-1";
00303     }
00304 
00305     // read one keybind
00306     virtual void ReadVal(std::istream &s)
00307     {
00308         tString in;
00309         std::string id;
00310         s >> id;
00311         if ( id != "-1" )
00312         {
00313             // try to fetch the uInput belonging to the id
00314             uInput * input = su_GetInput( id );
00315 
00316             if ( !input )
00317             {
00318                 // if the id is a number, the setting is in a legacy format.
00319                 std::istringstream readValue( id );
00320                 int value = -1;
00321                 readValue >> value;
00322 
00323                 if ( value >= 0 && value < (int)su_inputs.size() )
00324                 {
00325                     input = su_inputs[ value ];
00326                 }
00327             }
00328 
00329             if ( !input )
00330             {
00331                 input = su_NewInput( id, tString("") );
00332             }
00333 
00334             tASSERT( input );
00335 
00336             s >> in;
00337             if (uBindPlayer::IsKeyWord(in))
00338             {
00339                 tJUST_CONTROLLED_PTR< uBind > bind = uBindPlayer::NewBind(s);
00340                 if ( bind->act )
00341                 {
00342                     input->SetBind( bind );
00343                 }
00344             }
00345         }
00346         char c=' ';
00347         while (c!='\n' && s.good() && !s.eof()) c=s.get();
00348     }
00349 };
00350 
00351 // we need just one
00352 static tConfItem_key x;
00353 
00354 static uAction *s_playerActions;
00355 static uAction *s_cameraActions;
00356 static uAction *s_globalActions;
00357 
00358 uActionPlayer::uActionPlayer(const char *name,
00359                              int priority,
00360                              uInputType t)
00361     :uAction(s_playerActions,name,priority,t){}
00362 
00363 uActionPlayer::uActionPlayer(const char *name,
00364                              const tOutput& desc,
00365                              const tOutput& help,
00366                              int priority,
00367                              uInputType t)
00368         :uAction(s_playerActions,name,desc,help,priority,t){}
00369 
00370 uActionPlayer::~uActionPlayer(){}
00371 
00372 bool uActionPlayer::operator==(const uActionPlayer &x){
00373     return x.globalID == globalID;
00374 }
00375 
00376 uActionPlayer *uActionPlayer::Find(int id){
00377     uAction *run = s_playerActions;
00378 
00379     while (run){
00380         if (run->ID() == id)
00381             return static_cast<uActionPlayer*>(run);
00382     }
00383 
00384     return NULL;
00385 }
00386 
00387 
00388 uActionCamera::uActionCamera(const char *name,
00389                              int priority,
00390                              uInputType t)
00391     :uAction(s_cameraActions,name,priority,t){}
00392 
00393 uActionCamera::~uActionCamera(){}
00394 
00395 bool uActionCamera::operator==(const uActionCamera &x){
00396     return x.globalID == globalID;
00397 }
00398 
00399 
00400 // global actions
00401 uActionGlobal::uActionGlobal(const char *name,
00402                              int priority,
00403                              uInputType t)
00404         :uAction(s_globalActions,name,priority,t){}
00405 
00406 uActionGlobal::~uActionGlobal(){}
00407 
00408 bool uActionGlobal::operator==(const uActionGlobal &x){
00409     return x.globalID == globalID;
00410 }
00411 
00412 bool uActionGlobal::IsBreakingGlobalBind(int sym){
00413     if ( sym >= (int)su_inputs.size() || sym < 0 )
00414         return false;
00415 
00416     uInput * input = su_inputs[ sym ];
00417     if ( !input )
00418         return false;
00419 
00420     uBind * bind = input->GetBind();
00421     if ( !bind )
00422         return false;
00423 
00424     uAction *act = bind->act;
00425     if (!act)
00426         return false;
00427 
00428     return uActionGlobalFunc::IsBreakingGlobalBind(act);
00429 }
00430 
00431 static void keyboard_init()
00432 {
00433 }
00434 
00435 static void keyboard_exit()
00436 {
00437 }
00438 
00439 #ifndef NOJOYSTICK
00440 
00441 #ifndef DEDICATED
00442 class uJoystick
00443 {
00444 public:
00445     int id;
00446 
00447     // joystick name
00448     tString name, internalName;
00449 
00450     // number of compotents
00451     int numAxes, numButtons, numBalls, numHats;
00452 
00453     enum Direction
00454     {
00455         Left = 0,
00456         Right = 1,
00457         Up = 2,
00458         Down = 3
00459     };
00460 
00461     uJoystick( int id_ ): id( id_ )
00462     {
00463         tASSERT( id >= 0 && id < SDL_NumJoysticks() );
00464 
00465         name = SDL_JoystickName( id );
00466 
00467         std::ostringstream iName;
00468         iName << "JOYSTICK_";
00469         for ( char const * c = name.c_str(); *c; ++c )
00470         {
00471             if ( isblank( *c ) )
00472             {
00473                 iName << "_";
00474             }
00475             else
00476             {
00477                 iName << char(toupper( *c ));
00478             }
00479         }
00480 
00481         internalName = iName.str();
00482 
00483         SDL_Joystick * stick = SDL_JoystickOpen( id );
00484         numAxes = SDL_JoystickNumAxes( stick );
00485         numButtons = SDL_JoystickNumButtons( stick );
00486         numBalls = SDL_JoystickNumBalls( stick );
00487         numHats = SDL_JoystickNumHats( stick );
00488 
00489         // populate input types
00490         if ( numAxes >= 1 )
00491         {
00492             axes[0].push_back( su_NewInput( GetPersistentID( "AXIS", 0, "-" ), GetName( "left" ) ) );
00493             axes[1].push_back( su_NewInput( GetPersistentID( "AXIS", 0, "+" ), GetName( "right" ) ) );
00494         }
00495 
00496         if ( numAxes >= 2 )
00497         {
00498             axes[0].push_back( su_NewInput( GetPersistentID( "AXIS", 1, "-" ), GetName( "up" ) ) );
00499             axes[1].push_back( su_NewInput( GetPersistentID( "AXIS", 1, "+" ), GetName( "down" ) ) );
00500         }
00501 
00502         for ( int axis = 2; axis < numAxes; ++axis )
00503         {
00504             axes[0].push_back( su_NewInput( GetPersistentID( "AXIS", axis, "-" ), GetName( "axis", axis, "-" ) ) );
00505             axes[1].push_back( su_NewInput( GetPersistentID( "AXIS", axis, "+" ), GetName( "axis", axis, "+" ) ) );
00506         }
00507 
00508         for ( int button = 0; button < numButtons; ++button )
00509         {
00510             buttons.push_back( su_NewInput( GetPersistentID( "BUTTON", button ), GetName( "button", button ) ) );
00511         }
00512 
00513         char const * directionInternal[] = { "LEFT", "RIGHT", "UP", "DOWN" };
00514         char const * directionHuman[] = { "left", "right", "up", "down" };
00515 
00516         for ( int dir = 0; dir < 4; ++dir )
00517         {
00518             char const * internal = directionInternal[dir];
00519             char const * human = directionHuman[dir];
00520 
00521             for ( int ball = 0; ball < numBalls; ++ball )
00522             {
00523                 balls[dir].push_back( su_NewInput( GetPersistentID( "BALL", ball, internal ), GetName( "ball", ball, human ) ) );
00524             }
00525 
00526             for ( int hat = 0; hat < numHats; ++hat )
00527             {
00528                 hats[dir].push_back( su_NewInput( GetPersistentID( "HAT", hat, internal ), GetName( "hat", hat, human ) ) );
00529             }
00530         }
00531 
00532         hatDirection.resize( numHats );
00533     }
00534 
00535     uInput * GetAxis( int index, int dir )
00536     {
00537         tASSERT( index >= 0 && index < numAxes );
00538         tASSERT( 0 == dir || 1 == dir );
00539 
00540         axes[1-dir][index]->SetPressed(0);
00541         return axes[dir][index];
00542     }
00543 
00544     uInput * GetButton( int index )
00545     {
00546         tASSERT( index >= 0 && index < numButtons );
00547 
00548         return buttons[index];
00549     }
00550 
00551     uInput * GetBall( int index, Direction dir )
00552     {
00553         tASSERT( index >= 0 && index < numBalls );
00554 
00555         balls[dir ^ 1][index]->SetPressed(0);
00556         return balls[dir][index];
00557     }
00558 
00559     uInput * GetHat( int index, Direction dir )
00560     {
00561         tASSERT( index >= 0 && index < numHats );
00562 
00563         hats[dir ^ 1][index]->SetPressed(0);
00564         return hats[dir][index];
00565     }
00566 
00567     int & GetHatDirection( int index, int axis )
00568     {
00569         tASSERT( index >= 0 && index < numHats );
00570         tASSERT( 0 == axis || 1 == axis );
00571 
00572         return hatDirection[index].dir[axis];
00573     }
00574 private:
00575     // various input arrays
00576     uInputs axes[2], buttons, balls[4], hats[4];
00577 
00578     struct HatDirections
00579     {
00580         int dir[2];
00581         HatDirections(){
00582             dir[0] = dir[1] = 0;
00583         }
00584     };
00585 
00586     std::vector< HatDirections > hatDirection;
00587 
00588     // returns an uInput unique name
00589     tString GetPersistentID( char const * type, int subID, char const * suffix = NULL ) const
00590     {
00591         std::ostringstream o;
00592         o << internalName << "_" << type << "_" << subID;
00593         if ( suffix )
00594         {
00595             o << "_" << suffix;
00596         }
00597         return o.str();
00598     }
00599 
00600     // same for the public name
00601     tString GetName( char const * type, int subID, char const * suffix = NULL ) const
00602     {
00603         std::ostringstream o;
00604         o << "Joystick " << id+1 << " " << type << " " << subID+1;
00605         if ( suffix )
00606         {
00607             o << " " << suffix;
00608         }
00609         return o.str();
00610     }
00611 
00612     // special axes: x and y
00613     tString GetName( char const * type ) const
00614     {
00615         std::ostringstream o;
00616         o << "Joystick " << id+1 << " " << type;
00617         return o.str();
00618     }
00619 };
00620 
00621 // class that manages joysticks
00622 class uJoystickInput
00623 {
00624 public:
00625     uJoystickInput()
00626     {
00627         // create joysticks
00628         int numJoysticks = SDL_NumJoysticks();
00629         for ( int i = 0; i < numJoysticks; ++i )
00630         {
00631             joysticks.push_back( new uJoystick( i ) );
00632         }
00633     }
00634 
00635     ~uJoystickInput()
00636     {
00637         // delete joysticks
00638         for ( std::vector< uJoystick * >::iterator iter = joysticks.begin(); iter != joysticks.end(); ++iter )
00639         {
00640             delete(*iter);
00641             *iter = 0;
00642         }
00643     }
00644 
00645     // array of joysticks
00646     std::vector< uJoystick * > joysticks;
00647 };
00648 
00649 static uJoystickInput & su_GetJoystickInput()
00650 {
00651     static uJoystickInput filler;
00652     return filler;
00653 }
00654 
00655 static uJoystick * su_GetJoystick( int id )
00656 {
00657     uJoystickInput & joysticks = su_GetJoystickInput();
00658     tASSERT( id >= 0 && id < (int)joysticks.joysticks.size() );
00659 
00660     return joysticks.joysticks[id];
00661 }
00662 
00663 void su_JoystickInit()
00664 {
00665     su_GetJoystickInput();
00666     SDL_JoystickEventState( SDL_ENABLE );
00667 }
00668 #endif
00669 #endif
00670 
00671 static tInitExit keyboard_ie(&keyboard_init, &keyboard_exit);
00672 
00673 // *********************************************
00674 // generic keypress/mouse movement binding class
00675 // *********************************************
00676 
00677 uBind::~uBind(){}
00678 
00679 uBind::uBind(uAction *a ):lastValue_(0), delayedValue_(0), lastInput_(0), lastTime_(-1), act(a){}
00680 
00681 uBind::uBind(std::istream &s): lastValue_(0), delayedValue_(0), lastInput_(0), lastTime_(-1), act(NULL)
00682 {
00683     std::string name;
00684     s >> name;
00685     act = uAction::Find( name.c_str() );
00686 }
00687 
00688 void uBind::Write(std::ostream &s){
00689     s << act->internalName << '\t';
00690 }
00691 
00692 bool GlobalAct(uAction *act,REAL x){
00693     return uActionGlobalFunc::GlobalAct(act,x);
00694 }
00695 
00696 bool uBind::Activate(REAL x, bool delayed )
00697 {
00698     delayedValue_ = x;
00699 
00700     if ( !delayed || !Delayable() )
00701     {
00702         lastValue_ = x;
00703         return this->DoActivate( x );
00704     }
00705 
00706     return true;
00707 }
00708 
00709 void uBind::HanldeDelayed()
00710 {
00711     if ( lastValue_ != delayedValue_ )
00712     {
00713         lastValue_ = delayedValue_;
00714         this->DoActivate( delayedValue_ );
00715     }
00716 }
00717 
00718 REAL su_doubleBindTimeout=-10.0f;
00719 
00720 bool uBind::IsDoubleBind( uInput const * input )
00721 {
00722     double currentTime = tSysTimeFloat();
00723 
00724     // if a different key was used for this action a short while ago, give alarm.
00725     bool ret = ( su_doubleBindTimeout > 0 && input != lastInput_ && currentTime - lastTime_ < su_doubleBindTimeout );
00726 
00727     // store last usage
00728     lastInput_ = input;
00729     lastTime_ = currentTime;
00730 
00731     // return result
00732     return ret;
00733 }
00734 
00735 // *******************
00736 // player config
00737 // *******************
00738 
00739 static int nextid = 0;
00740 
00741 uPlayerPrototype* uPlayerPrototype::PlayerConfig(int i){
00742     tASSERT(i>=0 && i<uMAX_PLAYERS);
00743     return playerConfig[i];
00744 }
00745 
00746 
00747 uPlayerPrototype::uPlayerPrototype(){
00748     static bool inited=false;
00749     if (!inited)
00750     {
00751         for (int i=uMAX_PLAYERS-1; i >=0; i--)
00752             playerConfig[i] = NULL;
00753 
00754         inited = true;
00755     }
00756 
00757     id = nextid++;
00758     tASSERT(id < uMAX_PLAYERS);
00759     playerConfig[id] = this;
00760 
00761 
00762 }
00763 
00764 uPlayerPrototype::~uPlayerPrototype(){
00765     playerConfig[id] = NULL;
00766 }
00767 
00768 uPlayerPrototype* uPlayerPrototype::playerConfig[uMAX_PLAYERS];
00769 
00770 int uPlayerPrototype::Num(){
00771     return nextid;
00772 }
00773 
00774 // *******************
00775 // Input configuration
00776 // *******************
00777 
00778 REAL mouse_sensitivity=REAL(.1);
00779 
00780 // number of transformed events per SDL event
00781 #define su_TRANSFORM_PASSES 2
00782 
00783 struct uTransformEventInfo
00784 {
00785     uInput * input;   // the input event type received
00786     float value;      // the strenght of the event
00787     bool needsRepeat; // if the event should trigger a continuous action (camera movement), should it be repeated?
00788 
00789     uTransformEventInfo(): input(0), value(0), needsRepeat(false){}
00790     uTransformEventInfo( uInput * input_, float value_ = 1 , bool needsRepeat_ = true ): input(input_), value(value_), needsRepeat(needsRepeat_){}
00791 };
00792 
00793 // transform SDL event into vector of abstract events
00794 #ifndef DEDICATED
00795 static void su_TransformEvent( SDL_Event & e, std::vector< uTransformEventInfo > & info )
00796 {
00797     switch (e.type)
00798     {
00799     case SDL_MOUSEMOTION:
00800         {
00801             // ignore events generated by mouse grabbing
00802             if ( su_mouseGrab &&
00803                     e.motion.x==sr_screenWidth/2 && e.motion.x==sr_screenHeight/2)
00804             {
00805                 return;
00806             }
00807 
00808             // we generate up to four events per mouse movement
00809             info.reserve(4);
00810 
00811             REAL xrel=e.motion.xrel;
00812             if (xrel > 0) // right
00813             {
00814                 info.push_back( uTransformEventInfo(
00815                                     su_GetMouseInput().x_minus,
00816                                     0,
00817                                     false ) );
00818                 info.push_back( uTransformEventInfo(
00819                                     su_GetMouseInput().x_plus,
00820                                     xrel * mouse_sensitivity,
00821                                     false ) );
00822             }
00823 
00824             if (xrel < 0) // left
00825             {
00826                 info.push_back( uTransformEventInfo(
00827                                     su_GetMouseInput().x_plus,
00828                                     0,
00829                                     false ) );
00830                 info.push_back( uTransformEventInfo(
00831                                     su_GetMouseInput().x_minus,
00832                                     -xrel * mouse_sensitivity,
00833                                     false ) );
00834             }
00835 
00836             // invert mouse movement
00837             REAL yrel=-e.motion.yrel;
00838             if (yrel>0) // up
00839             {
00840                 info.push_back( uTransformEventInfo(
00841                                     su_GetMouseInput().y_minus,
00842                                     0,
00843                                     false ) );
00844                 info.push_back( uTransformEventInfo(
00845                                     su_GetMouseInput().y_plus,
00846                                     yrel * mouse_sensitivity,
00847                                     false ) );
00848             }
00849             if (yrel<0) // down
00850             {
00851                 info.push_back( uTransformEventInfo(
00852                                     su_GetMouseInput().y_plus,
00853                                     0,
00854                                     false ) );
00855                 info.push_back( uTransformEventInfo(
00856                                     su_GetMouseInput().y_minus,
00857                                     -yrel * mouse_sensitivity,
00858                                     false ) );
00859             }
00860         }
00861         break;
00862     case SDL_MOUSEBUTTONDOWN:
00863     case SDL_MOUSEBUTTONUP:
00864         {
00865             int button=e.button.button;
00866             if (button<=MOUSE_BUTTONS)
00867             {
00868                 info.push_back( uTransformEventInfo(
00869                                     su_GetMouseInput().button[ button ],
00870                                     ( e.type == SDL_MOUSEBUTTONDOWN ) ? 1 : 0 ) );
00871             }
00872         }
00873         break;
00874     case SDL_KEYDOWN:
00875     case SDL_KEYUP:
00876         {
00877             SDL_keysym &c = e.key.keysym;
00878 
00879             info.push_back( uTransformEventInfo(
00880                                 su_GetKeyInput().sdl_keys[ c.sym ],
00881                                 ( e.type == SDL_KEYDOWN ) ? 1 : 0 ) );
00882 
00883             break;
00884         }
00885 #ifndef NOJOYSTICK
00886     case SDL_JOYAXISMOTION:
00887         {
00888             uJoystick * joystick = su_GetJoystick( e.jaxis.which );
00889             int dir = e.jaxis.value > 0 ? 1 : 0;
00890 
00891             info.push_back( uTransformEventInfo(
00892                                 joystick->GetAxis( e.jaxis.axis, 1-dir ),
00893                                 0 ) );
00894             info.push_back( uTransformEventInfo(
00895                                 joystick->GetAxis( e.jaxis.axis, dir ),
00896                                 fabs( e.jaxis.value )/32768 ) );
00897 
00898             break;
00899         }
00900     case SDL_JOYBUTTONDOWN:
00901     case SDL_JOYBUTTONUP:
00902         info.push_back( uTransformEventInfo(
00903                             su_GetJoystick( e.jbutton.which )->GetButton( e.jbutton.button ),
00904                             ( e.type == SDL_JOYBUTTONDOWN ) ? 1 : 0 ) );
00905         break;
00906     case SDL_JOYHATMOTION:
00907         {
00908             info.reserve(4);
00909 
00910             uJoystick * joystick = su_GetJoystick( e.jhat.which );
00911             int hat = e.jhat.hat;
00912             int hatDirection = e.jhat.value;
00913 
00914             // left/right hat motion
00915             {
00916                 int & lastDir = joystick->GetHatDirection( hat, 0 );
00917                 int newDir =
00918                     ( ( hatDirection & SDL_HAT_LEFT ) ? -1 : 0 ) +
00919                     ( ( hatDirection & SDL_HAT_RIGHT ) ? +1 : 0 );
00920 
00921                 // negate previous events
00922                 if ( lastDir < 0 && newDir >= 0 )
00923                 {
00924                     info.push_back( uTransformEventInfo(
00925                                         joystick->GetHat( hat, uJoystick::Left ),
00926                                         0 ) );
00927                 }
00928 
00929                 if ( lastDir > 0 && newDir <= 0 )
00930                 {
00931                     info.push_back( uTransformEventInfo(
00932                                         joystick->GetHat( hat, uJoystick::Right ),
00933                                         0 ) );
00934                 }
00935 
00936                 // create new events
00937                 if ( lastDir >= 0 && newDir < 0 )
00938                 {
00939                     info.push_back( uTransformEventInfo(
00940                                         joystick->GetHat( hat, uJoystick::Left ),
00941                                         1 ) );
00942                 }
00943 
00944                 if ( lastDir <= 0 && newDir > 0 )
00945                 {
00946                     info.push_back( uTransformEventInfo(
00947                                         joystick->GetHat( hat, uJoystick::Right ),
00948                                         1 ) );
00949                 }
00950 
00951                 lastDir = newDir;
00952             }
00953 
00954             // up/down hat motion
00955             {
00956                 int & lastDir = joystick->GetHatDirection( hat, 1 );
00957                 int newDir =
00958                     ( ( hatDirection & SDL_HAT_UP ) ? -1 : 0 ) +
00959                     ( ( hatDirection & SDL_HAT_DOWN ) ? +1 : 0 );
00960 
00961                 // negate previous events
00962                 if ( lastDir < 0 && newDir >= 0 )
00963                 {
00964                     info.push_back( uTransformEventInfo(
00965                                         joystick->GetHat( hat, uJoystick::Up ),
00966                                         0 ) );
00967                 }
00968 
00969                 if ( lastDir > 0 && newDir <= 0 )
00970                 {
00971                     info.push_back( uTransformEventInfo(
00972                                         joystick->GetHat( hat, uJoystick::Down ),
00973                                         0 ) );
00974                 }
00975 
00976                 // create new events
00977                 if ( lastDir >= 0 && newDir < 0 )
00978                 {
00979                     info.push_back( uTransformEventInfo(
00980                                         joystick->GetHat( hat, uJoystick::Up ),
00981                                         1 ) );
00982                 }
00983 
00984                 if ( lastDir <= 0 && newDir > 0 )
00985                 {
00986                     info.push_back( uTransformEventInfo(
00987                                         joystick->GetHat( hat, uJoystick::Down ),
00988                                         1 ) );
00989                 }
00990 
00991                 lastDir = newDir;
00992             }
00993         }
00994         break;
00995     case SDL_JOYBALLMOTION:
00996         {
00997             info.reserve(4);
00998 
00999             uJoystick * joystick = su_GetJoystick( e.jball.which );
01000             int ball = e.jball.ball;
01001 
01002             REAL xrel=e.jball.xrel;
01003             if (xrel > 0) // right
01004             {
01005                 info.push_back( uTransformEventInfo(
01006                                     joystick->GetBall( ball, uJoystick::Left ),
01007                                     0,
01008                                     false ) );
01009                 info.push_back( uTransformEventInfo(
01010                                     joystick->GetBall( ball, uJoystick::Right ),
01011                                     xrel,
01012                                     false ) );
01013             }
01014 
01015             if (xrel < 0) // left
01016             {
01017                 info.push_back( uTransformEventInfo(
01018                                     joystick->GetBall( ball, uJoystick::Right ),
01019                                     0,
01020                                     false ) );
01021                 info.push_back( uTransformEventInfo(
01022                                     joystick->GetBall( ball, uJoystick::Left ),
01023                                     -xrel,
01024                                     false ) );
01025             }
01026 
01027             // invert ball movement
01028             REAL yrel=-e.jball.yrel;
01029             if (yrel>0) // up
01030             {
01031                 info.push_back( uTransformEventInfo(
01032                                     joystick->GetBall( ball, uJoystick::Down ),
01033                                     0,
01034                                     false ) );
01035                 info.push_back( uTransformEventInfo(
01036                                     joystick->GetBall( ball, uJoystick::Up ),
01037                                     yrel,
01038                                     false ) );
01039             }
01040             if (yrel<0) // down
01041             {
01042                 info.push_back( uTransformEventInfo(
01043                                     joystick->GetBall( ball, uJoystick::Up ),
01044                                     0,
01045                                     false ) );
01046                 info.push_back( uTransformEventInfo(
01047                                     joystick->GetBall( ball, uJoystick::Down ),
01048                                     -yrel,
01049                                     false ) );
01050             }
01051         }
01052         break;
01053 #endif
01054     default:
01055         break;
01056     }
01057 }
01058 #endif // DEDICATED
01059 
01060 // *****************************************************
01061 //  Menuitem for input selection
01062 // *****************************************************
01063 
01064 class uMenuItemInput: uMenuItem{
01065     uAction      *act;
01066     int         ePlayer;
01067     bool        active;
01068 public:
01069     uMenuItemInput(uMenu *M,uAction *a,int p)
01070             :uMenuItem(M,a->helpText),act(a),ePlayer(p),active(0){
01071     }
01072 
01073     virtual ~uMenuItemInput(){}
01074 
01075     virtual void Render(REAL x,REAL y,REAL alpha=1,bool selected=0)
01076     {
01077         DisplayText(REAL(x-.02),y,act->description,selected,alpha,1);
01078 
01079         if (active)
01080         {
01081             tString s;
01082             s << tOutput("$input_press_any_key");
01083             DisplayText(REAL(x+.02),y,s,selected,alpha,-1);
01084         }
01085         else
01086         {
01087             tString s;
01088 
01089             bool first=1;
01090 
01091             for ( uInputs::const_iterator i = su_inputs.begin(); i != su_inputs.end(); ++i )
01092             {
01093                 uBind * bind = (*i)->GetBind();
01094                 if ( bind && (*i)->Name().size() > 0 &&
01095                         bind->act==act &&
01096                         bind->CheckPlayer(ePlayer) )
01097                 {
01098                     if (!first)
01099                         s << ", ";
01100                     else
01101                         first=0;
01102 
01103                     s << (*i)->Name();
01104                 }
01105             }
01106             if (!first)
01107             {
01108                 DisplayText(REAL(x+.02),y,s,selected,alpha,-1);
01109             }
01110             else
01111             {
01112                 DisplayText(REAL(x+.02),y,tOutput("$input_items_unbound"),selected,alpha,-1);
01113             }
01114         }
01115     }
01116 
01117     virtual void Enter()
01118     {
01119         active=1;
01120     }
01121 
01122 #define MTHRESH 5
01123 #define MREL    2
01124 
01125 #ifndef DEDICATED
01126 
01127     virtual bool Event(SDL_Event &e){
01128         if ( e.type == SDL_KEYDOWN )
01129         {
01130             SDL_keysym &c = e.key.keysym;
01131             if (!active)
01132             {
01133                 if (c.sym==SDLK_DELETE || c.sym==SDLK_BACKSPACE)
01134                 {
01135                     // clear all bindings
01136                     for ( uInputs::const_iterator i = su_inputs.begin(); i != su_inputs.end(); ++i )
01137                     {
01138                         uBind * bind = (*i)->GetBind();
01139                         if ( bind &&
01140                                 bind->act==act &&
01141                                 bind->CheckPlayer(ePlayer) )
01142                         {
01143                             (*i)->SetBind( NULL );
01144                         }
01145                     }
01146                     return true;
01147                 }
01148                 return false;
01149             }
01150 
01151             // ignore escape
01152             if ( c.sym == SDLK_ESCAPE )
01153             {
01154                 return false;
01155             }
01156         }
01157 
01158         // transform events
01159         std::vector< uTransformEventInfo > events;
01160         su_TransformEvent( e, events );
01161 
01162         for ( std::vector< uTransformEventInfo >::const_iterator i = events.begin(); i != events.end(); ++i )
01163         {
01164             uTransformEventInfo const & info = *i;
01165             if ( info.input && info.value > 0.5 && active )
01166             {
01167                 uBind * bind = info.input->GetBind();
01168                 if ( bind &&
01169                         bind->act==act &&
01170                         bind->CheckPlayer(ePlayer))
01171                 {
01172                     info.input->SetBind( NULL );
01173                 }
01174                 else
01175                 {
01176                     info.input->SetBind( uBindPlayer::NewBind(act,ePlayer) );
01177                 }
01178 
01179                 active = false;
01180                 return true;
01181             }
01182         }
01183 
01184         return false;
01185     }
01186 #endif
01187 
01188     virtual tString Help(){
01189         tString ret;
01190         ret << helpText << "\n";
01191         ret << tOutput("$input_item_help");
01192         return ret;
01193     }
01194 };
01195 
01196 namespace
01197 {
01198 class Input_Comparator
01199 {
01200 public:
01201     static int Compare( const uAction* a, const uAction* b )
01202     {
01203         if ( a->priority < b->priority )
01204             return 1;
01205         else if ( a->priority > b->priority )
01206             return -1;
01207         return tString::CompareAlphaNumerical( a->internalName, b->internalName );
01208     }
01209 };
01210 }
01211 
01212 static int Input_Compare( const tListItemBase* a, const tListItemBase* b)
01213 
01214 {
01215     return Input_Comparator::Compare( (const uAction*)a, (const uAction*)b );
01216 }
01217 
01218 
01219 static void s_InputConfigGeneric(int ePlayer, uAction *&actions,const tOutput &title){
01220     uMenuItemInput **input;
01221 
01222     uMenu input_menu(title);
01223 
01224     actions->tListItemBase::Sort(&Input_Compare);
01225 
01226     int len = actions->Len();
01227 
01228     input=tNEW(uMenuItemInput*)[len];
01229     int a=0;
01230     for (uAction *A=actions;A; A = A->Next()){
01231         input[a++]=new uMenuItemInput(&input_menu,
01232                                       A,
01233                                       ePlayer+1);
01234 
01235     }
01236 
01237     input_menu.ReverseItems();
01238     input_menu.Enter();
01239 
01240     for (int b=a-1;b>=0;b--)
01241         delete input[b];
01242     delete[] input;
01243 }
01244 
01245 void su_InputConfig(int ePlayer){
01246 
01247     tOutput name;
01248     name.SetTemplateParameter(1, ePlayer+1);
01249     name.SetTemplateParameter(2, uPlayerPrototype::PlayerConfig(ePlayer)->Name());
01250     name << "$input_for_player";
01251 
01252     s_InputConfigGeneric(ePlayer,s_playerActions,name);
01253 }
01254 
01255 void su_InputConfigCamera(int player){
01256 
01257     tOutput name;
01258     name.SetTemplateParameter(1, uPlayerPrototype::PlayerConfig(player)->Name());
01259     name << "$camera_controls";
01260 
01261     s_InputConfigGeneric(player,s_cameraActions,name);
01262 }
01263 
01264 void su_InputConfigGlobal(){
01265     s_InputConfigGeneric(-1,s_globalActions,"$input_items_global");
01266 }
01267 
01268 
01269 REAL key_sensitivity=40;
01270 static double lastTime=0;
01271 static REAL ts=0;
01272 
01273 static bool su_delayed = false;
01274 
01275 void su_HandleDelayedEvents ()
01276 {
01277     // nothing to do
01278     if ( !su_delayed )
01279     {
01280         return;
01281     }
01282 
01283     su_delayed = false;
01284 
01285     for ( uInputs::const_iterator i = su_inputs.begin(); i != su_inputs.end(); ++i )
01286     {
01287         uBind * bind = (*i)->GetBind();
01288         if ( bind )
01289         {
01290             bind->HanldeDelayed();
01291         }
01292     }
01293 }
01294 
01295 bool su_HandleEvent(SDL_Event &e, bool delayed ){
01296 #ifndef DEDICATED
01297     if ( su_delayed && !delayed )
01298     {
01299         su_HandleDelayedEvents();
01300     }
01301 
01302     su_delayed = delayed;
01303 
01304     // transform events
01305     bool ret = false;
01306 
01307     std::vector< uTransformEventInfo > events;
01308     su_TransformEvent( e, events );
01309 
01310     for ( std::vector< uTransformEventInfo >::const_iterator i = events.begin(); i != events.end(); ++i )
01311     {
01312         uTransformEventInfo info = *i;
01313 
01314         if ( info.input )
01315         {
01316             // store input state for later repeat
01317             if ( info.needsRepeat )
01318             {
01319                 info.input->SetPressed( info.value > 0 ? info.value : 0 );
01320             }
01321 
01322             // activate binding
01323             uBind * bind = info.input->GetBind();
01324             if ( bind )
01325             {
01326                 if ( bind->IsDoubleBind( info.input ) )
01327                 {
01328                     return true;
01329                 }
01330 
01331                 if ( info.needsRepeat && bind->act && bind->act->type == uAction::uINPUT_ANALOG )
01332                 {
01333                     info.value *= ts*key_sensitivity;
01334                 }
01335 
01336                 ret |= bind->Activate( info.value, delayed );
01337             }
01338         }
01339     }
01340 
01341     return ret;
01342 #endif
01343     return false;
01344 }
01345 
01346 void su_InputSync(){
01347     double time=tSysTimeFloat();
01348     ts=REAL(time-lastTime);
01349 
01350     //static REAL tsSmooth=0;
01351     //tsSmooth+=REAL(ts*.1);
01352     //tsSmooth/=REAL(1.1);
01353     lastTime=time;
01354 
01355     // key repeat
01356     for ( uInputs::const_iterator i = su_inputs.begin(); i != su_inputs.end(); ++i )
01357     {
01358         uInput * input = *i;
01359         uBind * bind = input->GetBind();
01360         if ( input->GetPressed() > 0 && bind &&
01361                 bind->act && bind->act->type == uAction::uINPUT_ANALOG )
01362         {
01363             bind->Activate( ts * key_sensitivity * input->GetPressed(), su_delayed );
01364         }
01365     }
01366 }
01367 
01368 void su_ClearKeys()
01369 {
01370     // clears stored keypresses
01371     for ( uInputs::const_iterator i = su_inputs.begin(); i != su_inputs.end(); ++i )
01372     {
01373         uInput * input = *i;
01374         uBind * bind = input->GetBind();
01375         if ( input->GetPressed() > 0 && bind )
01376         {
01377             bind->Activate( -1, su_delayed );
01378             input->SetPressed( 0 );
01379         }
01380     }
01381 }
01382 
01383 // *****************
01384 // Player binds
01385 // *****************
01386 
01387 static char const * Player_keyword="PLAYER_BIND";
01388 
01389 uBindPlayer::uBindPlayer(uAction *a,int p):uBind(a),ePlayer(p){}
01390 
01391 uBindPlayer::~uBindPlayer(){}
01392 
01393 uBindPlayer * uBindPlayer::NewBind(std::istream &s)
01394 {
01395     // read action
01396     std::string actionName;
01397     s >> actionName;
01398     uAction * act = uAction::Find( actionName.c_str() );
01399 
01400     // read player ID
01401     int player;
01402     s >> player;
01403 
01404     // delegate
01405     return NewBind( act, player );
01406 }
01407 
01408 uBindPlayer * uBindPlayer::NewBind( uAction * action, int player )
01409 {
01410     // see if the bind has an alias
01411     for ( uInputs::const_iterator i = su_inputs.begin(); i != su_inputs.end(); ++i )
01412     {
01413         uInput * input = *i;
01414         uBind * old = input->GetBind();
01415 
01416         // compare action
01417         if ( old && old->act == action )
01418         {
01419             uBindPlayer * oldPlayer = dynamic_cast< uBindPlayer * >( old );
01420             if ( oldPlayer && oldPlayer->ePlayer == player )
01421                 return oldPlayer;
01422         }
01423     }
01424 
01425     // no alias found, return new bind
01426     return tNEW(uBindPlayer)( action, player );
01427 }
01428 
01429 bool uBindPlayer::IsKeyWord(const char *n){
01430     return !strcmp(n,Player_keyword);
01431 }
01432 
01433 bool uBindPlayer::CheckPlayer(int p){
01434     return p==ePlayer;
01435 }
01436 
01437 void uBindPlayer::Write(std::ostream &s){
01438     s << Player_keyword << '\t';
01439     uBind::Write(s);
01440     s << ePlayer;
01441 }
01442 
01443 bool uBindPlayer::Delayable()
01444 {
01445     return ( ePlayer!=0 );
01446 }
01447 
01448 bool uBindPlayer::DoActivate(REAL x){
01449     if (ePlayer==0)
01450         return  GlobalAct(act,x);
01451     else
01452         return uPlayerPrototype::PlayerConfig(ePlayer-1)->Act(act,x);
01453 }
01454 
01455 
01456 // *****************
01457 // Global actions
01458 // *****************
01459 
01460 static uActionGlobalFunc *uActionGlobal_anchor=NULL;
01461 
01462 uActionGlobalFunc::uActionGlobalFunc(uActionGlobal *a, ACTION_FUNC *f,
01463                                      bool rebind )
01464         :tListItem<uActionGlobalFunc>(uActionGlobal_anchor), func (f), act(a),
01465 rebindable(rebind){}
01466 
01467 bool uActionGlobalFunc::IsBreakingGlobalBind(uAction *act){
01468     for (uActionGlobalFunc *run = uActionGlobal_anchor; run ; run = run->Next())
01469         if (run->act == act && !run->rebindable)
01470             return true;
01471 
01472     return false;
01473 }
01474 
01475 bool uActionGlobalFunc::GlobalAct(uAction *act, REAL x){
01476     for (uActionGlobalFunc *run = uActionGlobal_anchor; run ; run = run->Next())
01477         if (run->act == act && run->func(x))
01478             return true;
01479 
01480     return false;
01481 }
01482 
01483 static uActionGlobal mess_up("MESS_UP");
01484 
01485 static uActionGlobal mess_down("MESS_DOWN");
01486 
01487 static bool messup_func(REAL x){
01488     if (x>0){
01489         sr_con.Scroll(-1);
01490     }
01491     return true;
01492 }
01493 
01494 static bool messdown_func(REAL x){
01495     if (x>0){
01496         sr_con.Scroll(1);
01497     }
01498     return true;
01499 }
01500 
01501 static uActionGlobalFunc mu(&mess_up,&messup_func);
01502 static uActionGlobalFunc md(&mess_down,&messdown_func);

Generated on Sat Mar 15 22:56:13 2008 for Armagetron Advanced by  doxygen 1.5.4