Input: Reworked most of the input-related code. Zapper/Famicom support added. NetPlay and Movies now support any input type

This commit is contained in:
Souryo 2016-02-05 23:14:27 -05:00
parent a65907c440
commit c26a45ab8f
55 changed files with 2727 additions and 1141 deletions

View file

@ -0,0 +1,80 @@
#include "stdafx.h"
#include "BaseControlDevice.h"
#include "ControlManager.h"
#include "Movie.h"
#include "EmulationSettings.h"
#include "GameClient.h"
#include "GameServerConnection.h"
BaseControlDevice::BaseControlDevice(uint8_t port)
{
_port = port;
_famiconDevice = EmulationSettings::GetConsoleType() == ConsoleType::Famicom;
if(EmulationSettings::GetControllerType(port) == ControllerType::StandardController) {
AddKeyMappings(EmulationSettings::GetControllerKeys(port));
}
}
BaseControlDevice::~BaseControlDevice()
{
}
void BaseControlDevice::StreamState(bool saving)
{
Stream<uint8_t>(_currentState);
}
uint8_t BaseControlDevice::GetPort()
{
return _port;
}
void BaseControlDevice::AddKeyMappings(KeyMappingSet keyMappings)
{
if(keyMappings.Mapping1.HasKeySet()) {
_keyMappings.push_back(keyMappings.Mapping1);
}
if(keyMappings.Mapping2.HasKeySet()) {
_keyMappings.push_back(keyMappings.Mapping2);
}
if(keyMappings.Mapping3.HasKeySet()) {
_keyMappings.push_back(keyMappings.Mapping3);
}
if(keyMappings.Mapping4.HasKeySet()) {
_keyMappings.push_back(keyMappings.Mapping4);
}
_turboSpeed = keyMappings.TurboSpeed;
}
void BaseControlDevice::RefreshStateBuffer()
{
//Do nothing by default - used by standard controllers and some others
}
uint8_t BaseControlDevice::ProcessNetPlayState(uint32_t netplayState)
{
return netplayState;
}
uint8_t BaseControlDevice::GetControlState()
{
GameServerConnection* netPlayDevice = nullptr;
if(Movie::Playing()) {
_currentState = Movie::GetInstance()->GetState(_port);
} else if(GameClient::Connected()) {
_currentState = GameClient::GetControllerState(_port);
} else if(netPlayDevice = GameServerConnection::GetNetPlayDevice(_port)) {
_currentState = ProcessNetPlayState(netPlayDevice->GetState());
} else {
_currentState = RefreshState();
}
if(Movie::Recording()) {
Movie::GetInstance()->RecordState(_port, _currentState);
}
//For NetPlay
ControlManager::BroadcastInput(_port, _currentState);
return _currentState;
}

58
Core/BaseControlDevice.h Normal file
View file

@ -0,0 +1,58 @@
#pragma once
#include "stdafx.h"
#include "EmulationSettings.h"
#include "Snapshotable.h"
struct ButtonState
{
bool Up = false;
bool Down = false;
bool Left = false;
bool Right = false;
bool A = false;
bool B = false;
bool Select = false;
bool Start = false;
uint8_t ToByte()
{
//"Button status for each controller is returned as an 8-bit report in the following order: A, B, Select, Start, Up, Down, Left, Right."
return (uint8_t)A | ((uint8_t)B << 1) | ((uint8_t)Select << 2) | ((uint8_t)Start << 3) |
((uint8_t)Up << 4) | ((uint8_t)Down << 5) | ((uint8_t)Left << 6) | ((uint8_t)Right << 7);
}
};
class BaseControlDevice : public Snapshotable
{
protected:
uint8_t _port;
uint8_t _currentState;
vector<KeyMapping> _keyMappings;
uint32_t _turboSpeed = 0;
bool _famiconDevice = false;
uint8_t GetPort();
void AddKeyMappings(KeyMappingSet keyMappings);
//Defined in controller-specific code and called when we need to read a device's state
virtual uint8_t RefreshState() = 0;
virtual uint8_t ProcessNetPlayState(uint32_t netplayState);
virtual void StreamState(bool saving);
public:
//Used by controller-specific code to get the current state (buttons, position, etc)
uint8_t GetControlState();
BaseControlDevice(uint8_t port);
virtual ~BaseControlDevice();
//Called when reading $4016/7
virtual uint8_t GetPortOutput() = 0;
//Used by standard controllers when $4017.1 is set
virtual void RefreshStateBuffer();
};

View file

@ -230,7 +230,7 @@ void Console::Run()
_runLock.Acquire();
}
bool paused = EmulationSettings::CheckFlag(EmulationFlags::Paused) || (EmulationSettings::CheckFlag(EmulationFlags::InBackground) && EmulationSettings::CheckFlag(EmulationFlags::PauseWhenInBackground));
bool paused = EmulationSettings::IsPaused();
if(paused && !_stop) {
MessageManager::SendNotification(ConsoleNotificationType::GamePaused);
_runLock.Release();
@ -241,7 +241,7 @@ void Console::Run()
while(paused) {
//Sleep until emulation is resumed
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(100));
paused = EmulationSettings::CheckFlag(EmulationFlags::Paused) || (EmulationSettings::CheckFlag(EmulationFlags::InBackground) && EmulationSettings::CheckFlag(EmulationFlags::PauseWhenInBackground));
paused = EmulationSettings::IsPaused();
}
_runLock.Acquire();
MessageManager::SendNotification(ConsoleNotificationType::GameResumed);
@ -276,11 +276,21 @@ void Console::Run()
double Console::UpdateNesModel()
{
bool configChanged = false;
if(EmulationSettings::NeedControllerUpdate()) {
_controlManager->UpdateControlDevices();
configChanged = true;
}
NesModel model = EmulationSettings::GetNesModel();
uint32_t emulationSpeed = EmulationSettings::GetEmulationSpeed();
if(model == NesModel::Auto) {
model = _mapper->IsPalRom() ? NesModel::PAL : NesModel::NTSC;
}
if(_model != model) {
_model = model;
configChanged = true;
}
double frameDelay;
if(emulationSpeed == 0) {
@ -298,6 +308,10 @@ double Console::UpdateNesModel()
_ppu->SetNesModel(model);
_apu->SetNesModel(model);
if(configChanged) {
MessageManager::SendNotification(ConsoleNotificationType::ConfigChanged);
}
return frameDelay;
}
@ -346,4 +360,9 @@ std::weak_ptr<Debugger> Console::GetDebugger()
void Console::StopDebugger()
{
_debugger.reset();
}
NesModel Console::GetNesModel()
{
return Instance->_model;
}

View file

@ -27,6 +27,8 @@ class Console
unique_ptr<ControlManager> _controlManager;
shared_ptr<MemoryManager> _memoryManager;
NesModel _model;
string _romFilepath;
bool _stop = false;
@ -54,6 +56,7 @@ class Console
std::weak_ptr<Debugger> GetDebugger();
void StopDebugger();
static NesModel GetNesModel();
static void SaveState(ostream &saveStream);
static void LoadState(istream &loadStream);
static void LoadState(uint8_t *buffer, uint32_t bufferSize);

View file

@ -1,12 +1,14 @@
#include "stdafx.h"
#include "ControlManager.h"
#include "StandardController.h"
#include "Zapper.h"
#include "EmulationSettings.h"
#include "Console.h"
#include "GameServerConnection.h"
unique_ptr<IKeyManager> ControlManager::_keyManager = nullptr;
IControlDevice* ControlManager::ControlDevices[] = { nullptr, nullptr, nullptr, nullptr };
IControlDevice* ControlManager::OriginalControlDevices[] = { nullptr, nullptr, nullptr, nullptr };
IGameBroadcaster* ControlManager::GameBroadcaster = nullptr;
SimpleLock ControlManager::ControllerLock[4];
shared_ptr<BaseControlDevice> ControlManager::_controlDevices[2];
IGameBroadcaster* ControlManager::_gameBroadcaster = nullptr;
ControlManager::ControlManager()
{
@ -52,154 +54,110 @@ uint32_t ControlManager::GetKeyCode(string keyName)
void ControlManager::RegisterBroadcaster(IGameBroadcaster* gameBroadcaster)
{
ControlManager::GameBroadcaster = gameBroadcaster;
ControlManager::_gameBroadcaster = gameBroadcaster;
}
void ControlManager::UnregisterBroadcaster(IGameBroadcaster* gameBroadcaster)
{
if(ControlManager::GameBroadcaster == gameBroadcaster) {
ControlManager::GameBroadcaster = nullptr;
if(ControlManager::_gameBroadcaster == gameBroadcaster) {
ControlManager::_gameBroadcaster = nullptr;
}
}
void ControlManager::BackupControlDevices()
void ControlManager::BroadcastInput(uint8_t port, uint8_t state)
{
for(int i = 0; i < 4; i++) {
OriginalControlDevices[i] = ControlDevices[i];
if(ControlManager::_gameBroadcaster) {
//Used when acting as a game server
ControlManager::_gameBroadcaster->BroadcastInput(state, port);
}
}
void ControlManager::RestoreControlDevices()
shared_ptr<BaseControlDevice> ControlManager::GetControlDevice(uint8_t port)
{
for(int i = 0; i < 4; i++) {
ControlManager::ControllerLock[i].Acquire();
ControlDevices[i] = OriginalControlDevices[i];
ControlManager::ControllerLock[i].Release();
}
return ControlManager::_controlDevices[port];
}
IControlDevice* ControlManager::GetControlDevice(uint8_t port)
void ControlManager::RegisterControlDevice(shared_ptr<BaseControlDevice> controlDevice, uint8_t port)
{
return ControlManager::ControlDevices[port];
ControlManager::_controlDevices[port] = controlDevice;
}
void ControlManager::RegisterControlDevice(IControlDevice* controlDevice, uint8_t port)
void ControlManager::UnregisterControlDevice(uint8_t port)
{
ControlManager::ControllerLock[port].Acquire();
ControlManager::ControlDevices[port] = controlDevice;
ControlManager::ControllerLock[port].Release();
}
void ControlManager::UnregisterControlDevice(IControlDevice* controlDevice)
{
for(int i = 0; i < 4; i++) {
if(ControlManager::ControlDevices[i] == controlDevice) {
ControlManager::ControllerLock[i].Acquire();
ControlManager::ControlDevices[i] = nullptr;
ControlManager::ControllerLock[i].Release();
break;
}
}
ControlManager::_controlDevices[port].reset();
}
void ControlManager::RefreshAllPorts()
{
RefreshStateBuffer(0);
RefreshStateBuffer(1);
}
if(_refreshState) {
if(_keyManager) {
_keyManager->RefreshState();
}
uint8_t ControlManager::GetControllerState(uint8_t controllerID)
{
ControlManager::ControllerLock[controllerID].Acquire();
IControlDevice* controlDevice = ControlManager::ControlDevices[controllerID];
uint8_t state;
if(Movie::Playing()) {
state = Movie::Instance->GetState(controllerID);
} else {
if(controlDevice) {
if(_keyManager) {
_keyManager->RefreshState();
for(int i = 0; i < 2; i++) {
if(ControlManager::_controlDevices[i]) {
ControlManager::_controlDevices[i]->RefreshStateBuffer();
}
state = controlDevice->GetButtonState().ToByte();
} else {
state = 0x00;
}
}
ControlManager::ControllerLock[controllerID].Release();
//Used when recording movies
Movie::Instance->RecordState(controllerID, state);
if(ControlManager::GameBroadcaster) {
//Used when acting as a game server
ControlManager::GameBroadcaster->BroadcastInput(state, controllerID);
}
return state;
}
bool ControlManager::HasFourScoreAdapter()
void ControlManager::UpdateControlDevices()
{
//When a movie is playing, always assume 4 controllers are plugged in (TODO: Change this so movies know how many controllers were plugged when recording)
return ControlManager::ControlDevices[2] != nullptr || ControlManager::ControlDevices[3] != nullptr || Movie::Playing();
}
void ControlManager::RefreshStateBuffer(uint8_t port)
{
if(port >= 2) {
throw std::runtime_error("Invalid port");
bool fourScore = EmulationSettings::CheckFlag(EmulationFlags::HasFourScore);
if(EmulationSettings::GetConsoleType() == ConsoleType::Famicom && EmulationSettings::GetExpansionDevice() != ExpansionPortDevice::FourPlayerAdapter) {
fourScore = false;
}
//First 8 bits : Gamepad 1/2
uint32_t state = GetControllerState(port);
if(HasFourScoreAdapter()) {
//Next 8 bits = Gamepad 3/4
state |= GetControllerState(port + 2) << 8;
for(int i = 0; i < 2; i++) {
shared_ptr<BaseControlDevice> device;
if(fourScore) {
//Need to set standard controller in all slots if four score (to allow emulation to work correctly)
device.reset(new StandardController(i));
} else {
switch(EmulationSettings::GetControllerType(i)) {
case ControllerType::StandardController: device.reset(new StandardController(i)); break;
case ControllerType::Zapper: device.reset(new Zapper(i)); break;
}
}
//Last 8 bits = signature
//Signature for port 0 = 0x10, reversed bit order => 0x08
//Signature for port 1 = 0x20, reversed bit order => 0x04
state |= (port == 0 ? 0x08 : 0x04) << 16;
} else {
//"All subsequent reads will return D=1 on an authentic controller but may return D=0 on third party controllers."
state |= 0xFFFF00;
if(device) {
ControlManager::RegisterControlDevice(device, i);
if(fourScore) {
std::dynamic_pointer_cast<StandardController>(device)->AddAdditionalController(shared_ptr<StandardController>(new StandardController(i + 2)));
} else if(i == 1 && EmulationSettings::GetConsoleType() == ConsoleType::Famicom && EmulationSettings::GetExpansionDevice() == ExpansionPortDevice::Zapper) {
std::dynamic_pointer_cast<StandardController>(device)->AddAdditionalController(shared_ptr<Zapper>(new Zapper(2)));
}
} else {
//Remove current device if it's no longer in use
ControlManager::UnregisterControlDevice(i);
}
}
_stateBuffer[port] = state;
}
uint8_t ControlManager::GetPortValue(uint8_t port)
{
if(port >= 2) {
throw std::runtime_error("Invalid port");
}
if(_refreshState) {
RefreshStateBuffer(port);
RefreshAllPorts();
}
uint8_t returnValue = _stateBuffer[port] & 0x01;
_stateBuffer[port] >>= 1;
//"All subsequent reads will return D=1 on an authentic controller but may return D=0 on third party controllers."
_stateBuffer[port] |= 0x800000;
//"In the NES and Famicom, the top three (or five) bits are not driven, and so retain the bits of the previous byte on the bus.
//Usually this is the most significant byte of the address of the controller port - 0x40.
//Paperboy relies on this behavior and requires that reads from the controller ports return exactly $40 or $41 as appropriate."
return 0x40 | returnValue;
shared_ptr<BaseControlDevice> device = GetControlDevice(port);
if(device) {
return 0x40 | device->GetPortOutput();
} else {
return 0x40;
}
}
uint8_t ControlManager::ReadRAM(uint16_t addr)
{
switch(addr) {
case 0x4016:
return GetPortValue(0);
case 0x4017:
return GetPortValue(1);
case 0x4016: return GetPortValue(0);
case 0x4017: return GetPortValue(1);
}
return 0;
@ -207,19 +165,90 @@ uint8_t ControlManager::ReadRAM(uint16_t addr)
void ControlManager::WriteRAM(uint16_t addr, uint8_t value)
{
switch(addr) {
case 0x4016:
_refreshState = (value & 0x01) == 0x01;
if(_refreshState) {
RefreshAllPorts();
}
break;
//$4016 writes
_refreshState = (value & 0x01) == 0x01;
if(_refreshState) {
RefreshAllPorts();
}
}
void ControlManager::StreamState(bool saving)
{
StreamArray<uint32_t>(_stateBuffer, 2);
Stream<bool>(_refreshState);
//Restore controllers that were being used at the time the snapshot was made
//This is particularely important to ensure proper sync during NetPlay
ControllerType controllerTypes[4];
NesModel nesModel;
ExpansionPortDevice expansionDevice;
ConsoleType consoleType;
if(saving) {
nesModel = Console::GetNesModel();
expansionDevice = EmulationSettings::GetExpansionDevice();
consoleType = EmulationSettings::GetConsoleType();
for(int i = 0; i < 4; i++) {
controllerTypes[i] = EmulationSettings::GetControllerType(i);
}
}
Stream<NesModel>(nesModel);
Stream<ExpansionPortDevice>(expansionDevice);
Stream<ConsoleType>(consoleType);
for(int i = 0; i < 4; i++) {
Stream<ControllerType>(controllerTypes[i]);
}
if(!saving) {
EmulationSettings::SetNesModel(nesModel);
EmulationSettings::SetExpansionDevice(expansionDevice);
EmulationSettings::SetConsoleType(consoleType);
for(int i = 0; i < 4; i++) {
EmulationSettings::SetControllerType(i, controllerTypes[i]);
}
UpdateControlDevices();
if(GetControlDevice(0)) {
Stream(GetControlDevice(0));
}
if(GetControlDevice(1)) {
Stream(GetControlDevice(1));
}
}
}
shared_ptr<Zapper> ControlManager::GetZapper(uint8_t port)
{
shared_ptr<Zapper> zapper = std::dynamic_pointer_cast<Zapper>(GetControlDevice(port));
if(zapper) {
return zapper;
} else {
shared_ptr<StandardController> controller = std::dynamic_pointer_cast<StandardController>(GetControlDevice(port));
if(controller) {
return controller->GetZapper();
}
}
return nullptr;
}
bool ControlManager::HasZapper()
{
return GetZapper(0) != nullptr || GetZapper(1) != nullptr;
}
void ControlManager::ZapperSetPosition(uint8_t port, int32_t x, int32_t y)
{
shared_ptr<Zapper> zapper = GetZapper(port);
if(zapper) {
zapper->SetPosition(x, y);
}
}
void ControlManager::ZapperSetTriggerState(uint8_t port, bool pulled)
{
shared_ptr<Zapper> zapper = GetZapper(port);
if(zapper) {
zapper->SetTriggerState(pulled);
}
}

View file

@ -1,7 +1,7 @@
#pragma once
#include "stdafx.h"
#include "IControlDevice.h"
#include "BaseControlDevice.h"
#include "IMemoryHandler.h"
#include "Movie.h"
#include "IGameBroadcaster.h"
@ -9,30 +9,33 @@
#include "../Utilities/SimpleLock.h"
#include "IKeyManager.h"
class BaseControlDevice;
class Zapper;
class ControlManager : public Snapshotable, public IMemoryHandler
{
private:
static unique_ptr<IKeyManager> _keyManager;
static IControlDevice* ControlDevices[4];
static IControlDevice* OriginalControlDevices[4];
static IGameBroadcaster* GameBroadcaster;
static SimpleLock ControllerLock[4];
static shared_ptr<BaseControlDevice> _controlDevices[2];
static IGameBroadcaster* _gameBroadcaster;
bool _refreshState = false;
uint32_t _stateBuffer[2];
void RefreshAllPorts();
uint8_t GetControllerState(uint8_t port);
bool HasFourScoreAdapter();
void RefreshStateBuffer(uint8_t port);
uint8_t GetPortValue(uint8_t port);
static shared_ptr<Zapper> GetZapper(uint8_t port);
static void RegisterControlDevice(shared_ptr<BaseControlDevice> controlDevice, uint8_t port);
void UnregisterControlDevice(uint8_t port);
protected:
virtual void StreamState(bool saving);
public:
ControlManager();
void UpdateControlDevices();
static void RegisterBroadcaster(IGameBroadcaster* gameBroadcaster);
static void UnregisterBroadcaster(IGameBroadcaster* gameBroadcaster);
@ -41,12 +44,14 @@ class ControlManager : public Snapshotable, public IMemoryHandler
static uint32_t GetPressedKey();
static string GetKeyName(uint32_t keyCode);
static uint32_t GetKeyCode(string keyName);
static shared_ptr<BaseControlDevice> GetControlDevice(uint8_t port);
static void BackupControlDevices();
static void RestoreControlDevices();
static IControlDevice* GetControlDevice(uint8_t port);
static void RegisterControlDevice(IControlDevice* controlDevice, uint8_t port);
static void UnregisterControlDevice(IControlDevice* controlDevice);
static bool HasZapper();
static void ZapperSetPosition(uint8_t port, int32_t x, int32_t y);
static void ZapperSetTriggerState(uint8_t port, bool pulled);
static void BroadcastInput(uint8_t port, uint8_t state);
void GetMemoryRanges(MemoryRanges &ranges)
{

View file

@ -447,7 +447,7 @@
<ClInclude Include="HdNesPack.h" />
<ClInclude Include="HdPpu.h" />
<ClInclude Include="IAudioDevice.h" />
<ClInclude Include="IControlDevice.h" />
<ClInclude Include="BaseControlDevice.h" />
<ClInclude Include="IGameBroadcaster.h" />
<ClInclude Include="IKeyManager.h" />
<ClInclude Include="IMemoryHandler.h" />
@ -506,18 +506,19 @@
<ClInclude Include="UnRom_94.h" />
<ClInclude Include="VideoDecoder.h" />
<ClInclude Include="BaseVideoFilter.h" />
<ClInclude Include="VirtualController.h" />
<ClInclude Include="VRC1.h" />
<ClInclude Include="VRC2_4.h" />
<ClInclude Include="VRC3.h" />
<ClInclude Include="VRC6.h" />
<ClInclude Include="VRC7.h" />
<ClInclude Include="VrcIrq.h" />
<ClInclude Include="Zapper.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="APU.cpp" />
<ClCompile Include="ApuLengthCounter.cpp" />
<ClCompile Include="AutoRomTest.cpp" />
<ClCompile Include="BaseControlDevice.cpp" />
<ClCompile Include="BaseMapper.cpp" />
<ClCompile Include="Breakpoint.cpp" />
<ClCompile Include="CheatManager.cpp" />
@ -563,7 +564,7 @@
<ClCompile Include="VideoRenderer.cpp" />
<ClCompile Include="VideoDecoder.cpp" />
<ClCompile Include="BaseVideoFilter.cpp" />
<ClCompile Include="VirtualController.cpp" />
<ClCompile Include="Zapper.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View file

@ -63,6 +63,9 @@
<Filter Include="Nes\Mappers\FDS">
<UniqueIdentifier>{4a7af167-f6cb-4173-b7ca-04ed7c5858b1}</UniqueIdentifier>
</Filter>
<Filter Include="Nes\Controllers">
<UniqueIdentifier>{acd315c2-48ad-4243-a997-bb9a970c24bd}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
@ -71,9 +74,6 @@
<ClInclude Include="IAudioDevice.h">
<Filter>Nes\Interfaces</Filter>
</ClInclude>
<ClInclude Include="IControlDevice.h">
<Filter>Nes\Interfaces</Filter>
</ClInclude>
<ClInclude Include="IMemoryHandler.h">
<Filter>Nes\Interfaces</Filter>
</ClInclude>
@ -263,9 +263,6 @@
<ClInclude Include="IGameBroadcaster.h">
<Filter>NetPlay</Filter>
</ClInclude>
<ClInclude Include="VirtualController.h">
<Filter>NetPlay</Filter>
</ClInclude>
<ClInclude Include="Console.h">
<Filter>Nes</Filter>
</ClInclude>
@ -281,9 +278,6 @@
<ClInclude Include="PPU.h">
<Filter>Nes</Filter>
</ClInclude>
<ClInclude Include="StandardController.h">
<Filter>Nes</Filter>
</ClInclude>
<ClInclude Include="CPU.h">
<Filter>Nes</Filter>
</ClInclude>
@ -536,6 +530,15 @@
<ClInclude Include="VideoRenderer.h">
<Filter>VideoDecoder</Filter>
</ClInclude>
<ClInclude Include="StandardController.h">
<Filter>Nes\Controllers</Filter>
</ClInclude>
<ClInclude Include="Zapper.h">
<Filter>Nes\Controllers</Filter>
</ClInclude>
<ClInclude Include="BaseControlDevice.h">
<Filter>Nes\Controllers</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
@ -598,9 +601,6 @@
<ClCompile Include="GameServerConnection.cpp">
<Filter>NetPlay</Filter>
</ClCompile>
<ClCompile Include="VirtualController.cpp">
<Filter>NetPlay</Filter>
</ClCompile>
<ClCompile Include="Console.cpp">
<Filter>Nes</Filter>
</ClCompile>
@ -619,9 +619,6 @@
<ClCompile Include="PPU.cpp">
<Filter>Nes</Filter>
</ClCompile>
<ClCompile Include="StandardController.cpp">
<Filter>Nes</Filter>
</ClCompile>
<ClCompile Include="CheatManager.cpp">
<Filter>Nes</Filter>
</ClCompile>
@ -658,5 +655,14 @@
<ClCompile Include="VideoRenderer.cpp">
<Filter>VideoDecoder</Filter>
</ClCompile>
<ClCompile Include="StandardController.cpp">
<Filter>Nes\Controllers</Filter>
</ClCompile>
<ClCompile Include="Zapper.cpp">
<Filter>Nes\Controllers</Filter>
</ClCompile>
<ClCompile Include="BaseControlDevice.cpp">
<Filter>Nes\Controllers</Filter>
</ClCompile>
</ItemGroup>
</Project>

View file

@ -30,4 +30,10 @@ uint32_t EmulationSettings::_emulationSpeed = 100;
OverscanDimensions EmulationSettings::_overscan;
VideoFilterType EmulationSettings::_videoFilterType = VideoFilterType::None;
uint32_t EmulationSettings::_videoScale = 1;
uint32_t EmulationSettings::_videoScale = 1;
ConsoleType EmulationSettings::_consoleType = ConsoleType::Nes;
ExpansionPortDevice EmulationSettings::_expansionDevice = ExpansionPortDevice::None;
ControllerType EmulationSettings::_controllerTypes[4] = { ControllerType::None, ControllerType::None, ControllerType::None, ControllerType::None };
KeyMappingSet EmulationSettings::_controllerKeys[4] = { KeyMappingSet(), KeyMappingSet(), KeyMappingSet(), KeyMappingSet() };
bool EmulationSettings::_needControllerUpdate = false;

View file

@ -2,6 +2,7 @@
#include "stdafx.h"
#include "MessageManager.h"
#include "GameClient.h"
enum EmulationFlags
{
@ -11,6 +12,7 @@ enum EmulationFlags
AllowInvalidInput = 0x08,
RemoveSpriteLimit = 0x10,
UseHdPacks = 0x20,
HasFourScore = 0x40,
PauseOnMovieEnd = 0x0100,
PauseWhenInBackground = 0x0200,
@ -78,6 +80,57 @@ struct OverscanDimensions
}
};
enum class ConsoleType
{
Nes = 0,
Famicom = 1,
VsSystem = 2,
};
enum class ControllerType
{
None = 0,
StandardController = 1,
Zapper = 2,
};
enum class ExpansionPortDevice
{
None = 0,
Zapper = 1,
FourPlayerAdapter = 2,
};
struct KeyMapping
{
uint32_t A = 0;
uint32_t B = 0;
uint32_t Up = 0;
uint32_t Down = 0;
uint32_t Left = 0;
uint32_t Right = 0;
uint32_t Start = 0;
uint32_t Select = 0;
uint32_t TurboA = 0;
uint32_t TurboB = 0;
uint32_t TurboStart = 0;
uint32_t TurboSelect = 0;
bool HasKeySet()
{
return A || B || Up || Down || Left || Right || Start || Select || TurboA || TurboB || TurboStart || TurboSelect;
}
};
struct KeyMappingSet
{
KeyMapping Mapping1;
KeyMapping Mapping2;
KeyMapping Mapping3;
KeyMapping Mapping4;
uint32_t TurboSpeed;
};
class EmulationSettings
{
private:
@ -98,6 +151,12 @@ private:
static VideoFilterType _videoFilterType;
static uint32_t _videoScale;
static ConsoleType _consoleType;
static ExpansionPortDevice _expansionDevice;
static ControllerType _controllerTypes[4];
static KeyMappingSet _controllerKeys[4];
static bool _needControllerUpdate;
public:
static uint32_t GetMesenVersion()
{
@ -124,6 +183,11 @@ public:
return (_flags & flag) == flag;
}
static bool IsPaused()
{
return CheckFlag(EmulationFlags::Paused) || (CheckFlag(EmulationFlags::InBackground) && CheckFlag(EmulationFlags::PauseWhenInBackground) && !GameClient::Connected());
}
static void SetNesModel(NesModel model)
{
_model = model;
@ -234,4 +298,58 @@ public:
{
memcpy(PpuPaletteArgb, paletteBuffer, sizeof(PpuPaletteArgb));
}
static void SetExpansionDevice(ExpansionPortDevice expansionDevice)
{
_expansionDevice = expansionDevice;
_needControllerUpdate = true;
}
static ExpansionPortDevice GetExpansionDevice()
{
return _expansionDevice;
}
static void SetConsoleType(ConsoleType type)
{
_consoleType = type;
_needControllerUpdate = true;
}
static ConsoleType GetConsoleType()
{
return _consoleType;
}
static void SetControllerType(uint8_t port, ControllerType type)
{
_controllerTypes[port] = type;
_needControllerUpdate = true;
}
static ControllerType GetControllerType(uint8_t port)
{
return _controllerTypes[port];
}
static void SetControllerKeys(uint8_t port, KeyMappingSet keyMappings)
{
_controllerKeys[port] = keyMappings;
_needControllerUpdate = true;
}
static KeyMappingSet GetControllerKeys(uint8_t port)
{
return _controllerKeys[port];
}
static bool NeedControllerUpdate()
{
if(_needControllerUpdate) {
_needControllerUpdate = false;
return true;
} else {
return false;
}
}
};

View file

@ -7,6 +7,7 @@ using std::thread;
#include "Console.h"
#include "../Utilities/Socket.h"
#include "ClientConnectionData.h"
#include "GameClientConnection.h"
unique_ptr<GameClient> GameClient::Instance;
@ -57,15 +58,6 @@ void GameClient::PrivateConnect(shared_ptr<ClientConnectionData> connectionData)
}
}
void GameClient::PrivateDisconnect()
{
if(_connected) {
_connected = false;
_socket.reset();
_connection.reset();
}
}
void GameClient::Exec()
{
if(_connected) {
@ -89,4 +81,9 @@ void GameClient::ProcessNotification(ConsoleNotificationType type, void* paramet
if(type == ConsoleNotificationType::GameLoaded && std::this_thread::get_id() != _clientThread->get_id()) {
GameClient::Disconnect();
}
}
uint8_t GameClient::GetControllerState(uint8_t port)
{
return Instance->_connection->GetControllerState(port);
}

View file

@ -1,11 +1,11 @@
#pragma once
#include "stdafx.h"
#include "GameClientConnection.h"
#include <thread>
#include "INotificationListener.h"
using std::thread;
class Socket;
class GameClientConnection;
class ClientConnectionData;
class thread;
class GameClient : public INotificationListener
{
@ -20,7 +20,6 @@ private:
void PrivateConnect(shared_ptr<ClientConnectionData> connectionData);
void Exec();
void PrivateDisconnect();
public:
GameClient();
@ -30,5 +29,7 @@ public:
static void Connect(shared_ptr<ClientConnectionData> connectionData);
static void Disconnect();
static uint8_t GetControllerState(uint8_t port);
void ProcessNotification(ConsoleNotificationType type, void* parameter);
};

View file

@ -8,23 +8,21 @@
#include "Console.h"
#include "EmulationSettings.h"
#include "ControlManager.h"
#include "VirtualController.h"
#include "ClientConnectionData.h"
#include "StandardController.h"
GameClientConnection::GameClientConnection(shared_ptr<Socket> socket, shared_ptr<ClientConnectionData> connectionData) : GameConnection(socket, connectionData)
{
_controlDevice = ControlManager::GetControlDevice(0);
ControlManager::BackupControlDevices();
MessageManager::DisplayMessage("Net Play", "Connected to server.");
SendHandshake();
}
GameClientConnection::~GameClientConnection()
{
_virtualControllers.clear();
ControlManager::RestoreControlDevices();
_shutdown = true;
DisableControllers();
MessageManager::SendNotification(ConsoleNotificationType::DisconnectedFromServer);
MessageManager::DisplayMessage("Net Play", "Connection to server lost.");
}
@ -34,54 +32,49 @@ void GameClientConnection::SendHandshake()
SendNetMessage(message);
}
void GameClientConnection::InitializeVirtualControllers()
void GameClientConnection::ClearInputData()
{
for(int i = 0; i < 4; i++) {
_virtualControllers.push_back(unique_ptr<VirtualController>(new VirtualController(i)));
_inputSize[i] = 0;
_inputData[i].clear();
}
}
void GameClientConnection::DisposeVirtualControllers()
{
_virtualControllers.clear();
}
void GameClientConnection::ProcessMessage(NetMessage* message)
{
uint8_t port;
uint8_t state;
GameInformationMessage* gameInfo;
switch(message->GetType()) {
case MessageType::SaveState:
if(_gameLoaded) {
DisposeVirtualControllers();
DisableControllers();
Console::Pause();
ClearInputData();
((SaveStateMessage*)message)->LoadState();
_enableControllers = true;
switch(EmulationSettings::GetControllerType(_controllerPort)) {
case ControllerType::StandardController: _controlDevice.reset(new StandardController(0)); break;
case ControllerType::Zapper: _controlDevice = ControlManager::GetControlDevice(_controllerPort); break;
}
Console::Resume();
InitializeVirtualControllers();
}
break;
case MessageType::MovieData:
if(_gameLoaded) {
port = ((MovieDataMessage*)message)->GetPortNumber();
state = ((MovieDataMessage*)message)->GetInputState();
_virtualControllers[port]->PushState(state);
PushControllerState(((MovieDataMessage*)message)->GetPortNumber(), ((MovieDataMessage*)message)->GetInputState());
}
break;
case MessageType::GameInformation:
DisableControllers();
Console::Pause();
gameInfo = (GameInformationMessage*)message;
if(gameInfo->GetPort() != _controllerPort) {
_controllerPort = gameInfo->GetPort();
MessageManager::DisplayMessage("Net Play", string("Connected as player ") + std::to_string(_controllerPort + 1));
}
DisposeVirtualControllers();
ClearInputData();
_gameLoaded = gameInfo->AttemptLoadGame();
if(gameInfo->IsPaused()) {
@ -89,17 +82,78 @@ void GameClientConnection::ProcessMessage(NetMessage* message)
} else {
EmulationSettings::ClearFlags(EmulationFlags::Paused);
}
Console::Resume();
break;
default:
break;
}
}
void GameClientConnection::PushControllerState(uint8_t port, uint8_t state)
{
LockHandler lock = _writeLock.AcquireSafe();
_inputData[port].push_back(state);
_inputSize[port]++;
if(_inputData[port].size() >= _minimumQueueSize) {
_waitForInput[port].Signal();
}
}
void GameClientConnection::DisableControllers()
{
//Used to prevent deadlocks when client is trying to fill its buffer while the host changes the current game/settings/etc. (i.e situations where we need to call Console::Pause())
ClearInputData();
_enableControllers = false;
for(int i = 0; i < 4; i++) {
_waitForInput[i].Signal();
}
}
uint8_t GameClientConnection::GetControllerState(uint8_t port)
{
if(_enableControllers) {
while(_inputSize[port] == 0) {
_waitForInput[port].Wait();
if(port == 0 && _minimumQueueSize < 10) {
//Increase buffer size - reduces freezes at the cost of additional lag
_minimumQueueSize++;
}
if(_shutdown || !_enableControllers) {
return 0;
}
}
LockHandler lock = _writeLock.AcquireSafe();
uint8_t state = _inputData[port].front();
_inputData[port].pop_front();
_inputSize[port]--;
if(_inputData[port].size() > _minimumQueueSize) {
//Too much data, catch up
EmulationSettings::SetEmulationSpeed(0);
} else {
EmulationSettings::SetEmulationSpeed(100);
}
return state;
}
return 0;
}
void GameClientConnection::SendInput()
{
if(_gameLoaded) {
uint8_t inputState = _controlDevice->GetButtonState().ToByte();
uint32_t inputState = 0;
if(std::dynamic_pointer_cast<Zapper>(_controlDevice)) {
shared_ptr<Zapper> zapper = std::dynamic_pointer_cast<Zapper>(_controlDevice);
inputState = zapper->GetZapperState();
} else if(std::dynamic_pointer_cast<StandardController>(_controlDevice)) {
shared_ptr<StandardController> controller = std::dynamic_pointer_cast<StandardController>(_controlDevice);
inputState = controller->GetButtonState();
}
if(_lastInputSent != inputState) {
InputDataMessage message(inputState);
SendNetMessage(message);

View file

@ -1,24 +1,34 @@
#pragma once
#include "stdafx.h"
#include <deque>
#include "GameConnection.h"
#include "IControlDevice.h"
#include "../Utilities/AutoResetEvent.h"
#include "../Utilities/SimpleLock.h"
#include "StandardController.h"
class ClientConnectionData;
class VirtualController;
class GameClientConnection : public GameConnection
{
private:
vector<unique_ptr<VirtualController>> _virtualControllers;
IControlDevice* _controlDevice;
uint8_t _lastInputSent = 0x00;
std::deque<uint8_t> _inputData[4];
atomic<uint32_t> _inputSize[4];
AutoResetEvent _waitForInput[4];
SimpleLock _writeLock;
atomic<bool> _shutdown;
atomic<bool> _enableControllers = false;
atomic<uint32_t> _minimumQueueSize = 3;
shared_ptr<BaseControlDevice> _controlDevice;
uint32_t _lastInputSent = 0x00;
bool _gameLoaded = false;
uint8_t _controllerPort = 255;
private:
void SendHandshake();
void InitializeVirtualControllers();
void DisposeVirtualControllers();
void ClearInputData();
void PushControllerState(uint8_t port, uint8_t state);
void DisableControllers();
protected:
void ProcessMessage(NetMessage* message);
@ -26,6 +36,7 @@ protected:
public:
GameClientConnection(shared_ptr<Socket> socket, shared_ptr<ClientConnectionData> connectionData);
~GameClientConnection();
uint8_t GetControllerState(uint8_t port);
void SendInput();
};

View file

@ -29,8 +29,7 @@ void GameServer::AcceptConnections()
while(true) {
shared_ptr<Socket> socket = _listener->Accept();
if(!socket->ConnectionError()) {
_openConnections.push_back(shared_ptr<GameServerConnection>(new GameServerConnection(socket, 1, this)));
std::cout << "Client connected." << std::endl;
_openConnections.push_back(shared_ptr<GameServerConnection>(new GameServerConnection(socket, 1)));
} else {
break;
}

View file

@ -10,15 +10,14 @@
#include "ControlManager.h"
#include "ClientConnectionData.h"
#include "EmulationSettings.h"
#include "StandardController.h"
GameServerConnection::GameServerConnection(shared_ptr<Socket> socket, int controllerPort, IGameBroadcaster* gameBroadcaster) : GameConnection(socket, nullptr)
GameServerConnection* GameServerConnection::_netPlayDevices[4] = { nullptr,nullptr,nullptr, nullptr };
GameServerConnection::GameServerConnection(shared_ptr<Socket> socket, int controllerPort) : GameConnection(socket, nullptr)
{
//Server-side connection
_gameBroadcaster = gameBroadcaster;
_controllerPort = controllerPort;
ControlManager::BackupControlDevices();
MessageManager::RegisterNotificationListener(this);
}
@ -30,8 +29,7 @@ GameServerConnection::~GameServerConnection()
MessageManager::DisplayMessage("Net Play", "Player " + std::to_string(_controllerPort + 1) + " disconnected.");
}
ControlManager::RestoreControlDevices();
UnregisterNetPlayDevice(this);
MessageManager::UnregisterNotificationListener(this);
}
@ -53,11 +51,17 @@ void GameServerConnection::SendMovieData(uint8_t state, uint8_t port)
}
}
ButtonState GameServerConnection::GetButtonState()
void GameServerConnection::PushState(uint32_t state)
{
if(_inputData.size() == 0 || state != _inputData.back()) {
_inputData.push_back(state);
}
}
uint32_t GameServerConnection::GetState()
{
ButtonState state;
size_t inputBufferSize = _inputData.size();
uint8_t stateData = 0;
uint32_t stateData = 0;
if(inputBufferSize > 0) {
stateData = _inputData.front();
if(inputBufferSize > 1) {
@ -65,8 +69,7 @@ ButtonState GameServerConnection::GetButtonState()
_inputData.pop_front();
}
}
state.FromByte(stateData);
return state;
return stateData;
}
void GameServerConnection::ProcessMessage(NetMessage* message)
@ -85,18 +88,13 @@ void GameServerConnection::ProcessMessage(NetMessage* message)
}
_handshakeCompleted = true;
ControlManager::RegisterControlDevice(this, _controllerPort);
RegisterNetPlayDevice(this, _controllerPort);
Console::Resume();
}
break;
case MessageType::InputData:
{
uint8_t state = ((InputDataMessage*)message)->GetInputState();
if(_inputData.size() == 0 || state != _inputData.back()) {
_inputData.push_back(state);
}
PushState(((InputDataMessage*)message)->GetInputState());
break;
}
default:
break;
}
@ -112,9 +110,32 @@ void GameServerConnection::ProcessNotification(ConsoleNotificationType type, voi
case ConsoleNotificationType::StateLoaded:
case ConsoleNotificationType::CheatAdded:
case ConsoleNotificationType::FdsDiskChanged:
case ConsoleNotificationType::ConfigChanged:
SendGameInformation();
break;
default:
break;
}
}
void GameServerConnection::RegisterNetPlayDevice(GameServerConnection* device, uint8_t port)
{
GameServerConnection::_netPlayDevices[port] = device;
}
void GameServerConnection::UnregisterNetPlayDevice(GameServerConnection* device)
{
if(device != nullptr) {
for(int i = 0; i < 4; i++) {
if(GameServerConnection::_netPlayDevices[i] == device) {
GameServerConnection::_netPlayDevices[i] = nullptr;
break;
}
}
}
}
GameServerConnection* GameServerConnection::GetNetPlayDevice(uint8_t port)
{
return GameServerConnection::_netPlayDevices[port];
}

View file

@ -1,29 +1,35 @@
#pragma once
#include "stdafx.h"
#include <deque>
#include "GameConnection.h"
#include "IControlDevice.h"
#include "StandardController.h"
#include "IGameBroadcaster.h"
#include "INotificationListener.h"
class GameServerConnection : public GameConnection, public IControlDevice, public INotificationListener
class GameServerConnection : public GameConnection, public INotificationListener
{
private:
int _controllerPort;
list<uint8_t> _inputData;
IGameBroadcaster* _gameBroadcaster;
static GameServerConnection* _netPlayDevices[4];
list<uint32_t> _inputData;
int _controllerPort;
bool _handshakeCompleted = false;
void PushState(uint32_t state);
void SendGameInformation();
static void RegisterNetPlayDevice(GameServerConnection* connection, uint8_t port);
static void UnregisterNetPlayDevice(GameServerConnection* device);
protected:
void ProcessMessage(NetMessage* message);
public:
GameServerConnection(shared_ptr<Socket> socket, int controllerPort, IGameBroadcaster* gameBroadcaster);
GameServerConnection(shared_ptr<Socket> socket, int controllerPort);
~GameServerConnection();
void SendGameInformation();
uint32_t GetState();
void SendMovieData(uint8_t state, uint8_t port);
ButtonState GetButtonState();
virtual void ProcessNotification(ConsoleNotificationType type, void* parameter);
static GameServerConnection* GetNetPlayDevice(uint8_t port);
};

View file

@ -1,42 +0,0 @@
#pragma once
#include "stdafx.h"
struct ButtonState
{
bool Up = false;
bool Down = false;
bool Left = false;
bool Right = false;
bool A = false;
bool B = false;
bool Select = false;
bool Start = false;
uint8_t ToByte()
{
//"Button status for each controller is returned as an 8-bit report in the following order: A, B, Select, Start, Up, Down, Left, Right."
return (uint8_t)A | ((uint8_t)B << 1) | ((uint8_t)Select << 2) | ((uint8_t)Start << 3) |
((uint8_t)Up << 4) | ((uint8_t)Down << 5) | ((uint8_t)Left << 6) | ((uint8_t)Right << 7);
}
void FromByte(uint8_t stateData)
{
A = (stateData & 0x01) == 0x01;
B = (stateData & 0x02) == 0x02;
Select = (stateData & 0x04) == 0x04;
Start = (stateData & 0x08) == 0x08;
Up = (stateData & 0x10) == 0x10;
Down = (stateData & 0x20) == 0x20;
Left = (stateData & 0x40) == 0x40;
Right = (stateData & 0x80) == 0x80;
}
};
class IControlDevice
{
public:
virtual ButtonState GetButtonState() = 0;
};

View file

@ -17,6 +17,8 @@ enum class ConsoleNotificationType
ResolutionChanged = 11,
FdsDiskChanged = 12,
FdsBiosNotFound = 13,
ConfigChanged = 14,
DisconnectedFromServer = 15
};
class INotificationListener

View file

@ -5,22 +5,23 @@
class InputDataMessage : public NetMessage
{
private:
uint8_t _inputState;
uint32_t _inputState;
protected:
virtual void ProtectedStreamState()
{
Stream<uint8_t>(_inputState);
Stream<uint32_t>(_inputState);
}
public:
InputDataMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) { }
InputDataMessage(uint8_t inputState) : NetMessage(MessageType::InputData)
InputDataMessage(uint32_t inputState) : NetMessage(MessageType::InputData)
{
_inputState = inputState;
}
uint8_t GetInputState()
uint32_t GetInputState()
{
return _inputState;
}

View file

@ -5,7 +5,17 @@
#include "../Utilities/FolderUtilities.h"
#include "RomLoader.h"
Movie* Movie::Instance = new Movie();
shared_ptr<Movie> Movie::_instance(new Movie());
Movie::~Movie()
{
_instance = nullptr;
}
shared_ptr<Movie> Movie::GetInstance()
{
return _instance;
}
void Movie::PushState(uint8_t port)
{
@ -137,57 +147,101 @@ void Movie::PlayMovie(stringstream &filestream, bool autoLoadRom, string filenam
void Movie::Record(string filename, bool reset)
{
Instance->StartRecording(filename, reset);
if(_instance) {
_instance->StartRecording(filename, reset);
}
}
void Movie::Play(string filename)
{
ifstream file(filename, ios::in | ios::binary);
std::stringstream ss;
if(_instance) {
ifstream file(filename, ios::in | ios::binary);
std::stringstream ss;
if(file) {
ss << file.rdbuf();
file.close();
Instance->PlayMovie(ss, true, filename);
if(file) {
ss << file.rdbuf();
file.close();
_instance->PlayMovie(ss, true, filename);
}
}
}
void Movie::Play(std::stringstream &filestream, bool autoLoadRom)
{
Instance->PlayMovie(filestream, autoLoadRom);
if(_instance) {
_instance->PlayMovie(filestream, autoLoadRom);
}
}
void Movie::Stop()
{
Instance->StopAll();
if(_instance) {
_instance->StopAll();
}
}
bool Movie::Playing()
{
return Instance->_playing;
if(_instance) {
return _instance->_playing;
} else {
return false;
}
}
bool Movie::Recording()
{
return Instance->_recording;
if(_instance) {
return _instance->_recording;
} else {
return false;
}
}
struct MovieHeader
{
char Header[3] = { 'M', 'M', 'O' };
uint32_t MesenVersion;
uint32_t MovieFormatVersion;
uint32_t RomCrc32;
uint32_t Region;
uint32_t ConsoleType;
uint8_t ControllerTypes[4];
uint32_t ExpansionDevice;
uint32_t FilenameLength;
};
bool Movie::Save()
{
_file.write("MMO", 3);
_data.SaveStateSize = (uint32_t)_startState.tellp();
string romFilepath = Console::GetROMPath();
string romFilename = FolderUtilities::GetFilename(romFilepath, true);
uint32_t romCrc32 = RomLoader::GetCRC32(romFilepath);
_file.write((char*)&romCrc32, sizeof(romCrc32));
MovieHeader header = {};
header.MesenVersion = EmulationSettings::GetMesenVersion();
header.MovieFormatVersion = 1;
header.RomCrc32 = RomLoader::GetCRC32(romFilepath);
header.Region = (uint32_t)Console::GetNesModel();
header.ConsoleType = (uint32_t)EmulationSettings::GetConsoleType();
header.ExpansionDevice = (uint32_t)EmulationSettings::GetExpansionDevice();
for(int port = 0; port < 4; port++) {
header.ControllerTypes[port] = (uint32_t)EmulationSettings::GetControllerType(port);
}
header.FilenameLength = (uint32_t)romFilename.size();
uint32_t romNameSize = (uint32_t)romFilename.size();
_file.write((char*)&romNameSize, sizeof(uint32_t));
_file.write((char*)romFilename.c_str(), romNameSize);
_file.write((char*)header.Header, sizeof(header.Header));
_file.write((char*)&header.MesenVersion, sizeof(header.MesenVersion));
_file.write((char*)&header.MovieFormatVersion, sizeof(header.MovieFormatVersion));
_file.write((char*)&header.RomCrc32, sizeof(header.RomCrc32));
_file.write((char*)&header.Region, sizeof(header.Region));
_file.write((char*)&header.ConsoleType, sizeof(header.ConsoleType));
_file.write((char*)&header.ControllerTypes, sizeof(header.ControllerTypes));
_file.write((char*)&header.ExpansionDevice, sizeof(header.ExpansionDevice));
_file.write((char*)&header.FilenameLength, sizeof(header.FilenameLength));
_file.write((char*)romFilename.c_str(), header.FilenameLength);
_data.SaveStateSize = (uint32_t)_startState.tellp();
_file.write((char*)&_data.SaveStateSize, sizeof(uint32_t));
if(_data.SaveStateSize > 0) {
@ -215,30 +269,39 @@ bool Movie::Save()
bool Movie::Load(std::stringstream &file, bool autoLoadRom)
{
char header[3];
file.read((char*)&header, 3);
MovieHeader header = {};
file.read((char*)header.Header, sizeof(header.Header));
if(memcmp((char*)&header, "MMO", 3) != 0) {
if(memcmp(header.Header, "MMO", 3) != 0) {
//Invalid movie file
return false;
}
uint32_t romCrc32;
file.read((char*)&romCrc32, sizeof(romCrc32));
file.read((char*)&header.MesenVersion, sizeof(header.MesenVersion));
file.read((char*)&header.MovieFormatVersion, sizeof(header.MovieFormatVersion));
file.read((char*)&header.RomCrc32, sizeof(header.RomCrc32));
file.read((char*)&header.Region, sizeof(header.Region));
file.read((char*)&header.ConsoleType, sizeof(header.ConsoleType));
file.read((char*)&header.ControllerTypes, sizeof(header.ControllerTypes));
file.read((char*)&header.ExpansionDevice, sizeof(header.ExpansionDevice));
file.read((char*)&header.FilenameLength, sizeof(header.FilenameLength));
uint32_t romNameSize;
file.read((char*)&romNameSize, sizeof(uint32_t));
EmulationSettings::SetConsoleType((ConsoleType)header.ConsoleType);
EmulationSettings::SetExpansionDevice((ExpansionPortDevice)header.ExpansionDevice);
for(int port = 0; port < 4; port++) {
EmulationSettings::SetControllerType(port, (ControllerType)header.ControllerTypes[port]);
}
char* romFilename = new char[romNameSize + 1];
memset(romFilename, 0, (romNameSize + 1));
file.read((char*)romFilename, romNameSize);
char* romFilename = new char[header.FilenameLength + 1];
memset(romFilename, 0, header.FilenameLength + 1);
file.read((char*)romFilename, header.FilenameLength);
bool loadedGame = true;
if(autoLoadRom) {
string currentRom = Console::GetROMPath();
if(currentRom.empty() || romCrc32 != RomLoader::GetCRC32(currentRom)) {
if(currentRom.empty() || header.RomCrc32 != RomLoader::GetCRC32(currentRom)) {
//Loaded game isn't the same as the game used for the movie, attempt to load the correct game
loadedGame = Console::LoadROM(romFilename, romCrc32);
loadedGame = Console::LoadROM(romFilename, header.RomCrc32);
}
}

View file

@ -11,10 +11,8 @@ struct MovieData
class Movie
{
friend class ControlManager;
private:
static Movie* Instance;
static shared_ptr<Movie> _instance;
bool _recording = false;
bool _playing = false;
uint8_t _counter[4];
@ -33,13 +31,16 @@ class Movie
void StopAll();
void Reset();
void RecordState(uint8_t port, uint8_t state);
uint8_t GetState(uint8_t port);
bool Save();
bool Load(std::stringstream &file, bool autoLoadRom);
public:
~Movie();
void RecordState(uint8_t port, uint8_t state);
uint8_t GetState(uint8_t port);
static shared_ptr<Movie> GetInstance();
static void Record(string filename, bool reset);
static void Play(string filename);
static void Play(std::stringstream &filestream, bool autoLoadRom);

View file

@ -3,6 +3,7 @@
#include "stdafx.h"
#include "Snapshotable.h"
#include "MemoryManager.h"
#include "EmulationSettings.h"
enum class NesModel;
@ -266,4 +267,12 @@ class PPU : public IMemoryHandler, public Snapshotable
{
return _secondarySpriteRAM;
}
static uint32_t GetPixelBrightness(uint8_t x, uint8_t y)
{
//Used by Zapper, gives a rough approximation of the brightness level of the specific pixel
uint16_t pixelData = PPU::Instance->_currentOutputBuffer[y << 8 | x];
uint32_t argbColor = EmulationSettings::GetRgbPalette()[pixelData & 0x3F];
return (argbColor & 0xFF) + ((argbColor >> 8) & 0xFF) + ((argbColor >> 16) & 0xFF);
}
};

View file

@ -16,11 +16,10 @@ private:
protected:
virtual void ProtectedStreamState()
{
vector<CodeInfo> cheats;
StreamArray((void**)&_stateData, _dataSize);
if(_sending) {
vector<CodeInfo> cheats;
cheats = CheatManager::GetCheats();
_cheats = cheats.size() > 0 ? &cheats[0] : nullptr;
_cheatArraySize = (uint32_t)cheats.size() * sizeof(CodeInfo);
@ -28,11 +27,6 @@ protected:
delete[] _stateData;
} else {
StreamArray((void**)&_cheats, _cheatArraySize);
for(uint32_t i = 0; i < _cheatArraySize / sizeof(CodeInfo); i++) {
cheats.push_back(((CodeInfo*)_cheats)[i]);
}
CheatManager::SetCheats(cheats);
}
}
@ -55,5 +49,11 @@ public:
void LoadState()
{
Console::LoadState((uint8_t*)_stateData, _dataSize);
vector<CodeInfo> cheats;
for(uint32_t i = 0; i < _cheatArraySize / sizeof(CodeInfo); i++) {
cheats.push_back(((CodeInfo*)_cheats)[i]);
}
CheatManager::SetCheats(cheats);
}
};

View file

@ -4,27 +4,18 @@
#include "PPU.h"
#include "EmulationSettings.h"
StandardController::StandardController(uint8_t port)
void StandardController::StreamState(bool saving)
{
ControlManager::RegisterControlDevice(this, port);
BaseControlDevice::StreamState(saving);
Stream<uint32_t>(_stateBuffer);
Stream<uint32_t>(_stateBufferFamicom);
if(_additionalController) {
Stream(_additionalController);
}
}
StandardController::~StandardController()
{
ControlManager::UnregisterControlDevice(this);
}
void StandardController::AddKeyMappings(KeyMapping keyMapping)
{
_keyMappings.push_back(keyMapping);
}
void StandardController::ClearKeyMappings()
{
_keyMappings.clear();
}
ButtonState StandardController::GetButtonState()
uint8_t StandardController::GetButtonState()
{
ButtonState state;
@ -42,7 +33,7 @@ ButtonState StandardController::GetButtonState()
state.Right |= ControlManager::IsKeyPressed(keyMapping.Right);
//Turbo buttons - need to be applied for at least 2 reads in a row (some games require this)
uint8_t turboFreq = 1 << (4 - keyMapping.TurboSpeed);
uint8_t turboFreq = 1 << (4 - _turboSpeed);
bool turboOn = (uint8_t)(PPU::GetFrameCount() % turboFreq) < turboFreq / 2;
if(turboOn) {
state.A |= ControlManager::IsKeyPressed(keyMapping.TurboA);
@ -62,5 +53,72 @@ ButtonState StandardController::GetButtonState()
}
}
return state;
return state.ToByte();
}
uint8_t StandardController::GetPortOutput()
{
uint8_t returnValue = _stateBuffer & 0x01;
_stateBuffer >>= 1;
if(_famiconDevice && _additionalController) {
if(_hasZapper) {
returnValue |= _additionalController->GetPortOutput();
} else {
returnValue |= (_stateBufferFamicom & 0x01) << 1;
_stateBufferFamicom >>= 1;
_stateBuffer |= 0x800000;
}
}
//"All subsequent reads will return D=1 on an authentic controller but may return D=0 on third party controllers."
_stateBuffer |= 0x800000;
return returnValue;
}
void StandardController::RefreshStateBuffer()
{
_stateBuffer = GetControlState();
if(_additionalController) {
//Next 8 bits = Gamepad 3/4
if(_famiconDevice) {
//Four player adapter (Famicom)
_stateBufferFamicom = _additionalController->GetControlState();
_stateBufferFamicom |= 0xFFFF00;
} else {
//Four-score adapter (NES)
_stateBuffer |= _additionalController->GetControlState() << 8;
//Last 8 bits = signature
//Signature for port 0 = 0x10, reversed bit order => 0x08
//Signature for port 1 = 0x20, reversed bit order => 0x04
_stateBuffer |= (GetPort() == 0 ? 0x08 : 0x04) << 16;
}
} else {
//"All subsequent reads will return D=1 on an authentic controller but may return D=0 on third party controllers."
_stateBuffer |= 0xFFFF00;
}
}
uint8_t StandardController::RefreshState()
{
return GetButtonState();
}
void StandardController::AddAdditionalController(shared_ptr<BaseControlDevice> controller)
{
if(std::dynamic_pointer_cast<Zapper>(controller)) {
_hasZapper = true;
}
_additionalController = controller;
}
shared_ptr<Zapper> StandardController::GetZapper()
{
if(_hasZapper) {
return std::dynamic_pointer_cast<Zapper>(_additionalController);
} else {
return nullptr;
}
}

View file

@ -1,37 +1,29 @@
#pragma once
#include "stdafx.h"
#include "BaseControlDevice.h"
#include "Zapper.h"
#include "IControlDevice.h"
struct KeyMapping
{
uint32_t A;
uint32_t B;
uint32_t Up;
uint32_t Down;
uint32_t Left;
uint32_t Right;
uint32_t Start;
uint32_t Select;
uint32_t TurboA;
uint32_t TurboB;
uint32_t TurboStart;
uint32_t TurboSelect;
uint32_t TurboSpeed;
};
class StandardController : public IControlDevice
class StandardController : public BaseControlDevice
{
private:
vector<KeyMapping> _keyMappings;
uint32_t _stateBuffer;
uint32_t _stateBufferFamicom;
bool _hasZapper;
shared_ptr<BaseControlDevice> _additionalController;
protected:
uint8_t RefreshState();
virtual void StreamState(bool saving);
public:
StandardController(uint8_t port);
~StandardController();
using BaseControlDevice::BaseControlDevice;
void AddKeyMappings(KeyMapping keyMapping);
void ClearKeyMappings();
virtual uint8_t GetButtonState();
uint8_t GetPortOutput();
void RefreshStateBuffer();
ButtonState GetButtonState();
shared_ptr<Zapper> GetZapper();
void AddAdditionalController(shared_ptr<BaseControlDevice> controller);
};

View file

@ -1,63 +0,0 @@
#include "stdafx.h"
#include "VirtualController.h"
#include "ControlManager.h"
#include "Console.h"
#include "EmulationSettings.h"
VirtualController::VirtualController(uint8_t port)
{
_port = port;
_queueSize = 0;
_waiting = false;
_shutdown = false;
ControlManager::RegisterControlDevice(this, _port);
}
VirtualController::~VirtualController()
{
_shutdown = true;
while(_waiting.load());
ControlManager::UnregisterControlDevice(this);
}
ButtonState VirtualController::GetButtonState()
{
ButtonState state;
if(_queueSize.load() == 0) {
_waiting = true;
while(_queueSize.load() <= _minimumBuffer) {
if(_minimumBuffer < 10) {
_minimumBuffer++;
}
if(_shutdown.load()) {
_waiting = false;
return state;
}
}
_waiting = false;
}
_writeLock.Acquire();
state.FromByte(_inputData.front());
_inputData.pop_front();
_queueSize--;
if(_queueSize.load() > _minimumBuffer) {
EmulationSettings::SetEmulationSpeed(0);
} else {
EmulationSettings::SetEmulationSpeed(100);
}
_writeLock.Release();
return state;
}
void VirtualController::PushState(uint8_t state)
{
_writeLock.Acquire();
_inputData.push_back(state);
_queueSize++;
_writeLock.Release();
}

View file

@ -1,27 +0,0 @@
#pragma once
#include "stdafx.h"
#include <atomic>
using std::atomic;
#include "IControlDevice.h"
#include "../Utilities/SimpleLock.h"
class VirtualController : public IControlDevice
{
list<uint8_t> _inputData;
bool _paused = false;
atomic<uint32_t> _queueSize;
atomic<bool> _waiting;
atomic<bool> _shutdown;
SimpleLock _writeLock;
uint8_t _port;
uint32_t _minimumBuffer = 3;
public:
VirtualController(uint8_t port);
~VirtualController();
ButtonState GetButtonState();
void PushState(uint8_t state);
};

86
Core/Zapper.cpp Normal file
View file

@ -0,0 +1,86 @@
#include "stdafx.h"
#include "Zapper.h"
#include "CPU.h"
#include "PPU.h"
struct ZapperButtonState
{
bool TriggerPressed = false;
bool LightNotDetected = false;
uint8_t ToByte()
{
return (LightNotDetected ? 0x08 : 0x00) | (TriggerPressed ? 0x10 : 0x00);
}
};
void Zapper::StreamState(bool saving)
{
BaseControlDevice::StreamState(saving);
Stream<int32_t>(_xPosition);
Stream<int32_t>(_yPosition);
Stream<bool>(_pulled);
}
void Zapper::SetPosition(int32_t x, int32_t y)
{
_xPosition = x;
_yPosition = y;
}
void Zapper::SetTriggerState(bool pulled)
{
_pulled = pulled;
}
uint32_t Zapper::GetZapperState()
{
//Used by netplay
uint32_t state;
if(_yPosition == -1 || _xPosition == -1) {
state = 0x80000000;
} else {
state = _xPosition | (_yPosition << 8);
}
if(_pulled) {
state |= 0x40000000;
}
return state;
}
uint8_t Zapper::ProcessNetPlayState(uint32_t netplayState)
{
if(netplayState >> 31) {
_xPosition = -1;
_yPosition = -1;
} else {
_xPosition = netplayState & 0xFF;
_yPosition = (netplayState >> 8) & 0xFF;
}
_pulled = ((netplayState >> 30) & 0x01) == 0x01;
return RefreshState();
}
uint8_t Zapper::RefreshState()
{
ZapperButtonState state;
state.TriggerPressed = _pulled;
int32_t scanline = PPU::GetCurrentScanline();
int32_t cycle = PPU::GetCurrentCycle();
if(_xPosition == -1 || _yPosition == -1 || scanline > 240 || scanline < _yPosition || (scanline == _yPosition && cycle < _xPosition) || PPU::GetPixelBrightness(_xPosition, _yPosition) < 50) {
//Light cannot be detected if the Y/X position is further ahead than the PPU, or if the PPU drew a dark color
state.LightNotDetected = true;
}
return state.ToByte();
}
uint8_t Zapper::GetPortOutput()
{
return GetControlState();
}

25
Core/Zapper.h Normal file
View file

@ -0,0 +1,25 @@
#pragma once
#include "stdafx.h"
#include "BaseControlDevice.h"
class Zapper : public BaseControlDevice
{
private:
bool _pulled;
int32_t _xPosition;
int32_t _yPosition;
protected:
uint8_t RefreshState();
uint8_t ProcessNetPlayState(uint32_t netplayState);
void StreamState(bool saving);
public:
using BaseControlDevice::BaseControlDevice;
uint8_t GetPortOutput();
uint32_t GetZapperState();
void SetPosition(int32_t x, int32_t y);
void SetTriggerState(bool pulled);
};

View file

@ -15,9 +15,9 @@ namespace Mesen.GUI.Config
public PreferenceInfo PreferenceInfo;
public AudioInfo AudioInfo;
public VideoInfo VideoInfo;
public InputInfo InputInfo;
public List<string> RecentFiles;
public List<CheatInfo> Cheats;
public List<ControllerInfo> Controllers;
public bool ShowOnlyCheatsForCurrentGame;
public bool AutoLoadIpsPatches;
public NesModel Region;
@ -34,13 +34,13 @@ namespace Mesen.GUI.Config
VideoInfo = new VideoInfo();
PreferenceInfo = new PreferenceInfo();
RecentFiles = new List<string>();
Controllers = new List<ControllerInfo>();
InputInfo = new InputInfo();
Cheats = new List<CheatInfo>();
}
public void ApplyConfig()
{
ControllerInfo.ApplyConfig();
InputInfo.ApplyConfig();
VideoInfo.ApplyConfig();
AudioInfo.ApplyConfig();
PreferenceInfo.ApplyConfig();
@ -50,11 +50,7 @@ namespace Mesen.GUI.Config
public void InitializeDefaults()
{
while(Controllers.Count < 4) {
var controllerInfo = new ControllerInfo();
controllerInfo.ControllerType = Controllers.Count < 2 ? ControllerType.StandardController : ControllerType.None;
Controllers.Add(controllerInfo);
}
InputInfo.InitializeDefaults();
}
public void AddRecentFile(string filepath)

View file

@ -1,70 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Mesen.GUI.Config
{
public enum ControllerType
{
None = 0,
StandardController = 1,
}
public class KeyMappings
{
public string A = "A";
public string B = "S";
public string Select = "W";
public string Start = "Q";
public string Up = "Up Arrow";
public string Down = "Down Arrow";
public string Left = "Left Arrow";
public string Right = "Right Arrow";
public string TurboA = "Z";
public string TurboB = "X";
public string TurboStart = "";
public string TurboSelect = "";
public UInt32 TurboSpeed;
public InteropEmu.KeyMapping ToInteropMapping()
{
InteropEmu.KeyMapping mapping = new InteropEmu.KeyMapping();
mapping.A = InteropEmu.GetKeyCode(A);
mapping.B = InteropEmu.GetKeyCode(B);
mapping.Start = InteropEmu.GetKeyCode(Start);
mapping.Select = InteropEmu.GetKeyCode(Select);
mapping.Up = InteropEmu.GetKeyCode(Up);
mapping.Down = InteropEmu.GetKeyCode(Down);
mapping.Left = InteropEmu.GetKeyCode(Left);
mapping.Right = InteropEmu.GetKeyCode(Right);
mapping.TurboA = InteropEmu.GetKeyCode(TurboA);
mapping.TurboB = InteropEmu.GetKeyCode(TurboB);
mapping.TurboStart = InteropEmu.GetKeyCode(TurboStart);
mapping.TurboSelect = InteropEmu.GetKeyCode(TurboSelect);
mapping.TurboSpeed = TurboSpeed;
return mapping;
}
}
public class ControllerInfo
{
public ControllerType ControllerType = ControllerType.StandardController;
public KeyMappings Keys = new KeyMappings();
public static void ApplyConfig()
{
for(int i = 0; i < 4; i++) {
InteropEmu.ClearKeyMappings(i);
if(ConfigManager.Config.Controllers[i].ControllerType != ControllerType.None) {
InteropEmu.AddKeyMappings(i, ConfigManager.Config.Controllers[i].Keys.ToInteropMapping());
}
}
}
}
}

145
GUI.NET/Config/InputInfo.cs Normal file
View file

@ -0,0 +1,145 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Mesen.GUI.Config
{
public class KeyMappings
{
public string A;
public string B;
public string Select;
public string Start;
public string Up;
public string Down;
public string Left;
public string Right;
public string TurboA;
public string TurboB;
public string TurboStart;
public string TurboSelect;
public KeyMappings()
{
}
public KeyMappings(int controllerIndex, int keySetIndex)
{
if(controllerIndex == 0) {
if(keySetIndex == 0) {
A = "A";
B = "S";
Select = "W";
Start = "Q";
Up = "Up Arrow";
Down = "Down Arrow";
Left = "Left Arrow";
Right = "Right Arrow";
TurboA = "Z";
TurboB = "X";
} else if(keySetIndex == 1) {
A = "Pad1 A";
B = "Pad1 X";
Select = "Pad1 Back";
Start = "Pad1 Start";
Up = "Pad1 Up";
Down = "Pad1 Down";
Left = "Pad1 Left";
Right = "Pad1 Right";
TurboA = "Pad1 B";
TurboB = "Pad1 Y";
}
}
}
public InteropEmu.KeyMapping ToInteropMapping()
{
InteropEmu.KeyMapping mapping = new InteropEmu.KeyMapping();
mapping.A = InteropEmu.GetKeyCode(A);
mapping.B = InteropEmu.GetKeyCode(B);
mapping.Start = InteropEmu.GetKeyCode(Start);
mapping.Select = InteropEmu.GetKeyCode(Select);
mapping.Up = InteropEmu.GetKeyCode(Up);
mapping.Down = InteropEmu.GetKeyCode(Down);
mapping.Left = InteropEmu.GetKeyCode(Left);
mapping.Right = InteropEmu.GetKeyCode(Right);
mapping.TurboA = InteropEmu.GetKeyCode(TurboA);
mapping.TurboB = InteropEmu.GetKeyCode(TurboB);
mapping.TurboStart = InteropEmu.GetKeyCode(TurboStart);
mapping.TurboSelect = InteropEmu.GetKeyCode(TurboSelect);
return mapping;
}
}
public class ControllerInfo
{
public InteropEmu.ControllerType ControllerType = InteropEmu.ControllerType.StandardController;
public List<KeyMappings> Keys = new List<KeyMappings>();
public UInt32 TurboSpeed = 2;
public InteropEmu.KeyMappingSet GetKeyMappingSet()
{
while(Keys.Count < 4) {
Keys.Add(new KeyMappings());
}
InteropEmu.KeyMappingSet mappingSet = new InteropEmu.KeyMappingSet();
mappingSet.Mapping1 = Keys[0].ToInteropMapping();
mappingSet.Mapping2 = Keys[1].ToInteropMapping();
mappingSet.Mapping3 = Keys[2].ToInteropMapping();
mappingSet.Mapping4 = Keys[3].ToInteropMapping();
mappingSet.TurboSpeed = TurboSpeed;
return mappingSet;
}
}
public class InputInfo
{
public ConsoleType ConsoleType = ConsoleType.Nes;
public InteropEmu.ExpansionPortDevice ExpansionPortDevice = InteropEmu.ExpansionPortDevice.None;
public bool UseFourScore = false;
public List<ControllerInfo> Controllers = new List<ControllerInfo>();
public void InitializeDefaults()
{
while(Controllers.Count < 4) {
var controllerInfo = new ControllerInfo();
controllerInfo.ControllerType = Controllers.Count == 0 ? InteropEmu.ControllerType.StandardController : InteropEmu.ControllerType.None;
if(Controllers.Count == 0) {
controllerInfo.Keys.Add(new KeyMappings(0, 0));
controllerInfo.Keys.Add(new KeyMappings(0, 1));
}
Controllers.Add(controllerInfo);
}
}
public static void ApplyConfig()
{
InputInfo inputInfo = ConfigManager.Config.InputInfo;
InteropEmu.ExpansionPortDevice expansionDevice;
if(inputInfo.ConsoleType == ConsoleType.Nes) {
expansionDevice = InteropEmu.ExpansionPortDevice.None;
} else {
expansionDevice = inputInfo.ExpansionPortDevice;
}
InteropEmu.SetConsoleType(inputInfo.ConsoleType);
InteropEmu.SetExpansionDevice(inputInfo.ExpansionPortDevice);
InteropEmu.SetFlag(EmulationFlags.HasFourScore, (inputInfo.ConsoleType == ConsoleType.Nes && inputInfo.UseFourScore) || (inputInfo.ConsoleType == ConsoleType.Famicom && expansionDevice == InteropEmu.ExpansionPortDevice.FourPlayerAdapter));
for(int i = 0; i < 4; i++) {
InteropEmu.SetControllerType(i, inputInfo.Controllers[i].ControllerType);
InteropEmu.SetControllerKeys(i, inputInfo.Controllers[i].GetKeyMappingSet());
}
}
}
}

View file

@ -1,20 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Mesen.GUI.Controls
{
public partial class DXViewer : UserControl
{
public DXViewer()
{
InitializeComponent();
}
}
}

View file

@ -1,6 +1,6 @@
namespace Mesen.GUI.Controls
{
partial class DXViewer
partial class ctrlRenderer
{
/// <summary>
/// Required designer variable.
@ -27,8 +27,18 @@
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
this.SuspendLayout();
//
// ctrlRenderer
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Name = "ctrlRenderer";
this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.ctrlRenderer_MouseDown);
this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.ctrlRenderer_MouseMove);
this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.ctrlRenderer_MouseUp);
this.ResumeLayout(false);
}
#endregion

View file

@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Mesen.GUI.Config;
namespace Mesen.GUI.Controls
{
public partial class ctrlRenderer : UserControl
{
private bool _rightButtonDown = false;
public ctrlRenderer()
{
InitializeComponent();
}
private void ctrlRenderer_MouseDown(object sender, MouseEventArgs e)
{
if(e.Button == MouseButtons.Left) {
InteropEmu.ZapperSetTriggerState(0, true);
InteropEmu.ZapperSetTriggerState(1, true);
} else if(e.Button == MouseButtons.Right) {
_rightButtonDown = true;
}
}
private void ctrlRenderer_MouseMove(object sender, MouseEventArgs e)
{
if(InteropEmu.HasZapper()) {
this.Cursor = Cursors.Cross;
} else {
this.Cursor = Cursors.Default;
}
if(_rightButtonDown) {
InteropEmu.ZapperSetPosition(0, -1, -1);
InteropEmu.ZapperSetPosition(1, -1, -1);
} else {
//TODO
InteropEmu.ZapperSetPosition(0, e.X/4, e.Y/4);
InteropEmu.ZapperSetPosition(1, e.X/4, e.Y/4);
}
}
private void ctrlRenderer_MouseUp(object sender, MouseEventArgs e)
{
if(e.Button == MouseButtons.Left) {
InteropEmu.ZapperSetTriggerState(0, false);
InteropEmu.ZapperSetTriggerState(1, false);
} else if(e.Button == MouseButtons.Right) {
_rightButtonDown = false;
}
}
}
}

View file

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View file

@ -26,6 +26,16 @@ namespace Mesen.GUI.Forms
_validateTimer.Interval = 50;
_validateTimer.Tick += OnValidateInput;
_validateTimer.Start();
this.ShowInTaskbar = false;
}
public new bool ShowInTaskbar
{
set
{
base.ShowInTaskbar = false;
}
}
protected override void OnLoad(EventArgs e)
@ -135,6 +145,7 @@ namespace Mesen.GUI.Forms
protected void UpdateUI()
{
this.Updating = true;
foreach(KeyValuePair<string, Control> kvp in _bindings) {
if(!_fieldInfo.ContainsKey(kvp.Key)) {
throw new Exception("Invalid binding key");
@ -162,6 +173,8 @@ namespace Mesen.GUI.Forms
}
} else if(kvp.Value is ctrlTrackbar) {
((ctrlTrackbar)kvp.Value).Value = (int)(uint)value;
} else if(kvp.Value is TrackBar) {
((TrackBar)kvp.Value).Value = (int)(uint)value;
} else if(kvp.Value is NumericUpDown) {
NumericUpDown nud = kvp.Value as NumericUpDown;
decimal val = (decimal)(uint)value;
@ -191,7 +204,14 @@ namespace Mesen.GUI.Forms
}
}
}
this.Updating = false;
this.AfterUpdateUI();
}
virtual protected void AfterUpdateUI()
{
}
protected void UpdateObject()
@ -219,11 +239,14 @@ namespace Mesen.GUI.Forms
field.SetValue(Entity, kvp.Value.Controls.OfType<RadioButton>().FirstOrDefault(r => r.Checked).Tag);
} else if(kvp.Value is ctrlTrackbar) {
field.SetValue(Entity, (UInt32)((ctrlTrackbar)kvp.Value).Value);
} else if(kvp.Value is TrackBar) {
field.SetValue(Entity, (UInt32)((TrackBar)kvp.Value).Value);
} else if(kvp.Value is NumericUpDown) {
field.SetValue(Entity, (UInt32)((NumericUpDown)kvp.Value).Value);
} else if(kvp.Value is ComboBox) {
if(field.FieldType.IsSubclassOf(typeof(Enum))) {
field.SetValue(Entity, Enum.Parse(field.FieldType, ((ComboBox)kvp.Value).SelectedItem.ToString()));
object selectedItem = ((ComboBox)kvp.Value).SelectedItem;
field.SetValue(Entity, selectedItem == null ? 0 : Enum.Parse(field.FieldType, selectedItem.ToString()));
} else if(field.FieldType == typeof(UInt32)) {
UInt32 numericValue;
string item = Regex.Replace(((ComboBox)kvp.Value).SelectedItem.ToString(), "[^0-9]", "");

View file

@ -28,9 +28,9 @@
private void InitializeComponent()
{
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.lblControllerType = new System.Windows.Forms.Label();
this.cboControllerType = new System.Windows.Forms.ComboBox();
this.ctrlStandardController = new Mesen.GUI.Forms.Config.ctrlStandardController();
this.cboControllerType = new System.Windows.Forms.ComboBox();
this.lblControllerType = new System.Windows.Forms.Label();
this.tableLayoutPanel1.SuspendLayout();
this.SuspendLayout();
//
@ -51,6 +51,29 @@
this.tableLayoutPanel1.Size = new System.Drawing.Size(618, 353);
this.tableLayoutPanel1.TabIndex = 1;
//
// ctrlStandardController
//
this.tableLayoutPanel1.SetColumnSpan(this.ctrlStandardController, 2);
this.ctrlStandardController.Location = new System.Drawing.Point(3, 30);
this.ctrlStandardController.Name = "ctrlStandardController";
this.ctrlStandardController.Size = new System.Drawing.Size(611, 320);
this.ctrlStandardController.TabIndex = 3;
//
// cboControllerType
//
this.cboControllerType.Dock = System.Windows.Forms.DockStyle.Top;
this.cboControllerType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cboControllerType.FormattingEnabled = true;
this.cboControllerType.Items.AddRange(new object[] {
"None",
"Standard NES Controller",
"Zapper"});
this.cboControllerType.Location = new System.Drawing.Point(90, 3);
this.cboControllerType.Name = "cboControllerType";
this.cboControllerType.Size = new System.Drawing.Size(525, 21);
this.cboControllerType.TabIndex = 2;
this.cboControllerType.SelectedIndexChanged += new System.EventHandler(this.cboControllerType_SelectedIndexChanged);
//
// lblControllerType
//
this.lblControllerType.Anchor = System.Windows.Forms.AnchorStyles.Left;
@ -61,28 +84,6 @@
this.lblControllerType.TabIndex = 1;
this.lblControllerType.Text = "Controller Type:";
//
// cboControllerType
//
this.cboControllerType.Dock = System.Windows.Forms.DockStyle.Top;
this.cboControllerType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cboControllerType.FormattingEnabled = true;
this.cboControllerType.Items.AddRange(new object[] {
"None",
"Standard NES Controller"});
this.cboControllerType.Location = new System.Drawing.Point(90, 3);
this.cboControllerType.Name = "cboControllerType";
this.cboControllerType.Size = new System.Drawing.Size(525, 21);
this.cboControllerType.TabIndex = 2;
this.cboControllerType.SelectedIndexChanged += new System.EventHandler(this.cboControllerType_SelectedIndexChanged);
//
// ctrlStandardController
//
this.tableLayoutPanel1.SetColumnSpan(this.ctrlStandardController, 2);
this.ctrlStandardController.Location = new System.Drawing.Point(3, 30);
this.ctrlStandardController.Name = "ctrlStandardController";
this.ctrlStandardController.Size = new System.Drawing.Size(611, 320);
this.ctrlStandardController.TabIndex = 3;
//
// ctrlInputPortConfig
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@ -99,8 +100,8 @@
#endregion
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private ctrlStandardController ctrlStandardController;
private System.Windows.Forms.Label lblControllerType;
private System.Windows.Forms.ComboBox cboControllerType;
private ctrlStandardController ctrlStandardController;
}
}

View file

@ -23,20 +23,20 @@ namespace Mesen.GUI.Forms.Config
public void Initialize(ControllerInfo controllerInfo)
{
_controllerInfo = controllerInfo;
ctrlStandardController.Initialize(controllerInfo.Keys);
//ctrlStandardController.Initialize(controllerInfo.Keys);
cboControllerType.SelectedIndex = (int)_controllerInfo.ControllerType;
}
public void UpdateConfig()
{
_controllerInfo.Keys = ctrlStandardController.GetKeyMappings();
_controllerInfo.ControllerType = (ControllerType)cboControllerType.SelectedIndex;
//_controllerInfo.Keys = ctrlStandardController.GetKeyMappings();
_controllerInfo.ControllerType = (InteropEmu.ControllerType)cboControllerType.SelectedIndex;
}
private void cboControllerType_SelectedIndexChanged(object sender, EventArgs e)
{
ctrlStandardController.Visible = ((ControllerType)cboControllerType.SelectedIndex == ControllerType.StandardController);
ctrlStandardController.Visible = ((InteropEmu.ControllerType)cboControllerType.SelectedIndex == InteropEmu.ControllerType.StandardController);
}
}
}

View file

@ -28,210 +28,24 @@
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ctrlStandardController));
this.btnTurboB = new System.Windows.Forms.Button();
this.btnSelect = new System.Windows.Forms.Button();
this.btnTurboA = new System.Windows.Forms.Button();
this.btnStart = new System.Windows.Forms.Button();
this.btnDown = new System.Windows.Forms.Button();
this.btnA = new System.Windows.Forms.Button();
this.btnUp = new System.Windows.Forms.Button();
this.btnB = new System.Windows.Forms.Button();
this.btnLeft = new System.Windows.Forms.Button();
this.btnRight = new System.Windows.Forms.Button();
this.picControllerLayout = new System.Windows.Forms.PictureBox();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.trkTurboSpeed = new System.Windows.Forms.TrackBar();
this.lblTurboSpeed = new System.Windows.Forms.Label();
this.panel1 = new System.Windows.Forms.Panel();
this.lblSlow = new System.Windows.Forms.Label();
this.lblTurboFast = new System.Windows.Forms.Label();
this.panel2 = new System.Windows.Forms.Panel();
((System.ComponentModel.ISupportInitialize)(this.picControllerLayout)).BeginInit();
this.tableLayoutPanel1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.trkTurboSpeed)).BeginInit();
this.panel1.SuspendLayout();
this.picControllerLayout = new System.Windows.Forms.PictureBox();
this.btnA = new System.Windows.Forms.Button();
this.btnDown = new System.Windows.Forms.Button();
this.btnUp = new System.Windows.Forms.Button();
this.btnStart = new System.Windows.Forms.Button();
this.btnB = new System.Windows.Forms.Button();
this.btnTurboA = new System.Windows.Forms.Button();
this.btnLeft = new System.Windows.Forms.Button();
this.btnSelect = new System.Windows.Forms.Button();
this.btnRight = new System.Windows.Forms.Button();
this.btnTurboB = new System.Windows.Forms.Button();
this.panel2.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.picControllerLayout)).BeginInit();
this.SuspendLayout();
//
// btnTurboB
//
this.btnTurboB.Location = new System.Drawing.Point(417, 43);
this.btnTurboB.Name = "btnTurboB";
this.btnTurboB.Size = new System.Drawing.Size(61, 59);
this.btnTurboB.TabIndex = 21;
this.btnTurboB.Text = "B";
this.btnTurboB.UseVisualStyleBackColor = true;
this.btnTurboB.Click += new System.EventHandler(this.btnMapping_Click);
//
// btnSelect
//
this.btnSelect.Location = new System.Drawing.Point(234, 166);
this.btnSelect.Name = "btnSelect";
this.btnSelect.Size = new System.Drawing.Size(61, 37);
this.btnSelect.TabIndex = 12;
this.btnSelect.Text = "Q";
this.btnSelect.UseVisualStyleBackColor = true;
this.btnSelect.Click += new System.EventHandler(this.btnMapping_Click);
//
// btnTurboA
//
this.btnTurboA.Location = new System.Drawing.Point(499, 43);
this.btnTurboA.Name = "btnTurboA";
this.btnTurboA.Size = new System.Drawing.Size(61, 59);
this.btnTurboA.TabIndex = 20;
this.btnTurboA.Text = "A";
this.btnTurboA.UseVisualStyleBackColor = true;
this.btnTurboA.Click += new System.EventHandler(this.btnMapping_Click);
//
// btnStart
//
this.btnStart.Location = new System.Drawing.Point(315, 166);
this.btnStart.Name = "btnStart";
this.btnStart.Size = new System.Drawing.Size(61, 37);
this.btnStart.TabIndex = 13;
this.btnStart.Text = "W";
this.btnStart.UseVisualStyleBackColor = true;
this.btnStart.Click += new System.EventHandler(this.btnMapping_Click);
//
// btnDown
//
this.btnDown.Location = new System.Drawing.Point(88, 177);
this.btnDown.Name = "btnDown";
this.btnDown.Size = new System.Drawing.Size(50, 35);
this.btnDown.TabIndex = 19;
this.btnDown.Text = "Down";
this.btnDown.UseVisualStyleBackColor = true;
this.btnDown.Click += new System.EventHandler(this.btnMapping_Click);
//
// btnA
//
this.btnA.Location = new System.Drawing.Point(499, 155);
this.btnA.Name = "btnA";
this.btnA.Size = new System.Drawing.Size(61, 59);
this.btnA.TabIndex = 14;
this.btnA.Text = "A";
this.btnA.UseVisualStyleBackColor = true;
this.btnA.Click += new System.EventHandler(this.btnMapping_Click);
//
// btnUp
//
this.btnUp.Location = new System.Drawing.Point(88, 95);
this.btnUp.Name = "btnUp";
this.btnUp.Size = new System.Drawing.Size(50, 35);
this.btnUp.TabIndex = 18;
this.btnUp.Text = "Up";
this.btnUp.UseVisualStyleBackColor = true;
this.btnUp.Click += new System.EventHandler(this.btnMapping_Click);
//
// btnB
//
this.btnB.Location = new System.Drawing.Point(417, 155);
this.btnB.Name = "btnB";
this.btnB.Size = new System.Drawing.Size(61, 59);
this.btnB.TabIndex = 15;
this.btnB.Text = "B";
this.btnB.UseVisualStyleBackColor = true;
this.btnB.Click += new System.EventHandler(this.btnMapping_Click);
//
// btnLeft
//
this.btnLeft.Location = new System.Drawing.Point(53, 136);
this.btnLeft.Name = "btnLeft";
this.btnLeft.Size = new System.Drawing.Size(50, 35);
this.btnLeft.TabIndex = 17;
this.btnLeft.Text = "Left";
this.btnLeft.UseVisualStyleBackColor = true;
this.btnLeft.Click += new System.EventHandler(this.btnMapping_Click);
//
// btnRight
//
this.btnRight.Location = new System.Drawing.Point(123, 136);
this.btnRight.Name = "btnRight";
this.btnRight.Size = new System.Drawing.Size(50, 35);
this.btnRight.TabIndex = 16;
this.btnRight.Text = "Right";
this.btnRight.UseVisualStyleBackColor = true;
this.btnRight.Click += new System.EventHandler(this.btnMapping_Click);
//
// picControllerLayout
//
this.picControllerLayout.Image = ((System.Drawing.Image)(resources.GetObject("picControllerLayout.Image")));
this.picControllerLayout.Location = new System.Drawing.Point(-8, -12);
this.picControllerLayout.Name = "picControllerLayout";
this.picControllerLayout.Size = new System.Drawing.Size(629, 292);
this.picControllerLayout.TabIndex = 11;
this.picControllerLayout.TabStop = false;
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.ColumnCount = 3;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.Controls.Add(this.trkTurboSpeed, 2, 1);
this.tableLayoutPanel1.Controls.Add(this.lblTurboSpeed, 1, 1);
this.tableLayoutPanel1.Controls.Add(this.panel1, 2, 2);
this.tableLayoutPanel1.Controls.Add(this.panel2, 0, 0);
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(0, 0, 0, 0);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 3;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 32F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.Size = new System.Drawing.Size(613, 316);
this.tableLayoutPanel1.TabIndex = 22;
//
// trkTurboSpeed
//
this.trkTurboSpeed.LargeChange = 2;
this.trkTurboSpeed.Location = new System.Drawing.Point(493, 272);
this.trkTurboSpeed.Maximum = 3;
this.trkTurboSpeed.Name = "trkTurboSpeed";
this.trkTurboSpeed.Size = new System.Drawing.Size(117, 26);
this.trkTurboSpeed.TabIndex = 0;
//
// lblTurboSpeed
//
this.lblTurboSpeed.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblTurboSpeed.AutoSize = true;
this.lblTurboSpeed.Location = new System.Drawing.Point(415, 278);
this.lblTurboSpeed.Name = "lblTurboSpeed";
this.lblTurboSpeed.Size = new System.Drawing.Size(72, 13);
this.lblTurboSpeed.TabIndex = 1;
this.lblTurboSpeed.Text = "Turbo Speed:";
//
// panel1
//
this.panel1.Controls.Add(this.lblTurboFast);
this.panel1.Controls.Add(this.lblSlow);
this.panel1.Location = new System.Drawing.Point(490, 301);
this.panel1.Margin = new System.Windows.Forms.Padding(0, 0, 0, 0);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(120, 15);
this.panel1.TabIndex = 2;
//
// lblSlow
//
this.lblSlow.AutoSize = true;
this.lblSlow.Location = new System.Drawing.Point(3, 0);
this.lblSlow.Name = "lblSlow";
this.lblSlow.Size = new System.Drawing.Size(30, 13);
this.lblSlow.TabIndex = 0;
this.lblSlow.Text = "Slow";
//
// lblTurboFast
//
this.lblTurboFast.AutoSize = true;
this.lblTurboFast.Location = new System.Drawing.Point(90, 0);
this.lblTurboFast.Name = "lblTurboFast";
this.lblTurboFast.Size = new System.Drawing.Size(27, 13);
this.lblTurboFast.TabIndex = 1;
this.lblTurboFast.Text = "Fast";
//
// panel2
//
this.tableLayoutPanel1.SetColumnSpan(this.panel2, 3);
this.panel2.Controls.Add(this.btnTurboB);
this.panel2.Controls.Add(this.btnRight);
this.panel2.Controls.Add(this.btnSelect);
@ -245,48 +59,146 @@
this.panel2.Controls.Add(this.picControllerLayout);
this.panel2.Dock = System.Windows.Forms.DockStyle.Fill;
this.panel2.Location = new System.Drawing.Point(0, 0);
this.panel2.Margin = new System.Windows.Forms.Padding(0, 0, 0, 0);
this.panel2.Margin = new System.Windows.Forms.Padding(0);
this.panel2.Name = "panel2";
this.panel2.Size = new System.Drawing.Size(613, 269);
this.panel2.Size = new System.Drawing.Size(585, 210);
this.panel2.TabIndex = 3;
//
// picControllerLayout
//
this.picControllerLayout.Image = ((System.Drawing.Image)(resources.GetObject("picControllerLayout.Image")));
this.picControllerLayout.Location = new System.Drawing.Point(0, 0);
this.picControllerLayout.Name = "picControllerLayout";
this.picControllerLayout.Size = new System.Drawing.Size(615, 211);
this.picControllerLayout.TabIndex = 11;
this.picControllerLayout.TabStop = false;
//
// btnA
//
this.btnA.Location = new System.Drawing.Point(499, 105);
this.btnA.Name = "btnA";
this.btnA.Size = new System.Drawing.Size(61, 59);
this.btnA.TabIndex = 14;
this.btnA.Text = "A";
this.btnA.UseVisualStyleBackColor = true;
this.btnA.Click += new System.EventHandler(this.btnMapping_Click);
//
// btnDown
//
this.btnDown.Location = new System.Drawing.Point(68, 141);
this.btnDown.Name = "btnDown";
this.btnDown.Size = new System.Drawing.Size(64, 35);
this.btnDown.TabIndex = 19;
this.btnDown.Text = "Down";
this.btnDown.UseVisualStyleBackColor = true;
this.btnDown.Click += new System.EventHandler(this.btnMapping_Click);
//
// btnUp
//
this.btnUp.Location = new System.Drawing.Point(68, 34);
this.btnUp.Name = "btnUp";
this.btnUp.Size = new System.Drawing.Size(64, 35);
this.btnUp.TabIndex = 18;
this.btnUp.Text = "Up";
this.btnUp.UseVisualStyleBackColor = true;
this.btnUp.Click += new System.EventHandler(this.btnMapping_Click);
//
// btnStart
//
this.btnStart.Location = new System.Drawing.Point(316, 131);
this.btnStart.Name = "btnStart";
this.btnStart.Size = new System.Drawing.Size(61, 37);
this.btnStart.TabIndex = 13;
this.btnStart.Text = "W";
this.btnStart.UseVisualStyleBackColor = true;
this.btnStart.Click += new System.EventHandler(this.btnMapping_Click);
//
// btnB
//
this.btnB.Location = new System.Drawing.Point(417, 105);
this.btnB.Name = "btnB";
this.btnB.Size = new System.Drawing.Size(61, 59);
this.btnB.TabIndex = 15;
this.btnB.Text = "B";
this.btnB.UseVisualStyleBackColor = true;
this.btnB.Click += new System.EventHandler(this.btnMapping_Click);
//
// btnTurboA
//
this.btnTurboA.Location = new System.Drawing.Point(499, 17);
this.btnTurboA.Name = "btnTurboA";
this.btnTurboA.Size = new System.Drawing.Size(61, 59);
this.btnTurboA.TabIndex = 20;
this.btnTurboA.Text = "A";
this.btnTurboA.UseVisualStyleBackColor = true;
this.btnTurboA.Click += new System.EventHandler(this.btnMapping_Click);
//
// btnLeft
//
this.btnLeft.Location = new System.Drawing.Point(29, 90);
this.btnLeft.Name = "btnLeft";
this.btnLeft.Size = new System.Drawing.Size(64, 35);
this.btnLeft.TabIndex = 17;
this.btnLeft.Text = "Left";
this.btnLeft.UseVisualStyleBackColor = true;
this.btnLeft.Click += new System.EventHandler(this.btnMapping_Click);
//
// btnSelect
//
this.btnSelect.Location = new System.Drawing.Point(234, 131);
this.btnSelect.Name = "btnSelect";
this.btnSelect.Size = new System.Drawing.Size(61, 37);
this.btnSelect.TabIndex = 12;
this.btnSelect.Text = "Q";
this.btnSelect.UseVisualStyleBackColor = true;
this.btnSelect.Click += new System.EventHandler(this.btnMapping_Click);
//
// btnRight
//
this.btnRight.Location = new System.Drawing.Point(108, 90);
this.btnRight.Name = "btnRight";
this.btnRight.Size = new System.Drawing.Size(64, 35);
this.btnRight.TabIndex = 16;
this.btnRight.Text = "Right";
this.btnRight.UseVisualStyleBackColor = true;
this.btnRight.Click += new System.EventHandler(this.btnMapping_Click);
//
// btnTurboB
//
this.btnTurboB.Location = new System.Drawing.Point(417, 17);
this.btnTurboB.Name = "btnTurboB";
this.btnTurboB.Size = new System.Drawing.Size(61, 59);
this.btnTurboB.TabIndex = 21;
this.btnTurboB.Text = "B";
this.btnTurboB.UseVisualStyleBackColor = true;
this.btnTurboB.Click += new System.EventHandler(this.btnMapping_Click);
//
// ctrlStandardController
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.tableLayoutPanel1);
this.Controls.Add(this.panel2);
this.Name = "ctrlStandardController";
this.Size = new System.Drawing.Size(612, 317);
((System.ComponentModel.ISupportInitialize)(this.picControllerLayout)).EndInit();
this.tableLayoutPanel1.ResumeLayout(false);
this.tableLayoutPanel1.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.trkTurboSpeed)).EndInit();
this.panel1.ResumeLayout(false);
this.panel1.PerformLayout();
this.Size = new System.Drawing.Size(585, 210);
this.panel2.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.picControllerLayout)).EndInit();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Panel panel2;
private System.Windows.Forms.Button btnTurboB;
private System.Windows.Forms.Button btnRight;
private System.Windows.Forms.Button btnSelect;
private System.Windows.Forms.Button btnLeft;
private System.Windows.Forms.Button btnTurboA;
private System.Windows.Forms.Button btnB;
private System.Windows.Forms.Button btnStart;
private System.Windows.Forms.Button btnUp;
private System.Windows.Forms.Button btnDown;
private System.Windows.Forms.Button btnA;
private System.Windows.Forms.Button btnUp;
private System.Windows.Forms.Button btnB;
private System.Windows.Forms.Button btnLeft;
private System.Windows.Forms.Button btnRight;
private System.Windows.Forms.PictureBox picControllerLayout;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.TrackBar trkTurboSpeed;
private System.Windows.Forms.Label lblTurboSpeed;
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.Label lblTurboFast;
private System.Windows.Forms.Label lblSlow;
private System.Windows.Forms.Panel panel2;
}
}

View file

@ -30,9 +30,20 @@ namespace Mesen.GUI.Forms.Config
btnRight.Text = mappings.Right;
btnTurboA.Text = mappings.TurboA;
btnTurboB.Text = mappings.TurboB;
trkTurboSpeed.Value = (Int32)mappings.TurboSpeed;
trkTurboSpeed.BackColor = Color.FromArgb(255, trkTurboSpeed.Parent.BackColor);
}
public void ClearKeys()
{
btnA.Text = "";
btnB.Text = "";
btnStart.Text = "";
btnSelect.Text = "";
btnUp.Text = "";
btnDown.Text = "";
btnLeft.Text = "";
btnRight.Text = "";
btnTurboA.Text = "";
btnTurboB.Text = "";
}
private void btnMapping_Click(object sender, EventArgs e)
@ -57,7 +68,6 @@ namespace Mesen.GUI.Forms.Config
TurboB = btnTurboB.Text,
TurboSelect = string.Empty,
TurboStart = string.Empty,
TurboSpeed = (UInt32)trkTurboSpeed.Value
};
return mappings;
}

View file

@ -120,126 +120,166 @@
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="picControllerLayout.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
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
KuYPLuZfrE1Fv6zbg29c3E9TB6/Ycn7XMM8nMZlMim9BhabuMeNhm7pW8damo+LDaur6ityf09ylrlH2
3NT1y8m9xv0yc1+dfH7v4Nl93mjqKvr9in0V9em9bxV9nz9d3KfX5s/Lv62v6vW/L34IokJTB6/Ycn7X
MM8nMZlMim9BxfPmnuZfAxHj+Xl/uvUBIq3tXlW8temoODYDfzzzo7P5XrNrTV03Jeef+9ll7j/KG+8R
Syp23dS1in55+dulG7BuvF78QEpFr+NlU/e18tzEVbxxVbWi16bXtd9L1++765deP3+cP7ufpg5eseX8
rmGeT2IymRTfggpN3WPGQzd1rSI2HRXHZqD/PXp+X1fF+zV1/cMS55/7sWWum5GHaeqOKvonibuB/vlF
PjV1vXb9XPQ6HvVL1s9XP3vc+bPbPyu/P94+y/fa90BTB6/Qcn7XMM8nMZlMim9BhabuMePhm7qjihdN
R8VTM3B+n3MV79fUve3l1++Wh3j59VLFz8svL3IvmrqK/pUu3cB1vn9w5aivpPbVz48u97ts6o4/UPGV
Y27Ja+rgFVvO7xrm+SQmk0nxLah43tzT/GsgYjw/70+3PkCktX0tKp6bjooPq6n7YunBq/5BiYr+6dVu
YD+93O6Xursp+87F/Xodz5uzvmrazfXle+M+WXrwteX2G2tT8btyeSVQUwev2HJ+1zDPJzGZTIpvQYWm
7jHjYZu6iqtNR8VzM3Dh+MuHe826+Tife/rlwBXd1PXLgedz538poef7a/UVqH6/2GdK13t+z95yvz03
df19dZPVN1pfffthuF9/3+dNXb8/7unXzFyq+FX5xTJOTd03S3+dj5/ljk20pg5eoeX8rmGeT2IymRTf
gornzT3NvwYixvPz/nTrA0Ra2z2quNp0VHSTd5w793SFraKvKF3O/WqZ+8VZ7uj/n9Xun+7sH5joN/cf
57uZefrFxmf368blqeZeVRz/QsbTy6YA71LF0/+hl/lrYjKZFN+CCk3dY8bDNnVHFXdtOir6vXy7+vNf
AFtR0R9qmOeTmEwmxbegQlP3mPHwTR0A+9Xb0mFryvNJTCaT4ltQoal7zNDUAbBbvS0dtqY8n8RkMim+
BRWauscMTR0Au9Xb0mFryvNJTCaT4ltQoal7zNDUAbBbvS0dtqY8n8RkMim+BRWauscMTR0Au9Xb0mFr
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
w9JudSxN4uTegdtxMDGTJx9jTjD8v3jG6a1XrR1S21eOSVIrkh4ReXj2a1WX/FBwsjZLlqN3x8trr+8t
4UselnarY2kSJ/cO3I6Difmj4M23WbWMOcxMHqe1feWYJBRJT4/xgpIsFXFj6xP9GPucJW+JxwVLlqNx
3rlN7T09lZ+Th6Xd6liaxMm9A7fjYGL+MHjzl61axhxmJo/T2r5yTJIfYzOs4QgIE/7FtdfrbMkdgwdn
nX+UsORG8fTo9ef3IeFLHpZ2q2NpEif3DtyOg4n5g+DNt121TM98enxGfGZ8Vnx2fE5cFFeMK8XFceW4
SnChv6vG1eLqcY24ZlwrrhPXjevFDeKGcaPgyAA3feXee9xahtt2cMFFrnvFZR34yDznU3DOGUuqLFdR
aPD3/vK4XXxFfGXw0fA7xFcHE8PXxNfGneLOcZe4a3xdfH18Q9w97hH3jHvFveMb4z5x3/jmuF/cP74l
HhDfFg+Mb48Hx3fEdwb/7/y74ruDE4y/J74vHhZvDMYpv/NOqe0r0rYSTnRffaqt0vfoeEutr6eEL3lY
2q2OpUmc3DtwOw4m5iXBmzkcz38MfjoeG/w/zcfHzwaH658YTwo++vpz8fPxC/GUeGo8LfgevxTPiGfG
s+KX49nxK/Gc+LX49XhucGG234znxwvi8vit+O3g0zi/Ey8KPrb84vj94PelsOPIAuepcE4VJ5/z6Seu
pcN1n7hAJldo5n5f3JuOm/hyF/nXB8sMTLhvCv5f4FvjbcFJmO+Id8a74j3x3nhfcBuHD8aHguujfCQ+
Gpyj8Ffx18Gnhf4m/jbYntoPirqdUttXpDlhGA9DubRbHUuTOLl34HYcTMzvBW9WfxRMFE4UUBRSFFQU
VhRYFFoUXBReFGAUYhRkFGYUaBRqFGwUbhRwFHIUdBR2FHgUehR8FH4UgBSCFIQUhhSIFIoUjBSOFJAU
khSUFJYUmBSaFJwUnhSgFKIUpBSmFKgUqhSsFK4UsBSyFLQUthS4FLoUvBS+FMAUwhTEFMYUyBTKFMwU
zhTQFNIU1BTWFNgU2hTcFN4U4BTiFOQU5hToFOoU7BTuPxk/ET8eHD3bKbV9RZoThvEwlEu71bE0yTi5
8x8iHu8LZ+I/6gSdxs9jO1ok7R6WQh4eLGmwtMESB0sdLHmw9MESCEshLImwNMISCUslLJmwdMISCksp
fB+WVlhiYamFJReWXliCYSmGJRmWZliiYamGJRuWbljCYSmHJR2WdljiYamHJR+WflgCYimIJSGOIrDc
wlIRS0YsHbGExFISS0osLbHExFITS04sPbEExVIUS1IsTTHJslTFkhVLVyxhsZTFkhZLWyxxsdTFkhdL
XyyBsRTGkhhLYyyRsVTGkhlLZyyhsZTGkhpLayyxmQNKbV+R5oRhPAzl0m51LE1CAbP6N56AT5ygk/55
4GdaJBljzkptX5HmhGE8DOXSbnUsUbJ51Gcf9n2katNJ/7yV2vY9JsaYc1PbV6Q5YRgPQ7m0Wx2S2owx
56a2r0hzwjAehnJptzoktRljzk1tX5HmhGE8DOXSbnVIajPGnJvaviLNCcN4GMql3eqQ1GaMOTe1fUWa
E4bxMJRLu9Uhqc0Yc25q+4o0JwzjYSiXdqtDUpsx5tzU9hVpThjGw1Au7VaHpDZjzLmp7SvSnDCMh6Fc
2q0OSW1mman9rSUdD/4zMPynoLRbHZIkScdksxZqdkiSJB2TzVqo2SFJknRMNmuhZockSdIx2ayFmh2S
JEnHZLMWanZIkiQdk81aqNkhSZJ0TDZroWaHJEnSMdmshZodkiRJx2SzFmp2SJIkHZPNWqjZIUmSdEw2
a6FmhyRJ0jHZrIWaHZIkScdksxZqdkiSJB2TzVqo2SFJknRMNmuhczokSZKOmUWSJElSxTlFkiRJkkaf
/LT/D/XHWcQRIejmAAAAAElFTkSuQmCC
</value>
</data>
</root>

View file

@ -0,0 +1,305 @@
namespace Mesen.GUI.Forms.Config
{
partial class frmControllerConfig
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if(disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.ctrlStandardController0 = new Mesen.GUI.Forms.Config.ctrlStandardController();
this.tabMain = new System.Windows.Forms.TabControl();
this.tpgSet1 = new System.Windows.Forms.TabPage();
this.tpgSet2 = new System.Windows.Forms.TabPage();
this.ctrlStandardController1 = new Mesen.GUI.Forms.Config.ctrlStandardController();
this.tpgSet3 = new System.Windows.Forms.TabPage();
this.ctrlStandardController2 = new Mesen.GUI.Forms.Config.ctrlStandardController();
this.tpgSet4 = new System.Windows.Forms.TabPage();
this.ctrlStandardController3 = new Mesen.GUI.Forms.Config.ctrlStandardController();
this.btnClear = new System.Windows.Forms.Button();
this.btnReset = new System.Windows.Forms.Button();
this.flowLayoutPanel2 = new System.Windows.Forms.FlowLayoutPanel();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.trkTurboSpeed = new System.Windows.Forms.TrackBar();
this.lblTurboSpeed = new System.Windows.Forms.Label();
this.panel1 = new System.Windows.Forms.Panel();
this.lblTurboFast = new System.Windows.Forms.Label();
this.lblSlow = new System.Windows.Forms.Label();
this.baseConfigPanel.SuspendLayout();
this.tabMain.SuspendLayout();
this.tpgSet1.SuspendLayout();
this.tpgSet2.SuspendLayout();
this.tpgSet3.SuspendLayout();
this.tpgSet4.SuspendLayout();
this.flowLayoutPanel2.SuspendLayout();
this.tableLayoutPanel1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.trkTurboSpeed)).BeginInit();
this.panel1.SuspendLayout();
this.SuspendLayout();
//
// baseConfigPanel
//
this.baseConfigPanel.Controls.Add(this.flowLayoutPanel2);
this.baseConfigPanel.Location = new System.Drawing.Point(0, 288);
this.baseConfigPanel.Size = new System.Drawing.Size(599, 29);
this.baseConfigPanel.Controls.SetChildIndex(this.flowLayoutPanel2, 0);
//
// ctrlStandardController0
//
this.ctrlStandardController0.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlStandardController0.Location = new System.Drawing.Point(0, 0);
this.ctrlStandardController0.Margin = new System.Windows.Forms.Padding(0);
this.ctrlStandardController0.Name = "ctrlStandardController0";
this.ctrlStandardController0.Size = new System.Drawing.Size(585, 209);
this.ctrlStandardController0.TabIndex = 0;
//
// tabMain
//
this.tableLayoutPanel1.SetColumnSpan(this.tabMain, 3);
this.tabMain.Controls.Add(this.tpgSet1);
this.tabMain.Controls.Add(this.tpgSet2);
this.tabMain.Controls.Add(this.tpgSet3);
this.tabMain.Controls.Add(this.tpgSet4);
this.tabMain.Dock = System.Windows.Forms.DockStyle.Fill;
this.tabMain.Location = new System.Drawing.Point(3, 3);
this.tabMain.Name = "tabMain";
this.tabMain.SelectedIndex = 0;
this.tabMain.Size = new System.Drawing.Size(593, 235);
this.tabMain.TabIndex = 3;
//
// tpgSet1
//
this.tpgSet1.Controls.Add(this.ctrlStandardController0);
this.tpgSet1.Location = new System.Drawing.Point(4, 22);
this.tpgSet1.Name = "tpgSet1";
this.tpgSet1.Size = new System.Drawing.Size(585, 209);
this.tpgSet1.TabIndex = 0;
this.tpgSet1.Text = "Key Set #1";
this.tpgSet1.UseVisualStyleBackColor = true;
//
// tpgSet2
//
this.tpgSet2.Controls.Add(this.ctrlStandardController1);
this.tpgSet2.Location = new System.Drawing.Point(4, 22);
this.tpgSet2.Name = "tpgSet2";
this.tpgSet2.Size = new System.Drawing.Size(585, 209);
this.tpgSet2.TabIndex = 1;
this.tpgSet2.Text = "Key Set #2";
this.tpgSet2.UseVisualStyleBackColor = true;
//
// ctrlStandardController1
//
this.ctrlStandardController1.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlStandardController1.Location = new System.Drawing.Point(0, 0);
this.ctrlStandardController1.Margin = new System.Windows.Forms.Padding(0);
this.ctrlStandardController1.Name = "ctrlStandardController1";
this.ctrlStandardController1.Size = new System.Drawing.Size(585, 209);
this.ctrlStandardController1.TabIndex = 1;
//
// tpgSet3
//
this.tpgSet3.Controls.Add(this.ctrlStandardController2);
this.tpgSet3.Location = new System.Drawing.Point(4, 22);
this.tpgSet3.Name = "tpgSet3";
this.tpgSet3.Size = new System.Drawing.Size(585, 209);
this.tpgSet3.TabIndex = 2;
this.tpgSet3.Text = "Key Set #3";
this.tpgSet3.UseVisualStyleBackColor = true;
//
// ctrlStandardController2
//
this.ctrlStandardController2.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlStandardController2.Location = new System.Drawing.Point(0, 0);
this.ctrlStandardController2.Margin = new System.Windows.Forms.Padding(0);
this.ctrlStandardController2.Name = "ctrlStandardController2";
this.ctrlStandardController2.Size = new System.Drawing.Size(585, 209);
this.ctrlStandardController2.TabIndex = 1;
//
// tpgSet4
//
this.tpgSet4.Controls.Add(this.ctrlStandardController3);
this.tpgSet4.Location = new System.Drawing.Point(4, 22);
this.tpgSet4.Name = "tpgSet4";
this.tpgSet4.Size = new System.Drawing.Size(585, 209);
this.tpgSet4.TabIndex = 3;
this.tpgSet4.Text = "Key Set #4";
this.tpgSet4.UseVisualStyleBackColor = true;
//
// ctrlStandardController3
//
this.ctrlStandardController3.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlStandardController3.Location = new System.Drawing.Point(0, 0);
this.ctrlStandardController3.Margin = new System.Windows.Forms.Padding(0);
this.ctrlStandardController3.Name = "ctrlStandardController3";
this.ctrlStandardController3.Size = new System.Drawing.Size(585, 209);
this.ctrlStandardController3.TabIndex = 1;
//
// btnClear
//
this.btnClear.Location = new System.Drawing.Point(118, 3);
this.btnClear.Name = "btnClear";
this.btnClear.Size = new System.Drawing.Size(109, 23);
this.btnClear.TabIndex = 3;
this.btnClear.Text = "Clear Key Bindings";
this.btnClear.UseVisualStyleBackColor = true;
this.btnClear.Click += new System.EventHandler(this.btnClear_Click);
//
// btnReset
//
this.btnReset.Location = new System.Drawing.Point(3, 3);
this.btnReset.Name = "btnReset";
this.btnReset.Size = new System.Drawing.Size(109, 23);
this.btnReset.TabIndex = 4;
this.btnReset.Text = "Reset to Default";
this.btnReset.UseVisualStyleBackColor = true;
this.btnReset.Visible = false;
this.btnReset.Click += new System.EventHandler(this.btnReset_Click);
//
// flowLayoutPanel2
//
this.flowLayoutPanel2.Controls.Add(this.btnReset);
this.flowLayoutPanel2.Controls.Add(this.btnClear);
this.flowLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Left;
this.flowLayoutPanel2.Location = new System.Drawing.Point(0, 0);
this.flowLayoutPanel2.Margin = new System.Windows.Forms.Padding(0);
this.flowLayoutPanel2.Name = "flowLayoutPanel2";
this.flowLayoutPanel2.Size = new System.Drawing.Size(396, 29);
this.flowLayoutPanel2.TabIndex = 5;
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.ColumnCount = 3;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.Controls.Add(this.trkTurboSpeed, 2, 1);
this.tableLayoutPanel1.Controls.Add(this.lblTurboSpeed, 1, 1);
this.tableLayoutPanel1.Controls.Add(this.panel1, 2, 2);
this.tableLayoutPanel1.Controls.Add(this.tabMain, 0, 0);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 3;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 32F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.Size = new System.Drawing.Size(599, 288);
this.tableLayoutPanel1.TabIndex = 23;
//
// trkTurboSpeed
//
this.trkTurboSpeed.LargeChange = 2;
this.trkTurboSpeed.Location = new System.Drawing.Point(479, 244);
this.trkTurboSpeed.Maximum = 3;
this.trkTurboSpeed.Name = "trkTurboSpeed";
this.trkTurboSpeed.Size = new System.Drawing.Size(117, 26);
this.trkTurboSpeed.TabIndex = 0;
//
// lblTurboSpeed
//
this.lblTurboSpeed.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblTurboSpeed.AutoSize = true;
this.lblTurboSpeed.Location = new System.Drawing.Point(401, 250);
this.lblTurboSpeed.Name = "lblTurboSpeed";
this.lblTurboSpeed.Size = new System.Drawing.Size(72, 13);
this.lblTurboSpeed.TabIndex = 1;
this.lblTurboSpeed.Text = "Turbo Speed:";
//
// panel1
//
this.panel1.Controls.Add(this.lblTurboFast);
this.panel1.Controls.Add(this.lblSlow);
this.panel1.Location = new System.Drawing.Point(476, 273);
this.panel1.Margin = new System.Windows.Forms.Padding(0);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(120, 15);
this.panel1.TabIndex = 2;
//
// lblTurboFast
//
this.lblTurboFast.AutoSize = true;
this.lblTurboFast.Location = new System.Drawing.Point(90, 0);
this.lblTurboFast.Name = "lblTurboFast";
this.lblTurboFast.Size = new System.Drawing.Size(27, 13);
this.lblTurboFast.TabIndex = 1;
this.lblTurboFast.Text = "Fast";
//
// lblSlow
//
this.lblSlow.AutoSize = true;
this.lblSlow.Location = new System.Drawing.Point(3, 0);
this.lblSlow.Name = "lblSlow";
this.lblSlow.Size = new System.Drawing.Size(30, 13);
this.lblSlow.TabIndex = 0;
this.lblSlow.Text = "Slow";
//
// frmControllerConfig
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(599, 317);
this.Controls.Add(this.tableLayoutPanel1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
this.Name = "frmControllerConfig";
this.Text = "Standard Controller";
this.Controls.SetChildIndex(this.baseConfigPanel, 0);
this.Controls.SetChildIndex(this.tableLayoutPanel1, 0);
this.baseConfigPanel.ResumeLayout(false);
this.tabMain.ResumeLayout(false);
this.tpgSet1.ResumeLayout(false);
this.tpgSet2.ResumeLayout(false);
this.tpgSet3.ResumeLayout(false);
this.tpgSet4.ResumeLayout(false);
this.flowLayoutPanel2.ResumeLayout(false);
this.tableLayoutPanel1.ResumeLayout(false);
this.tableLayoutPanel1.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.trkTurboSpeed)).EndInit();
this.panel1.ResumeLayout(false);
this.panel1.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private ctrlStandardController ctrlStandardController0;
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel2;
private System.Windows.Forms.Button btnReset;
private System.Windows.Forms.Button btnClear;
private System.Windows.Forms.TabControl tabMain;
private System.Windows.Forms.TabPage tpgSet1;
private System.Windows.Forms.TabPage tpgSet2;
private ctrlStandardController ctrlStandardController1;
private System.Windows.Forms.TabPage tpgSet3;
private ctrlStandardController ctrlStandardController2;
private System.Windows.Forms.TabPage tpgSet4;
private ctrlStandardController ctrlStandardController3;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.TrackBar trkTurboSpeed;
private System.Windows.Forms.Label lblTurboSpeed;
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.Label lblTurboFast;
private System.Windows.Forms.Label lblSlow;
}
}

View file

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Mesen.GUI.Config;
namespace Mesen.GUI.Forms.Config
{
public partial class frmControllerConfig : BaseConfigForm
{
public frmControllerConfig(ControllerInfo controllerInfo)
{
InitializeComponent();
Entity = controllerInfo;
AddBinding("TurboSpeed", trkTurboSpeed);
ctrlStandardController0.Initialize(controllerInfo.Keys[0]);
ctrlStandardController1.Initialize(controllerInfo.Keys[1]);
ctrlStandardController2.Initialize(controllerInfo.Keys[2]);
ctrlStandardController3.Initialize(controllerInfo.Keys[3]);
}
protected override void UpdateConfig()
{
ControllerInfo controllerInfo = (ControllerInfo)Entity;
controllerInfo.Keys[0] = ctrlStandardController0.GetKeyMappings();
controllerInfo.Keys[1] = ctrlStandardController1.GetKeyMappings();
controllerInfo.Keys[2] = ctrlStandardController2.GetKeyMappings();
controllerInfo.Keys[3] = ctrlStandardController3.GetKeyMappings();
base.UpdateConfig();
}
private void btnClear_Click(object sender, EventArgs e)
{
ControllerInfo controllerInfo = (ControllerInfo)Entity;
if(tabMain.SelectedTab == tpgSet1) {
ctrlStandardController0.ClearKeys();
} else if(tabMain.SelectedTab == tpgSet2) {
ctrlStandardController1.ClearKeys();
} else if(tabMain.SelectedTab == tpgSet3) {
ctrlStandardController2.ClearKeys();
} else if(tabMain.SelectedTab == tpgSet4) {
ctrlStandardController3.ClearKeys();
}
}
private void btnReset_Click(object sender, EventArgs e)
{
}
}
}

View file

@ -0,0 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>

View file

@ -28,115 +28,277 @@
private void InitializeComponent()
{
this.tabMain = new System.Windows.Forms.TabControl();
this.tpgPort1 = new System.Windows.Forms.TabPage();
this.ctrlInputPortConfig1 = new Mesen.GUI.Forms.Config.ctrlInputPortConfig();
this.tpgPort2 = new System.Windows.Forms.TabPage();
this.ctrlInputPortConfig2 = new Mesen.GUI.Forms.Config.ctrlInputPortConfig();
this.tpgPort3 = new System.Windows.Forms.TabPage();
this.ctrlInputPortConfig3 = new Mesen.GUI.Forms.Config.ctrlInputPortConfig();
this.tpgPort4 = new System.Windows.Forms.TabPage();
this.ctrlInputPortConfig4 = new Mesen.GUI.Forms.Config.ctrlInputPortConfig();
this.tpgControllers = new System.Windows.Forms.TabPage();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.btnSetupP4 = new System.Windows.Forms.Button();
this.btnSetupP3 = new System.Windows.Forms.Button();
this.lblPlayer1 = new System.Windows.Forms.Label();
this.lblPlayer2 = new System.Windows.Forms.Label();
this.cboPlayer4 = new System.Windows.Forms.ComboBox();
this.cboPlayer3 = new System.Windows.Forms.ComboBox();
this.cboPlayer1 = new System.Windows.Forms.ComboBox();
this.lblPlayer4 = new System.Windows.Forms.Label();
this.cboPlayer2 = new System.Windows.Forms.ComboBox();
this.lblPlayer3 = new System.Windows.Forms.Label();
this.btnSetupP1 = new System.Windows.Forms.Button();
this.btnSetupP2 = new System.Windows.Forms.Button();
this.lblNesType = new System.Windows.Forms.Label();
this.cboConsoleType = new System.Windows.Forms.ComboBox();
this.lblExpansionPort = new System.Windows.Forms.Label();
this.cboExpansionPort = new System.Windows.Forms.ComboBox();
this.chkFourScore = new System.Windows.Forms.CheckBox();
this.tpgEmulatorKeys = new System.Windows.Forms.TabPage();
this.tabMain.SuspendLayout();
this.tpgPort1.SuspendLayout();
this.tpgPort2.SuspendLayout();
this.tpgPort3.SuspendLayout();
this.tpgPort4.SuspendLayout();
this.tpgControllers.SuspendLayout();
this.tableLayoutPanel1.SuspendLayout();
this.SuspendLayout();
//
// baseConfigPanel
//
this.baseConfigPanel.Location = new System.Drawing.Point(0, 224);
this.baseConfigPanel.Size = new System.Drawing.Size(348, 29);
//
// tabMain
//
this.tabMain.Controls.Add(this.tpgPort1);
this.tabMain.Controls.Add(this.tpgPort2);
this.tabMain.Controls.Add(this.tpgPort3);
this.tabMain.Controls.Add(this.tpgPort4);
this.tabMain.Controls.Add(this.tpgControllers);
this.tabMain.Controls.Add(this.tpgEmulatorKeys);
this.tabMain.Dock = System.Windows.Forms.DockStyle.Fill;
this.tabMain.Location = new System.Drawing.Point(0, 0);
this.tabMain.Name = "tabMain";
this.tabMain.SelectedIndex = 0;
this.tabMain.Size = new System.Drawing.Size(633, 376);
this.tabMain.Size = new System.Drawing.Size(348, 253);
this.tabMain.TabIndex = 11;
//
// tpgPort1
// tpgControllers
//
this.tpgPort1.Controls.Add(this.ctrlInputPortConfig1);
this.tpgPort1.Location = new System.Drawing.Point(4, 22);
this.tpgPort1.Name = "tpgPort1";
this.tpgPort1.Size = new System.Drawing.Size(625, 350);
this.tpgPort1.TabIndex = 0;
this.tpgPort1.Text = "Port 1";
this.tpgPort1.UseVisualStyleBackColor = true;
this.tpgControllers.Controls.Add(this.tableLayoutPanel1);
this.tpgControllers.Location = new System.Drawing.Point(4, 22);
this.tpgControllers.Name = "tpgControllers";
this.tpgControllers.Size = new System.Drawing.Size(340, 227);
this.tpgControllers.TabIndex = 0;
this.tpgControllers.Text = "Controllers";
this.tpgControllers.UseVisualStyleBackColor = true;
//
// ctrlInputPortConfig1
// tableLayoutPanel1
//
this.ctrlInputPortConfig1.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlInputPortConfig1.Location = new System.Drawing.Point(0, 0);
this.ctrlInputPortConfig1.Margin = new System.Windows.Forms.Padding(0);
this.ctrlInputPortConfig1.Name = "ctrlInputPortConfig1";
this.ctrlInputPortConfig1.Size = new System.Drawing.Size(625, 350);
this.ctrlInputPortConfig1.TabIndex = 0;
this.tableLayoutPanel1.ColumnCount = 3;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.Controls.Add(this.btnSetupP4, 2, 7);
this.tableLayoutPanel1.Controls.Add(this.btnSetupP3, 2, 6);
this.tableLayoutPanel1.Controls.Add(this.lblPlayer1, 0, 2);
this.tableLayoutPanel1.Controls.Add(this.lblPlayer2, 0, 3);
this.tableLayoutPanel1.Controls.Add(this.cboPlayer4, 1, 7);
this.tableLayoutPanel1.Controls.Add(this.cboPlayer3, 1, 6);
this.tableLayoutPanel1.Controls.Add(this.cboPlayer1, 1, 2);
this.tableLayoutPanel1.Controls.Add(this.lblPlayer4, 0, 7);
this.tableLayoutPanel1.Controls.Add(this.cboPlayer2, 1, 3);
this.tableLayoutPanel1.Controls.Add(this.lblPlayer3, 0, 6);
this.tableLayoutPanel1.Controls.Add(this.btnSetupP1, 2, 2);
this.tableLayoutPanel1.Controls.Add(this.btnSetupP2, 2, 3);
this.tableLayoutPanel1.Controls.Add(this.lblNesType, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.cboConsoleType, 1, 0);
this.tableLayoutPanel1.Controls.Add(this.lblExpansionPort, 0, 5);
this.tableLayoutPanel1.Controls.Add(this.cboExpansionPort, 1, 5);
this.tableLayoutPanel1.Controls.Add(this.chkFourScore, 0, 4);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 9;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 10F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(340, 227);
this.tableLayoutPanel1.TabIndex = 0;
//
// tpgPort2
// btnSetupP4
//
this.tpgPort2.Controls.Add(this.ctrlInputPortConfig2);
this.tpgPort2.Location = new System.Drawing.Point(4, 22);
this.tpgPort2.Name = "tpgPort2";
this.tpgPort2.Size = new System.Drawing.Size(625, 359);
this.tpgPort2.TabIndex = 1;
this.tpgPort2.Text = "Port 2";
this.tpgPort2.UseVisualStyleBackColor = true;
this.btnSetupP4.Location = new System.Drawing.Point(279, 171);
this.btnSetupP4.Name = "btnSetupP4";
this.btnSetupP4.Size = new System.Drawing.Size(56, 21);
this.btnSetupP4.TabIndex = 12;
this.btnSetupP4.Text = "Setup";
this.btnSetupP4.UseVisualStyleBackColor = true;
this.btnSetupP4.Click += new System.EventHandler(this.btnSetup_Click);
//
// ctrlInputPortConfig2
// btnSetupP3
//
this.ctrlInputPortConfig2.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlInputPortConfig2.Location = new System.Drawing.Point(0, 0);
this.ctrlInputPortConfig2.Name = "ctrlInputPortConfig2";
this.ctrlInputPortConfig2.Size = new System.Drawing.Size(625, 359);
this.ctrlInputPortConfig2.TabIndex = 1;
this.btnSetupP3.Location = new System.Drawing.Point(279, 144);
this.btnSetupP3.Name = "btnSetupP3";
this.btnSetupP3.Size = new System.Drawing.Size(56, 21);
this.btnSetupP3.TabIndex = 11;
this.btnSetupP3.Text = "Setup";
this.btnSetupP3.UseVisualStyleBackColor = true;
this.btnSetupP3.Click += new System.EventHandler(this.btnSetup_Click);
//
// tpgPort3
// lblPlayer1
//
this.tpgPort3.Controls.Add(this.ctrlInputPortConfig3);
this.tpgPort3.Location = new System.Drawing.Point(4, 22);
this.tpgPort3.Name = "tpgPort3";
this.tpgPort3.Size = new System.Drawing.Size(625, 359);
this.tpgPort3.TabIndex = 2;
this.tpgPort3.Text = "Port 3";
this.tpgPort3.UseVisualStyleBackColor = true;
this.lblPlayer1.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblPlayer1.AutoSize = true;
this.lblPlayer1.Location = new System.Drawing.Point(3, 44);
this.lblPlayer1.Name = "lblPlayer1";
this.lblPlayer1.Size = new System.Drawing.Size(48, 13);
this.lblPlayer1.TabIndex = 0;
this.lblPlayer1.Text = "Player 1:";
//
// ctrlInputPortConfig3
// lblPlayer2
//
this.ctrlInputPortConfig3.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlInputPortConfig3.Location = new System.Drawing.Point(0, 0);
this.ctrlInputPortConfig3.Name = "ctrlInputPortConfig3";
this.ctrlInputPortConfig3.Size = new System.Drawing.Size(625, 359);
this.ctrlInputPortConfig3.TabIndex = 1;
this.lblPlayer2.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblPlayer2.AutoSize = true;
this.lblPlayer2.Location = new System.Drawing.Point(3, 71);
this.lblPlayer2.Name = "lblPlayer2";
this.lblPlayer2.Size = new System.Drawing.Size(48, 13);
this.lblPlayer2.TabIndex = 1;
this.lblPlayer2.Text = "Player 2:";
//
// tpgPort4
// cboPlayer4
//
this.tpgPort4.Controls.Add(this.ctrlInputPortConfig4);
this.tpgPort4.Location = new System.Drawing.Point(4, 22);
this.tpgPort4.Name = "tpgPort4";
this.tpgPort4.Size = new System.Drawing.Size(625, 359);
this.tpgPort4.TabIndex = 3;
this.tpgPort4.Text = "Port 4";
this.tpgPort4.UseVisualStyleBackColor = true;
this.cboPlayer4.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cboPlayer4.FormattingEnabled = true;
this.cboPlayer4.Location = new System.Drawing.Point(90, 171);
this.cboPlayer4.Name = "cboPlayer4";
this.cboPlayer4.Size = new System.Drawing.Size(183, 21);
this.cboPlayer4.TabIndex = 8;
this.cboPlayer4.SelectedIndexChanged += new System.EventHandler(this.cboPlayerController_SelectedIndexChanged);
//
// ctrlInputPortConfig4
// cboPlayer3
//
this.ctrlInputPortConfig4.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlInputPortConfig4.Location = new System.Drawing.Point(0, 0);
this.ctrlInputPortConfig4.Margin = new System.Windows.Forms.Padding(0);
this.ctrlInputPortConfig4.Name = "ctrlInputPortConfig4";
this.ctrlInputPortConfig4.Size = new System.Drawing.Size(625, 359);
this.ctrlInputPortConfig4.TabIndex = 1;
this.cboPlayer3.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cboPlayer3.FormattingEnabled = true;
this.cboPlayer3.Location = new System.Drawing.Point(90, 144);
this.cboPlayer3.Name = "cboPlayer3";
this.cboPlayer3.Size = new System.Drawing.Size(183, 21);
this.cboPlayer3.TabIndex = 7;
this.cboPlayer3.SelectedIndexChanged += new System.EventHandler(this.cboPlayerController_SelectedIndexChanged);
//
// cboPlayer1
//
this.cboPlayer1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cboPlayer1.FormattingEnabled = true;
this.cboPlayer1.Location = new System.Drawing.Point(90, 40);
this.cboPlayer1.Name = "cboPlayer1";
this.cboPlayer1.Size = new System.Drawing.Size(183, 21);
this.cboPlayer1.TabIndex = 4;
this.cboPlayer1.SelectedIndexChanged += new System.EventHandler(this.cboPlayerController_SelectedIndexChanged);
//
// lblPlayer4
//
this.lblPlayer4.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblPlayer4.AutoSize = true;
this.lblPlayer4.Location = new System.Drawing.Point(3, 175);
this.lblPlayer4.Name = "lblPlayer4";
this.lblPlayer4.Size = new System.Drawing.Size(48, 13);
this.lblPlayer4.TabIndex = 3;
this.lblPlayer4.Text = "Player 4:";
//
// cboPlayer2
//
this.cboPlayer2.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cboPlayer2.FormattingEnabled = true;
this.cboPlayer2.Location = new System.Drawing.Point(90, 67);
this.cboPlayer2.Name = "cboPlayer2";
this.cboPlayer2.Size = new System.Drawing.Size(183, 21);
this.cboPlayer2.TabIndex = 6;
this.cboPlayer2.SelectedIndexChanged += new System.EventHandler(this.cboPlayerController_SelectedIndexChanged);
//
// lblPlayer3
//
this.lblPlayer3.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblPlayer3.AutoSize = true;
this.lblPlayer3.Location = new System.Drawing.Point(3, 148);
this.lblPlayer3.Name = "lblPlayer3";
this.lblPlayer3.Size = new System.Drawing.Size(48, 13);
this.lblPlayer3.TabIndex = 2;
this.lblPlayer3.Text = "Player 3:";
//
// btnSetupP1
//
this.btnSetupP1.Location = new System.Drawing.Point(279, 40);
this.btnSetupP1.Name = "btnSetupP1";
this.btnSetupP1.Size = new System.Drawing.Size(56, 21);
this.btnSetupP1.TabIndex = 9;
this.btnSetupP1.Text = "Setup";
this.btnSetupP1.UseVisualStyleBackColor = true;
this.btnSetupP1.Click += new System.EventHandler(this.btnSetup_Click);
//
// btnSetupP2
//
this.btnSetupP2.Location = new System.Drawing.Point(279, 67);
this.btnSetupP2.Name = "btnSetupP2";
this.btnSetupP2.Size = new System.Drawing.Size(56, 21);
this.btnSetupP2.TabIndex = 10;
this.btnSetupP2.Text = "Setup";
this.btnSetupP2.UseVisualStyleBackColor = true;
this.btnSetupP2.Click += new System.EventHandler(this.btnSetup_Click);
//
// lblNesType
//
this.lblNesType.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblNesType.AutoSize = true;
this.lblNesType.Location = new System.Drawing.Point(3, 7);
this.lblNesType.Name = "lblNesType";
this.lblNesType.Size = new System.Drawing.Size(75, 13);
this.lblNesType.TabIndex = 13;
this.lblNesType.Text = "Console Type:";
//
// cboNesType
//
this.cboConsoleType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cboConsoleType.FormattingEnabled = true;
this.cboConsoleType.Items.AddRange(new object[] {
"NES",
"Famicom"});
this.cboConsoleType.Location = new System.Drawing.Point(90, 3);
this.cboConsoleType.Name = "cboNesType";
this.cboConsoleType.Size = new System.Drawing.Size(109, 21);
this.cboConsoleType.TabIndex = 14;
this.cboConsoleType.SelectedIndexChanged += new System.EventHandler(this.cboNesType_SelectedIndexChanged);
//
// lblExpansionPort
//
this.lblExpansionPort.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblExpansionPort.AutoSize = true;
this.lblExpansionPort.Location = new System.Drawing.Point(3, 121);
this.lblExpansionPort.Name = "lblExpansionPort";
this.lblExpansionPort.Size = new System.Drawing.Size(81, 13);
this.lblExpansionPort.TabIndex = 16;
this.lblExpansionPort.Text = "Expansion Port:";
//
// cboExpansionPort
//
this.cboExpansionPort.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cboExpansionPort.FormattingEnabled = true;
this.cboExpansionPort.Location = new System.Drawing.Point(90, 117);
this.cboExpansionPort.Name = "cboExpansionPort";
this.cboExpansionPort.Size = new System.Drawing.Size(183, 21);
this.cboExpansionPort.TabIndex = 17;
this.cboExpansionPort.SelectedIndexChanged += new System.EventHandler(this.cboExpansionPort_SelectedIndexChanged);
//
// chkFourScore
//
this.chkFourScore.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.chkFourScore.AutoSize = true;
this.tableLayoutPanel1.SetColumnSpan(this.chkFourScore, 2);
this.chkFourScore.Location = new System.Drawing.Point(3, 94);
this.chkFourScore.Name = "chkFourScore";
this.chkFourScore.Size = new System.Drawing.Size(151, 17);
this.chkFourScore.TabIndex = 15;
this.chkFourScore.Text = "Use Four Score accessory";
this.chkFourScore.UseVisualStyleBackColor = true;
this.chkFourScore.CheckedChanged += new System.EventHandler(this.chkFourScore_CheckedChanged);
//
// tpgEmulatorKeys
//
this.tpgEmulatorKeys.Location = new System.Drawing.Point(4, 22);
this.tpgEmulatorKeys.Name = "tpgEmulatorKeys";
this.tpgEmulatorKeys.Size = new System.Drawing.Size(625, 359);
this.tpgEmulatorKeys.Size = new System.Drawing.Size(340, 227);
this.tpgEmulatorKeys.TabIndex = 4;
this.tpgEmulatorKeys.Text = "Emulator Keys";
this.tpgEmulatorKeys.UseVisualStyleBackColor = true;
@ -145,17 +307,18 @@
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(633, 406);
this.ClientSize = new System.Drawing.Size(348, 253);
this.Controls.Add(this.tabMain);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Name = "frmInputConfig";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Input Settings";
this.Controls.SetChildIndex(this.tabMain, 0);
this.Controls.SetChildIndex(this.baseConfigPanel, 0);
this.tabMain.ResumeLayout(false);
this.tpgPort1.ResumeLayout(false);
this.tpgPort2.ResumeLayout(false);
this.tpgPort3.ResumeLayout(false);
this.tpgPort4.ResumeLayout(false);
this.tpgControllers.ResumeLayout(false);
this.tableLayoutPanel1.ResumeLayout(false);
this.tableLayoutPanel1.PerformLayout();
this.ResumeLayout(false);
}
@ -163,15 +326,25 @@
#endregion
private System.Windows.Forms.TabControl tabMain;
private System.Windows.Forms.TabPage tpgPort2;
private System.Windows.Forms.TabPage tpgPort3;
private System.Windows.Forms.TabPage tpgPort4;
private System.Windows.Forms.TabPage tpgEmulatorKeys;
private System.Windows.Forms.TabPage tpgPort1;
private ctrlInputPortConfig ctrlInputPortConfig1;
private ctrlInputPortConfig ctrlInputPortConfig2;
private ctrlInputPortConfig ctrlInputPortConfig3;
private ctrlInputPortConfig ctrlInputPortConfig4;
private System.Windows.Forms.TabPage tpgControllers;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.Label lblPlayer1;
private System.Windows.Forms.Label lblPlayer2;
private System.Windows.Forms.Label lblPlayer3;
private System.Windows.Forms.Label lblPlayer4;
private System.Windows.Forms.ComboBox cboPlayer1;
private System.Windows.Forms.ComboBox cboPlayer2;
private System.Windows.Forms.Button btnSetupP1;
private System.Windows.Forms.Button btnSetupP2;
private System.Windows.Forms.Label lblNesType;
private System.Windows.Forms.ComboBox cboConsoleType;
private System.Windows.Forms.Label lblExpansionPort;
private System.Windows.Forms.ComboBox cboExpansionPort;
private System.Windows.Forms.CheckBox chkFourScore;
private System.Windows.Forms.Button btnSetupP3;
private System.Windows.Forms.Button btnSetupP4;
private System.Windows.Forms.ComboBox cboPlayer3;
private System.Windows.Forms.ComboBox cboPlayer4;
}
}

View file

@ -17,20 +17,157 @@ namespace Mesen.GUI.Forms.Config
{
InitializeComponent();
ctrlInputPortConfig1.Initialize(ConfigManager.Config.Controllers[0]);
ctrlInputPortConfig2.Initialize(ConfigManager.Config.Controllers[1]);
ctrlInputPortConfig3.Initialize(ConfigManager.Config.Controllers[2]);
ctrlInputPortConfig4.Initialize(ConfigManager.Config.Controllers[3]);
Entity = ConfigManager.Config.InputInfo;
AddBinding("ExpansionPortDevice", cboExpansionPort);
AddBinding("ConsoleType", cboConsoleType);
AddBinding("UseFourScore", chkFourScore);
}
protected override void AfterUpdateUI()
{
base.AfterUpdateUI();
this.UpdateInterface();
InputInfo inputInfo = (InputInfo)Entity;
cboPlayer1.SelectedItem = inputInfo.Controllers[0].ControllerType.ToString();
cboPlayer2.SelectedItem = inputInfo.Controllers[1].ControllerType.ToString();
cboPlayer3.SelectedItem = inputInfo.Controllers[2].ControllerType.ToString();
cboPlayer4.SelectedItem = inputInfo.Controllers[3].ControllerType.ToString();
}
private void UpdateAvailableControllerTypes()
{
bool isNes = ((InputInfo)Entity).ConsoleType == ConsoleType.Nes;
bool p3and4visible = (isNes && chkFourScore.Checked) || (!isNes && ((InputInfo)Entity).ExpansionPortDevice == InteropEmu.ExpansionPortDevice.FourPlayerAdapter);
List<InteropEmu.ControllerType> controllerTypes = new List<InteropEmu.ControllerType>(new InteropEmu.ControllerType[] { InteropEmu.ControllerType.StandardController });
SetAvailableControllerTypes(cboPlayer3, controllerTypes.ToArray());
SetAvailableControllerTypes(cboPlayer4, controllerTypes.ToArray());
if(isNes && !chkFourScore.Checked) {
controllerTypes.Add(InteropEmu.ControllerType.Zapper);
}
SetAvailableControllerTypes(cboPlayer1, controllerTypes.ToArray());
SetAvailableControllerTypes(cboPlayer2, controllerTypes.ToArray());
}
private void SetAvailableControllerTypes(ComboBox comboBox, InteropEmu.ControllerType[] controllerTypes)
{
object currentSelection = comboBox.SelectedItem;
comboBox.Items.Clear();
comboBox.Items.Add(InteropEmu.ControllerType.None.ToString());
foreach(InteropEmu.ControllerType type in controllerTypes) {
comboBox.Items.Add(type.ToString());
}
comboBox.SelectedItem = currentSelection;
if(comboBox.SelectedIndex < 0) {
comboBox.SelectedIndex = 0;
}
}
protected override void UpdateConfig()
{
ctrlInputPortConfig1.UpdateConfig();
ctrlInputPortConfig2.UpdateConfig();
ctrlInputPortConfig3.UpdateConfig();
ctrlInputPortConfig4.UpdateConfig();
InputInfo inputInfo = (InputInfo)Entity;
ControllerInfo.ApplyConfig();
inputInfo.Controllers[0].ControllerType = (InteropEmu.ControllerType)Enum.Parse(typeof(InteropEmu.ControllerType), cboPlayer1.SelectedItem.ToString());
inputInfo.Controllers[1].ControllerType = (InteropEmu.ControllerType)Enum.Parse(typeof(InteropEmu.ControllerType), cboPlayer2.SelectedItem.ToString());
inputInfo.Controllers[2].ControllerType = (InteropEmu.ControllerType)Enum.Parse(typeof(InteropEmu.ControllerType), cboPlayer3.SelectedItem.ToString());
inputInfo.Controllers[3].ControllerType = (InteropEmu.ControllerType)Enum.Parse(typeof(InteropEmu.ControllerType), cboPlayer4.SelectedItem.ToString());
InputInfo.ApplyConfig();
}
private void UpdateInterface()
{
if(!this.Updating) {
UpdateObject();
bool isNes = ((InputInfo)Entity).ConsoleType == ConsoleType.Nes;
cboExpansionPort.Visible = !isNes;
lblExpansionPort.Visible = !isNes;
chkFourScore.Visible = isNes;
UpdatePlayer3And4Visibility();
UpdateAvailableControllerTypes();
}
}
private void UpdatePlayer3And4Visibility()
{
bool isNes = ((InputInfo)Entity).ConsoleType == ConsoleType.Nes;
bool visible = (isNes && chkFourScore.Checked) || (!isNes && ((InputInfo)Entity).ExpansionPortDevice == InteropEmu.ExpansionPortDevice.FourPlayerAdapter);
lblPlayer3.Visible = visible;
lblPlayer4.Visible = visible;
cboPlayer3.Visible = visible;
cboPlayer4.Visible = visible;
btnSetupP3.Visible = visible;
btnSetupP4.Visible = visible;
}
private void cboNesType_SelectedIndexChanged(object sender, EventArgs e)
{
UpdateInterface();
}
private void chkFourScore_CheckedChanged(object sender, EventArgs e)
{
UpdateInterface();
}
private void cboExpansionPort_SelectedIndexChanged(object sender, EventArgs e)
{
UpdateInterface();
}
private void cboPlayerController_SelectedIndexChanged(object sender, EventArgs e)
{
bool enableButton = (((ComboBox)sender).SelectedItem.Equals(InteropEmu.ControllerType.StandardController.ToString()));
if(sender == cboPlayer1) {
btnSetupP1.Enabled = enableButton;
} else if(sender == cboPlayer2) {
btnSetupP2.Enabled = enableButton;
} else if(sender == cboPlayer3) {
btnSetupP3.Enabled = enableButton;
} else if(sender == cboPlayer4) {
btnSetupP4.Enabled = enableButton;
}
}
private void btnSetup_Click(object sender, EventArgs e)
{
int index = 0;
if(sender == btnSetupP1) {
index = 0;
} else if(sender == btnSetupP2) {
index = 1;
} else if(sender == btnSetupP3) {
index = 2;
} else if(sender == btnSetupP4) {
index = 3;
}
var frm = new frmControllerConfig(ConfigManager.Config.InputInfo.Controllers[index]);
Button btn = (Button)sender;
Point point = btn.PointToScreen(new Point(0, btn.Height));
Rectangle screen = Screen.FromControl(btn).Bounds;
if(frm.Height + point.Y > screen.Bottom) {
//Show on top instead
point.Y -= btn.Height + frm.Height;
}
if(frm.Width + point.X > screen.Right) {
//Show on left instead
point.X -= frm.Width - btn.Width;
}
frm.StartPosition = FormStartPosition.Manual;
frm.Top = point.Y;
frm.Left = point.X;
frm.ShowDialog(this);
}
}
}

View file

@ -117,4 +117,7 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>

View file

@ -90,12 +90,9 @@
this.mnuTools = new System.Windows.Forms.ToolStripMenuItem();
this.mnuNetPlay = new System.Windows.Forms.ToolStripMenuItem();
this.mnuStartServer = new System.Windows.Forms.ToolStripMenuItem();
this.mnuStopServer = new System.Windows.Forms.ToolStripMenuItem();
this.mnuConnect = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripSeparator();
this.mnuFindServer = new System.Windows.Forms.ToolStripMenuItem();
this.mnuConnect = new System.Windows.Forms.ToolStripMenuItem();
this.mnuDisconnect = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem3 = new System.Windows.Forms.ToolStripSeparator();
this.mnuProfile = new System.Windows.Forms.ToolStripMenuItem();
this.mnuCheats = new System.Windows.Forms.ToolStripMenuItem();
this.mnuMovies = new System.Windows.Forms.ToolStripMenuItem();
@ -104,6 +101,7 @@
this.mnuRecordFromStart = new System.Windows.Forms.ToolStripMenuItem();
this.mnuRecordFromNow = new System.Windows.Forms.ToolStripMenuItem();
this.mnuStopMovie = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem12 = new System.Windows.Forms.ToolStripSeparator();
this.mnuTests = new System.Windows.Forms.ToolStripMenuItem();
this.mnuTestRun = new System.Windows.Forms.ToolStripMenuItem();
this.mnuTestRecordFrom = new System.Windows.Forms.ToolStripMenuItem();
@ -114,15 +112,14 @@
this.mnuTestStopRecording = new System.Windows.Forms.ToolStripMenuItem();
this.mnuRunAllTests = new System.Windows.Forms.ToolStripMenuItem();
this.mnuDebugger = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator();
this.mnuTakeScreenshot = new System.Windows.Forms.ToolStripMenuItem();
this.mnuHelp = new System.Windows.Forms.ToolStripMenuItem();
this.mnuCheckForUpdates = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem5 = new System.Windows.Forms.ToolStripSeparator();
this.mnuAbout = new System.Windows.Forms.ToolStripMenuItem();
this.menuTimer = new System.Windows.Forms.Timer(this.components);
this.dxViewer = new Mesen.GUI.Controls.DXViewer();
this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator();
this.toolStripMenuItem12 = new System.Windows.Forms.ToolStripSeparator();
this.ctrlRenderer = new Mesen.GUI.Controls.ctrlRenderer();
this.menuStrip.SuspendLayout();
this.SuspendLayout();
//
@ -160,49 +157,49 @@
this.mnuOpen.Image = global::Mesen.GUI.Properties.Resources.folder;
this.mnuOpen.Name = "mnuOpen";
this.mnuOpen.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.O)));
this.mnuOpen.Size = new System.Drawing.Size(152, 22);
this.mnuOpen.Size = new System.Drawing.Size(146, 22);
this.mnuOpen.Text = "Open";
this.mnuOpen.Click += new System.EventHandler(this.mnuOpen_Click);
//
// toolStripMenuItem4
//
this.toolStripMenuItem4.Name = "toolStripMenuItem4";
this.toolStripMenuItem4.Size = new System.Drawing.Size(149, 6);
this.toolStripMenuItem4.Size = new System.Drawing.Size(143, 6);
//
// mnuSaveState
//
this.mnuSaveState.Name = "mnuSaveState";
this.mnuSaveState.Size = new System.Drawing.Size(152, 22);
this.mnuSaveState.Size = new System.Drawing.Size(146, 22);
this.mnuSaveState.Text = "Save State";
this.mnuSaveState.DropDownOpening += new System.EventHandler(this.mnuSaveState_DropDownOpening);
//
// mnuLoadState
//
this.mnuLoadState.Name = "mnuLoadState";
this.mnuLoadState.Size = new System.Drawing.Size(152, 22);
this.mnuLoadState.Size = new System.Drawing.Size(146, 22);
this.mnuLoadState.Text = "Load State";
this.mnuLoadState.DropDownOpening += new System.EventHandler(this.mnuLoadState_DropDownOpening);
//
// toolStripMenuItem7
//
this.toolStripMenuItem7.Name = "toolStripMenuItem7";
this.toolStripMenuItem7.Size = new System.Drawing.Size(149, 6);
this.toolStripMenuItem7.Size = new System.Drawing.Size(143, 6);
//
// mnuRecentFiles
//
this.mnuRecentFiles.Name = "mnuRecentFiles";
this.mnuRecentFiles.Size = new System.Drawing.Size(152, 22);
this.mnuRecentFiles.Size = new System.Drawing.Size(146, 22);
this.mnuRecentFiles.Text = "Recent Files";
//
// toolStripMenuItem6
//
this.toolStripMenuItem6.Name = "toolStripMenuItem6";
this.toolStripMenuItem6.Size = new System.Drawing.Size(149, 6);
this.toolStripMenuItem6.Size = new System.Drawing.Size(143, 6);
//
// mnuExit
//
this.mnuExit.Name = "mnuExit";
this.mnuExit.Size = new System.Drawing.Size(152, 22);
this.mnuExit.Size = new System.Drawing.Size(146, 22);
this.mnuExit.Text = "Exit";
this.mnuExit.Click += new System.EventHandler(this.mnuExit_Click);
//
@ -558,12 +555,9 @@
//
this.mnuNetPlay.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mnuStartServer,
this.mnuStopServer,
this.mnuConnect,
this.toolStripMenuItem2,
this.mnuFindServer,
this.mnuConnect,
this.mnuDisconnect,
this.toolStripMenuItem3,
this.mnuProfile});
this.mnuNetPlay.Image = global::Mesen.GUI.Properties.Resources.globe_network;
this.mnuNetPlay.Name = "mnuNetPlay";
@ -577,12 +571,12 @@
this.mnuStartServer.Text = "Start Server";
this.mnuStartServer.Click += new System.EventHandler(this.mnuStartServer_Click);
//
// mnuStopServer
// mnuConnect
//
this.mnuStopServer.Name = "mnuStopServer";
this.mnuStopServer.Size = new System.Drawing.Size(177, 22);
this.mnuStopServer.Text = "Stop Server";
this.mnuStopServer.Click += new System.EventHandler(this.mnuStopServer_Click);
this.mnuConnect.Name = "mnuConnect";
this.mnuConnect.Size = new System.Drawing.Size(177, 22);
this.mnuConnect.Text = "Connect to Server";
this.mnuConnect.Click += new System.EventHandler(this.mnuConnect_Click);
//
// toolStripMenuItem2
//
@ -595,25 +589,7 @@
this.mnuFindServer.Name = "mnuFindServer";
this.mnuFindServer.Size = new System.Drawing.Size(177, 22);
this.mnuFindServer.Text = "Find Public Server...";
//
// mnuConnect
//
this.mnuConnect.Name = "mnuConnect";
this.mnuConnect.Size = new System.Drawing.Size(177, 22);
this.mnuConnect.Text = "Connect...";
this.mnuConnect.Click += new System.EventHandler(this.mnuConnect_Click);
//
// mnuDisconnect
//
this.mnuDisconnect.Name = "mnuDisconnect";
this.mnuDisconnect.Size = new System.Drawing.Size(177, 22);
this.mnuDisconnect.Text = "Disconnect";
this.mnuDisconnect.Click += new System.EventHandler(this.mnuDisconnect_Click);
//
// toolStripMenuItem3
//
this.toolStripMenuItem3.Name = "toolStripMenuItem3";
this.toolStripMenuItem3.Size = new System.Drawing.Size(174, 6);
this.mnuFindServer.Visible = false;
//
// mnuProfile
//
@ -677,6 +653,11 @@
this.mnuStopMovie.Text = "Stop";
this.mnuStopMovie.Click += new System.EventHandler(this.mnuStopMovie_Click);
//
// toolStripMenuItem12
//
this.toolStripMenuItem12.Name = "toolStripMenuItem12";
this.toolStripMenuItem12.Size = new System.Drawing.Size(182, 6);
//
// mnuTests
//
this.mnuTests.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
@ -758,6 +739,11 @@
this.mnuDebugger.Text = "Debugger";
this.mnuDebugger.Click += new System.EventHandler(this.mnuDebugger_Click);
//
// toolStripMenuItem1
//
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
this.toolStripMenuItem1.Size = new System.Drawing.Size(182, 6);
//
// mnuTakeScreenshot
//
this.mnuTakeScreenshot.Image = global::Mesen.GUI.Properties.Resources.camera;
@ -801,24 +787,14 @@
//
this.menuTimer.Tick += new System.EventHandler(this.menuTimer_Tick);
//
// dxViewer
// ctrlRenderer
//
this.dxViewer.BackColor = System.Drawing.Color.Black;
this.dxViewer.Location = new System.Drawing.Point(0, 24);
this.dxViewer.Margin = new System.Windows.Forms.Padding(0);
this.dxViewer.Name = "dxViewer";
this.dxViewer.Size = new System.Drawing.Size(263, 176);
this.dxViewer.TabIndex = 1;
//
// toolStripMenuItem1
//
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
this.toolStripMenuItem1.Size = new System.Drawing.Size(182, 6);
//
// toolStripMenuItem12
//
this.toolStripMenuItem12.Name = "toolStripMenuItem12";
this.toolStripMenuItem12.Size = new System.Drawing.Size(182, 6);
this.ctrlRenderer.BackColor = System.Drawing.Color.Black;
this.ctrlRenderer.Location = new System.Drawing.Point(0, 24);
this.ctrlRenderer.Margin = new System.Windows.Forms.Padding(0);
this.ctrlRenderer.Name = "ctrlRenderer";
this.ctrlRenderer.Size = new System.Drawing.Size(263, 176);
this.ctrlRenderer.TabIndex = 1;
//
// frmMain
//
@ -829,7 +805,7 @@
this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.BackColor = System.Drawing.Color.Black;
this.ClientSize = new System.Drawing.Size(365, 272);
this.Controls.Add(this.dxViewer);
this.Controls.Add(this.ctrlRenderer);
this.Controls.Add(this.menuStrip);
this.MainMenuStrip = this.menuStrip;
this.Name = "frmMain";
@ -849,7 +825,7 @@
private System.Windows.Forms.ToolStripMenuItem mnuFile;
private System.Windows.Forms.ToolStripMenuItem mnuOpen;
private System.Windows.Forms.ToolStripMenuItem mnuGame;
private Mesen.GUI.Controls.DXViewer dxViewer;
private Mesen.GUI.Controls.ctrlRenderer ctrlRenderer;
private System.Windows.Forms.ToolStripMenuItem mnuPause;
private System.Windows.Forms.ToolStripMenuItem mnuReset;
private System.Windows.Forms.ToolStripMenuItem mnuStop;
@ -862,11 +838,8 @@
private System.Windows.Forms.ToolStripMenuItem mnuTools;
private System.Windows.Forms.ToolStripMenuItem mnuNetPlay;
private System.Windows.Forms.ToolStripMenuItem mnuStartServer;
private System.Windows.Forms.ToolStripMenuItem mnuStopServer;
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem2;
private System.Windows.Forms.ToolStripMenuItem mnuConnect;
private System.Windows.Forms.ToolStripMenuItem mnuDisconnect;
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem3;
private System.Windows.Forms.ToolStripMenuItem mnuProfile;
private System.Windows.Forms.ToolStripMenuItem mnuMovies;
private System.Windows.Forms.ToolStripMenuItem mnuPlayMovie;

View file

@ -74,7 +74,7 @@ namespace Mesen.GUI.Forms
void InitializeEmu()
{
InteropEmu.InitializeEmu(ConfigManager.HomeFolder, this.Handle, this.dxViewer.Handle);
InteropEmu.InitializeEmu(ConfigManager.HomeFolder, this.Handle, this.ctrlRenderer.Handle);
foreach(string romPath in ConfigManager.Config.RecentFiles) {
InteropEmu.AddKnowGameFolder(Path.GetDirectoryName(romPath).ToLowerInvariant());
}
@ -183,7 +183,7 @@ namespace Mesen.GUI.Forms
case VideoAspectRatio.Standard: size.Width = (int)(size.Height * 4 / 3.0); break;
case VideoAspectRatio.Widescreen: size.Width = (int)(size.Height * 16 / 9.0); break;
}
dxViewer.Size = new Size(size.Width, size.Height);
ctrlRenderer.Size = new Size(size.Width, size.Height);
}
private void _notifListener_OnNotification(InteropEmu.NotificationEventArgs e)
@ -198,6 +198,10 @@ namespace Mesen.GUI.Forms
this.StartEmuThread();
break;
case InteropEmu.ConsoleNotificationType.DisconnectedFromServer:
ConfigManager.Config.ApplyConfig();
break;
case InteropEmu.ConsoleNotificationType.GameStopped:
CheatInfo.ClearCheats();
break;
@ -320,33 +324,40 @@ namespace Mesen.GUI.Forms
this.Text = "Mesen - " + _currentGame;
}
mnuSaveState.Enabled = mnuLoadState.Enabled = mnuPause.Enabled = mnuStop.Enabled = mnuReset.Enabled = (_emuThread != null && !InteropEmu.IsConnected());
bool isNetPlayClient = InteropEmu.IsConnected();
mnuSaveState.Enabled = mnuLoadState.Enabled = mnuPause.Enabled = mnuStop.Enabled = mnuReset.Enabled = (_emuThread != null && !isNetPlayClient);
mnuPause.Text = InteropEmu.IsPaused() ? "Resume" : "Pause";
mnuPause.Image = InteropEmu.IsPaused() ? Mesen.GUI.Properties.Resources.control_play : Mesen.GUI.Properties.Resources.control_pause;
bool netPlay = InteropEmu.IsServerRunning() || InteropEmu.IsConnected();
bool netPlay = InteropEmu.IsServerRunning() || isNetPlayClient;
mnuStartServer.Enabled = !netPlay;
mnuStopServer.Enabled = !mnuStartServer.Enabled && !InteropEmu.IsConnected();
mnuStartServer.Enabled = !isNetPlayClient;
mnuConnect.Enabled = !InteropEmu.IsServerRunning();
mnuConnect.Enabled = !netPlay;
mnuDisconnect.Enabled = !mnuConnect.Enabled && !InteropEmu.IsServerRunning();
mnuStartServer.Text = InteropEmu.IsServerRunning() ? "Stop Server" : "Start Server";
mnuConnect.Text = isNetPlayClient ? "Disconnect" : "Connect to Server";
mnuCheats.Enabled = !InteropEmu.IsConnected();
mnuEmulationSpeed.Enabled = !InteropEmu.IsConnected();
mnuCheats.Enabled = !isNetPlayClient;
mnuEmulationSpeed.Enabled = !isNetPlayClient;
mnuIncreaseSpeed.Enabled = !isNetPlayClient;
mnuDecreaseSpeed.Enabled = !isNetPlayClient;
mnuEmuSpeedMaximumSpeed.Enabled = !isNetPlayClient;
mnuInput.Enabled = !isNetPlayClient;
mnuRegion.Enabled = !isNetPlayClient;
bool moviePlaying = InteropEmu.MoviePlaying();
bool movieRecording = InteropEmu.MovieRecording();
mnuPlayMovie.Enabled = !netPlay && !moviePlaying && !movieRecording;
mnuStopMovie.Enabled = _emuThread != null && !netPlay && (moviePlaying || movieRecording);
mnuRecordFrom.Enabled = _emuThread != null && !moviePlaying && !movieRecording;
mnuRecordFromStart.Enabled = _emuThread != null && !InteropEmu.IsConnected() && !moviePlaying && !movieRecording;
mnuRecordFromStart.Enabled = _emuThread != null && !isNetPlayClient && !moviePlaying && !movieRecording;
mnuRecordFromNow.Enabled = _emuThread != null && !moviePlaying && !movieRecording;
bool testRecording = InteropEmu.RomTestRecording();
mnuTestRun.Enabled = !netPlay && !moviePlaying && !movieRecording;
mnuTestStopRecording.Enabled = _emuThread != null && testRecording;
mnuTestRecordStart.Enabled = _emuThread != null && !InteropEmu.IsConnected() && !moviePlaying && !movieRecording;
mnuTestRecordStart.Enabled = _emuThread != null && !isNetPlayClient && !moviePlaying && !movieRecording;
mnuTestRecordNow.Enabled = _emuThread != null && !moviePlaying && !movieRecording;
mnuTestRecordMovie.Enabled = !netPlay && !moviePlaying && !movieRecording;
mnuTestRecordTest.Enabled = !netPlay && !moviePlaying && !movieRecording;
@ -494,17 +505,25 @@ namespace Mesen.GUI.Forms
private void mnuStartServer_Click(object sender, EventArgs e)
{
frmServerConfig frm = new frmServerConfig();
if(frm.ShowDialog(sender) == System.Windows.Forms.DialogResult.OK) {
InteropEmu.StartServer(ConfigManager.Config.ServerInfo.Port);
if(InteropEmu.IsServerRunning()) {
Task.Run(() => InteropEmu.StopServer());
} else {
frmServerConfig frm = new frmServerConfig();
if(frm.ShowDialog(sender) == System.Windows.Forms.DialogResult.OK) {
InteropEmu.StartServer(ConfigManager.Config.ServerInfo.Port);
}
}
}
private void mnuConnect_Click(object sender, EventArgs e)
{
frmClientConfig frm = new frmClientConfig();
if(frm.ShowDialog(sender) == System.Windows.Forms.DialogResult.OK) {
InteropEmu.Connect(ConfigManager.Config.ClientConnectionInfo.Host, ConfigManager.Config.ClientConnectionInfo.Port, ConfigManager.Config.Profile.PlayerName, ConfigManager.Config.Profile.PlayerAvatar, (UInt16)ConfigManager.Config.Profile.PlayerAvatar.Length);
if(InteropEmu.IsConnected()) {
Task.Run(() => InteropEmu.Disconnect());
} else {
frmClientConfig frm = new frmClientConfig();
if(frm.ShowDialog(sender) == System.Windows.Forms.DialogResult.OK) {
InteropEmu.Connect(ConfigManager.Config.ClientConnectionInfo.Host, ConfigManager.Config.ClientConnectionInfo.Port, ConfigManager.Config.Profile.PlayerName, ConfigManager.Config.Profile.PlayerAvatar, (UInt16)ConfigManager.Config.Profile.PlayerAvatar.Length);
}
}
}
@ -512,16 +531,6 @@ namespace Mesen.GUI.Forms
{
new frmPlayerProfile().ShowDialog(sender);
}
private void mnuStopServer_Click(object sender, EventArgs e)
{
Task.Run(() => InteropEmu.StopServer());
}
private void mnuDisconnect_Click(object sender, EventArgs e)
{
Task.Run(() => InteropEmu.Disconnect());
}
private void mnuExit_Click(object sender, EventArgs e)
{
@ -712,7 +721,7 @@ namespace Mesen.GUI.Forms
private void mnuCheats_Click(object sender, EventArgs e)
{
frmCheatList frm = new frmCheatList();
frm.Show(this);
frm.Show(sender, this);
frm.FormClosed += (object a, FormClosedEventArgs b) => {
frm = null;
CheatInfo.ApplyCheats();

View file

@ -161,7 +161,7 @@
<Compile Include="Config\PreferenceInfo.cs" />
<Compile Include="Config\VideoInfo.cs" />
<Compile Include="Config\CheatInfo.cs" />
<Compile Include="Config\ControllerInfo.cs" />
<Compile Include="Config\InputInfo.cs" />
<Compile Include="Config\ClientConnection.cs" />
<Compile Include="Config\Configuration.cs" />
<Compile Include="Config\ImageExtensions.cs" />
@ -175,11 +175,11 @@
<Compile Include="Controls\ctrlTrackbar.Designer.cs">
<DependentUpon>ctrlTrackbar.cs</DependentUpon>
</Compile>
<Compile Include="Controls\DXViewer.cs">
<Compile Include="Controls\ctrlRenderer.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Controls\DXViewer.Designer.cs">
<DependentUpon>DXViewer.cs</DependentUpon>
<Compile Include="Controls\ctrlRenderer.Designer.cs">
<DependentUpon>ctrlRenderer.cs</DependentUpon>
</Compile>
<Compile Include="Controls\MyListView.cs">
<SubType>Component</SubType>
@ -322,6 +322,12 @@
<Compile Include="Forms\Config\ctrlStandardController.Designer.cs">
<DependentUpon>ctrlStandardController.cs</DependentUpon>
</Compile>
<Compile Include="Forms\Config\frmControllerConfig.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\Config\frmControllerConfig.Designer.cs">
<DependentUpon>frmControllerConfig.cs</DependentUpon>
</Compile>
<Compile Include="Forms\Config\frmGetKey.cs">
<SubType>Form</SubType>
</Compile>
@ -397,6 +403,9 @@
<EmbeddedResource Include="Controls\ctrlTrackbar.resx">
<DependentUpon>ctrlTrackbar.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Controls\ctrlRenderer.resx">
<DependentUpon>ctrlRenderer.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Debugger\Controls\ctrlBreakpoints.resx">
<DependentUpon>ctrlBreakpoints.cs</DependentUpon>
</EmbeddedResource>
@ -463,6 +472,9 @@
<EmbeddedResource Include="Forms\Config\ctrlStandardController.resx">
<DependentUpon>ctrlStandardController.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\Config\frmControllerConfig.resx">
<DependentUpon>frmControllerConfig.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\Config\frmGetKey.resx">
<DependentUpon>frmGetKey.cs</DependentUpon>
</EmbeddedResource>

View file

@ -22,11 +22,19 @@ namespace Mesen.GUI
[DllImport(DLLPath)] public static extern void ApplyIpsPatch([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(UTF8Marshaler))]string filename);
[DllImport(DLLPath)] public static extern void AddKnowGameFolder([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(UTF8Marshaler))]string folder);
[DllImport(DLLPath)] public static extern void AddKeyMappings(int port, KeyMapping mapping);
[DllImport(DLLPath)] public static extern void ClearKeyMappings(int port);
[DllImport(DLLPath)] public static extern void ZapperSetTriggerState(Int32 port, [MarshalAs(UnmanagedType.I1)]bool pulled);
[DllImport(DLLPath)] public static extern void ZapperSetPosition(Int32 port, Int32 x, Int32 y);
[DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool HasZapper();
[DllImport(DLLPath)] public static extern void SetControllerType(int port, ControllerType type);
[DllImport(DLLPath)] public static extern void SetControllerKeys(int port, KeyMappingSet mapping);
[DllImport(DLLPath)] public static extern void SetExpansionDevice(ExpansionPortDevice device);
[DllImport(DLLPath)] public static extern void SetConsoleType(ConsoleType type);
[DllImport(DLLPath)] public static extern UInt32 GetPressedKey();
[DllImport(DLLPath)] public static extern UInt32 GetKeyCode([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(UTF8Marshaler))]string keyName);
[DllImport(DLLPath, EntryPoint="GetKeyName")] private static extern IntPtr GetKeyNameWrapper(UInt32 key);
[DllImport(DLLPath)] public static extern void Run();
[DllImport(DLLPath)] public static extern void Pause();
@ -286,6 +294,24 @@ namespace Mesen.GUI
ResolutionChanged = 11,
FdsDiskChanged = 12,
FdsBiosNotFound = 13,
ConfigChanged = 14,
DisconnectedFromServer = 15
}
public enum ControllerType
{
None = 0,
StandardController = 1,
Zapper = 2,
}
public struct KeyMappingSet
{
public KeyMapping Mapping1;
public KeyMapping Mapping2;
public KeyMapping Mapping3;
public KeyMapping Mapping4;
public UInt32 TurboSpeed;
}
public struct KeyMapping
@ -302,7 +328,13 @@ namespace Mesen.GUI
public UInt32 TurboB;
public UInt32 TurboStart;
public UInt32 TurboSelect;
public UInt32 TurboSpeed;
}
public enum ExpansionPortDevice
{
None = 0,
Zapper = 1,
FourPlayerAdapter = 2,
}
public struct ScreenSize
@ -467,6 +499,7 @@ namespace Mesen.GUI
AllowInvalidInput = 0x08,
RemoveSpriteLimit = 0x10,
UseHdPacks = 0x20,
HasFourScore = 0x40,
PauseOnMovieEnd = 0x0100,
PauseWhenInBackground = 0x0200,
@ -519,6 +552,13 @@ namespace Mesen.GUI
Dendy = 3,
}
public enum ConsoleType
{
Nes = 0,
Famicom = 1,
//VsSystem = 2,
}
public enum AudioChannel
{
Square1 = 0,

View file

@ -10,7 +10,6 @@
#include "../Core/ClientConnectionData.h"
#include "../Core/SaveStateManager.h"
#include "../Core/CheatManager.h"
#include "../Core/StandardController.h"
#include "../Core/EmulationSettings.h"
#include "../Core/VideoDecoder.h"
#include "../Core/AutoRomTest.h"
@ -18,7 +17,6 @@
NES::Renderer *_renderer = nullptr;
SoundManager *_soundManager = nullptr;
vector<shared_ptr<StandardController>> _inputDevices;
HWND _windowHandle = nullptr;
HWND _viewerHandle = nullptr;
string _returnString;
@ -60,10 +58,6 @@ namespace InteropEmu {
_soundManager = new SoundManager(_windowHandle);
ControlManager::RegisterKeyManager(new WindowsKeyManager(_windowHandle));
for(int i = 0; i < 4; i++) {
_inputDevices.push_back(shared_ptr<StandardController>(new StandardController(i)));
}
}
}
@ -71,8 +65,14 @@ namespace InteropEmu {
DllExport void __stdcall ApplyIpsPatch(char* filename) { Console::ApplyIpsPatch(filename); }
DllExport void __stdcall AddKnowGameFolder(char* folder) { FolderUtilities::AddKnowGameFolder(folder); }
DllExport void __stdcall AddKeyMappings(uint32_t port, KeyMapping mapping) { _inputDevices[port]->AddKeyMappings(mapping); }
DllExport void __stdcall ClearKeyMappings(uint32_t port) { _inputDevices[port]->ClearKeyMappings(); }
DllExport void __stdcall SetControllerType(uint32_t port, ControllerType type) { EmulationSettings::SetControllerType(port, type); }
DllExport void __stdcall SetControllerKeys(uint32_t port, KeyMappingSet mappings) { EmulationSettings::SetControllerKeys(port, mappings); }
DllExport void __stdcall SetExpansionDevice(ExpansionPortDevice device) { EmulationSettings::SetExpansionDevice(device); }
DllExport void __stdcall SetConsoleType(ConsoleType type) { EmulationSettings::SetConsoleType(type); }
DllExport bool __stdcall HasZapper() { return ControlManager::HasZapper(); }
DllExport void __stdcall ZapperSetTriggerState(int32_t port, bool pulled) { ControlManager::ZapperSetTriggerState(port, pulled); }
DllExport void __stdcall ZapperSetPosition(int32_t port, int32_t x, int32_t y) { ControlManager::ZapperSetPosition(port, x, y); }
DllExport uint32_t __stdcall GetPressedKey() { return ControlManager::GetPressedKey(); }
DllExport const char* __stdcall GetKeyName(uint32_t keyCode)
@ -80,7 +80,13 @@ namespace InteropEmu {
_returnString = ControlManager::GetKeyName(keyCode);
return _returnString.c_str();
}
DllExport uint32_t __stdcall GetKeyCode(char* keyName) { return ControlManager::GetKeyCode(keyName); }
DllExport uint32_t __stdcall GetKeyCode(char* keyName) {
if(keyName) {
return ControlManager::GetKeyCode(keyName);
} else {
return 0;
}
}
DllExport void __stdcall Run()
{

View file

@ -395,7 +395,7 @@ namespace NES
void Renderer::Render()
{
bool paused = EmulationSettings::CheckFlag(EmulationFlags::Paused) || (EmulationSettings::CheckFlag(EmulationFlags::InBackground) && EmulationSettings::CheckFlag(EmulationFlags::PauseWhenInBackground));
bool paused = EmulationSettings::IsPaused();
if(_noUpdateCount > 10 || _frameChanged || paused || !_toasts.empty()) {
_frameLock.Acquire();