00001 /* 00002 * Copyright (C) 2003-2009 Olivier Boudeville 00003 * 00004 * This file is part of the OSDL library. 00005 * 00006 * The OSDL library is free software: you can redistribute it and/or modify 00007 * it under the terms of either the GNU Lesser General Public License or 00008 * the GNU General Public License, as they are published by the Free Software 00009 * Foundation, either version 3 of these Licenses, or (at your option) 00010 * any later version. 00011 * 00012 * The OSDL library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU Lesser General Public License and the GNU General Public License 00016 * for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License and of the GNU General Public License along with the OSDL library. 00020 * If not, see <http://www.gnu.org/licenses/>. 00021 * 00022 * Author: Olivier Boudeville (olivier.boudeville@esperide.com) 00023 * 00024 */ 00025 00026 00027 #include "OSDLJoystickHandler.h" 00028 00029 #include "OSDLJoystick.h" // for Joystick 00030 #include "OSDLClassicalJoystick.h" // for ClassicalJoystick 00031 #include "OSDLController.h" // for axisChanged 00032 00033 #include "OSDLUtils.h" // for getBackendLastError 00034 #include "OSDLBasic.h" // for CommonModule 00035 00036 00037 #include "Ceylan.h" // for Ceylan logs 00038 00039 00040 00041 using std::string ; 00042 using std::list ; 00043 00044 using namespace Ceylan::Log ; 00045 00046 using namespace OSDL::Events ; 00047 00048 00049 00050 const string DebugPrefix = " " ; 00051 00052 00053 00054 #ifdef OSDL_USES_CONFIG_H 00055 #include <OSDLConfig.h> // for OSDL_VERBOSE_JOYSTICK_HANDLER and al 00056 #endif // OSDL_USES_CONFIG_H 00057 00058 00059 #if OSDL_ARCH_NINTENDO_DS 00060 #include "OSDLConfigForNintendoDS.h" // for OSDL_USES_SDL and al 00061 #endif // OSDL_ARCH_NINTENDO_DS 00062 00063 00064 00065 #if OSDL_USES_SDL 00066 00067 #include "SDL.h" // for SDL_JoystickEventState, etc. 00068 00069 #endif // OSDL_USES_SDL 00070 00071 00072 00073 #if OSDL_VERBOSE_JOYSTICK_HANDLER 00074 00075 #include <iostream> 00076 #define OSDL_JOYSTICK_HANDLER_LOG( message ) std::cout << "[OSDL Joystick Handler] " << message << std::endl ; 00077 00078 #else // OSDL_VERBOSE_JOYSTICK_HANDLER 00079 00080 #define OSDL_JOYSTICK_HANDLER_LOG( message ) 00081 00082 #endif // OSDL_VERBOSE_JOYSTICK_HANDLER 00083 00084 00085 00086 00087 00088 JoystickHandler::JoystickHandler( bool useClassicalJoysticks ) : 00089 InputDeviceHandler(), 00090 _joystickCount( 0 ), 00091 _joysticks( 0 ), 00092 _useClassicalJoysticks( useClassicalJoysticks ) 00093 { 00094 00095 #if OSDL_USES_SDL 00096 00097 send( "Initializing joystick subsystem." ) ; 00098 00099 if ( SDL_InitSubSystem( CommonModule::UseVideo ) 00100 != CommonModule::BackendSuccess ) 00101 throw JoystickException( "JoystickHandler constructor: " 00102 "unable to initialize joystick subsystem: " 00103 + Utils::getBackendLastError() ) ; 00104 00105 // We want joystick changes to be translated into events: 00106 SDL_JoystickEventState( SDL_ENABLE ) ; 00107 00108 update() ; 00109 00110 send( "Joystick subsystem initialized." ) ; 00111 00112 dropIdentifier() ; 00113 00114 #else // OSDL_USES_SDL 00115 00116 throw InputDeviceHandlerException( "JoystickHandler constructor failed:" 00117 "no SDL support available" ) ; 00118 00119 #endif // OSDL_USES_SDL 00120 00121 } 00122 00123 00124 00125 JoystickHandler::~JoystickHandler() throw() 00126 { 00127 00128 #if OSDL_USES_SDL 00129 00130 send( "Stopping joystick subsystem." ) ; 00131 00132 // Joysticks instances are owned by the handler: 00133 blank() ; 00134 00135 SDL_QuitSubSystem( CommonModule::UseJoystick ) ; 00136 00137 send( "Joystick subsystem stopped." ) ; 00138 00139 #endif // OSDL_USES_SDL 00140 00141 } 00142 00143 00144 00145 void JoystickHandler::update() 00146 { 00147 00148 /* 00149 * Joystick instances have to be deleted so that the 00150 * _useClassicalJoysticks value is taken into account 00151 * (it might have changed since last call). 00152 * 00153 */ 00154 blank() ; 00155 00156 00157 // Here the joystick array must be created. 00158 _joystickCount = GetAvailableJoystickCount() ; 00159 00160 send( Ceylan::toString( _joystickCount ) + " joystick(s) auto-detected." ) ; 00161 00162 /* 00163 * This array, faster than a list, will contain _joystickCount pointers 00164 * to Joystick instances: 00165 * 00166 */ 00167 _joysticks = new Joystick *[ _joystickCount ] ; 00168 00169 for ( JoystickNumber i = 0; i < _joystickCount; i++ ) 00170 if ( _useClassicalJoysticks ) 00171 _joysticks[i] = new ClassicalJoystick( i ) ; 00172 else 00173 _joysticks[i] = new Joystick( i ) ; 00174 00175 } 00176 00177 00178 00179 void JoystickHandler::openJoystick( JoystickNumber index ) 00180 { 00181 00182 /* 00183 * Beware, joystick list might be out of synch, test is not exactly 00184 * equivalent to _joystickCount. 00185 * 00186 */ 00187 if ( index >= GetAvailableJoystickCount() ) 00188 throw JoystickException( "JoystickHandler::openJoystick: index " 00189 + Ceylan::toString( index) + " out of bounds (" 00190 + Ceylan::toString( GetAvailableJoystickCount() ) 00191 + " joystick(s) attached)." ) ; 00192 00193 if ( index >= _joystickCount ) 00194 throw JoystickException( "JoystickHandler::openJoystick: index " 00195 + Ceylan::toString( index) + " out of bounds (" 00196 + Ceylan::toString( _joystickCount ) 00197 + " joystick(s) attached according to internal joystick list)." ) ; 00198 00199 #if OSDL_DEBUG 00200 if ( _joysticks[ index ] == 0 ) 00201 throw JoystickException( "JoystickHandler::openJoystick: " 00202 "no known joystick for index " + Ceylan::toString( index ) + "." ) ; 00203 #endif // OSDL_DEBUG 00204 00205 if ( ! _joysticks[ index ]->isOpen() ) 00206 _joysticks[ index ]->open() ; 00207 00208 } 00209 00210 00211 00212 void JoystickHandler::linkToController( JoystickNumber index, 00213 OSDL::MVC::Controller & controller ) 00214 { 00215 00216 /* 00217 * Beware, joystick list might be out of synch, test is not exactly 00218 * equivalent to _joystickCount. 00219 * 00220 */ 00221 if ( index >= static_cast<JoystickNumber>( GetAvailableJoystickCount() ) ) 00222 throw JoystickException( "JoystickHandler::linkToController: index " 00223 + Ceylan::toString( index) + " out of bounds (" 00224 + Ceylan::toString( GetAvailableJoystickCount() ) 00225 + " joystick(s) attached)." ) ; 00226 00227 if ( index >= _joystickCount ) 00228 throw JoystickException( "JoystickHandler::linkToController: index " 00229 + Ceylan::toString( index) + " out of bounds (" 00230 + Ceylan::toString( _joystickCount ) 00231 + " joystick(s) attached according to internal joystick list)." ) ; 00232 00233 #if OSDL_DEBUG 00234 if ( _joysticks[ index ] == 0 ) 00235 throw JoystickException( "JoystickHandler::linkToController: " 00236 "no known joystick for index " + Ceylan::toString( index ) + "." ) ; 00237 #endif // OSDL_DEBUG 00238 00239 _joysticks[ index ]->setController( controller ) ; 00240 00241 } 00242 00243 00244 00245 const string JoystickHandler::toString( Ceylan::VerbosityLevels level ) const 00246 { 00247 00248 string res ; 00249 00250 if ( _joystickCount > 0 ) 00251 res = "Joystick handler managing " 00252 + Ceylan::toString( _joystickCount ) + " joystick(s)" ; 00253 else 00254 return "Joystick handler does not manage any joystick" ; 00255 00256 if ( level == Ceylan::low ) 00257 return res ; 00258 00259 res += ". Listing detected joystick(s): " ; 00260 00261 list<string> joysticks ; 00262 00263 for ( JoystickNumber i = 0; i < _joystickCount; i++ ) 00264 if ( _joysticks[i] != 0 ) 00265 joysticks.push_back( _joysticks[i]->toString( level ) ) ; 00266 else 00267 joysticks.push_back( "no joystick at index " 00268 + Ceylan::toString( i ) + " (abnormal)" ) ; 00269 00270 return res + Ceylan::formatStringList( joysticks ) ; 00271 00272 } 00273 00274 00275 00276 JoystickNumber JoystickHandler::GetAvailableJoystickCount() 00277 { 00278 00279 #if OSDL_USES_SDL 00280 00281 return static_cast<JoystickNumber>( SDL_NumJoysticks() ) ; 00282 00283 #else // OSDL_USES_SDL 00284 00285 return 0 ; 00286 00287 #endif // OSDL_USES_SDL 00288 00289 } 00290 00291 00292 00293 00294 // Protected section. 00295 00296 00297 00298 void JoystickHandler::axisChanged( const JoystickAxisEvent & joystickEvent ) 00299 const 00300 { 00301 00302 #if OSDL_USES_SDL 00303 00304 #if OSDL_DEBUG 00305 checkJoystickAt( joystickEvent.which ) ; 00306 #endif // OSDL_DEBUG 00307 00308 _joysticks[ joystickEvent.which ]->axisChanged( joystickEvent ) ; 00309 00310 #endif // OSDL_USES_SDL 00311 00312 } 00313 00314 00315 00316 void JoystickHandler::trackballChanged( 00317 const JoystickTrackballEvent & joystickEvent ) const 00318 { 00319 00320 #if OSDL_USES_SDL 00321 00322 #if OSDL_DEBUG 00323 checkJoystickAt( joystickEvent.which ) ; 00324 #endif // OSDL_DEBUG 00325 00326 _joysticks[ joystickEvent.which ]->trackballChanged( joystickEvent ) ; 00327 00328 #endif // OSDL_USES_SDL 00329 00330 } 00331 00332 00333 00334 void JoystickHandler::hatChanged( const JoystickHatEvent & joystickEvent ) const 00335 { 00336 00337 #if OSDL_USES_SDL 00338 00339 #if OSDL_DEBUG 00340 checkJoystickAt( joystickEvent.which ) ; 00341 #endif // OSDL_DEBUG 00342 00343 _joysticks[ joystickEvent.which ]->hatChanged( joystickEvent ) ; 00344 00345 #endif // OSDL_USES_SDL 00346 00347 } 00348 00349 00350 00351 void JoystickHandler::buttonPressed( const JoystickButtonEvent & joystickEvent ) 00352 const 00353 { 00354 00355 #if OSDL_USES_SDL 00356 00357 #if OSDL_DEBUG 00358 checkJoystickAt( joystickEvent.which ) ; 00359 #endif // OSDL_DEBUG 00360 00361 _joysticks[ joystickEvent.which ]->buttonPressed( joystickEvent ) ; 00362 00363 #endif // OSDL_USES_SDL 00364 00365 } 00366 00367 00368 00369 void JoystickHandler::buttonReleased( 00370 const JoystickButtonEvent & joystickEvent ) const 00371 { 00372 00373 #if OSDL_USES_SDL 00374 00375 #if OSDL_DEBUG 00376 checkJoystickAt( joystickEvent.which ) ; 00377 #endif // OSDL_DEBUG 00378 00379 _joysticks[ joystickEvent.which ]->buttonReleased( joystickEvent ) ; 00380 00381 #endif // OSDL_USES_SDL 00382 00383 } 00384 00385 00386 00387 void JoystickHandler::blank() 00388 { 00389 00390 if ( _joysticks != 0 ) 00391 { 00392 00393 for ( JoystickNumber c = 0; c < _joystickCount; c++ ) 00394 { 00395 delete _joysticks[c] ; 00396 } 00397 00398 delete [] _joysticks ; 00399 _joysticks = 0 ; 00400 } 00401 00402 _joystickCount = 0 ; 00403 00404 } 00405 00406 00407 00408 void JoystickHandler::checkJoystickAt( JoystickNumber index ) const 00409 { 00410 00411 if ( index >= _joystickCount ) 00412 Ceylan::emergencyShutdown( 00413 "JoystickHandler::checkJoystickAt: index " 00414 + Ceylan::toNumericalString( index ) 00415 + " out of bounds (maximum value is " 00416 + Ceylan::toNumericalString( _joystickCount - 1 ) + ")." ) ; 00417 00418 if ( _joysticks[ index ] == 0 ) 00419 Ceylan::emergencyShutdown( "JoystickHandler::checkJoystickAt: " 00420 "no joystick intance at index " 00421 + Ceylan::toNumericalString( index ) + "." ) ; 00422 00423 if ( ! _joysticks[ index ]->isOpen() ) 00424 Ceylan::emergencyShutdown( 00425 "JoystickHandler::checkJoystickAt: joystick at index " 00426 + Ceylan::toNumericalString( index ) + " was not open." ) ; 00427 00428 } 00429