Mesen/Core/StandardController.cpp

124 lines
3.6 KiB
C++

#include "stdafx.h"
#include "StandardController.h"
#include "ControlManager.h"
#include "PPU.h"
#include "EmulationSettings.h"
void StandardController::StreamState(bool saving)
{
BaseControlDevice::StreamState(saving);
Stream<uint32_t>(_stateBuffer);
Stream<uint32_t>(_stateBufferFamicom);
if(_additionalController) {
Stream(_additionalController);
}
}
uint8_t StandardController::GetButtonState()
{
ButtonState state;
if(!EmulationSettings::CheckFlag(EmulationFlags::InBackground) || EmulationSettings::CheckFlag(EmulationFlags::AllowBackgroundInput)) {
for(size_t i = 0, len = _keyMappings.size(); i < len; i++) {
KeyMapping keyMapping = _keyMappings[i];
state.A |= ControlManager::IsKeyPressed(keyMapping.A);
state.B |= ControlManager::IsKeyPressed(keyMapping.B);
state.Select |= ControlManager::IsKeyPressed(keyMapping.Select);
state.Start |= ControlManager::IsKeyPressed(keyMapping.Start);
state.Up |= ControlManager::IsKeyPressed(keyMapping.Up);
state.Down |= ControlManager::IsKeyPressed(keyMapping.Down);
state.Left |= ControlManager::IsKeyPressed(keyMapping.Left);
state.Right |= ControlManager::IsKeyPressed(keyMapping.Right);
//Turbo buttons - need to be applied for at least 2 reads in a row (some games require this)
uint8_t turboFreq = 1 << (4 - _turboSpeed);
bool turboOn = (uint8_t)(PPU::GetFrameCount() % turboFreq) < turboFreq / 2;
if(turboOn) {
state.A |= ControlManager::IsKeyPressed(keyMapping.TurboA);
state.B |= ControlManager::IsKeyPressed(keyMapping.TurboB);
state.Start |= ControlManager::IsKeyPressed(keyMapping.TurboStart);
state.Select |= ControlManager::IsKeyPressed(keyMapping.TurboSelect);
}
}
if(!EmulationSettings::CheckFlag(EmulationFlags::AllowInvalidInput)) {
if(state.Up && state.Down) {
state.Down = false;
}
if(state.Left && state.Right) {
state.Right = false;
}
}
}
return state.ToByte();
}
uint8_t StandardController::GetPortOutput()
{
uint8_t returnValue = _stateBuffer & 0x01;
_stateBuffer >>= 1;
if(_famiconDevice && _additionalController) {
if(_hasZapper) {
returnValue |= _additionalController->GetPortOutput();
} else {
returnValue |= (_stateBufferFamicom & 0x01) << 1;
_stateBufferFamicom >>= 1;
_stateBuffer |= 0x800000;
}
}
//"All subsequent reads will return D=1 on an authentic controller but may return D=0 on third party controllers."
_stateBuffer |= 0x800000;
return returnValue;
}
void StandardController::RefreshStateBuffer()
{
_stateBuffer = GetControlState();
if(_additionalController) {
//Next 8 bits = Gamepad 3/4
if(_famiconDevice) {
//Four player adapter (Famicom)
_stateBufferFamicom = _additionalController->GetControlState();
_stateBufferFamicom |= 0xFFFF00;
} else {
//Four-score adapter (NES)
_stateBuffer |= _additionalController->GetControlState() << 8;
//Last 8 bits = signature
//Signature for port 0 = 0x10, reversed bit order => 0x08
//Signature for port 1 = 0x20, reversed bit order => 0x04
_stateBuffer |= (GetPort() == 0 ? 0x08 : 0x04) << 16;
}
} else {
//"All subsequent reads will return D=1 on an authentic controller but may return D=0 on third party controllers."
_stateBuffer |= 0xFFFF00;
}
}
uint8_t StandardController::RefreshState()
{
return GetButtonState();
}
void StandardController::AddAdditionalController(shared_ptr<BaseControlDevice> controller)
{
if(std::dynamic_pointer_cast<Zapper>(controller)) {
_hasZapper = true;
}
_additionalController = controller;
}
shared_ptr<Zapper> StandardController::GetZapper()
{
if(_hasZapper) {
return std::dynamic_pointer_cast<Zapper>(_additionalController);
} else {
return nullptr;
}
}