Debugger: Added controllers tool

This commit is contained in:
Sour 2022-07-09 19:39:35 -04:00
parent 62696595b6
commit 61fbae131c
29 changed files with 570 additions and 17 deletions

View file

@ -428,3 +428,24 @@ struct CpuInstructionProgress
uint32_t LastOpCode = 0;
MemoryOperationInfo LastMemOperation = {};
};
struct DebugControllerState
{
bool A;
bool B;
bool X;
bool Y;
bool L;
bool R;
bool Up;
bool Down;
bool Left;
bool Right;
bool Select;
bool Start;
bool HasPressedButton()
{
return A || B || X || Y || L || R || Up || Down || Left || Right || Select || Start;
}
};

View file

@ -35,6 +35,7 @@
#include "Gameboy/GbTypes.h"
#include "PCE/Debugger/PceDebugger.h"
#include "PCE/PceTypes.h"
#include "Shared/BaseControlManager.h"
#include "Shared/EmuSettings.h"
#include "Shared/Audio/SoundMixer.h"
#include "Shared/NotificationManager.h"
@ -358,6 +359,10 @@ void Debugger::ProcessEvent(EventType type)
switch(type) {
default: break;
case EventType::InputPolled:
_debuggers[(int)_mainCpuType].Debugger->ProcessInputOverrides(_inputOverrides);
break;
case EventType::StartFrame: {
_emu->GetNotificationManager()->SendNotification(ConsoleNotificationType::EventViewerRefresh, (void*)_mainCpuType);
BaseEventManager* evtMgr = GetEventManager(_mainCpuType);
@ -664,6 +669,19 @@ void Debugger::SetBreakpoints(Breakpoint breakpoints[], uint32_t length)
}
}
void Debugger::SetInputOverrides(uint32_t index, DebugControllerState state)
{
_inputOverrides[index] = state;
}
void Debugger::GetAvailableInputOverrides(uint8_t* availableIndexes)
{
BaseControlManager* controlManager = _console->GetControlManager();
for(int i = 0; i < 8; i++) {
availableIndexes[i] = controlManager->GetControlDeviceByIndex(i) != nullptr;
}
}
void Debugger::Log(string message)
{
auto lock = _logLock.AcquireSafe();

View file

@ -81,6 +81,8 @@ private:
atomic<uint32_t> _breakRequestCount;
atomic<uint32_t> _suspendRequestCount;
DebugControllerState _inputOverrides[8] = {};
bool _waitForBreakResume = false;
void Reset();
@ -150,6 +152,9 @@ public:
void SetBreakpoints(Breakpoint breakpoints[], uint32_t length);
void SetInputOverrides(uint32_t index, DebugControllerState state);
void GetAvailableInputOverrides(uint8_t* availableIndexes);
void Log(string message);
string GetLog();

View file

@ -32,6 +32,7 @@ public:
virtual void ProcessConfigChange() {}
virtual void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi) {}
virtual void ProcessInputOverrides(DebugControllerState inputOverrides[8]) {}
virtual void DrawPartialFrame() { }

View file

@ -1,6 +1,7 @@
#include "stdafx.h"
#include "Gameboy/Gameboy.h"
#include "Gameboy/GbMemoryManager.h"
#include "Gameboy/Input/GbController.h"
#include "Gameboy/Debugger/DummyGbCpu.h"
#include "Gameboy/Debugger/GbDebugger.h"
#include "Gameboy/Debugger/GameboyDisUtils.h"
@ -26,6 +27,7 @@
#include "SNES/BaseCartridge.h"
#include "Shared/EmuSettings.h"
#include "Shared/Emulator.h"
#include "Shared/BaseControlManager.h"
#include "MemoryOperationType.h"
GbDebugger::GbDebugger(Debugger* debugger)
@ -416,3 +418,22 @@ void GbDebugger::SaveRomToDisk(string filename, bool saveAsIps, CdlStripOption s
file.close();
}
}
void GbDebugger::ProcessInputOverrides(DebugControllerState inputOverrides[8])
{
BaseControlManager* controlManager = _gameboy->GetControlManager();
for(int i = 0; i < 8; i++) {
shared_ptr<GbController> controller = std::dynamic_pointer_cast<GbController>(controlManager->GetControlDeviceByIndex(i));
if(controller && inputOverrides[i].HasPressedButton()) {
controller->SetBitValue(GbController::Buttons::A, inputOverrides[i].A);
controller->SetBitValue(GbController::Buttons::B, inputOverrides[i].B);
controller->SetBitValue(GbController::Buttons::Select, inputOverrides[i].Select);
controller->SetBitValue(GbController::Buttons::Start, inputOverrides[i].Start);
controller->SetBitValue(GbController::Buttons::Up, inputOverrides[i].Up);
controller->SetBitValue(GbController::Buttons::Down, inputOverrides[i].Down);
controller->SetBitValue(GbController::Buttons::Left, inputOverrides[i].Left);
controller->SetBitValue(GbController::Buttons::Right, inputOverrides[i].Right);
}
}
controlManager->RefreshHubState();
}

View file

@ -71,6 +71,8 @@ public:
void SaveRomToDisk(string filename, bool saveAsIps, CdlStripOption stripOption);
void ProcessInputOverrides(DebugControllerState inputOverrides[8]);
void SetProgramCounter(uint32_t addr) override;
uint32_t GetProgramCounter(bool getInstPc) override;

View file

@ -16,6 +16,7 @@
#include "NES/NesPpu.h"
#include "NES/BaseMapper.h"
#include "NES/NesMemoryManager.h"
#include "NES/Input/NesController.h"
#include "NES/Mappers/NsfMapper.h"
#include "NES/Debugger/DummyNesCpu.h"
#include "NES/Debugger/NesCodeDataLogger.h"
@ -31,6 +32,7 @@
#include "Utilities/CRC32.h"
#include "Shared/EmuSettings.h"
#include "Shared/SettingTypes.h"
#include "Shared/BaseControlManager.h"
#include "Shared/Emulator.h"
#include "MemoryOperationType.h"
@ -472,4 +474,23 @@ void NesDebugger::SaveRomToDisk(string filename, bool saveAsIps, CdlStripOption
file.write((char*)output.data(), output.size());
file.close();
}
}
}
void NesDebugger::ProcessInputOverrides(DebugControllerState inputOverrides[8])
{
BaseControlManager* controlManager = _console->GetControlManager();
for(int i = 0; i < 8; i++) {
shared_ptr<NesController> controller = std::dynamic_pointer_cast<NesController>(controlManager->GetControlDeviceByIndex(i));
if(controller && inputOverrides[i].HasPressedButton()) {
controller->SetBitValue(NesController::Buttons::A, inputOverrides[i].A);
controller->SetBitValue(NesController::Buttons::B, inputOverrides[i].B);
controller->SetBitValue(NesController::Buttons::Select, inputOverrides[i].Select);
controller->SetBitValue(NesController::Buttons::Start, inputOverrides[i].Start);
controller->SetBitValue(NesController::Buttons::Up, inputOverrides[i].Up);
controller->SetBitValue(NesController::Buttons::Down, inputOverrides[i].Down);
controller->SetBitValue(NesController::Buttons::Left, inputOverrides[i].Left);
controller->SetBitValue(NesController::Buttons::Right, inputOverrides[i].Right);
}
}
controlManager->RefreshHubState();
}

View file

@ -76,6 +76,8 @@ public:
void ProcessPpuWrite(uint16_t addr, uint8_t value, MemoryType memoryType);
void ProcessPpuCycle();
void ProcessInputOverrides(DebugControllerState inputOverrides[8]);
void Run() override;
void Step(int32_t stepCount, StepType type) override;

View file

@ -16,6 +16,7 @@
#include "PCE/PceVce.h"
#include "PCE/PceVpc.h"
#include "PCE/PceMemoryManager.h"
#include "PCE/Input/PceController.h"
#include "PCE/Debugger/PceDebugger.h"
#include "PCE/Debugger/PceTraceLogger.h"
#include "PCE/Debugger/PceVdcTools.h"
@ -26,6 +27,7 @@
#include "Utilities/HexUtilities.h"
#include "Utilities/FolderUtilities.h"
#include "Utilities/Patches/IpsPatcher.h"
#include "Shared/BaseControlManager.h"
#include "Shared/EmuSettings.h"
#include "Shared/SettingTypes.h"
#include "Shared/Emulator.h"
@ -427,4 +429,23 @@ void PceDebugger::SaveRomToDisk(string filename, bool saveAsIps, CdlStripOption
file.write((char*)output.data(), output.size());
file.close();
}
}
}
void PceDebugger::ProcessInputOverrides(DebugControllerState inputOverrides[8])
{
BaseControlManager* controlManager = _console->GetControlManager();
for(int i = 0; i < 8; i++) {
shared_ptr<PceController> controller = std::dynamic_pointer_cast<PceController>(controlManager->GetControlDeviceByIndex(i));
if(controller && inputOverrides[i].HasPressedButton()) {
controller->SetBitValue(PceController::Buttons::I, inputOverrides[i].A);
controller->SetBitValue(PceController::Buttons::II, inputOverrides[i].B);
controller->SetBitValue(PceController::Buttons::Select, inputOverrides[i].Select);
controller->SetBitValue(PceController::Buttons::Run, inputOverrides[i].Start);
controller->SetBitValue(PceController::Buttons::Up, inputOverrides[i].Up);
controller->SetBitValue(PceController::Buttons::Down, inputOverrides[i].Down);
controller->SetBitValue(PceController::Buttons::Left, inputOverrides[i].Left);
controller->SetBitValue(PceController::Buttons::Right, inputOverrides[i].Right);
}
}
controlManager->RefreshHubState();
}

View file

@ -90,6 +90,7 @@ public:
ITraceLogger* GetTraceLogger() override;
PpuTools* GetPpuTools() override;
void SaveRomToDisk(string filename, bool saveAsIps, CdlStripOption stripOption);
void ProcessInputOverrides(DebugControllerState inputOverrides[8]);
CallstackManager* GetCallstackManager() override;
IAssembler* GetAssembler() override;
BaseEventManager* GetEventManager() override;

View file

@ -7,6 +7,7 @@
#include "SNES/Spc.h"
#include "SNES/SnesPpu.h"
#include "SNES/MemoryMappings.h"
#include "SNES/Input/SnesController.h"
#include "SNES/Debugger/DummySnesCpu.h"
#include "SNES/Debugger/SnesDisUtils.h"
#include "SNES/Debugger/SnesCodeDataLogger.h"
@ -28,6 +29,7 @@
#include "Debugger/Debugger.h"
#include "Debugger/CodeDataLogger.h"
#include "Shared/SettingTypes.h"
#include "Shared/BaseControlManager.h"
#include "Shared/EmuSettings.h"
#include "Shared/Emulator.h"
#include "Utilities/HexUtilities.h"
@ -513,4 +515,27 @@ void SnesDebugger::SaveRomToDisk(string filename, bool saveAsIps, CdlStripOption
file.write((char*)output.data(), output.size());
file.close();
}
}
}
void SnesDebugger::ProcessInputOverrides(DebugControllerState inputOverrides[8])
{
BaseControlManager* controlManager = _console->GetControlManager();
for(int i = 0; i < 8; i++) {
shared_ptr<SnesController> controller = std::dynamic_pointer_cast<SnesController>(controlManager->GetControlDeviceByIndex(i));
if(controller && inputOverrides[i].HasPressedButton()) {
controller->SetBitValue(SnesController::Buttons::A, inputOverrides[i].A);
controller->SetBitValue(SnesController::Buttons::B, inputOverrides[i].B);
controller->SetBitValue(SnesController::Buttons::X, inputOverrides[i].X);
controller->SetBitValue(SnesController::Buttons::Y, inputOverrides[i].Y);
controller->SetBitValue(SnesController::Buttons::L, inputOverrides[i].L);
controller->SetBitValue(SnesController::Buttons::R, inputOverrides[i].R);
controller->SetBitValue(SnesController::Buttons::Select, inputOverrides[i].Select);
controller->SetBitValue(SnesController::Buttons::Start, inputOverrides[i].Start);
controller->SetBitValue(SnesController::Buttons::Up, inputOverrides[i].Up);
controller->SetBitValue(SnesController::Buttons::Down, inputOverrides[i].Down);
controller->SetBitValue(SnesController::Buttons::Left, inputOverrides[i].Left);
controller->SetBitValue(SnesController::Buttons::Right, inputOverrides[i].Right);
}
}
controlManager->RefreshHubState();
}

View file

@ -116,4 +116,5 @@ public:
void GetPpuState(BaseState& state) override;
void SetPpuState(BaseState& state) override;
void SaveRomToDisk(string filename, bool saveAsIps, CdlStripOption stripOption);
void ProcessInputOverrides(DebugControllerState inputOverrides[8]);
};

View file

@ -3,6 +3,7 @@
#include "Shared/Emulator.h"
#include "Shared/EmuSettings.h"
#include "Shared/KeyManager.h"
#include "Shared/ControllerHub.h"
#include "Shared/Interfaces/IKeyManager.h"
#include "Shared/Interfaces/IInputProvider.h"
#include "Shared/Interfaces/IInputRecorder.h"
@ -80,6 +81,48 @@ shared_ptr<BaseControlDevice> BaseControlManager::GetControlDevice(uint8_t port)
return nullptr;
}
shared_ptr<BaseControlDevice> BaseControlManager::GetControlDeviceByIndex(uint8_t index)
{
auto lock = _deviceLock.AcquireSafe();
int counter = 0;
for(size_t i = 0; i < _controlDevices.size(); i++) {
if(_controlDevices[i] && _controlDevices[i]->GetPort() <= 2) {
shared_ptr<IControllerHub> hub = std::dynamic_pointer_cast<IControllerHub>(_controlDevices[i]);
if(hub) {
int portCount = hub->GetHubPortCount();
for(int i = 0; i < portCount; i++) {
shared_ptr<BaseControlDevice> device = hub->GetController(i);
if(counter == index) {
return device;
}
counter++;
}
} else {
if(counter == index) {
return _controlDevices[i];
}
counter++;
}
}
}
return nullptr;
}
void BaseControlManager::RefreshHubState()
{
auto lock = _deviceLock.AcquireSafe();
for(size_t i = 0; i < _controlDevices.size(); i++) {
if(_controlDevices[i] && _controlDevices[i]->GetPort() <= 2) {
shared_ptr<IControllerHub> hub = std::dynamic_pointer_cast<IControllerHub>(_controlDevices[i]);
if(hub) {
hub->RefreshHubState();
}
}
}
}
vector<shared_ptr<BaseControlDevice>> BaseControlManager::GetControlDevices()
{
return _controlDevices;

View file

@ -56,6 +56,8 @@ public:
vector<ControllerData> GetPortStates();
shared_ptr<BaseControlDevice> GetControlDevice(uint8_t port);
shared_ptr<BaseControlDevice> GetControlDeviceByIndex(uint8_t index);
void RefreshHubState();
vector<shared_ptr<BaseControlDevice>> GetControlDevices();
template<typename T>

View file

@ -10,8 +10,16 @@
#include "Utilities/Serializer.h"
#include "Utilities/StringUtilities.h"
class IControllerHub
{
public:
virtual void RefreshHubState() = 0;
virtual int GetHubPortCount() = 0;
virtual shared_ptr<BaseControlDevice> GetController(int index) = 0;
};
template<int HubPortCount>
class ControllerHub : public BaseControlDevice
class ControllerHub : public BaseControlDevice, public IControllerHub
{
protected:
shared_ptr<BaseControlDevice> _ports[HubPortCount];
@ -40,7 +48,11 @@ protected:
uint8_t ReadPort(int i)
{
return _ports[i]->ReadRam(0x4016);
if(_ports[i]) {
return _ports[i]->ReadRam(0x4016);
} else {
return 0;
}
}
public:
@ -67,7 +79,6 @@ public:
break;
}
}
}
void WriteRam(uint16_t addr, uint8_t value) override
@ -160,4 +171,25 @@ public:
return false;
}
void RefreshHubState() override
{
//Used when the connected devices are updated by code (e.g by the debugger)
_state.State.clear();
UpdateStateFromPorts();
}
int GetHubPortCount() override
{
return HubPortCount;
}
shared_ptr<BaseControlDevice> GetController(int index) override
{
if(index >= HubPortCount) {
return nullptr;
}
return _ports[index];
}
};

View file

@ -83,7 +83,10 @@ extern "C"
DllExport void __stdcall StopLogTraceToFile() { WithDebugger(void, GetTraceLogFileSaver()->StopLogging()); }
DllExport void __stdcall SetBreakpoints(Breakpoint breakpoints[], uint32_t length) { WithDebugger(void, SetBreakpoints(breakpoints, length)); }
DllExport void __stdcall SetInputOverrides(uint32_t index, DebugControllerState state) { WithDebugger(void, SetInputOverrides(index, state)); }
DllExport void __stdcall GetAvailableInputOverrides(uint8_t* availableIndexes) { WithDebugger(void, GetAvailableInputOverrides(availableIndexes)); }
DllExport void __stdcall GetTokenList(CpuType cpuType, char* tokenList) { WithDebugger(void, GetTokenList(cpuType, tokenList)); }
DllExport int32_t __stdcall EvaluateExpression(const char* expression, CpuType cpuType, EvalResultType* resultType, bool useCache) { return WithDebugger(int32_t, EvaluateExpression(expression, cpuType, *resultType, useCache)); }

View file

@ -28,6 +28,7 @@ namespace Mesen.Debugger
public ToolContainerViewModel<LabelListViewModel> LabelListTool { get; private set; }
public ToolContainerViewModel<FunctionListViewModel> FunctionListTool { get; private set; }
public ToolContainerViewModel<FindResultListViewModel> FindResultListTool { get; private set; }
public ToolContainerViewModel<ControllerListViewModel> ControllerListTool { get; private set; }
private DockEntryDefinition? _savedRootDef;
@ -45,6 +46,7 @@ namespace Mesen.Debugger
LabelListTool = new("Labels");
FunctionListTool = new("Functions");
FindResultListTool = new("Find Results");
ControllerListTool = new("Controllers");
_savedRootDef = savedRootDef;
}
@ -82,7 +84,7 @@ namespace Mesen.Debugger
new MesenProportionalDockSplitter(),
new ToolDock {
Proportion = 0.5,
VisibleDockables = CreateList<IDockable>(LabelListTool, FunctionListTool, FindResultListTool)
VisibleDockables = CreateList<IDockable>(LabelListTool, FunctionListTool, FindResultListTool, ControllerListTool)
}
)
}
@ -200,6 +202,7 @@ namespace Mesen.Debugger
case nameof(LabelListViewModel): return LabelListTool;
case nameof(FunctionListViewModel): return FunctionListTool;
case nameof(FindResultListViewModel): return FindResultListTool;
case nameof(ControllerListViewModel): return ControllerListTool;
}
break;
}

View file

@ -319,6 +319,7 @@ namespace Mesen.Debugger.Utilities
ShowFunctionList,
ShowLabelList,
ShowCallStack,
ShowControllers,
ShowSettingsPanel,
ShowMemoryMappings,

View file

@ -0,0 +1,92 @@
using Avalonia;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Controls.Selection;
using Avalonia.Media;
using Dock.Model.ReactiveUI.Controls;
using Mesen.Config;
using Mesen.Debugger.Labels;
using Mesen.Debugger.Utilities;
using Mesen.Debugger.Windows;
using Mesen.Interop;
using Mesen.Utilities;
using Mesen.ViewModels;
using ReactiveUI.Fody.Helpers;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace Mesen.Debugger.ViewModels
{
public class ControllerInputViewModel : ViewModelBase
{
[Reactive] public bool ButtonA { get; set; }
[Reactive] public bool ButtonB { get; set; }
[Reactive] public bool ButtonX { get; set; }
[Reactive] public bool ButtonY { get; set; }
[Reactive] public bool ButtonL { get; set; }
[Reactive] public bool ButtonR { get; set; }
[Reactive] public bool ButtonUp { get; set; }
[Reactive] public bool ButtonDown { get; set; }
[Reactive] public bool ButtonLeft { get; set; }
[Reactive] public bool ButtonRight { get; set; }
[Reactive] public bool ButtonSelect { get; set; }
[Reactive] public bool ButtonStart { get; set; }
public int ControllerIndex { get; }
public bool IsSnes { get; }
[Obsolete("For designer only")]
public ControllerInputViewModel() : this(ConsoleType.Snes, 0) { }
public ControllerInputViewModel(ConsoleType consoleType, int index)
{
ControllerIndex = index + 1;
IsSnes = consoleType == ConsoleType.Snes;
if(Design.IsDesignMode) {
return;
}
PropertyChanged += ControllerInputViewModel_PropertyChanged;
}
private void ControllerInputViewModel_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
{
DebugApi.SetInputOverrides((uint)ControllerIndex - 1, new DebugControllerState() {
A = ButtonA,
B = ButtonB,
X = ButtonX,
Y = ButtonY,
L = ButtonL,
R = ButtonR,
Up = ButtonUp,
Down = ButtonDown,
Left = ButtonLeft,
Right = ButtonRight,
Select = ButtonSelect,
Start = ButtonStart
});
}
public void OnButtonClick(object param)
{
if(param is string buttonName) {
switch(buttonName) {
case "A": ButtonA = !ButtonA; break;
case "B": ButtonB = !ButtonB; break;
case "X": ButtonX = !ButtonX; break;
case "Y": ButtonY = !ButtonY; break;
case "L": ButtonL = !ButtonL; break;
case "R": ButtonR = !ButtonR; break;
case "Up": ButtonUp = !ButtonUp; break;
case "Down": ButtonDown = !ButtonDown; break;
case "Left": ButtonLeft = !ButtonLeft; break;
case "Right": ButtonRight = !ButtonRight; break;
case "Select": ButtonSelect = !ButtonSelect; break;
case "Start": ButtonStart = !ButtonStart; break;
}
}
}
}
}

View file

@ -0,0 +1,28 @@
using Avalonia.Controls;
using Mesen.Interop;
using Mesen.ViewModels;
using ReactiveUI.Fody.Helpers;
using System;
using System.Collections.Generic;
namespace Mesen.Debugger.ViewModels
{
public class ControllerListViewModel : ViewModelBase
{
[Reactive] public List<ControllerInputViewModel> Controllers { get; set; } = new();
[Obsolete("For designer only")]
public ControllerListViewModel() : this(ConsoleType.Snes) { }
public ControllerListViewModel(ConsoleType consoleType)
{
if(Design.IsDesignMode) {
return;
}
foreach(int index in DebugApi.GetAvailableInputOverrides()) {
Controllers.Add(new ControllerInputViewModel(consoleType, index));
}
}
}
}

View file

@ -49,6 +49,7 @@ namespace Mesen.Debugger.ViewModels
[Reactive] public SourceViewViewModel? SourceView { get; private set; }
[Reactive] public MemoryMappingViewModel? MemoryMappings { get; private set; }
[Reactive] public FindResultListViewModel FindResultList { get; private set; }
[Reactive] public ControllerListViewModel ControllerList { get; private set; }
[Reactive] public DebuggerDockFactory DockFactory { get; private set; }
[Reactive] public IRootDock DockLayout { get; private set; }
@ -78,13 +79,16 @@ namespace Mesen.Debugger.ViewModels
DebugApi.InitializeDebugger();
}
ConsoleType consoleType;
if(Design.IsDesignMode) {
CpuType = CpuType.Snes;
consoleType = ConsoleType.Snes;
} else {
RomInfo romInfo = EmuApi.GetRomInfo();
consoleType = romInfo.ConsoleType;
if(cpuType != null) {
CpuType = cpuType.Value;
if(romInfo.ConsoleType.GetMainCpuType() != CpuType) {
if(consoleType.GetMainCpuType() != CpuType) {
Title = ResourceHelper.GetEnumText(CpuType) + " Debugger";
Icon = new WindowIcon(ImageUtilities.BitmapFromAsset("Assets/" + CpuType.ToString() + "Debugger.png"));
IsMainCpuDebugger = false;
@ -104,6 +108,7 @@ namespace Mesen.Debugger.ViewModels
BreakpointList = new BreakpointListViewModel(CpuType, this);
LabelList = new LabelListViewModel(CpuType, this);
FindResultList = new FindResultListViewModel(this);
ControllerList = new ControllerListViewModel(consoleType);
if(CpuType.SupportsFunctionList()) {
FunctionList = new FunctionListViewModel(CpuType, this);
}
@ -130,6 +135,7 @@ namespace Mesen.Debugger.ViewModels
DockFactory.CallStackTool.Model = CallStack;
DockFactory.WatchListTool.Model = WatchList;
DockFactory.FindResultListTool.Model = FindResultList;
DockFactory.ControllerListTool.Model = ControllerList;
DockFactory.DisassemblyTool.Model = Disassembly;
DockFactory.SourceViewTool.Model = null;
DockFactory.StatusTool.Model = ConsoleStatus;
@ -508,11 +514,6 @@ namespace Mesen.Debugger.ViewModels
OnClick = () => cfg.ShowMemoryMappings = !cfg.ShowMemoryMappings
},
new ContextMenuSeparator(),
new ContextMenuAction() {
ActionType = ActionType.ShowWatchList,
IsSelected = () => IsToolVisible(DockFactory.WatchListTool),
OnClick = () => ToggleTool(DockFactory.WatchListTool)
},
new ContextMenuAction() {
ActionType = ActionType.ShowBreakpointList,
IsSelected = () => IsToolVisible(DockFactory.BreakpointListTool),
@ -523,6 +524,17 @@ namespace Mesen.Debugger.ViewModels
IsSelected = () => IsToolVisible(DockFactory.CallStackTool),
OnClick = () => ToggleTool(DockFactory.CallStackTool)
},
new ContextMenuAction() {
ActionType = ActionType.ShowConsoleStatus,
IsSelected = () => IsToolVisible(DockFactory.StatusTool),
OnClick = () => ToggleTool(DockFactory.StatusTool)
},
new ContextMenuAction() {
ActionType = ActionType.ShowControllers,
IsVisible = () => FunctionList != null,
IsSelected = () => IsToolVisible(DockFactory.ControllerListTool),
OnClick = () => ToggleTool(DockFactory.ControllerListTool)
},
new ContextMenuAction() {
ActionType = ActionType.ShowFunctionList,
IsVisible = () => FunctionList != null,
@ -535,9 +547,9 @@ namespace Mesen.Debugger.ViewModels
OnClick = () => ToggleTool(DockFactory.LabelListTool)
},
new ContextMenuAction() {
ActionType = ActionType.ShowConsoleStatus,
IsSelected = () => IsToolVisible(DockFactory.StatusTool),
OnClick = () => ToggleTool(DockFactory.StatusTool)
ActionType = ActionType.ShowWatchList,
IsSelected = () => IsToolVisible(DockFactory.WatchListTool),
OnClick = () => ToggleTool(DockFactory.WatchListTool)
},
new ContextMenuSeparator(),
new ContextMenuAction() {

View file

@ -0,0 +1,71 @@
<UserControl
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:l="using:Mesen.Localization"
xmlns:u="using:Mesen.Utilities"
xmlns:dvm="using:Mesen.Debugger.ViewModels"
mc:Ignorable="d" d:DesignWidth="100" d:DesignHeight="60"
x:Name="root"
HorizontalAlignment="Stretch"
x:DataType="dvm:ControllerInputViewModel"
x:Class="Mesen.Debugger.Views.ControllerInputView"
>
<Design.DataContext>
<dvm:ControllerInputViewModel />
</Design.DataContext>
<UserControl.Styles>
<Style Selector="Button">
<Setter Property="MinWidth" Value="0" />
<Setter Property="MinHeight" Value="0" />
<Setter Property="Width" Value="8" />
<Setter Property="Height" Value="8" />
<Setter Property="Margin" Value="0" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Background" Value="#303030" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Command" Value="{Binding OnButtonClick}" />
</Style>
<Style Selector="Button.selected">
<Setter Property="Background" Value="#FFFFFF" />
</Style>
</UserControl.Styles>
<Border BorderBrush="Gray" BorderThickness="1" Width="88" Height="32">
<Panel Background="#B0B0B0">
<Canvas>
<TextBlock
Text="{CompiledBinding ControllerIndex}"
Canvas.Top="4"
Canvas.Left="0"
Width="88"
TextAlignment="Center"
/>
<Button CommandParameter="Up" Canvas.Top="4" Canvas.Left="10" Classes.selected="{CompiledBinding ButtonUp}" />
<Button CommandParameter="Left" Canvas.Top="12" Canvas.Left="2" Classes.selected="{CompiledBinding ButtonLeft}" />
<Rectangle Fill="Black" Canvas.Top="12" Canvas.Left="10" Width="8" Height="8" />
<Button CommandParameter="Down" Canvas.Top="20" Canvas.Left="10" Classes.selected="{CompiledBinding ButtonDown}" />
<Button CommandParameter="Right" Canvas.Top="12" Canvas.Left="18" Classes.selected="{CompiledBinding ButtonRight}" />
<Button CommandParameter="Select" Canvas.Top="20" Canvas.Left="32" Width="11" Height="7" Classes.selected="{CompiledBinding ButtonSelect}" CornerRadius="3" />
<Button CommandParameter="Start" Canvas.Top="20" Canvas.Left="45" Width="11" Height="7" Classes.selected="{CompiledBinding ButtonStart}" CornerRadius="3" />
</Canvas>
<Canvas IsVisible="{CompiledBinding !IsSnes}" Width="25" Height="15" HorizontalAlignment="Right" VerticalAlignment="Bottom">
<Button CommandParameter="B" Canvas.Top="0" Canvas.Left="0" Classes.selected="{CompiledBinding ButtonB}" CornerRadius="6" Width="10" Height="10" />
<Button CommandParameter="A" Canvas.Top="0" Canvas.Left="12" Classes.selected="{CompiledBinding ButtonA}" CornerRadius="6" Width="10" Height="10" />
</Canvas>
<Canvas IsVisible="{CompiledBinding IsSnes}" Width="26" Height="26" HorizontalAlignment="Right" VerticalAlignment="Bottom">
<Button CommandParameter="X" Canvas.Top="0" Canvas.Left="8" Classes.selected="{CompiledBinding ButtonX}" CornerRadius="6" Width="9" Height="9"/>
<Button CommandParameter="Y" Canvas.Top="8" Canvas.Left="0" Classes.selected="{CompiledBinding ButtonY}" CornerRadius="6" Width="9" Height="9" />
<Button CommandParameter="B" Canvas.Top="16" Canvas.Left="8" Classes.selected="{CompiledBinding ButtonB}" CornerRadius="6" Width="9" Height="9" />
<Button CommandParameter="A" Canvas.Top="8" Canvas.Left="16" Classes.selected="{CompiledBinding ButtonA}" CornerRadius="6" Width="9" Height="9" />
</Canvas>
<Canvas IsVisible="{CompiledBinding IsSnes}" Width="86" Height="4" Margin="0 -1 0 0" VerticalAlignment="Top">
<Button CommandParameter="L" Canvas.Top="-1" Canvas.Left="6" Height="4" Width="16" Classes.selected="{CompiledBinding ButtonL}" />
<Button CommandParameter="R" Canvas.Top="-1" Canvas.Left="64" Height="4" Width="16" Classes.selected="{CompiledBinding ButtonR}" />
</Canvas>
</Panel>
</Border>
</UserControl>

View file

@ -0,0 +1,25 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
using Mesen.Config;
using Mesen.Utilities;
using Mesen.ViewModels;
using Mesen.Windows;
namespace Mesen.Debugger.Views
{
public class ControllerInputView : UserControl
{
public ControllerInputView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

View file

@ -0,0 +1,34 @@
<UserControl
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:l="using:Mesen.Localization"
xmlns:u="using:Mesen.Utilities"
xmlns:dvm="using:Mesen.Debugger.ViewModels"
xmlns:dv="using:Mesen.Debugger.Views"
mc:Ignorable="d" d:DesignWidth="200" d:DesignHeight="60"
x:Name="root"
HorizontalAlignment="Stretch"
x:DataType="dvm:ControllerListViewModel"
x:Class="Mesen.Debugger.Views.ControllerListView"
>
<Design.DataContext>
<dvm:ControllerListViewModel />
</Design.DataContext>
<ScrollViewer AllowAutoHide="False">
<ItemsPresenter Items="{CompiledBinding Controllers}" VerticalAlignment="Center">
<ItemsPresenter.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsPresenter.ItemsPanel>
<ItemsPresenter.ItemTemplate>
<DataTemplate>
<dv:ControllerInputView DataContext="{Binding}" Margin="1 1" />
</DataTemplate>
</ItemsPresenter.ItemTemplate>
</ItemsPresenter>
</ScrollViewer>
</UserControl>

View file

@ -0,0 +1,25 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
using Mesen.Config;
using Mesen.Utilities;
using Mesen.ViewModels;
using Mesen.Windows;
namespace Mesen.Debugger.Views
{
public class ControllerListView : UserControl
{
public ControllerListView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

View file

@ -31,6 +31,9 @@
<Style Selector="TabStrip:singleitem">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="idc|ToolControl,idc|DockControl,idc|ToolChromeControl">
<Setter Property="(ProportionalStackPanelSplitter.MinimumProportionSize)" Value="60" />
</Style>
</Window.Styles>
<Window.DataTemplates>

View file

@ -200,6 +200,23 @@ namespace Mesen.Interop
[DllImport(DllPath)] public static extern void ClearLabels();
[DllImport(DllPath)] public static extern void SetBreakpoints([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] InteropBreakpoint[] breakpoints, UInt32 length);
[DllImport(DllPath)] public static extern void SetInputOverrides(UInt32 index, DebugControllerState state);
[DllImport(DllPath)] private static extern void GetAvailableInputOverrides([In, Out] byte[] availableIndexes);
public static List<int> GetAvailableInputOverrides()
{
byte[] availableIndexes = new byte[8];
GetAvailableInputOverrides(availableIndexes);
List<int> indexes = new List<int>();
for(int i = 0; i < 8; i++) {
if(availableIndexes[i] != 0) {
indexes.Add(i);
}
}
return indexes;
}
[DllImport(DllPath)] public static extern void SaveRomToDisk([MarshalAs(UnmanagedType.LPUTF8Str)] string filename, [MarshalAs(UnmanagedType.I1)] bool saveAsIps, CdlStripOption cdlStripOption);
@ -1293,4 +1310,20 @@ namespace Mesen.Interop
[MarshalAs(UnmanagedType.I1)] public bool SearchBackwards;
[MarshalAs(UnmanagedType.I1)] public bool SkipFirstLine;
}
public struct DebugControllerState
{
[MarshalAs(UnmanagedType.I1)] public bool A;
[MarshalAs(UnmanagedType.I1)] public bool B;
[MarshalAs(UnmanagedType.I1)] public bool X;
[MarshalAs(UnmanagedType.I1)] public bool Y;
[MarshalAs(UnmanagedType.I1)] public bool L;
[MarshalAs(UnmanagedType.I1)] public bool R;
[MarshalAs(UnmanagedType.I1)] public bool Up;
[MarshalAs(UnmanagedType.I1)] public bool Down;
[MarshalAs(UnmanagedType.I1)] public bool Left;
[MarshalAs(UnmanagedType.I1)] public bool Right;
[MarshalAs(UnmanagedType.I1)] public bool Select;
[MarshalAs(UnmanagedType.I1)] public bool Start;
}
}

View file

@ -2472,6 +2472,7 @@
<Value ID="ShowWatchList">Show Watch List</Value>
<Value ID="ShowCallStack">Show Call Stack</Value>
<Value ID="ShowConsoleStatus">Show Console Status</Value>
<Value ID="ShowControllers">Show Controllers</Value>
<Value ID="ShowSettingsPanel">Show Settings Panel</Value>
<Value ID="ShowMemoryMappings">Show Memory Mappings</Value>

View file

@ -244,6 +244,12 @@
<Compile Update="Controls\OptionSection.axaml.cs">
<DependentUpon>OptionSection.axaml</DependentUpon>
</Compile>
<Compile Update="Debugger\Views\ControllerListView.axaml.cs">
<DependentUpon>ControllerListView.axaml</DependentUpon>
</Compile>
<Compile Update="Debugger\Views\ControllerInputView.axaml.cs">
<DependentUpon>ControllerInputView.axaml</DependentUpon>
</Compile>
<Compile Update="Debugger\Controls\NavButton.axaml.cs">
<DependentUpon>NavButton.axaml</DependentUpon>
</Compile>