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 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/NewUI/Controls/InputComboBox.axaml.cs b/NewUI/Controls/InputComboBox.axaml.cs
new file mode 100644
index 00000000..5b6c17ac
--- /dev/null
+++ b/NewUI/Controls/InputComboBox.axaml.cs
@@ -0,0 +1,81 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Data;
+using Avalonia.Interactivity;
+using Avalonia.Markup.Xaml;
+using Mesen.Config;
+using Mesen.Utilities;
+using Mesen.ViewModels;
+using Mesen.Windows;
+using System;
+
+namespace Mesen.Controls
+{
+ public class InputComboBox : UserControl
+ {
+ public static readonly StyledProperty ControllerTypeProperty = AvaloniaProperty.Register(nameof(ControllerType), defaultBindingMode: BindingMode.TwoWay);
+ public static readonly StyledProperty ConfigProperty = AvaloniaProperty.Register(nameof(Config), defaultBindingMode: BindingMode.TwoWay);
+
+ public static readonly StyledProperty AvailableValuesProperty = AvaloniaProperty.Register(nameof(AvailableValues));
+ public static readonly StyledProperty SetupEnabledProperty = AvaloniaProperty.Register(nameof(SetupEnabled));
+
+ public ControllerType ControllerType
+ {
+ get { return GetValue(ControllerTypeProperty); }
+ set { SetValue(ControllerTypeProperty, value); }
+ }
+
+ public ControllerConfig Config
+ {
+ get { return GetValue(ConfigProperty); }
+ set { SetValue(ConfigProperty, value); }
+ }
+
+ public bool SetupEnabled
+ {
+ get { return GetValue(SetupEnabledProperty); }
+ set { SetValue(SetupEnabledProperty, value); }
+ }
+
+ public Enum[] AvailableValues
+ {
+ get { return GetValue(AvailableValuesProperty); }
+ set { SetValue(AvailableValuesProperty, value); }
+ }
+
+ static InputComboBox()
+ {
+ ControllerTypeProperty.Changed.AddClassHandler((x, e) => {
+ x.SetupEnabled = x.ControllerType.CanConfigure();
+ });
+ }
+
+ public InputComboBox()
+ {
+ InitializeComponent();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ private async void btnSetup_Click(object sender, RoutedEventArgs e)
+ {
+ Button btn = (Button)sender;
+
+ PixelPoint startPosition = btn.PointToScreen(new Point(-7, btn.Height));
+
+ ControllerConfigWindow wnd = new ControllerConfigWindow();
+ wnd.WindowStartupLocation = WindowStartupLocation.Manual;
+ wnd.Position = startPosition;
+
+ ControllerConfig cfg = JsonHelper.Clone(Config);
+ wnd.DataContext = new ControllerConfigViewModel(ControllerType, cfg);
+
+ if(await wnd.ShowDialog(btn.Parent?.VisualRoot as Window)) {
+ Config = cfg;
+ }
+ }
+ }
+}
diff --git a/NewUI/Localization/resources.en.xml b/NewUI/Localization/resources.en.xml
index 10b61c94..4ea80389 100644
--- a/NewUI/Localization/resources.en.xml
+++ b/NewUI/Localization/resources.en.xml
@@ -68,36 +68,39 @@
+