Mesen/Core/ControlManager.cpp

287 lines
7.9 KiB
C++
Raw Normal View History

2014-06-21 19:43:41 +00:00
#include "stdafx.h"
#include "ControlManager.h"
#include "StandardController.h"
#include "Zapper.h"
#include "ArkanoidController.h"
#include "EmulationSettings.h"
#include "Console.h"
#include "GameServerConnection.h"
2014-06-21 19:43:41 +00:00
unique_ptr<IKeyManager> ControlManager::_keyManager = nullptr;
shared_ptr<BaseControlDevice> ControlManager::_controlDevices[2] = { nullptr, nullptr };
IGameBroadcaster* ControlManager::_gameBroadcaster = nullptr;
MousePosition ControlManager::_mousePosition = { -1, -1 };
2014-06-21 19:43:41 +00:00
ControlManager::ControlManager()
{
}
ControlManager::~ControlManager()
{
}
void ControlManager::RegisterKeyManager(IKeyManager* keyManager)
{
_keyManager.reset(keyManager);
}
bool ControlManager::IsKeyPressed(uint32_t keyCode)
{
if(_keyManager != nullptr) {
return _keyManager->IsKeyPressed(keyCode);
}
return false;
}
bool ControlManager::IsMouseButtonPressed(MouseButton button)
{
if(_keyManager != nullptr) {
return _keyManager->IsMouseButtonPressed(button);
}
return false;
}
uint32_t ControlManager::GetPressedKey()
{
if(_keyManager != nullptr) {
return _keyManager->GetPressedKey();
}
return 0;
}
string ControlManager::GetKeyName(uint32_t keyCode)
{
if(_keyManager != nullptr) {
return _keyManager->GetKeyName(keyCode);
}
return 0;
}
uint32_t ControlManager::GetKeyCode(string keyName)
{
if(_keyManager != nullptr) {
return _keyManager->GetKeyCode(keyName);
}
return 0;
}
void ControlManager::RegisterBroadcaster(IGameBroadcaster* gameBroadcaster)
{
ControlManager::_gameBroadcaster = gameBroadcaster;
}
void ControlManager::UnregisterBroadcaster(IGameBroadcaster* gameBroadcaster)
{
if(ControlManager::_gameBroadcaster == gameBroadcaster) {
ControlManager::_gameBroadcaster = nullptr;
}
}
void ControlManager::BroadcastInput(uint8_t port, uint8_t state)
{
if(ControlManager::_gameBroadcaster) {
//Used when acting as a game server
ControlManager::_gameBroadcaster->BroadcastInput(state, port);
}
}
shared_ptr<BaseControlDevice> ControlManager::GetControlDevice(uint8_t port)
{
return ControlManager::_controlDevices[port];
}
void ControlManager::RegisterControlDevice(shared_ptr<BaseControlDevice> controlDevice, uint8_t port)
{
ControlManager::_controlDevices[port] = controlDevice;
}
void ControlManager::UnregisterControlDevice(uint8_t port)
2014-06-21 19:43:41 +00:00
{
ControlManager::_controlDevices[port].reset();
2014-06-21 19:43:41 +00:00
}
void ControlManager::RefreshAllPorts()
{
if(_keyManager) {
_keyManager->RefreshState();
}
for(int i = 0; i < 2; i++) {
if(ControlManager::_controlDevices[i]) {
ControlManager::_controlDevices[i]->RefreshStateBuffer();
}
}
2014-06-21 19:43:41 +00:00
}
2016-06-22 23:23:08 +00:00
shared_ptr<BaseControlDevice> ControlManager::GetZapper(uint8_t port)
{
return shared_ptr<BaseControlDevice>(new Zapper(port));
}
void ControlManager::UpdateControlDevices()
2014-06-21 19:43:41 +00:00
{
bool fourScore = EmulationSettings::CheckFlag(EmulationFlags::HasFourScore);
ExpansionPortDevice expansionDevice = EmulationSettings::GetExpansionDevice();
shared_ptr<BaseControlDevice> arkanoidController;
if(EmulationSettings::GetConsoleType() != ConsoleType::Famicom) {
expansionDevice = ExpansionPortDevice::None;
} else if(expansionDevice != ExpansionPortDevice::FourPlayerAdapter) {
fourScore = false;
if(expansionDevice == ExpansionPortDevice::ArkanoidController) {
arkanoidController.reset(new ArkanoidController(2));
}
}
2014-06-21 19:43:41 +00:00
for(int i = 0; i < 2; i++) {
shared_ptr<BaseControlDevice> device;
if(fourScore || expansionDevice == ExpansionPortDevice::ArkanoidController || i == 1 && expansionDevice == ExpansionPortDevice::Zapper) {
//Need to set standard controller in all slots if four score (to allow emulation to work correctly)
device.reset(new StandardController(i));
} else {
switch(EmulationSettings::GetControllerType(i)) {
case ControllerType::StandardController: device.reset(new StandardController(i)); break;
2016-06-22 23:23:08 +00:00
case ControllerType::Zapper: device = GetZapper(i); break;
case ControllerType::ArkanoidController: device.reset(new ArkanoidController(i)); break;
}
}
if(device) {
ControlManager::RegisterControlDevice(device, i);
if(fourScore) {
std::dynamic_pointer_cast<StandardController>(device)->AddAdditionalController(shared_ptr<StandardController>(new StandardController(i + 2)));
} else if(i == 1 && expansionDevice == ExpansionPortDevice::Zapper) {
std::dynamic_pointer_cast<StandardController>(device)->AddAdditionalController(shared_ptr<Zapper>(new Zapper(2)));
} else if(expansionDevice == ExpansionPortDevice::ArkanoidController) {
std::dynamic_pointer_cast<StandardController>(device)->AddAdditionalController(arkanoidController);
}
} else {
//Remove current device if it's no longer in use
ControlManager::UnregisterControlDevice(i);
}
}
}
uint8_t ControlManager::GetPortValue(uint8_t port)
{
if(_refreshState) {
//Reload until strobe bit is set to off
RefreshAllPorts();
}
shared_ptr<BaseControlDevice> device = GetControlDevice(port);
//"In the NES and Famicom, the top three (or five) bits are not driven, and so retain the bits of the previous byte on the bus.
//Usually this is the most significant byte of the address of the controller port - 0x40.
//Paperboy relies on this behavior and requires that reads from the controller ports return exactly $40 or $41 as appropriate."
uint8_t value = MemoryManager::GetOpenBus(0xE0);
if(device) {
value |= device->GetPortOutput();
}
return value;
}
uint8_t ControlManager::ReadRAM(uint16_t addr)
{
2016-07-10 22:22:37 +00:00
//Used for lag counter
//Any frame where the input is read does not count as lag
_isLagging = false;
switch(addr) {
case 0x4016: return GetPortValue(0);
case 0x4017: return GetPortValue(1);
}
return 0;
}
void ControlManager::WriteRAM(uint16_t addr, uint8_t value)
{
//$4016 writes
bool previousState = _refreshState;
_refreshState = (value & 0x01) == 0x01;
if(previousState && !_refreshState) {
//Refresh controller once strobe bit is disabled
RefreshAllPorts();
}
2014-06-21 19:43:41 +00:00
}
void ControlManager::Reset(bool softReset)
{
if(_keyManager != nullptr) {
_keyManager->UpdateDevices();
}
}
void ControlManager::StreamState(bool saving)
2014-06-21 19:43:41 +00:00
{
//Restore controllers that were being used at the time the snapshot was made
//This is particularely important to ensure proper sync during NetPlay
ControllerType controllerTypes[4];
NesModel nesModel;
ExpansionPortDevice expansionDevice;
ConsoleType consoleType;
bool hasFourScore;
if(saving) {
nesModel = Console::GetNesModel();
expansionDevice = EmulationSettings::GetExpansionDevice();
consoleType = EmulationSettings::GetConsoleType();
hasFourScore = EmulationSettings::CheckFlag(EmulationFlags::HasFourScore);
for(int i = 0; i < 4; i++) {
controllerTypes[i] = EmulationSettings::GetControllerType(i);
}
2014-06-21 19:43:41 +00:00
}
ArrayInfo<ControllerType> types = { controllerTypes, 4 };
Stream(_refreshState, _mousePosition.X, _mousePosition.Y, nesModel, expansionDevice, consoleType, types, hasFourScore);
2014-06-21 19:43:41 +00:00
if(!saving) {
EmulationSettings::SetNesModel(nesModel);
EmulationSettings::SetExpansionDevice(expansionDevice);
EmulationSettings::SetConsoleType(consoleType);
for(int i = 0; i < 4; i++) {
EmulationSettings::SetControllerType(i, controllerTypes[i]);
}
2014-06-21 19:43:41 +00:00
if(hasFourScore) {
EmulationSettings::SetFlags(EmulationFlags::HasFourScore);
} else {
EmulationSettings::ClearFlags(EmulationFlags::HasFourScore);
}
UpdateControlDevices();
}
2014-06-21 19:43:41 +00:00
SnapshotInfo device0{ GetControlDevice(0).get() };
SnapshotInfo device1{ GetControlDevice(1).get() };
Stream(device0, device1);
2014-06-21 19:43:41 +00:00
}
void ControlManager::SetMousePosition(double x, double y)
2014-06-21 19:43:41 +00:00
{
if(x < 0 || y < 0) {
_mousePosition.X = -1;
_mousePosition.Y = -1;
} else {
OverscanDimensions overscan = EmulationSettings::GetOverscanDimensions();
_mousePosition.X = (int32_t)(x * (PPU::ScreenWidth - overscan.Left - overscan.Right) + overscan.Left);
_mousePosition.Y = (int32_t)(y * (PPU::ScreenHeight - overscan.Top - overscan.Bottom) + overscan.Top);
}
}
2014-06-21 19:43:41 +00:00
MousePosition ControlManager::GetMousePosition()
{
return _mousePosition;
2016-07-10 22:22:37 +00:00
}
bool ControlManager::GetLagFlag()
{
bool flag = _isLagging;
_isLagging = true;
return flag;
2014-06-21 19:43:41 +00:00
}