Mesen/Core/StandardController.cpp

151 lines
4.8 KiB
C++

#include "stdafx.h"
#include "StandardController.h"
#include "ControlManager.h"
#include "PPU.h"
#include "EmulationSettings.h"
#include "ArkanoidController.h"
#include "OekaKidsTablet.h"
StandardController::StandardController(uint8_t port, bool emptyPort) : BaseControlDevice(port)
{
_isEmptyPort = emptyPort;
}
void StandardController::StreamState(bool saving)
{
BaseControlDevice::StreamState(saving);
SnapshotInfo additionalController{ _additionalController.get() };
Stream(_stateBuffer, _stateBufferFamicom, 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();
}
uint32_t StandardController::GetNetPlayState()
{
return GetButtonState();
}
uint8_t StandardController::GetPortOutput()
{
uint8_t returnValue = _stateBuffer & 0x01;
_stateBuffer >>= 1;
if(_famiconDevice && (_additionalController || EmulationSettings::CheckFlag(EmulationFlags::HasFourScore))) {
if(std::dynamic_pointer_cast<Zapper>(_additionalController) || std::dynamic_pointer_cast<OekaKidsTablet>(_additionalController)) {
returnValue |= _additionalController->GetPortOutput();
} else if(std::dynamic_pointer_cast<ArkanoidController>(_additionalController)) {
returnValue |= std::dynamic_pointer_cast<ArkanoidController>(_additionalController)->GetExpansionPortOutput(_port);
} else {
returnValue |= (_stateBufferFamicom & 0x01) << 1;
_stateBufferFamicom >>= 1;
_stateBufferFamicom |= 0x800000;
}
}
//"All subsequent reads will return D=1 on an authentic controller but may return D=0 on third party controllers."
_stateBuffer |= _isEmptyPort ? 0 : 0x800000;
return returnValue;
}
void StandardController::RefreshStateBuffer()
{
_stateBuffer = GetControlState();
_lastButtonState = _stateBuffer;
if((_additionalController && !std::dynamic_pointer_cast<Zapper>(_additionalController)) || EmulationSettings::CheckFlag(EmulationFlags::HasFourScore)) {
//Next 8 bits = Gamepad 3/4
if(_famiconDevice) {
if(std::dynamic_pointer_cast<ArkanoidController>(_additionalController) || std::dynamic_pointer_cast<OekaKidsTablet>(_additionalController)) {
_additionalController->RefreshStateBuffer();
} else {
//Four player adapter (Famicom)
_stateBufferFamicom = _additionalController ? _additionalController->GetControlState() : 0;
_stateBufferFamicom |= 0xFFFF00;
}
} else {
//Four-score adapter (NES)
_stateBuffer |= _additionalController ? (_additionalController->GetControlState() << 8) : 0;
//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 |= _isEmptyPort ? 0 : 0xFFFF00;
}
}
uint8_t StandardController::RefreshState()
{
return GetButtonState();
}
void StandardController::AddAdditionalController(shared_ptr<BaseControlDevice> controller)
{
_additionalController = controller;
}
shared_ptr<BaseControlDevice> StandardController::GetAdditionalController()
{
return _additionalController;
}
uint32_t StandardController::GetInternalState()
{
return _stateBuffer;
}
void StandardController::SetInternalState(uint32_t state)
{
_stateBuffer = state;
}
uint8_t StandardController::GetLastButtonState()
{
return _lastButtonState;
}