#include "stdafx.h" #include "ControlManager.h" #include "StandardController.h" #include "Zapper.h" #include "ArkanoidController.h" #include "OekaKidsTablet.h" #include "EmulationSettings.h" #include "Console.h" #include "GameServerConnection.h" unique_ptr ControlManager::_keyManager = nullptr; shared_ptr ControlManager::_controlDevices[2] = { nullptr, nullptr }; IGameBroadcaster* ControlManager::_gameBroadcaster = nullptr; MousePosition ControlManager::_mousePosition = { -1, -1 }; ControlManager::ControlManager() { } ControlManager::~ControlManager() { } void ControlManager::RegisterKeyManager(IKeyManager* keyManager) { _keyManager.reset(keyManager); } void ControlManager::RefreshKeyState() { if(_keyManager != nullptr) { return _keyManager->RefreshState(); } } 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 ControlManager::GetControlDevice(uint8_t port) { return ControlManager::_controlDevices[port]; } void ControlManager::RegisterControlDevice(shared_ptr controlDevice, uint8_t port) { ControlManager::_controlDevices[port] = controlDevice; } void ControlManager::UnregisterControlDevice(uint8_t port) { ControlManager::_controlDevices[port].reset(); } void ControlManager::RefreshAllPorts() { if(_keyManager) { _keyManager->RefreshState(); } for(int i = 0; i < 2; i++) { if(ControlManager::_controlDevices[i]) { ControlManager::_controlDevices[i]->RefreshStateBuffer(); } } } shared_ptr ControlManager::GetZapper(uint8_t port) { return shared_ptr(new Zapper(port)); } void ControlManager::UpdateControlDevices() { bool fourScore = EmulationSettings::CheckFlag(EmulationFlags::HasFourScore); ExpansionPortDevice expansionDevice = EmulationSettings::GetExpansionDevice(); if(EmulationSettings::GetConsoleType() != ConsoleType::Famicom) { expansionDevice = ExpansionPortDevice::None; } else if(expansionDevice != ExpansionPortDevice::FourPlayerAdapter) { fourScore = false; } for(int i = 0; i < 2; i++) { shared_ptr device; if(fourScore || EmulationSettings::GetConsoleType() == ConsoleType::Famicom) { //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; 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(device)->AddAdditionalController(shared_ptr(new StandardController(i + 2))); } else if(i == 1 || expansionDevice == ExpansionPortDevice::ArkanoidController) { switch(expansionDevice) { case ExpansionPortDevice::Zapper: std::dynamic_pointer_cast(device)->AddAdditionalController(shared_ptr(new Zapper(2))); break; case ExpansionPortDevice::ArkanoidController: std::dynamic_pointer_cast(device)->AddAdditionalController(shared_ptr(new ArkanoidController(2))); break; case ExpansionPortDevice::OekaKidsTablet: std::dynamic_pointer_cast(device)->AddAdditionalController(shared_ptr(new OekaKidsTablet(2))); break; default: break; } } } 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 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) { //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; } template shared_ptr ControlManager::GetExpansionDevice() { shared_ptr controller; controller = std::dynamic_pointer_cast(GetControlDevice(1)); if(controller) { shared_ptr expansionDevice; expansionDevice = std::dynamic_pointer_cast(controller->GetAdditionalController()); return expansionDevice; } return nullptr; } void ControlManager::WriteRAM(uint16_t addr, uint8_t value) { //$4016 writes bool previousState = _refreshState; _refreshState = (value & 0x01) == 0x01; auto tablet = GetExpansionDevice(); if(tablet) { tablet->WriteRam(value); } else { if(previousState && !_refreshState) { //Refresh controller once strobe bit is disabled RefreshAllPorts(); } } } void ControlManager::Reset(bool softReset) { if(_keyManager != nullptr) { _keyManager->UpdateDevices(); } } void ControlManager::StreamState(bool saving) { //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); } } ArrayInfo types = { controllerTypes, 4 }; Stream(_refreshState, _mousePosition.X, _mousePosition.Y, nesModel, expansionDevice, consoleType, types, hasFourScore); if(!saving) { EmulationSettings::SetNesModel(nesModel); EmulationSettings::SetExpansionDevice(expansionDevice); EmulationSettings::SetConsoleType(consoleType); for(int i = 0; i < 4; i++) { EmulationSettings::SetControllerType(i, controllerTypes[i]); } if(hasFourScore) { EmulationSettings::SetFlags(EmulationFlags::HasFourScore); } else { EmulationSettings::ClearFlags(EmulationFlags::HasFourScore); } UpdateControlDevices(); } SnapshotInfo device0{ GetControlDevice(0).get() }; SnapshotInfo device1{ GetControlDevice(1).get() }; Stream(device0, device1); } void ControlManager::SetMousePosition(double x, double y) { 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); } } MousePosition ControlManager::GetMousePosition() { return _mousePosition; } bool ControlManager::GetLagFlag() { bool flag = _isLagging; _isLagging = true; return flag; }