nestopia/source/core/api/NstApiInput.cpp
2012-09-02 13:13:55 -04:00

453 lines
14 KiB
C++

////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
//
// This file is part of Nestopia.
//
// Nestopia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Nestopia is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Nestopia; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////////////
#include <cstring>
#include <new>
#include <algorithm>
#include "../NstMachine.hpp"
#include "../NstCartridge.hpp"
#include "../input/NstInpDevice.hpp"
#include "../input/NstInpAdapter.hpp"
#include "../input/NstInpPad.hpp"
#include "../input/NstInpZapper.hpp"
#include "../input/NstInpPaddle.hpp"
#include "../input/NstInpPowerPad.hpp"
#include "../input/NstInpPowerGlove.hpp"
#include "../input/NstInpMouse.hpp"
#include "../input/NstInpFamilyTrainer.hpp"
#include "../input/NstInpFamilyKeyboard.hpp"
#include "../input/NstInpSuborKeyboard.hpp"
#include "../input/NstInpDoremikkoKeyboard.hpp"
#include "../input/NstInpHoriTrack.hpp"
#include "../input/NstInpPachinko.hpp"
#include "../input/NstInpOekaKidsTablet.hpp"
#include "../input/NstInpKonamiHyperShot.hpp"
#include "../input/NstInpBandaiHyperShot.hpp"
#include "../input/NstInpCrazyClimber.hpp"
#include "../input/NstInpMahjong.hpp"
#include "../input/NstInpExcitingBoxing.hpp"
#include "../input/NstInpTopRider.hpp"
#include "../input/NstInpPokkunMoguraa.hpp"
#include "../input/NstInpPartyTap.hpp"
#include "../input/NstInpRob.hpp"
#include "../input/NstInpTurboFile.hpp"
#include "../input/NstInpBarcodeWorld.hpp"
namespace Nes
{
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("s", on)
#endif
namespace Api
{
Input::ControllerCaller Input::controllerCallback;
Input::AdapterCaller Input::adapterCallback;
}
namespace Core
{
namespace Input
{
Controllers::PollCaller2< Controllers::Pad > Controllers::Pad::callback;
Controllers::PollCaller1< Controllers::Zapper > Controllers::Zapper::callback;
Controllers::PollCaller1< Controllers::Paddle > Controllers::Paddle::callback;
Controllers::PollCaller1< Controllers::PowerPad > Controllers::PowerPad::callback;
Controllers::PollCaller1< Controllers::PowerGlove > Controllers::PowerGlove::callback;
Controllers::PollCaller1< Controllers::Mouse > Controllers::Mouse::callback;
Controllers::PollCaller1< Controllers::FamilyTrainer > Controllers::FamilyTrainer::callback;
Controllers::PollCaller3< Controllers::FamilyKeyboard > Controllers::FamilyKeyboard::callback;
Controllers::PollCaller3< Controllers::SuborKeyboard > Controllers::SuborKeyboard::callback;
Controllers::PollCaller3< Controllers::DoremikkoKeyboard > Controllers::DoremikkoKeyboard::callback;
Controllers::PollCaller1< Controllers::HoriTrack > Controllers::HoriTrack::callback;
Controllers::PollCaller1< Controllers::Pachinko > Controllers::Pachinko::callback;
Controllers::PollCaller1< Controllers::VsSystem > Controllers::VsSystem::callback;
Controllers::PollCaller1< Controllers::OekaKidsTablet > Controllers::OekaKidsTablet::callback;
Controllers::PollCaller1< Controllers::KonamiHyperShot > Controllers::KonamiHyperShot::callback;
Controllers::PollCaller1< Controllers::BandaiHyperShot > Controllers::BandaiHyperShot::callback;
Controllers::PollCaller1< Controllers::CrazyClimber > Controllers::CrazyClimber::callback;
Controllers::PollCaller2< Controllers::Mahjong > Controllers::Mahjong::callback;
Controllers::PollCaller2< Controllers::ExcitingBoxing > Controllers::ExcitingBoxing::callback;
Controllers::PollCaller1< Controllers::TopRider > Controllers::TopRider::callback;
Controllers::PollCaller2< Controllers::PokkunMoguraa > Controllers::PokkunMoguraa::callback;
Controllers::PollCaller1< Controllers::PartyTap > Controllers::PartyTap::callback;
Controllers::PollCaller1< Controllers::KaraokeStudio > Controllers::KaraokeStudio::callback;
Controllers::PowerPad::PowerPad() throw()
{
std::fill( sideA, sideA + NUM_SIDE_A_BUTTONS, false );
std::fill( sideB, sideB + NUM_SIDE_B_BUTTONS, false );
}
Controllers::PowerGlove::PowerGlove() throw()
{
x = 0;
y = 0;
distance = 0;
wrist = 0;
gesture = GESTURE_OPEN;
}
Controllers::FamilyTrainer::FamilyTrainer() throw()
{
std::fill( sideA, sideA + NUM_SIDE_A_BUTTONS, false );
std::fill( sideB, sideB + NUM_SIDE_B_BUTTONS, false );
}
Controllers::FamilyKeyboard::FamilyKeyboard() throw()
{
std::memset( parts, 0x00, sizeof(parts) );
}
Controllers::SuborKeyboard::SuborKeyboard() throw()
{
std::memset( parts, 0x00, sizeof(parts) );
}
Controllers::Controllers() throw()
{
}
}
}
namespace Api
{
Result Input::ConnectController(const uint port,const Type type) throw()
{
Core::Input::Device* old = NULL;
switch (port)
{
case PORT_1:
case PORT_2:
if (emulator.extPort->GetDevice( port ).GetType() == type)
{
return RESULT_NOP;
}
else switch (type)
{
case UNCONNECTED:
old = new (std::nothrow) Core::Input::Device( emulator.cpu );
break;
case PAD1:
case PAD2:
case PAD3:
case PAD4:
old = new (std::nothrow) Core::Input::Pad( emulator.cpu, uint(type) - PAD1 );
break;
case ZAPPER:
old = new (std::nothrow) Core::Input::Zapper( emulator.cpu, emulator.ppu );
break;
case PADDLE:
old = new (std::nothrow) Core::Input::Paddle( emulator.cpu, false );
break;
case POWERPAD:
old = new (std::nothrow) Core::Input::PowerPad( emulator.cpu );
break;
case POWERGLOVE:
old = new (std::nothrow) Core::Input::PowerGlove( emulator.cpu );
break;
case MOUSE:
old = new (std::nothrow) Core::Input::Mouse( emulator.cpu );
break;
case ROB:
old = new (std::nothrow) Core::Input::Rob( emulator.cpu, emulator.ppu );
break;
default: return RESULT_ERR_INVALID_PARAM;
}
if (old)
old = &emulator.extPort->Connect( port, *old );
else
return RESULT_ERR_OUT_OF_MEMORY;
break;
case PORT_3:
case PORT_4:
if (emulator.extPort->NumPorts() > 2)
{
if (emulator.extPort->GetDevice( port ).GetType() == type)
{
return RESULT_NOP;
}
else switch (type)
{
case UNCONNECTED:
if (emulator.extPort->GetDevice( port == PORT_3 ? PORT_4 : PORT_3 ).GetType() == UNCONNECTED)
{
Core::Input::Adapter* const adapter = new (std::nothrow) Core::Input::AdapterTwo
(
emulator.extPort->GetDevice(0),
emulator.extPort->GetDevice(1),
emulator.extPort->GetType()
);
if (adapter == NULL)
return RESULT_ERR_OUT_OF_MEMORY;
for (uint i=2; i < 4; ++i)
delete &emulator.extPort->GetDevice(i);
delete emulator.extPort;
emulator.extPort = adapter;
}
else if (NULL != (old = new (std::nothrow) Core::Input::Device( emulator.cpu )))
{
old = &emulator.extPort->Connect( port, *old );
}
else
{
return RESULT_ERR_OUT_OF_MEMORY;
}
break;
case PAD1:
case PAD2:
case PAD3:
case PAD4:
if (NULL != (old = new (std::nothrow) Core::Input::Pad( emulator.cpu, uint(type) - PAD1 )))
{
old = &emulator.extPort->Connect( port, *old );
}
else
{
return RESULT_ERR_OUT_OF_MEMORY;
}
break;
default: return RESULT_ERR_INVALID_PARAM;
}
}
else
{
switch (type)
{
case UNCONNECTED:
return RESULT_NOP;
case PAD1:
case PAD2:
case PAD3:
case PAD4:
{
Core::Input::Device* const devices[2] =
{
new (std::nothrow) Core::Input::Device( emulator.cpu ),
new (std::nothrow) Core::Input::Pad( emulator.cpu, uint(type) - PAD1 )
};
Core::Input::Adapter* adapter;
if
(
devices[0] && devices[1] && NULL !=
(
adapter = new (std::nothrow) Core::Input::AdapterFour
(
emulator.extPort->GetDevice(0),
emulator.extPort->GetDevice(1),
*devices[port == PORT_3],
*devices[port != PORT_3],
emulator.extPort->GetType()
)
)
)
{
delete emulator.extPort;
emulator.extPort = adapter;
}
else
{
delete devices[0];
delete devices[1];
return RESULT_ERR_OUT_OF_MEMORY;
}
break;
}
default: return RESULT_ERR_INVALID_PARAM;
}
}
break;
case EXPANSION_PORT:
if (emulator.expPort->GetType() == type)
{
return RESULT_NOP;
}
else switch (type)
{
case UNCONNECTED: old = new (std::nothrow) Core::Input::Device( emulator.cpu ); break;
case PADDLE: old = new (std::nothrow) Core::Input::Paddle( emulator.cpu, true ); break;
case FAMILYTRAINER: old = new (std::nothrow) Core::Input::FamilyTrainer( emulator.cpu ); break;
case FAMILYKEYBOARD: old = new (std::nothrow) Core::Input::FamilyKeyboard( emulator.cpu, true ); break;
case SUBORKEYBOARD: old = new (std::nothrow) Core::Input::SuborKeyboard( emulator.cpu ); break;
case DOREMIKKOKEYBOARD: old = new (std::nothrow) Core::Input::DoremikkoKeyboard( emulator.cpu ); break;
case HORITRACK: old = new (std::nothrow) Core::Input::HoriTrack( emulator.cpu ); break;
case PACHINKO: old = new (std::nothrow) Core::Input::Pachinko( emulator.cpu ); break;
case OEKAKIDSTABLET: old = new (std::nothrow) Core::Input::OekaKidsTablet( emulator.cpu ); break;
case KONAMIHYPERSHOT: old = new (std::nothrow) Core::Input::KonamiHyperShot( emulator.cpu ); break;
case BANDAIHYPERSHOT: old = new (std::nothrow) Core::Input::BandaiHyperShot( emulator.cpu, emulator.ppu ); break;
case CRAZYCLIMBER: old = new (std::nothrow) Core::Input::CrazyClimber( emulator.cpu ); break;
case MAHJONG: old = new (std::nothrow) Core::Input::Mahjong( emulator.cpu ); break;
case EXCITINGBOXING: old = new (std::nothrow) Core::Input::ExcitingBoxing( emulator.cpu ); break;
case TOPRIDER: old = new (std::nothrow) Core::Input::TopRider( emulator.cpu ); break;
case POKKUNMOGURAA: old = new (std::nothrow) Core::Input::PokkunMoguraa( emulator.cpu ); break;
case PARTYTAP: old = new (std::nothrow) Core::Input::PartyTap( emulator.cpu ); break;
case TURBOFILE: old = new (std::nothrow) Core::Input::TurboFile( emulator.cpu ); break;
case BARCODEWORLD: old = new (std::nothrow) Core::Input::BarcodeWorld( emulator.cpu ); break;
default: return RESULT_ERR_INVALID_PARAM;
}
if (old)
std::swap( old, emulator.expPort );
else
return RESULT_ERR_OUT_OF_MEMORY;
break;
default: return RESULT_ERR_INVALID_PARAM;
}
delete old;
emulator.InitializeInputDevices();
controllerCallback( port, type );
return RESULT_OK;
}
Result Input::ConnectAdapter(Adapter adapter) throw()
{
if (emulator.extPort->SetType( adapter ))
{
adapterCallback( adapter );
return RESULT_OK;
}
else
{
return RESULT_NOP;
}
}
Result Input::AutoSelectController(uint port) throw()
{
if (port >= NUM_PORTS)
return RESULT_ERR_INVALID_PARAM;
Type type;
if (emulator.image)
{
type = static_cast<Type>(emulator.image->GetDesiredController( port ));
}
else switch (port)
{
case PORT_1: type = PAD1; break;
case PORT_2: type = PAD2; break;
default: type = UNCONNECTED; break;
}
return ConnectController( port, type );
}
Result Input::AutoSelectControllers() throw()
{
Result result = RESULT_NOP;
for (uint i=0; i < NUM_PORTS; ++i)
{
const Result tmp = AutoSelectController( i );
if (result > tmp)
result = tmp;
}
return result;
}
Result Input::AutoSelectAdapter() throw()
{
return ConnectAdapter( emulator.image ? static_cast<Adapter>(emulator.image->GetDesiredAdapter()) : ADAPTER_NES );
}
Input::Type Input::GetConnectedController(uint port) const throw()
{
if (port == EXPANSION_PORT)
return emulator.expPort->GetType();
if (port < emulator.extPort->NumPorts())
return emulator.extPort->GetDevice( port ).GetType();
return UNCONNECTED;
}
Input::Adapter Input::GetConnectedAdapter() const throw()
{
return emulator.extPort->GetType();
}
bool Input::IsControllerConnected(Type type) const throw()
{
if (emulator.expPort->GetType() == type)
return true;
for (uint ports=emulator.extPort->NumPorts(), i=0; i < ports; ++i)
{
if (emulator.extPort->GetDevice(i).GetType() == type)
return true;
}
return false;
}
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("", on)
#endif
}