diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 852cbcf4..550bf1d8 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -68,6 +68,7 @@ + @@ -115,6 +116,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index ea22f29b..cf6ba632 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -820,6 +820,8 @@ + + diff --git a/Core/Gameboy/Input/GbController.h b/Core/Gameboy/Input/GbController.h index 65f07102..fc157495 100644 --- a/Core/Gameboy/Input/GbController.h +++ b/Core/Gameboy/Input/GbController.h @@ -59,7 +59,7 @@ public: { } - void DrawController(InputHud& hud) + void InternalDrawController(InputHud& hud) override { hud.DrawOutline(35, 14); diff --git a/Core/NES/Input/FourScore.h b/Core/NES/Input/FourScore.h index b4bfb5d1..0f9bb551 100644 --- a/Core/NES/Input/FourScore.h +++ b/Core/NES/Input/FourScore.h @@ -1,50 +1,77 @@ #pragma once #include "stdafx.h" #include "Shared/BaseControlDevice.h" +#include "Shared/ControllerHub.h" #include "Utilities/Serializer.h" -class FourScore : public BaseControlDevice +class FourScore : public ControllerHub<4> { private: - uint32_t _signature4016 = 0; - uint32_t _signature4017 = 0; + uint8_t _signature[2] = {}; + uint8_t _sigCounter[2] = {}; protected: void Serialize(Serializer &s) override { - BaseControlDevice::Serialize(s); - s.Stream(_signature4016, _signature4017); + ControllerHub::Serialize(s); + s.Stream(_signature[0], _signature[1], _sigCounter[0], _sigCounter[1]); } void RefreshStateBuffer() override { //Signature for port 0 = 0x10, reversed bit order => 0x08 //Signature for port 1 = 0x20, reversed bit order => 0x04 - _signature4016 = (0x08 << 16); - _signature4017 = (0x04 << 16); + if(GetControllerType() == ControllerType::FourScore) { + _signature[0] = 0x08; + _signature[1] = 0x04; + } else { + //Signature is reversed for Hori 4p adapter + _signature[0] = 0x04; + _signature[1] = 0x08; + } + _sigCounter[0] = 16; + _sigCounter[1] = 16; } + public: - FourScore(Emulator* emu) : BaseControlDevice(emu, ControllerType::FourScore, BaseControlDevice::ExpDevicePort) + FourScore(Emulator* emu, ControllerType type, ControllerConfig controllers[]) : ControllerHub(emu, type, 0, controllers) { } + + void WriteRam(uint16_t addr, uint8_t value) + { + value &= 0x01; + ControllerHub::WriteRam(addr, value); + } uint8_t ReadRam(uint16_t addr) override { StrobeProcessRead(); uint8_t output = 0; - if(addr == 0x4016) { - output = _signature4016 & 0x01; - _signature4016 >>= 1; - } else if(addr == 0x4017) { - output = _signature4017 & 0x01; - _signature4017 >>= 1; + uint8_t i = addr - 0x4016; + + if(_sigCounter[i] > 0) { + _sigCounter[i]--; + + if(_sigCounter[i] < 8) { + i += 2; + } + + if(_ports[i]) { + output |= ReadPort(i); + } + } else { + output |= _signature[i] & 0x01; + _signature[i] = (_signature[i] >> 1) | 0x80; } + + output &= 0x01; + + if(GetControllerType() == ControllerType::FourPlayerAdapter) { + output <<= 1; + } + return output; } - - void WriteRam(uint16_t addr, uint8_t value) override - { - StrobeProcessWrite(value); - } }; diff --git a/Core/NES/Input/NesController.h b/Core/NES/Input/NesController.h index 36f4f5f4..96bddf83 100644 --- a/Core/NES/Input/NesController.h +++ b/Core/NES/Input/NesController.h @@ -13,7 +13,7 @@ private: uint32_t _turboSpeed = 0; protected: - uint32_t _stateBuffer = 0; + uint8_t _stateBuffer = 0; void Serialize(Serializer& s) override { @@ -69,16 +69,7 @@ protected: void RefreshStateBuffer() override { - if(_emu->GetControlManager()->HasControlDevice(ControllerType::FourScore)) { - if(_port >= 2) { - _stateBuffer = ToByte() << 8; - } else { - //Add some 0 bit padding to allow P3/P4 controller bits + signature bits - _stateBuffer = (_port == 0 ? 0xFF000000 : 0xFF000000) | ToByte(); - } - } else { - _stateBuffer = 0xFFFFFF00 | ToByte(); - } + _stateBuffer = ToByte(); } public: @@ -108,21 +99,17 @@ public: { uint8_t output = 0; - if((addr == 0x4016 && (_port & 0x01) == 0) || (addr == 0x4017 && (_port & 0x01) == 1)) { + if(IsCurrentPort(addr)) { StrobeProcessRead(); output = _stateBuffer & 0x01; - if(_port >= 2 && GetControllerType() == ControllerType::FamicomController) { - //Famicom outputs P3 & P4 on bit 1 - output <<= 1; - } _stateBuffer >>= 1; //"All subsequent reads will return D=1 on an authentic controller but may return D=0 on third party controllers." - _stateBuffer |= 0x80000000; + _stateBuffer |= 0x80; } - if(addr == 0x4016 && IsPressed(NesController::Buttons::Microphone)) { + if(addr == 0x4016 && _type == ControllerType::FamicomController && IsPressed(NesController::Buttons::Microphone)) { output |= 0x04; } @@ -134,7 +121,7 @@ public: StrobeProcessWrite(value); } - void DrawController(InputHud& hud) + void InternalDrawController(InputHud& hud) override { hud.DrawOutline(35, 14); @@ -150,6 +137,6 @@ public: hud.DrawButton(13, 9, 4, 2, IsPressed(Buttons::Select)); hud.DrawButton(18, 9, 4, 2, IsPressed(Buttons::Start)); - hud.DrawNumber(_port + 1, 16, 2); + hud.DrawNumber(hud.GetControllerIndex() + 1, 16, 2); } }; \ No newline at end of file diff --git a/Core/NES/Input/TwoPlayerAdapter.h b/Core/NES/Input/TwoPlayerAdapter.h new file mode 100644 index 00000000..22f65292 --- /dev/null +++ b/Core/NES/Input/TwoPlayerAdapter.h @@ -0,0 +1,31 @@ +#pragma once +#include "stdafx.h" +#include "Shared/BaseControlDevice.h" +#include "Shared/ControllerHub.h" +#include "Utilities/Serializer.h" + +class TwoPlayerAdapter : public ControllerHub<2> +{ +public: + TwoPlayerAdapter(Emulator* emu, ControllerType type, ControllerConfig controllers[]) : ControllerHub(emu, type, 0, controllers) + {} + + void WriteRam(uint16_t addr, uint8_t value) + { + value &= 0x01; + ControllerHub::WriteRam(addr, value); + } + + uint8_t ReadRam(uint16_t addr) override + { + StrobeProcessRead(); + uint8_t output = 0; + uint8_t i = addr - 0x4016; + + if(_ports[i]) { + output |= (ReadPort(i) & 0x01) << 1; + } + + return output; + } +}; diff --git a/Core/NES/Input/VsZapper.h b/Core/NES/Input/VsZapper.h index 39855b4a..961184d3 100644 --- a/Core/NES/Input/VsZapper.h +++ b/Core/NES/Input/VsZapper.h @@ -22,7 +22,7 @@ protected: } public: - VsZapper(NesConsole* console, uint8_t port) : Zapper(console, ControllerType::VsZapper, port) + VsZapper(NesConsole* console, uint8_t port) : Zapper(console, ControllerType::NesZapper, port) { } diff --git a/Core/NES/Mappers/VsSystem/VsControlManager.cpp b/Core/NES/Mappers/VsSystem/VsControlManager.cpp index ef49c706..2a56fb89 100644 --- a/Core/NES/Mappers/VsSystem/VsControlManager.cpp +++ b/Core/NES/Mappers/VsSystem/VsControlManager.cpp @@ -29,15 +29,6 @@ VsControlManager::~VsControlManager() UnregisterInputProvider(this); } -ControllerType VsControlManager::GetControllerType(uint8_t port) -{ - ControllerType type = NesControlManager::GetControllerType(port); - if(type == ControllerType::NesZapper) { - type = ControllerType::VsZapper; - } - return type; -} - void VsControlManager::Reset(bool softReset) { NesControlManager::Reset(softReset); diff --git a/Core/NES/Mappers/VsSystem/VsControlManager.h b/Core/NES/Mappers/VsSystem/VsControlManager.h index 4439378c..accba49a 100644 --- a/Core/NES/Mappers/VsSystem/VsControlManager.h +++ b/Core/NES/Mappers/VsSystem/VsControlManager.h @@ -41,7 +41,6 @@ private: }; protected: - ControllerType GetControllerType(uint8_t port) override; void RemapControllerButtons() override; uint8_t GetOpenBusMask(uint8_t port) override; diff --git a/Core/NES/NesControlManager.cpp b/Core/NES/NesControlManager.cpp index a3b2091d..03d35682 100644 --- a/Core/NES/NesControlManager.cpp +++ b/Core/NES/NesControlManager.cpp @@ -17,6 +17,7 @@ #include "NES/Input/Zapper.h" #include "NES/Input/ArkanoidController.h" #include "NES/Input/OekaKidsTablet.h" +#include "NES/Input/TwoPlayerAdapter.h" #include "NES/Input/FourScore.h" #include "NES/Input/PowerPad.h" #include "NES/Input/FamilyMatTrainer.h" @@ -46,29 +47,42 @@ NesControlManager::~NesControlManager() { } -ControllerType NesControlManager::GetControllerType(uint8_t port) -{ - return _emu->GetSettings()->GetNesConfig().Controllers[port].Type; -} - shared_ptr NesControlManager::CreateControllerDevice(ControllerType type, uint8_t port) { shared_ptr device; - NesConfig cfg = _emu->GetSettings()->GetNesConfig(); - KeyMappingSet keys = cfg.Controllers[port].Keys; + ControllerConfig controllers[4]; + NesConfig& cfg = _emu->GetSettings()->GetNesConfig(); + KeyMappingSet keys; + switch(port) { + default: + case 0: keys = cfg.Port1.Keys; break; + case 1: keys = cfg.Port2.Keys; break; + + //Used by VS system + case 2: keys = cfg.Port1SubPorts[2].Keys; break; + case 3: keys = cfg.Port1SubPorts[3].Keys; break; + } switch(type) { case ControllerType::None: break; case ControllerType::NesController: device.reset(new NesController(_emu, type, port, keys)); break; case ControllerType::FamicomController: device.reset(new NesController(_emu, type, port, keys)); break; - case ControllerType::NesZapper: device.reset(new Zapper(_console, type, port)); break; + case ControllerType::NesZapper: { + RomFormat romFormat = _console->GetRomFormat(); + if(romFormat == RomFormat::VsSystem || romFormat == RomFormat::VsDualSystem) { + device.reset(new VsZapper(_console, port)); + } else { + device.reset(new Zapper(_console, type, port)); + } + break; + } + case ControllerType::NesArkanoidController: device.reset(new ArkanoidController(_emu, type, port)); break; case ControllerType::SnesController: device.reset(new SnesController(_emu, port, keys)); break; case ControllerType::PowerPad: device.reset(new PowerPad(_emu, type, port, keys)); break; case ControllerType::SnesMouse: device.reset(new SnesMouse(_emu, port)); break; case ControllerType::SuborMouse: device.reset(new SuborMouse(_emu, port)); break; - case ControllerType::VsZapper: device.reset(new VsZapper(_console, port)); break; case ControllerType::VirtualBoyController: device.reset(new VirtualBoyController(_emu, port, keys)); break; //Exp port devices @@ -76,7 +90,7 @@ shared_ptr NesControlManager::CreateControllerDevice(Controll case ControllerType::FamicomArkanoidController: device.reset(new ArkanoidController(_emu, type, BaseControlDevice::ExpDevicePort)); break; case ControllerType::OekaKidsTablet: device.reset(new OekaKidsTablet(_emu)); break; case ControllerType::FamilyTrainerMat: device.reset(new FamilyMatTrainer(_emu, keys)); break; - case ControllerType::KonamiHyperShot: device.reset(new KonamiHyperShot(_emu, keys, cfg.Controllers[1].Keys)); break; + case ControllerType::KonamiHyperShot: device.reset(new KonamiHyperShot(_emu, keys, cfg.Port2.Keys)); break; case ControllerType::FamilyBasicKeyboard: device.reset(new FamilyBasicKeyboard(_emu, keys)); break; case ControllerType::PartyTap: device.reset(new PartyTap(_emu, keys)); break; case ControllerType::Pachinko: device.reset(new PachinkoController(_emu, keys)); break; @@ -88,9 +102,26 @@ shared_ptr NesControlManager::CreateControllerDevice(Controll case ControllerType::BandaiHyperShot: device.reset(new BandaiHyperShot(_console, keys)); break; case ControllerType::AsciiTurboFile: device.reset(new AsciiTurboFile(_emu)); break; case ControllerType::BattleBox: device.reset(new BattleBox(_emu)); break; - case ControllerType::FourScore: device.reset(new FourScore(_emu)); break; + + case ControllerType::FourScore: { + std::copy(cfg.Port1SubPorts, cfg.Port1SubPorts + 4, controllers); + controllers[0].Keys = cfg.Port1.Keys; + device.reset(new FourScore(_emu, type, controllers)); + break; + } + + case ControllerType::TwoPlayerAdapter: + case ControllerType::FourPlayerAdapter: { + std::copy(cfg.ExpPortSubPorts, cfg.ExpPortSubPorts + 4, controllers); + controllers[0].Keys = cfg.ExpPort.Keys; + if(type == ControllerType::TwoPlayerAdapter) { + device.reset(new TwoPlayerAdapter(_emu, type, controllers)); + } else { + device.reset(new FourScore(_emu, type, controllers)); + } + break; + } - case ControllerType::FourPlayerAdapter: default: break; } @@ -99,7 +130,7 @@ shared_ptr NesControlManager::CreateControllerDevice(Controll void NesControlManager::UpdateControlDevices() { - NesConfig cfg = _emu->GetSettings()->GetNesConfig(); + NesConfig& cfg = _emu->GetSettings()->GetNesConfig(); if(_emu->GetSettings()->IsEqual(_prevConfig, cfg) && _controlDevices.size() > 0) { //Do nothing if configuration is unchanged return; @@ -110,18 +141,15 @@ void NesControlManager::UpdateControlDevices() ClearDevices(); - ControllerType expansionDevice = GetControllerType(BaseControlDevice::ExpDevicePort); - bool allowFourPlayers = (expansionDevice == ControllerType::FourPlayerAdapter || expansionDevice == ControllerType::FourScore); - - for(int i = 0; i < (allowFourPlayers ? 4 : 2); i++) { - shared_ptr device = CreateControllerDevice(GetControllerType(i), i); + for(int i = 0; i < 2; i++) { + shared_ptr device = CreateControllerDevice(i == 0 ? cfg.Port1.Type : cfg.Port2.Type, i); if(device) { RegisterControlDevice(device); } } - if(expansionDevice != ControllerType::None) { - shared_ptr expDevice = CreateControllerDevice(expansionDevice, BaseControlDevice::ExpDevicePort); + if(cfg.ExpPort.Type != ControllerType::None) { + shared_ptr expDevice = CreateControllerDevice(cfg.ExpPort.Type, BaseControlDevice::ExpDevicePort); if(expDevice) { RegisterControlDevice(expDevice); } @@ -231,7 +259,7 @@ void NesControlManager::Reset(bool softReset) void NesControlManager::Serialize(Serializer& s) { //Restore controllers that were being used at the time the snapshot was made - //This is particularely important to ensure proper sync during NetPlay + //This is particularly important to ensure proper sync during NetPlay ControllerType controllerTypes[4]; ExpansionPortDevice expansionDevice; ConsoleType consoleType; diff --git a/Core/NES/NesControlManager.h b/Core/NES/NesControlManager.h index 79d2388e..e25b7e79 100644 --- a/Core/NES/NesControlManager.h +++ b/Core/NES/NesControlManager.h @@ -27,7 +27,6 @@ protected: NesConsole* _console; virtual void Serialize(Serializer& s) override; - virtual ControllerType GetControllerType(uint8_t port); virtual void RemapControllerButtons(); virtual uint8_t GetOpenBusMask(uint8_t port); diff --git a/Core/Netplay/GameServer.cpp b/Core/Netplay/GameServer.cpp index 106bb48c..012fcc54 100644 --- a/Core/Netplay/GameServer.cpp +++ b/Core/Netplay/GameServer.cpp @@ -4,7 +4,6 @@ #include "Netplay/PlayerListMessage.h" #include "Shared/Emulator.h" #include "Shared/Interfaces/IControlManager.h" -#include "SNES/Input/Multitap.h" #include "Shared/NotificationManager.h" #include "Shared/MessageManager.h" #include "Utilities/Socket.h" @@ -61,10 +60,10 @@ bool GameServer::SetInput(BaseControlDevice *device) { uint8_t port = device->GetPort(); - //TODO? if(device->GetControllerType() == ControllerType::Multitap) { + //TODO //Need special handling for the multitap, merge data from P3/4/5 with P1 (or P2, depending which port the multitap is plugged into) - GameServerConnection* connection = GetNetPlayDevice(port); + /*GameServerConnection* connection = GetNetPlayDevice(port); if(connection) { ((Multitap*)device)->SetControllerState(0, connection->GetState()); } @@ -74,7 +73,7 @@ bool GameServer::SetInput(BaseControlDevice *device) if(connection) { ((Multitap*)device)->SetControllerState(i - 1, connection->GetState()); } - } + }*/ } else { GameServerConnection* connection = GetNetPlayDevice(port); if(connection) { diff --git a/Core/SNES/Input/Multitap.cpp b/Core/SNES/Input/Multitap.cpp index 85de9182..a2a60be1 100644 --- a/Core/SNES/Input/Multitap.cpp +++ b/Core/SNES/Input/Multitap.cpp @@ -1,193 +1,31 @@ #include "stdafx.h" #include "SNES/Input/Multitap.h" -#include "SNES/Input/SnesController.h" #include "SNES/SnesConsole.h" #include "SNES/InternalRegisters.h" -#include "Shared/InputHud.h" #include "Shared/Emulator.h" -#include "Shared/EmuSettings.h" -string Multitap::GetKeyNames() +Multitap::Multitap(SnesConsole* console, uint8_t port, ControllerConfig controllers[]) : ControllerHub(console->GetEmulator(), ControllerType::Multitap, port, controllers) { - //Repeat key names 4x, once for each controller - return "ABXYLRSTUDLR:ABXYLRSTUDLR:ABXYLRSTUDLR:ABXYLRSTUDLR"; -} - -void Multitap::InternalSetStateFromInput() -{ - for(int i = 0; i < 4; i++) { - int offset = Multitap::ButtonCount * i; - for(KeyMapping& keyMapping : _mappings[i]) { - SetPressedState(Buttons::A + offset, keyMapping.A); - SetPressedState(Buttons::B + offset, keyMapping.B); - SetPressedState(Buttons::X + offset, keyMapping.X); - SetPressedState(Buttons::Y + offset, keyMapping.Y); - SetPressedState(Buttons::L + offset, keyMapping.L); - SetPressedState(Buttons::R + offset, keyMapping.R); - SetPressedState(Buttons::Start + offset, keyMapping.Start); - SetPressedState(Buttons::Select + offset, keyMapping.Select); - SetPressedState(Buttons::Up + offset, keyMapping.Up); - SetPressedState(Buttons::Down + offset, keyMapping.Down); - SetPressedState(Buttons::Left + offset, keyMapping.Left); - SetPressedState(Buttons::Right + offset, keyMapping.Right); - - uint8_t turboFreq = 1 << (4 - _turboSpeed[i]); - bool turboOn = (uint8_t)(_emu->GetPpuFrame().FrameCount % turboFreq) < turboFreq / 2; - if(turboOn) { - SetPressedState(Buttons::A + offset, keyMapping.TurboA); - SetPressedState(Buttons::B + offset, keyMapping.TurboB); - SetPressedState(Buttons::X + offset, keyMapping.TurboX); - SetPressedState(Buttons::Y + offset, keyMapping.TurboY); - SetPressedState(Buttons::L + offset, keyMapping.TurboL); - SetPressedState(Buttons::R + offset, keyMapping.TurboR); - } - } - } -} - -void Multitap::UpdateControllerState(uint8_t controllerNumber, SnesController &controller) -{ - int offset = Multitap::ButtonCount * controllerNumber; - SetBitValue(Buttons::A + offset, controller.IsPressed(Buttons::A)); - SetBitValue(Buttons::B + offset, controller.IsPressed(Buttons::B)); - SetBitValue(Buttons::X + offset, controller.IsPressed(Buttons::X)); - SetBitValue(Buttons::Y + offset, controller.IsPressed(Buttons::Y)); - SetBitValue(Buttons::L + offset, controller.IsPressed(Buttons::L)); - SetBitValue(Buttons::R + offset, controller.IsPressed(Buttons::R)); - SetBitValue(Buttons::Start + offset, controller.IsPressed(Buttons::Start)); - SetBitValue(Buttons::Select + offset, controller.IsPressed(Buttons::Select)); - SetBitValue(Buttons::Up + offset, controller.IsPressed(Buttons::Up)); - SetBitValue(Buttons::Down + offset, controller.IsPressed(Buttons::Down)); - SetBitValue(Buttons::Left + offset, controller.IsPressed(Buttons::Left)); - SetBitValue(Buttons::Right + offset, controller.IsPressed(Buttons::Right)); -} - -uint16_t Multitap::ToByte(uint8_t port) -{ - //"A Super NES controller returns a 16-bit report in a similar order: B, Y, Select, Start, Up, Down, Left, Right, A, X, L, R, then four 0 bits." - - int offset = port * Multitap::ButtonCount; - - return - (uint8_t)IsPressed(Buttons::B + offset) | - ((uint8_t)IsPressed(Buttons::Y + offset) << 1) | - ((uint8_t)IsPressed(Buttons::Select + offset) << 2) | - ((uint8_t)IsPressed(Buttons::Start + offset) << 3) | - ((uint8_t)IsPressed(Buttons::Up + offset) << 4) | - ((uint8_t)IsPressed(Buttons::Down + offset) << 5) | - ((uint8_t)IsPressed(Buttons::Left + offset) << 6) | - ((uint8_t)IsPressed(Buttons::Right + offset) << 7) | - ((uint8_t)IsPressed(Buttons::A + offset) << 8) | - ((uint8_t)IsPressed(Buttons::X + offset) << 9) | - ((uint8_t)IsPressed(Buttons::L + offset) << 10) | - ((uint8_t)IsPressed(Buttons::R + offset) << 11); -} - -void Multitap::Serialize(Serializer & s) -{ - BaseControlDevice::Serialize(s); - s.Stream(_stateBuffer[0], _stateBuffer[1], _stateBuffer[2], _stateBuffer[3]); -} - -void Multitap::RefreshStateBuffer() -{ - for(int i = 0; i < 4; i++) { - _stateBuffer[i] = ToByte(i); - } -} - -Multitap::Multitap(SnesConsole* console, uint8_t port, KeyMappingSet keyMappings1, KeyMappingSet keyMappings2, KeyMappingSet keyMappings3, KeyMappingSet keyMappings4) : BaseControlDevice(console->GetEmulator(), ControllerType::Multitap, port, keyMappings1) -{ - _turboSpeed[0] = keyMappings1.TurboSpeed; - _turboSpeed[1] = keyMappings2.TurboSpeed; - _turboSpeed[2] = keyMappings3.TurboSpeed; - _turboSpeed[3] = keyMappings4.TurboSpeed; - - _mappings[0] = keyMappings1.GetKeyMappingArray(); - _mappings[1] = keyMappings2.GetKeyMappingArray(); - _mappings[2] = keyMappings3.GetKeyMappingArray(); - _mappings[3] = keyMappings4.GetKeyMappingArray(); _internalRegs = console->GetInternalRegisters(); } -void Multitap::SetControllerState(uint8_t controllerNumber, ControlDeviceState state) -{ - SnesController controller(_emu, 0, KeyMappingSet()); - controller.SetRawState(state); - UpdateControllerState(controllerNumber, controller); -} - uint8_t Multitap::ReadRam(uint16_t addr) { - uint8_t selectBit = 0x80 >> ((_port == 0) ? 1 : 0); - uint8_t portSelect = (_internalRegs->GetIoPortOutput() & selectBit) ? 0 : 2; uint8_t output = 0; if(IsCurrentPort(addr)) { StrobeProcessRead(); - output = _stateBuffer[portSelect] & 0x01; - output |= (_stateBuffer[portSelect + 1] & 0x01) << 1; //P3 & P5 are reported in bit 1 + uint8_t selectBit = 0x80 >> ((_port == 0) ? 1 : 0); + uint8_t portSelect = (_internalRegs->GetIoPortOutput() & selectBit) ? 0 : 2; + output = ReadPort(portSelect) & 0x01; + output |= (ReadPort(portSelect + 1) & 0x01) << 1; //P3 & P5 are reported in bit 1 if(_strobe) { - //Bit 1 is always set when strobe is high - output |= 0x02; + //Bit 1 is always set and bit 0 is always clear (when strobe is high) + return 0x02; } - - _stateBuffer[portSelect] >>= 1; - _stateBuffer[portSelect + 1] >>= 1; - - //"All subsequent reads will return D=1 on an authentic controller but may return D=0 on third party controllers." - _stateBuffer[portSelect] |= 0x8000; - _stateBuffer[portSelect + 1] |= 0x8000; } return output; } - -void Multitap::WriteRam(uint16_t addr, uint8_t value) -{ - if(addr == 0x4016) { - StrobeProcessWrite(value); - } -} - -void Multitap::DrawController(InputHud& hud) -{ - InputConfig& cfg = _emu->GetSettings()->GetInputConfig(); - - for(int j = 0; j < 4; j++) { - int port = j == 0 ? _port : (j + 1); - if(cfg.DisplayInputPort[port]) { - DrawController(hud, port); - } - } -} - -void Multitap::DrawController(InputHud& hud, int port) -{ - int offset = port * Multitap::ButtonCount; - - hud.DrawOutline(35, 14); - - hud.DrawButton(5, 3, 3, 3, IsPressed(Buttons::Up + offset)); - hud.DrawButton(5, 9, 3, 3, IsPressed(Buttons::Down + offset)); - hud.DrawButton(2, 6, 3, 3, IsPressed(Buttons::Left + offset)); - hud.DrawButton(8, 6, 3, 3, IsPressed(Buttons::Right + offset)); - hud.DrawButton(5, 6, 3, 3, false); - - hud.DrawButton(27, 3, 3, 3, IsPressed(Buttons::X + offset)); - hud.DrawButton(27, 9, 3, 3, IsPressed(Buttons::B + offset)); - hud.DrawButton(30, 6, 3, 3, IsPressed(Buttons::A + offset)); - hud.DrawButton(24, 6, 3, 3, IsPressed(Buttons::Y + offset)); - - hud.DrawButton(4, 0, 5, 2, IsPressed(Buttons::L + offset)); - hud.DrawButton(26, 0, 5, 2, IsPressed(Buttons::R + offset)); - - hud.DrawButton(13, 9, 4, 2, IsPressed(Buttons::Select + offset)); - hud.DrawButton(18, 9, 4, 2, IsPressed(Buttons::Start + offset)); - - hud.DrawNumber(port + 1, 16, 2); - - hud.EndDrawController(); -} \ No newline at end of file diff --git a/Core/SNES/Input/Multitap.h b/Core/SNES/Input/Multitap.h index 98affe7f..86d5a58c 100644 --- a/Core/SNES/Input/Multitap.h +++ b/Core/SNES/Input/Multitap.h @@ -1,41 +1,18 @@ #pragma once #include "stdafx.h" #include "Shared/BaseControlDevice.h" -#include "Utilities/Serializer.h" +#include "Shared/ControllerHub.h" class InternalRegisters; -class SnesController; class SnesConsole; -class InputHud; -class Multitap : public BaseControlDevice +class Multitap : public ControllerHub<4> { private: - enum Buttons { A = 0, B, X, Y, L, R, Select, Start, Up, Down, Left, Right }; - static constexpr int ButtonCount = 12; - - vector _mappings[4]; - uint8_t _turboSpeed[4] = {}; - uint16_t _stateBuffer[4] = {}; InternalRegisters *_internalRegs = nullptr; - void DrawController(InputHud& hud, int port); - -protected: - string GetKeyNames() override; - void InternalSetStateFromInput() override; - void UpdateControllerState(uint8_t controllerNumber, SnesController &controller); - uint16_t ToByte(uint8_t port); - void Serialize(Serializer &s) override; - void RefreshStateBuffer() override; - public: - Multitap(SnesConsole* console, uint8_t port, KeyMappingSet keyMappings1, KeyMappingSet keyMappings2, KeyMappingSet keyMappings3, KeyMappingSet keyMappings4); - - void SetControllerState(uint8_t controllerNumber, ControlDeviceState state); + Multitap(SnesConsole* console, uint8_t port, ControllerConfig controllers[]); uint8_t ReadRam(uint16_t addr) override; - void WriteRam(uint16_t addr, uint8_t value) override; - - void DrawController(InputHud& hud) override; }; \ No newline at end of file diff --git a/Core/SNES/Input/SnesController.cpp b/Core/SNES/Input/SnesController.cpp index 35209156..93da295a 100644 --- a/Core/SNES/Input/SnesController.cpp +++ b/Core/SNES/Input/SnesController.cpp @@ -98,7 +98,7 @@ void SnesController::WriteRam(uint16_t addr, uint8_t value) StrobeProcessWrite(value); } -void SnesController::DrawController(InputHud& hud) +void SnesController::InternalDrawController(InputHud& hud) { hud.DrawOutline(35, 14); @@ -119,5 +119,5 @@ void SnesController::DrawController(InputHud& hud) hud.DrawButton(13, 9, 4, 2, IsPressed(Buttons::Select)); hud.DrawButton(18, 9, 4, 2, IsPressed(Buttons::Start)); - hud.DrawNumber(_port + 1, 16, 2); + hud.DrawNumber(hud.GetControllerIndex() + 1, 16, 2); } diff --git a/Core/SNES/Input/SnesController.h b/Core/SNES/Input/SnesController.h index 307fa637..49ca0604 100644 --- a/Core/SNES/Input/SnesController.h +++ b/Core/SNES/Input/SnesController.h @@ -24,5 +24,5 @@ public: uint8_t ReadRam(uint16_t addr) override; void WriteRam(uint16_t addr, uint8_t value) override; - void DrawController(InputHud& hud) override; + void InternalDrawController(InputHud& hud) override; }; \ No newline at end of file diff --git a/Core/SNES/Input/SnesMouse.h b/Core/SNES/Input/SnesMouse.h index c290a2b9..b792e576 100644 --- a/Core/SNES/Input/SnesMouse.h +++ b/Core/SNES/Input/SnesMouse.h @@ -87,13 +87,13 @@ public: _stateBuffer = (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4; } - void DrawController(InputHud& hud) + void InternalDrawController(InputHud& hud) override { hud.DrawOutline(11, 14); hud.DrawButton(1, 1, 4, 5, IsPressed(Buttons::Left)); hud.DrawButton(6, 1, 4, 5, IsPressed(Buttons::Right)); - hud.DrawNumber(_port + 1, 4, 7); + hud.DrawNumber(hud.GetControllerIndex() + 1, 4, 7); } }; \ No newline at end of file diff --git a/Core/SNES/SnesControlManager.cpp b/Core/SNES/SnesControlManager.cpp index 4036375a..5bc06476 100644 --- a/Core/SNES/SnesControlManager.cpp +++ b/Core/SNES/SnesControlManager.cpp @@ -26,23 +26,34 @@ SnesControlManager::~SnesControlManager() { } -ControllerType SnesControlManager::GetControllerType(uint8_t port) -{ - return _emu->GetSettings()->GetSnesConfig().Controllers[port].Type; -} - shared_ptr SnesControlManager::CreateControllerDevice(ControllerType type, uint8_t port) { shared_ptr device; - SnesConfig cfg = _emu->GetSettings()->GetSnesConfig(); + SnesConfig& cfg = _emu->GetSettings()->GetSnesConfig(); switch(type) { case ControllerType::None: break; - case ControllerType::SnesController: device.reset(new SnesController(_emu, port, cfg.Controllers[port].Keys)); break; + case ControllerType::SnesController: + device.reset(new SnesController(_emu, port, port == 0 ? cfg.Port1.Keys : cfg.Port2.Keys)); + break; + case ControllerType::SnesMouse: device.reset(new SnesMouse(_emu, port)); break; - case ControllerType::SuperScope: device.reset(new SuperScope(_console, port, cfg.Controllers[port].Keys)); break; - case ControllerType::Multitap: device.reset(new Multitap(_console, port, cfg.Controllers[port].Keys, cfg.Controllers[2].Keys, cfg.Controllers[3].Keys, cfg.Controllers[4].Keys)); break; + + case ControllerType::SuperScope: device.reset(new SuperScope(_console, port, port == 0 ? cfg.Port1.Keys : cfg.Port2.Keys)); break; + + case ControllerType::Multitap: { + ControllerConfig controllers[4]; + if(port == 0) { + std::copy(cfg.Port1SubPorts, cfg.Port1SubPorts + 4, controllers); + controllers[0].Keys = cfg.Port1.Keys; + } else { + std::copy(cfg.Port2SubPorts, cfg.Port2SubPorts + 4, controllers); + controllers[0].Keys = cfg.Port2.Keys; + } + device.reset(new Multitap(_console, port, controllers)); + break; + } default: throw std::runtime_error("Unsupported controller type"); @@ -53,7 +64,7 @@ shared_ptr SnesControlManager::CreateControllerDevice(Control void SnesControlManager::UpdateControlDevices() { - SnesConfig cfg = _emu->GetSettings()->GetSnesConfig(); + SnesConfig& cfg = _emu->GetSettings()->GetSnesConfig(); if(_emu->GetSettings()->IsEqual(_prevConfig, cfg) && _controlDevices.size() > 0) { //Do nothing if configuration is unchanged return; @@ -62,7 +73,7 @@ void SnesControlManager::UpdateControlDevices() auto lock = _deviceLock.AcquireSafe(); ClearDevices(); for(int i = 0; i < 2; i++) { - shared_ptr device = CreateControllerDevice(GetControllerType(i), i); + shared_ptr device = CreateControllerDevice(i == 0 ? cfg.Port1.Type : cfg.Port2.Type, i); if(device) { RegisterControlDevice(device); } @@ -88,8 +99,9 @@ void SnesControlManager::Write(uint16_t addr, uint8_t value) void SnesControlManager::Serialize(Serializer &s) { - SnesConfig cfg = _emu->GetSettings()->GetSnesConfig(); - s.Stream(cfg.Controllers[0].Type, cfg.Controllers[1].Type, cfg.Controllers[2].Type, cfg.Controllers[3].Type, cfg.Controllers[4].Type); + SnesConfig& cfg = _emu->GetSettings()->GetSnesConfig(); + //TODO + //s.Stream(cfg.Controllers[0].Type, cfg.Controllers[1].Type, cfg.Controllers[2].Type, cfg.Controllers[3].Type, cfg.Controllers[4].Type); if(!s.IsSaving()) { _emu->GetSettings()->SetSnesConfig(cfg); UpdateControlDevices(); diff --git a/Core/SNES/SnesControlManager.h b/Core/SNES/SnesControlManager.h index 64331750..5032c3f6 100644 --- a/Core/SNES/SnesControlManager.h +++ b/Core/SNES/SnesControlManager.h @@ -25,8 +25,6 @@ private: protected: SnesConsole* _console; - ControllerType GetControllerType(uint8_t port); - public: SnesControlManager(SnesConsole* console); virtual ~SnesControlManager(); diff --git a/Core/Shared/BaseControlDevice.cpp b/Core/Shared/BaseControlDevice.cpp index 9bccf9de..fc5e6f39 100644 --- a/Core/Shared/BaseControlDevice.cpp +++ b/Core/Shared/BaseControlDevice.cpp @@ -3,6 +3,7 @@ #include "Shared/Emulator.h" #include "Shared/KeyManager.h" #include "Shared/EmuSettings.h" +#include "Shared/InputHud.h" #include "Utilities/StringUtilities.h" #include "Utilities/Serializer.h" @@ -78,6 +79,15 @@ ControlDeviceState BaseControlDevice::GetRawState() return _state; } +void BaseControlDevice::DrawController(InputHud& hud) +{ + InputConfig& cfg = _emu->GetSettings()->GetInputConfig(); + if(hud.GetControllerIndex() < 8 && cfg.DisplayInputPort[hud.GetControllerIndex()]) { + InternalDrawController(hud); + } + hud.EndDrawController(); +} + void BaseControlDevice::SetRawState(ControlDeviceState state) { auto lock = _stateLock.AcquireSafe(); diff --git a/Core/Shared/BaseControlDevice.h b/Core/Shared/BaseControlDevice.h index 504aec01..fdfcc2d2 100644 --- a/Core/Shared/BaseControlDevice.h +++ b/Core/Shared/BaseControlDevice.h @@ -12,9 +12,10 @@ class InputHud; class BaseControlDevice : public ISerializable { private: - ControlDeviceState _state = {}; protected: + ControlDeviceState _state = {}; + Emulator* _emu = nullptr; vector _keyMappings; bool _strobe = false; @@ -24,7 +25,7 @@ protected: SimpleLock _stateLock; virtual void RefreshStateBuffer() { } - + void EnsureCapacity(int32_t minBitCount); uint32_t GetByteIndex(uint8_t bit); virtual bool HasCoordinates(); @@ -44,9 +45,9 @@ protected: void SetMovement(MouseMovement mov); MouseMovement GetMovement(); - + virtual void InternalSetStateFromInput(); - + public: static constexpr uint8_t ExpDevicePort = 4; static constexpr uint8_t ConsoleInputPort = 5; @@ -73,16 +74,17 @@ public: void InvertBit(uint8_t bit); void SetBitValue(uint8_t bit, bool set); - void SetTextState(string state); - string GetTextState(); + virtual void SetTextState(string state); + virtual string GetTextState(); void SetStateFromInput(); virtual void OnAfterSetState() { } - void SetRawState(ControlDeviceState state); - ControlDeviceState GetRawState(); + virtual void SetRawState(ControlDeviceState state); + virtual ControlDeviceState GetRawState(); - virtual void DrawController(InputHud& hud) {} + virtual void InternalDrawController(InputHud& hud) {} + virtual void DrawController(InputHud& hud); virtual uint8_t ReadRam(uint16_t addr) = 0; virtual void WriteRam(uint16_t addr, uint8_t value) = 0; diff --git a/Core/Shared/ControllerHub.h b/Core/Shared/ControllerHub.h new file mode 100644 index 00000000..edaff7cd --- /dev/null +++ b/Core/Shared/ControllerHub.h @@ -0,0 +1,138 @@ +#pragma once + +#include "stdafx.h" +#include "Shared/BaseControlDevice.h" +#include "Shared/InputHud.h" +#include "SNES/Input/SnesController.h" +#include "SNES/Input/SnesMouse.h" +#include "NES/Input/NesController.h" +#include "Utilities/Serializer.h" +#include "Utilities/StringUtilities.h" + +template +class ControllerHub : public BaseControlDevice +{ +protected: + shared_ptr _ports[HubPortCount]; + + void InternalSetStateFromInput() override + { + for(int i = 0; i < HubPortCount; i++) { + if(_ports[i]) { + _ports[i]->SetStateFromInput(); + } + } + + UpdateStateFromPorts(); + } + + void UpdateStateFromPorts() + { + for(int i = 0; i < HubPortCount; i++) { + if(_ports[i]) { + ControlDeviceState portState = _ports[i]->GetRawState(); + _state.State.push_back((uint8_t)portState.State.size()); + _state.State.insert(_state.State.end(), portState.State.begin(), portState.State.end()); + } + } + } + + uint8_t ReadPort(int i) + { + return _ports[i]->ReadRam(0x4016); + } + +public: + ControllerHub(Emulator* emu, ControllerType type, int port, ControllerConfig controllers[]) : BaseControlDevice(emu, type, port) + { + for(int i = 0; i < HubPortCount; i++) { + switch(controllers[i].Type) { + case ControllerType::FamicomController: + case ControllerType::NesController: + _ports[i].reset(new NesController(emu, controllers[i].Type, 0, controllers[i].Keys)); + break; + + case ControllerType::SnesController: + _ports[i].reset(new SnesController(emu, 0, controllers[i].Keys)); + break; + + case ControllerType::SnesMouse: + _ports[i].reset(new SnesMouse(emu, 0)); + break; + } + } + + } + + void WriteRam(uint16_t addr, uint8_t value) override + { + StrobeProcessWrite(value); + for(int i = 0; i < HubPortCount; i++) { + if(_ports[i]) { + _ports[i]->WriteRam(addr, value); + } + } + } + + void DrawController(InputHud& hud) override + { + for(int i = 0; i < HubPortCount; i++) { + if(_ports[i]) { + _ports[i]->DrawController(hud); + } else { + hud.EndDrawController(); + } + } + } + + void SetTextState(string state) override + { + vector portStates = StringUtilities::Split(state, ':'); + int i = 0; + for(string& portState : portStates) { + if(_ports[i]) { + _ports[i]->SetTextState(portState); + } + i++; + } + + UpdateStateFromPorts(); + } + + string GetTextState() override + { + auto lock = _stateLock.AcquireSafe(); + + string state; + for(int i = 0; i < HubPortCount; i++) { + if(i != 0) { + state += ":"; + } + if(_ports[i]) { + state += _ports[i]->GetTextState(); + } + } + + return state; + } + + void SetRawState(ControlDeviceState state) override + { + auto lock = _stateLock.AcquireSafe(); + _state = state; + + vector data = state.State; + int pos = 0; + + for(int i = 0; i < HubPortCount; i++) { + if(_ports[i]) { + int length = data[pos++]; + + ControlDeviceState portState; + portState.State.insert(portState.State.begin(), data.begin() + pos, data.begin() + pos + length); + _ports[i]->SetRawState(portState); + pos += length; + } + } + } +}; diff --git a/Core/Shared/InputHud.cpp b/Core/Shared/InputHud.cpp index 869fc4e1..b8f20183 100644 --- a/Core/Shared/InputHud.cpp +++ b/Core/Shared/InputHud.cpp @@ -59,6 +59,24 @@ void InputHud::DrawNumber(int number, int x, int y) _hud->DrawLine(x + _xOffset, 4 + y + _yOffset, x+2 + _xOffset, 4 + y + _yOffset, color[0], 1); break; + case 6: + _hud->DrawLine(x + _xOffset, y + _yOffset, x + 2 + _xOffset, y + _yOffset, color[0], 1); + _hud->DrawLine(x + _xOffset, 1 + y + _yOffset, x + _xOffset, y + _yOffset + 3, color[0], 1); + _hud->DrawLine(x + _xOffset, 2 + y + _yOffset, x + 2 + _xOffset, 2 + y + _yOffset, color[0], 1); + _hud->DrawPixel(x + 2 + _xOffset, 3 + y + _yOffset, color[0], 1); + _hud->DrawLine(x + _xOffset, 4 + y + _yOffset, x + 2 + _xOffset, 4 + y + _yOffset, color[0], 1); + break; + + case 7: + _hud->DrawLine(x + _xOffset, y + _yOffset, x + 2 + _xOffset, y + _yOffset, color[0], 1); + _hud->DrawLine(x + _xOffset + 2, y + _yOffset, x + _xOffset + 2, 4 + y + _yOffset, color[0], 1); + break; + + case 8: + _hud->DrawRectangle(x + _xOffset, y + _yOffset, 3, 5, color[0], false, 1); + _hud->DrawPixel(x + _xOffset + 1, y + _yOffset + 2, color[0], 1); + break; + default: break; } @@ -108,7 +126,6 @@ void InputHud::DrawController(ControllerData& data) controller->SetRawState(data.State); controller->DrawController(*this); - EndDrawController(); } void InputHud::EndDrawController() @@ -152,6 +169,8 @@ void InputHud::EndDrawController() _outlineWidth = 0; _outlineHeight = 0; } + + _controllerIndex++; } void InputHud::DrawControllers(FrameInfo size, vector controllerData) @@ -178,6 +197,7 @@ void InputHud::DrawControllers(FrameInfo size, vector controller break; } + _controllerIndex = 0; for(ControllerData& portData : controllerData) { DrawController(portData); } diff --git a/Core/Shared/InputHud.h b/Core/Shared/InputHud.h index ca66a177..c5a19466 100644 --- a/Core/Shared/InputHud.h +++ b/Core/Shared/InputHud.h @@ -16,6 +16,7 @@ private: int _yOffset = 0; int _outlineWidth = 0; int _outlineHeight = 0; + int _controllerIndex = 0; void DrawController(ControllerData& data); @@ -27,5 +28,7 @@ public: void DrawNumber(int number, int x, int y); void EndDrawController(); + int GetControllerIndex() { return _controllerIndex; } + void DrawControllers(FrameInfo size, vector controllerData); }; \ No newline at end of file diff --git a/Core/Shared/SettingTypes.h b/Core/Shared/SettingTypes.h index 05445a10..47e6bbb6 100644 --- a/Core/Shared/SettingTypes.h +++ b/Core/Shared/SettingTypes.h @@ -163,12 +163,12 @@ enum class ControllerType NesArkanoidController, PowerPad, SuborMouse, - VsZapper, VirtualBoyController, //NES/Famicon expansion devices FourScore, FamicomZapper, + TwoPlayerAdapter, FourPlayerAdapter, FamicomArkanoidController, OekaKidsTablet, @@ -279,7 +279,7 @@ struct InputConfig uint32_t MouseSensitivity = 1; InputDisplayPosition DisplayInputPosition = InputDisplayPosition::TopLeft; - bool DisplayInputPort[5] = { false, false, false, false, false}; + bool DisplayInputPort[8] = { }; bool DisplayInputHorizontally = true; }; @@ -347,7 +347,11 @@ struct GameboyConfig struct SnesConfig { - ControllerConfig Controllers[5]; + ControllerConfig Port1; + ControllerConfig Port2; + + ControllerConfig Port1SubPorts[4]; + ControllerConfig Port2SubPorts[4]; ConsoleRegion Region = ConsoleRegion::Auto; @@ -402,7 +406,13 @@ enum class NesConsoleType struct NesConfig { - ControllerConfig Controllers[5] = {}; + ControllerConfig Port1; + ControllerConfig Port2; + ControllerConfig ExpPort; + + ControllerConfig Port1SubPorts[4]; + ControllerConfig ExpPortSubPorts[4]; + uint32_t ZapperDetectionRadius = 0; ConsoleRegion Region = ConsoleRegion::Auto; diff --git a/NewUI/Config/InputConfig.cs b/NewUI/Config/InputConfig.cs index 0f1eab21..36f52b0c 100644 --- a/NewUI/Config/InputConfig.cs +++ b/NewUI/Config/InputConfig.cs @@ -22,6 +22,9 @@ namespace Mesen.Config [Reactive] public bool DisplayInputPort3 { get; set; } = false; [Reactive] public bool DisplayInputPort4 { get; set; } = false; [Reactive] public bool DisplayInputPort5 { get; set; } = false; + [Reactive] public bool DisplayInputPort6 { get; set; } = false; + [Reactive] public bool DisplayInputPort7 { get; set; } = false; + [Reactive] public bool DisplayInputPort8 { get; set; } = false; [Reactive] public bool DisplayInputHorizontally { get; set; } = true; public InputConfig() @@ -39,6 +42,9 @@ namespace Mesen.Config DisplayInputPort3 = this.DisplayInputPort3, DisplayInputPort4 = this.DisplayInputPort4, DisplayInputPort5 = this.DisplayInputPort5, + DisplayInputPort6 = this.DisplayInputPort6, + DisplayInputPort7 = this.DisplayInputPort7, + DisplayInputPort8 = this.DisplayInputPort8, DisplayInputHorizontally = this.DisplayInputHorizontally }); } @@ -193,6 +199,9 @@ namespace Mesen.Config [MarshalAs(UnmanagedType.I1)] public bool DisplayInputPort3; [MarshalAs(UnmanagedType.I1)] public bool DisplayInputPort4; [MarshalAs(UnmanagedType.I1)] public bool DisplayInputPort5; + [MarshalAs(UnmanagedType.I1)] public bool DisplayInputPort6; + [MarshalAs(UnmanagedType.I1)] public bool DisplayInputPort7; + [MarshalAs(UnmanagedType.I1)] public bool DisplayInputPort8; [MarshalAs(UnmanagedType.I1)] public bool DisplayInputHorizontally; } @@ -259,12 +268,12 @@ namespace Mesen.Config NesArkanoidController, PowerPad, SuborMouse, - VsZapper, VbController, //NES/Famicon expansion devices FourScore, FamicomZapper, + TwoPlayerAdapter, FourPlayerAdapter, FamicomArkanoidController, OekaKidsTablet, @@ -288,6 +297,33 @@ namespace Mesen.Config public static class ControllerTypeExtensions { + public static bool HasPresets(this ControllerType type) + { + switch(type) { + case ControllerType.SnesController: + case ControllerType.NesController: + case ControllerType.GameboyController: + return true; + } + + return false; + } + + public static bool HasTurbo(this ControllerType type) + { + switch(type) { + case ControllerType.SnesController: + case ControllerType.NesController: + case ControllerType.GameboyController: + case ControllerType.HoriTrack: + case ControllerType.Pachinko: + case ControllerType.KonamiHyperShot: + return true; + } + + return false; + } + public static bool CanConfigure(this ControllerType type) { switch(type) { @@ -303,6 +339,9 @@ namespace Mesen.Config case ControllerType.JissenMahjong: case ControllerType.ExcitingBoxing: case ControllerType.GameboyController: + //TODO + //case ControllerType.HoriTrack: + //case ControllerType.KonamiHyperShot: return true; } diff --git a/NewUI/Config/NesConfig.cs b/NewUI/Config/NesConfig.cs index e0970e83..33ade080 100644 --- a/NewUI/Config/NesConfig.cs +++ b/NewUI/Config/NesConfig.cs @@ -13,7 +13,20 @@ namespace Mesen.Config public class NesConfig : BaseConfig { //Input - [Reactive] public List Controllers { get; set; } = new List { new (), new (), new (), new (), new () }; + [Reactive] public NesControllerConfig Port1 { get; set; } = new(); + [Reactive] public NesControllerConfig Port2 { get; set; } = new(); + [Reactive] public NesControllerConfig ExpPort { get; set; } = new(); + + [Reactive] public NesControllerConfig Port1A { get; set; } = new(); + [Reactive] public NesControllerConfig Port1B { get; set; } = new(); + [Reactive] public NesControllerConfig Port1C { get; set; } = new(); + [Reactive] public NesControllerConfig Port1D { get; set; } = new(); + + [Reactive] public NesControllerConfig ExpPortA { get; set; } = new(); + [Reactive] public NesControllerConfig ExpPortB { get; set; } = new(); + [Reactive] public NesControllerConfig ExpPortC { get; set; } = new(); + [Reactive] public NesControllerConfig ExpPortD { get; set; } = new(); + [Reactive] public UInt32 ZapperDetectionRadius { get; set; } = 0; //General @@ -111,13 +124,20 @@ namespace Mesen.Config bool isFullPalette = UserPalette.Length == 512; ConfigApi.SetNesConfig(new InteropNesConfig() { - Controllers = new InteropControllerConfig[5] { - this.Controllers[0].ToInterop(), - this.Controllers[1].ToInterop(), - this.Controllers[2].ToInterop(), - this.Controllers[3].ToInterop(), - this.Controllers[4].ToInterop() - }, + Port1 = Port1.ToInterop(), + Port1A = Port1A.ToInterop(), + Port1B = Port1B.ToInterop(), + Port1C = Port1C.ToInterop(), + Port1D = Port1D.ToInterop(), + + Port2 = Port2.ToInterop(), + + ExpPort = ExpPort.ToInterop(), + ExpPortA = ExpPortA.ToInterop(), + ExpPortB = ExpPortB.ToInterop(), + ExpPortC = ExpPortC.ToInterop(), + ExpPortD = ExpPortD.ToInterop(), + ZapperDetectionRadius = ZapperDetectionRadius, Region = Region, @@ -230,16 +250,16 @@ namespace Mesen.Config mappings.Add(mapping); } - Controllers[0].Type = ControllerType.NesController; - Controllers[0].TurboSpeed = 2; + Port1.Type = ControllerType.NesController; + Port1.TurboSpeed = 2; if(mappings.Count > 0) { - Controllers[0].Mapping1 = mappings[0]; + Port1.Mapping1 = mappings[0]; if(mappings.Count > 1) { - Controllers[0].Mapping2 = mappings[1]; + Port1.Mapping2 = mappings[1]; if(mappings.Count > 2) { - Controllers[0].Mapping3 = mappings[2]; + Port1.Mapping3 = mappings[2]; if(mappings.Count > 3) { - Controllers[0].Mapping4 = mappings[3]; + Port1.Mapping4 = mappings[3]; } } } @@ -250,7 +270,20 @@ namespace Mesen.Config [StructLayout(LayoutKind.Sequential)] public struct InteropNesConfig { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] public InteropControllerConfig[] Controllers; + public InteropControllerConfig Port1; + public InteropControllerConfig Port2; + public InteropControllerConfig ExpPort; + + public InteropControllerConfig Port1A; + public InteropControllerConfig Port1B; + public InteropControllerConfig Port1C; + public InteropControllerConfig Port1D; + + public InteropControllerConfig ExpPortA; + public InteropControllerConfig ExpPortB; + public InteropControllerConfig ExpPortC; + public InteropControllerConfig ExpPortD; + public UInt32 ZapperDetectionRadius; public ConsoleRegion Region; diff --git a/NewUI/Config/SnesConfig.cs b/NewUI/Config/SnesConfig.cs index 9ac2ecac..6bc8e3a4 100644 --- a/NewUI/Config/SnesConfig.cs +++ b/NewUI/Config/SnesConfig.cs @@ -12,7 +12,18 @@ namespace Mesen.Config public class SnesConfig : BaseConfig { //Input - [Reactive] public List Controllers { get; set; } = new List { new ControllerConfig(), new ControllerConfig(), new ControllerConfig(), new ControllerConfig(), new ControllerConfig() }; + [Reactive] public ControllerConfig Port1 { get; set; } = new ControllerConfig(); + [Reactive] public ControllerConfig Port2 { get; set; } = new ControllerConfig(); + + [Reactive] public ControllerConfig Port1A { get; set; } = new ControllerConfig(); + [Reactive] public ControllerConfig Port1B { get; set; } = new ControllerConfig(); + [Reactive] public ControllerConfig Port1C { get; set; } = new ControllerConfig(); + [Reactive] public ControllerConfig Port1D { get; set; } = new ControllerConfig(); + + [Reactive] public ControllerConfig Port2A { get; set; } = new ControllerConfig(); + [Reactive] public ControllerConfig Port2B { get; set; } = new ControllerConfig(); + [Reactive] public ControllerConfig Port2C { get; set; } = new ControllerConfig(); + [Reactive] public ControllerConfig Port2D { get; set; } = new ControllerConfig(); [Reactive] public ConsoleRegion Region { get; set; } = ConsoleRegion.Auto; @@ -50,23 +61,18 @@ namespace Mesen.Config public void ApplyConfig() { - while(Controllers.Count < 5) { - Controllers.Add(new ControllerConfig()); - } - - //Force SNES controllers for multitap - Controllers[2].Type = ControllerType.SnesController; - Controllers[3].Type = ControllerType.SnesController; - Controllers[4].Type = ControllerType.SnesController; - ConfigApi.SetSnesConfig(new InteropSnesConfig() { - Controllers = new InteropControllerConfig[5] { - this.Controllers[0].ToInterop(), - this.Controllers[1].ToInterop(), - this.Controllers[2].ToInterop(), - this.Controllers[3].ToInterop(), - this.Controllers[4].ToInterop() - }, + Port1 = Port1.ToInterop(), + Port1A = Port1A.ToInterop(), + Port1B = Port1B.ToInterop(), + Port1C = Port1C.ToInterop(), + Port1D = Port1D.ToInterop(), + + Port2 = Port2.ToInterop(), + Port2A = Port2A.ToInterop(), + Port2B = Port2B.ToInterop(), + Port2C = Port2C.ToInterop(), + Port2D = Port2D.ToInterop(), Region = this.Region, @@ -119,16 +125,16 @@ namespace Mesen.Config mappings.Add(mapping); } - Controllers[0].Type = ControllerType.SnesController; - Controllers[0].TurboSpeed = 2; + Port1.Type = ControllerType.SnesController; + Port1.TurboSpeed = 2; if(mappings.Count > 0) { - Controllers[0].Mapping1 = mappings[0]; + Port1.Mapping1 = mappings[0]; if(mappings.Count > 1) { - Controllers[0].Mapping2 = mappings[1]; + Port1.Mapping2 = mappings[1]; if(mappings.Count > 2) { - Controllers[0].Mapping3 = mappings[2]; + Port1.Mapping3 = mappings[2]; if(mappings.Count > 3) { - Controllers[0].Mapping4 = mappings[3]; + Port1.Mapping4 = mappings[3]; } } } @@ -139,8 +145,18 @@ namespace Mesen.Config [StructLayout(LayoutKind.Sequential)] public struct InteropSnesConfig { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] - public InteropControllerConfig[] Controllers; + public InteropControllerConfig Port1; + public InteropControllerConfig Port2; + + public InteropControllerConfig Port1A; + public InteropControllerConfig Port1B; + public InteropControllerConfig Port1C; + public InteropControllerConfig Port1D; + + public InteropControllerConfig Port2A; + public InteropControllerConfig Port2B; + public InteropControllerConfig Port2C; + public InteropControllerConfig Port2D; public ConsoleRegion Region; diff --git a/NewUI/Controls/InputComboBox.axaml b/NewUI/Controls/InputComboBox.axaml new file mode 100644 index 00000000..baf2700d --- /dev/null +++ b/NewUI/Controls/InputComboBox.axaml @@ -0,0 +1,29 @@ + + + +