1 //////////////////////////////////////////////////////////////////////////////////////// 2 // 3 // Nestopia - NES/Famicom emulator written in C++ 4 // 5 // Copyright (C) 2003-2008 Martin Freij 6 // 7 // This file is part of Nestopia. 8 // 9 // Nestopia is free software; you can redistribute it and/or modify 10 // it under the terms of the GNU General Public License as published by 11 // the Free Software Foundation; either version 2 of the License, or 12 // (at your option) any later version. 13 // 14 // Nestopia is distributed in the hope that it will be useful, 15 // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 // GNU General Public License for more details. 18 // 19 // You should have received a copy of the GNU General Public License 20 // along with Nestopia; if not, write to the Free Software 21 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 // 23 //////////////////////////////////////////////////////////////////////////////////////// 24 25 #include <cstring> 26 #include <new> 27 #include <algorithm> 28 #include "../NstMachine.hpp" 29 #include "../NstCartridge.hpp" 30 #include "../input/NstInpDevice.hpp" 31 #include "../input/NstInpAdapter.hpp" 32 #include "../input/NstInpPad.hpp" 33 #include "../input/NstInpZapper.hpp" 34 #include "../input/NstInpPaddle.hpp" 35 #include "../input/NstInpPowerPad.hpp" 36 #include "../input/NstInpPowerGlove.hpp" 37 #include "../input/NstInpMouse.hpp" 38 #include "../input/NstInpFamilyTrainer.hpp" 39 #include "../input/NstInpFamilyKeyboard.hpp" 40 #include "../input/NstInpSuborKeyboard.hpp" 41 #include "../input/NstInpDoremikkoKeyboard.hpp" 42 #include "../input/NstInpHoriTrack.hpp" 43 #include "../input/NstInpPachinko.hpp" 44 #include "../input/NstInpOekaKidsTablet.hpp" 45 #include "../input/NstInpKonamiHyperShot.hpp" 46 #include "../input/NstInpBandaiHyperShot.hpp" 47 #include "../input/NstInpCrazyClimber.hpp" 48 #include "../input/NstInpMahjong.hpp" 49 #include "../input/NstInpExcitingBoxing.hpp" 50 #include "../input/NstInpTopRider.hpp" 51 #include "../input/NstInpPokkunMoguraa.hpp" 52 #include "../input/NstInpPartyTap.hpp" 53 #include "../input/NstInpRob.hpp" 54 #include "../input/NstInpTurboFile.hpp" 55 #include "../input/NstInpBarcodeWorld.hpp" 56 57 namespace Nes 58 { 59 #ifdef NST_MSVC_OPTIMIZE 60 #pragma optimize("s", on) 61 #endif 62 63 namespace Api 64 { 65 Input::ControllerCaller Input::controllerCallback; 66 Input::AdapterCaller Input::adapterCallback; 67 } 68 69 namespace Core 70 { 71 namespace Input 72 { 73 Controllers::PollCaller2< Controllers::Pad > Controllers::Pad::callback; 74 Controllers::PollCaller1< Controllers::Zapper > Controllers::Zapper::callback; 75 Controllers::PollCaller1< Controllers::Paddle > Controllers::Paddle::callback; 76 Controllers::PollCaller1< Controllers::PowerPad > Controllers::PowerPad::callback; 77 Controllers::PollCaller1< Controllers::PowerGlove > Controllers::PowerGlove::callback; 78 Controllers::PollCaller1< Controllers::Mouse > Controllers::Mouse::callback; 79 Controllers::PollCaller1< Controllers::FamilyTrainer > Controllers::FamilyTrainer::callback; 80 Controllers::PollCaller3< Controllers::FamilyKeyboard > Controllers::FamilyKeyboard::callback; 81 Controllers::PollCaller3< Controllers::SuborKeyboard > Controllers::SuborKeyboard::callback; 82 Controllers::PollCaller3< Controllers::DoremikkoKeyboard > Controllers::DoremikkoKeyboard::callback; 83 Controllers::PollCaller1< Controllers::HoriTrack > Controllers::HoriTrack::callback; 84 Controllers::PollCaller1< Controllers::Pachinko > Controllers::Pachinko::callback; 85 Controllers::PollCaller1< Controllers::VsSystem > Controllers::VsSystem::callback; 86 Controllers::PollCaller1< Controllers::OekaKidsTablet > Controllers::OekaKidsTablet::callback; 87 Controllers::PollCaller1< Controllers::KonamiHyperShot > Controllers::KonamiHyperShot::callback; 88 Controllers::PollCaller1< Controllers::BandaiHyperShot > Controllers::BandaiHyperShot::callback; 89 Controllers::PollCaller1< Controllers::CrazyClimber > Controllers::CrazyClimber::callback; 90 Controllers::PollCaller2< Controllers::Mahjong > Controllers::Mahjong::callback; 91 Controllers::PollCaller2< Controllers::ExcitingBoxing > Controllers::ExcitingBoxing::callback; 92 Controllers::PollCaller1< Controllers::TopRider > Controllers::TopRider::callback; 93 Controllers::PollCaller2< Controllers::PokkunMoguraa > Controllers::PokkunMoguraa::callback; 94 Controllers::PollCaller1< Controllers::PartyTap > Controllers::PartyTap::callback; 95 Controllers::PollCaller1< Controllers::KaraokeStudio > Controllers::KaraokeStudio::callback; 96 PowerPad()97 Controllers::PowerPad::PowerPad() throw() 98 { 99 std::fill( sideA, sideA + NUM_SIDE_A_BUTTONS, false ); 100 std::fill( sideB, sideB + NUM_SIDE_B_BUTTONS, false ); 101 } 102 PowerGlove()103 Controllers::PowerGlove::PowerGlove() throw() 104 { 105 x = 0; 106 y = 0; 107 distance = 0; 108 wrist = 0; 109 gesture = GESTURE_OPEN; 110 } 111 FamilyTrainer()112 Controllers::FamilyTrainer::FamilyTrainer() throw() 113 { 114 std::fill( sideA, sideA + NUM_SIDE_A_BUTTONS, false ); 115 std::fill( sideB, sideB + NUM_SIDE_B_BUTTONS, false ); 116 } 117 FamilyKeyboard()118 Controllers::FamilyKeyboard::FamilyKeyboard() throw() 119 { 120 std::memset( parts, 0x00, sizeof(parts) ); 121 } 122 SuborKeyboard()123 Controllers::SuborKeyboard::SuborKeyboard() throw() 124 { 125 std::memset( parts, 0x00, sizeof(parts) ); 126 } 127 Controllers()128 Controllers::Controllers() throw() 129 { 130 } 131 } 132 } 133 134 namespace Api 135 { ConnectController(const uint port,const Type type)136 Result Input::ConnectController(const uint port,const Type type) throw() 137 { 138 Core::Input::Device* old = NULL; 139 140 switch (port) 141 { 142 case PORT_1: 143 case PORT_2: 144 145 if (emulator.extPort->GetDevice( port ).GetType() == type) 146 { 147 return RESULT_NOP; 148 } 149 else switch (type) 150 { 151 case UNCONNECTED: 152 153 old = new (std::nothrow) Core::Input::Device( emulator.cpu ); 154 break; 155 156 case PAD1: 157 case PAD2: 158 case PAD3: 159 case PAD4: 160 161 old = new (std::nothrow) Core::Input::Pad( emulator.cpu, uint(type) - PAD1 ); 162 break; 163 164 case ZAPPER: 165 166 old = new (std::nothrow) Core::Input::Zapper( emulator.cpu, emulator.ppu ); 167 break; 168 169 case PADDLE: 170 171 old = new (std::nothrow) Core::Input::Paddle( emulator.cpu, false ); 172 break; 173 174 case POWERPAD: 175 176 old = new (std::nothrow) Core::Input::PowerPad( emulator.cpu ); 177 break; 178 179 case POWERGLOVE: 180 181 old = new (std::nothrow) Core::Input::PowerGlove( emulator.cpu ); 182 break; 183 184 case MOUSE: 185 186 old = new (std::nothrow) Core::Input::Mouse( emulator.cpu ); 187 break; 188 189 case ROB: 190 191 old = new (std::nothrow) Core::Input::Rob( emulator.cpu, emulator.ppu ); 192 break; 193 194 default: return RESULT_ERR_INVALID_PARAM; 195 } 196 197 if (old) 198 old = &emulator.extPort->Connect( port, *old ); 199 else 200 return RESULT_ERR_OUT_OF_MEMORY; 201 202 break; 203 204 case PORT_3: 205 case PORT_4: 206 207 if (emulator.extPort->NumPorts() > 2) 208 { 209 if (emulator.extPort->GetDevice( port ).GetType() == type) 210 { 211 return RESULT_NOP; 212 } 213 else switch (type) 214 { 215 case UNCONNECTED: 216 217 if (emulator.extPort->GetDevice( port == PORT_3 ? PORT_4 : PORT_3 ).GetType() == UNCONNECTED) 218 { 219 Core::Input::Adapter* const adapter = new (std::nothrow) Core::Input::AdapterTwo 220 ( 221 emulator.extPort->GetDevice(0), 222 emulator.extPort->GetDevice(1), 223 emulator.extPort->GetType() 224 ); 225 226 if (adapter == NULL) 227 return RESULT_ERR_OUT_OF_MEMORY; 228 229 for (uint i=2; i < 4; ++i) 230 delete &emulator.extPort->GetDevice(i); 231 232 delete emulator.extPort; 233 emulator.extPort = adapter; 234 } 235 else if (NULL != (old = new (std::nothrow) Core::Input::Device( emulator.cpu ))) 236 { 237 old = &emulator.extPort->Connect( port, *old ); 238 } 239 else 240 { 241 return RESULT_ERR_OUT_OF_MEMORY; 242 } 243 break; 244 245 case PAD1: 246 case PAD2: 247 case PAD3: 248 case PAD4: 249 250 if (NULL != (old = new (std::nothrow) Core::Input::Pad( emulator.cpu, uint(type) - PAD1 ))) 251 { 252 old = &emulator.extPort->Connect( port, *old ); 253 } 254 else 255 { 256 return RESULT_ERR_OUT_OF_MEMORY; 257 } 258 break; 259 260 default: return RESULT_ERR_INVALID_PARAM; 261 } 262 } 263 else 264 { 265 switch (type) 266 { 267 case UNCONNECTED: 268 269 return RESULT_NOP; 270 271 case PAD1: 272 case PAD2: 273 case PAD3: 274 case PAD4: 275 { 276 Core::Input::Device* const devices[2] = 277 { 278 new (std::nothrow) Core::Input::Device( emulator.cpu ), 279 new (std::nothrow) Core::Input::Pad( emulator.cpu, uint(type) - PAD1 ) 280 }; 281 282 Core::Input::Adapter* adapter; 283 284 if 285 ( 286 devices[0] && devices[1] && NULL != 287 ( 288 adapter = new (std::nothrow) Core::Input::AdapterFour 289 ( 290 emulator.extPort->GetDevice(0), 291 emulator.extPort->GetDevice(1), 292 *devices[port == PORT_3], 293 *devices[port != PORT_3], 294 emulator.extPort->GetType() 295 ) 296 ) 297 ) 298 { 299 delete emulator.extPort; 300 emulator.extPort = adapter; 301 } 302 else 303 { 304 delete devices[0]; 305 delete devices[1]; 306 307 return RESULT_ERR_OUT_OF_MEMORY; 308 } 309 break; 310 } 311 312 default: return RESULT_ERR_INVALID_PARAM; 313 } 314 } 315 break; 316 317 case EXPANSION_PORT: 318 319 if (emulator.expPort->GetType() == type) 320 { 321 return RESULT_NOP; 322 } 323 else switch (type) 324 { 325 case UNCONNECTED: old = new (std::nothrow) Core::Input::Device( emulator.cpu ); break; 326 case PADDLE: old = new (std::nothrow) Core::Input::Paddle( emulator.cpu, true ); break; 327 case FAMILYTRAINER: old = new (std::nothrow) Core::Input::FamilyTrainer( emulator.cpu ); break; 328 case FAMILYKEYBOARD: old = new (std::nothrow) Core::Input::FamilyKeyboard( emulator.cpu, true ); break; 329 case SUBORKEYBOARD: old = new (std::nothrow) Core::Input::SuborKeyboard( emulator.cpu ); break; 330 case DOREMIKKOKEYBOARD: old = new (std::nothrow) Core::Input::DoremikkoKeyboard( emulator.cpu ); break; 331 case HORITRACK: old = new (std::nothrow) Core::Input::HoriTrack( emulator.cpu ); break; 332 case PACHINKO: old = new (std::nothrow) Core::Input::Pachinko( emulator.cpu ); break; 333 case OEKAKIDSTABLET: old = new (std::nothrow) Core::Input::OekaKidsTablet( emulator.cpu ); break; 334 case KONAMIHYPERSHOT: old = new (std::nothrow) Core::Input::KonamiHyperShot( emulator.cpu ); break; 335 case BANDAIHYPERSHOT: old = new (std::nothrow) Core::Input::BandaiHyperShot( emulator.cpu, emulator.ppu ); break; 336 case CRAZYCLIMBER: old = new (std::nothrow) Core::Input::CrazyClimber( emulator.cpu ); break; 337 case MAHJONG: old = new (std::nothrow) Core::Input::Mahjong( emulator.cpu ); break; 338 case EXCITINGBOXING: old = new (std::nothrow) Core::Input::ExcitingBoxing( emulator.cpu ); break; 339 case TOPRIDER: old = new (std::nothrow) Core::Input::TopRider( emulator.cpu ); break; 340 case POKKUNMOGURAA: old = new (std::nothrow) Core::Input::PokkunMoguraa( emulator.cpu ); break; 341 case PARTYTAP: old = new (std::nothrow) Core::Input::PartyTap( emulator.cpu ); break; 342 case TURBOFILE: old = new (std::nothrow) Core::Input::TurboFile( emulator.cpu ); break; 343 case BARCODEWORLD: old = new (std::nothrow) Core::Input::BarcodeWorld( emulator.cpu ); break; 344 345 default: return RESULT_ERR_INVALID_PARAM; 346 } 347 348 if (old) 349 std::swap( old, emulator.expPort ); 350 else 351 return RESULT_ERR_OUT_OF_MEMORY; 352 353 break; 354 355 default: return RESULT_ERR_INVALID_PARAM; 356 } 357 358 delete old; 359 emulator.InitializeInputDevices(); 360 controllerCallback( port, type ); 361 362 return RESULT_OK; 363 } 364 ConnectAdapter(Adapter adapter)365 Result Input::ConnectAdapter(Adapter adapter) throw() 366 { 367 if (emulator.extPort->SetType( adapter )) 368 { 369 adapterCallback( adapter ); 370 return RESULT_OK; 371 } 372 else 373 { 374 return RESULT_NOP; 375 } 376 } 377 AutoSelectController(uint port)378 Result Input::AutoSelectController(uint port) throw() 379 { 380 if (port >= NUM_PORTS) 381 return RESULT_ERR_INVALID_PARAM; 382 383 Type type; 384 385 if (emulator.image) 386 { 387 type = static_cast<Type>(emulator.image->GetDesiredController( port )); 388 } 389 else switch (port) 390 { 391 case PORT_1: type = PAD1; break; 392 case PORT_2: type = PAD2; break; 393 default: type = UNCONNECTED; break; 394 } 395 396 return ConnectController( port, type ); 397 } 398 AutoSelectControllers()399 Result Input::AutoSelectControllers() throw() 400 { 401 Result result = RESULT_NOP; 402 403 for (uint i=0; i < NUM_PORTS; ++i) 404 { 405 const Result tmp = AutoSelectController( i ); 406 407 if (result > tmp) 408 result = tmp; 409 } 410 411 return result; 412 } 413 AutoSelectAdapter()414 Result Input::AutoSelectAdapter() throw() 415 { 416 return ConnectAdapter( emulator.image ? static_cast<Adapter>(emulator.image->GetDesiredAdapter()) : ADAPTER_NES ); 417 } 418 GetConnectedController(uint port) const419 Input::Type Input::GetConnectedController(uint port) const throw() 420 { 421 if (port == EXPANSION_PORT) 422 return emulator.expPort->GetType(); 423 424 if (port < emulator.extPort->NumPorts()) 425 return emulator.extPort->GetDevice( port ).GetType(); 426 427 return UNCONNECTED; 428 } 429 GetConnectedAdapter() const430 Input::Adapter Input::GetConnectedAdapter() const throw() 431 { 432 return emulator.extPort->GetType(); 433 } 434 IsControllerConnected(Type type) const435 bool Input::IsControllerConnected(Type type) const throw() 436 { 437 if (emulator.expPort->GetType() == type) 438 return true; 439 440 for (uint ports=emulator.extPort->NumPorts(), i=0; i < ports; ++i) 441 { 442 if (emulator.extPort->GetDevice(i).GetType() == type) 443 return true; 444 } 445 446 return false; 447 } 448 } 449 450 #ifdef NST_MSVC_OPTIMIZE 451 #pragma optimize("", on) 452 #endif 453 } 454