input-rec: remove input recording code from wx-related source

This commit is contained in:
Tyler Wilding 2022-11-27 15:43:29 -05:00 committed by refractionpcsx2
parent 8cbdd61f98
commit 07c3b6ad04
52 changed files with 45 additions and 3613 deletions

View File

@ -841,10 +841,9 @@ void cdvdReset()
// If we are recording, always use the same RTC setting // If we are recording, always use the same RTC setting
// for games that use the RTC to seed their RNG -- this is very important to be the same everytime! // for games that use the RTC to seed their RNG -- this is very important to be the same everytime!
#ifndef PCSX2_CORE bool input_recording_active = false;
const bool input_recording_active = g_InputRecording.IsActive(); #ifdef PCSX2_CORE
#else input_recording_active = g_InputRecording.isActive();
const bool input_recording_active = g_InputRecording.isActive();
#endif #endif
if (input_recording_active) if (input_recording_active)
{ {

View File

@ -1390,12 +1390,8 @@ set(pcsx2RecordingSources
${rec_src}/InputRecording.cpp ${rec_src}/InputRecording.cpp
${rec_src}/InputRecordingControls.cpp ${rec_src}/InputRecordingControls.cpp
${rec_src}/InputRecordingFile.cpp ${rec_src}/InputRecordingFile.cpp
${rec_src}/NewRecordingFrame.cpp
${rec_src}/PadData.cpp ${rec_src}/PadData.cpp
${rec_src}/Utilities/InputRecordingLogger.cpp ${rec_src}/Utilities/InputRecordingLogger.cpp
${rec_vp_src}/VirtualPad.cpp
${rec_vp_src}/VirtualPadData.cpp
${rec_vp_src}/VirtualPadResources.cpp
) )
# Recording headers # Recording headers
@ -1403,38 +1399,8 @@ set(pcsx2RecordingHeaders
${rec_src}/InputRecording.h ${rec_src}/InputRecording.h
${rec_src}/InputRecordingControls.h ${rec_src}/InputRecordingControls.h
${rec_src}/InputRecordingFile.h ${rec_src}/InputRecordingFile.h
${rec_src}/NewRecordingFrame.h
${rec_src}/PadData.h ${rec_src}/PadData.h
${rec_src}/Utilities/InputRecordingLogger.h ${rec_src}/Utilities/InputRecordingLogger.h
${rec_vp_src}/VirtualPad.h
${rec_vp_src}/VirtualPadData.h
${rec_vp_src}/VirtualPadResources.h
)
# Warning: the declaration of the .h are mandatory in case of resources files. It will ensure the creation
# from the bin2cpp tools at the right moment (ie .h must be created before the pcsx2 compilation)
# Recording - VirtualPad resources headers
set(res_rec_vp_src "${CMAKE_SOURCE_DIR}/pcsx2/Recording/VirtualPad/img")
set(pcsx2RecordingVirtualPadResources
${res_rec_vp_src}/circlePressed.h
${res_rec_vp_src}/controllerFull.h
${res_rec_vp_src}/controllerHalf.h
${res_rec_vp_src}/controllerThreeQuarters.h
${res_rec_vp_src}/crossPressed.h
${res_rec_vp_src}/downPressed.h
${res_rec_vp_src}/l1Pressed.h
${res_rec_vp_src}/l2Pressed.h
${res_rec_vp_src}/l3Pressed.h
${res_rec_vp_src}/leftPressed.h
${res_rec_vp_src}/r1Pressed.h
${res_rec_vp_src}/r2Pressed.h
${res_rec_vp_src}/r3Pressed.h
${res_rec_vp_src}/rightPressed.h
${res_rec_vp_src}/selectPressed.h
${res_rec_vp_src}/squarePressed.h
${res_rec_vp_src}/startPressed.h
${res_rec_vp_src}/trianglePressed.h
${res_rec_vp_src}/upPressed.h
) )
# System headers # System headers
@ -1737,18 +1703,6 @@ if(NOT PCSX2_CORE)
COMMAND ${BIN2CPP} "${res_src}/${res_file}.png" "${res_bin}/${res_file}" COMMAND ${BIN2CPP} "${res_src}/${res_file}.png" "${res_bin}/${res_file}"
) )
endforeach() endforeach()
### Generate Recording resource files
### Drop them into the folder alongside the png files
foreach(res_file IN ITEMS
circlePressed controllerFull controllerHalf controllerThreeQuarters crossPressed downPressed l1Pressed l2Pressed l3Pressed leftPressed
r1Pressed r2Pressed r3Pressed rightPressed selectPressed squarePressed startPressed trianglePressed upPressed)
add_custom_command(
OUTPUT "${res_rec_vp_src}/${res_file}.h"
DEPENDS ${BIN2CPPDEP} "${res_rec_vp_src}/${res_file}.png"
COMMAND ${BIN2CPP} "${res_rec_vp_src}/${res_file}.png" "${res_rec_vp_src}/${res_file}"
)
endforeach()
endif() endif()
# additonal include directories # additonal include directories

View File

@ -608,15 +608,6 @@ static __fi void frameLimit()
static __fi void VSyncStart(u32 sCycle) static __fi void VSyncStart(u32 sCycle)
{ {
if (EmuConfig.EnableRecordingTools)
{
// It is imperative that any frame locking that must happen occurs before Vsync is started
// Not doing so would sacrifice a frame of a savestate-based recording when loading any savestate
#ifndef PCSX2_CORE
g_InputRecordingControls.HandlePausingAndLocking();
#endif
}
#ifdef PCSX2_CORE #ifdef PCSX2_CORE
// Update vibration at the end of a frame. // Update vibration at the end of a frame.
PAD::Update(); PAD::Update();
@ -676,13 +667,6 @@ static __fi void GSVSync()
static __fi void VSyncEnd(u32 sCycle) static __fi void VSyncEnd(u32 sCycle)
{ {
#ifndef PCSX2_CORE
if (EmuConfig.EnableRecordingTools)
{
g_InputRecordingControls.CheckPauseStatus();
}
#endif
if(EmuConfig.Trace.Enabled && EmuConfig.Trace.EE.m_EnableAll) if(EmuConfig.Trace.Enabled && EmuConfig.Trace.EE.m_EnableAll)
SysTrace.EE.Counters.Write( " ================ EE COUNTER VSYNC END (frame: %d) ================", g_FrameCount ); SysTrace.EE.Counters.Write( " ================ EE COUNTER VSYNC END (frame: %d) ================", g_FrameCount );

View File

@ -15,24 +15,8 @@
#include "PrecompiledHeader.h" #include "PrecompiledHeader.h"
#ifndef PCSX2_CORE
// TODO - Vaser - kill with wxWidgets
#include "common/StringUtil.h"
#include "SaveState.h" #include "SaveState.h"
#include "Counters.h" #include "Counters.h"
#include "SaveState.h"
#include "gui/App.h"
#include "gui/AppSaveStates.h"
#include "DebugTools/Debug.h"
#include "GameDatabase.h"
#include "InputRecording.h"
#include "InputRecordingControls.h"
#include "Utilities/InputRecordingLogger.h"
#include <fmt/format.h>
void SaveStateBase::InputRecordingFreeze() void SaveStateBase::InputRecordingFreeze()
{ {
@ -40,430 +24,9 @@ void SaveStateBase::InputRecordingFreeze()
// CHANGING THIS WILL BREAK BACKWARDS COMPATIBILITY ON SAVESTATES // CHANGING THIS WILL BREAK BACKWARDS COMPATIBILITY ON SAVESTATES
FreezeTag("InputRecording"); FreezeTag("InputRecording");
Freeze(g_FrameCount); Freeze(g_FrameCount);
if (g_Conf->EmuOptions.EnableRecordingTools)
{
// Loading a save-state is an asynchronous task. If we are playing a recording
// that starts from a savestate (not power-on) and the starting (pcsx2 internal) frame
// marker has not been set (which comes from the save-state), we initialize it.
if (g_InputRecording.IsInitialLoad())
g_InputRecording.SetupInitialState(g_FrameCount);
else if (g_InputRecording.IsActive() && IsLoading())
g_InputRecording.SetFrameCounter(g_FrameCount);
}
} }
InputRecording g_InputRecording; #ifdef PCSX2_CORE
InputRecording::InputRecordingPad::InputRecordingPad()
{
padData = new PadData;
}
InputRecording::InputRecordingPad::~InputRecordingPad()
{
delete padData;
}
void InputRecording::InitVirtualPadWindows(wxWindow* parent)
{
for (int port = 0; port < 2; ++port)
if (!pads[port].virtualPad)
pads[port].virtualPad = new VirtualPad(parent, port, g_Conf->inputRecording);
}
void InputRecording::ShowVirtualPad(const int port)
{
pads[port].virtualPad->Show();
}
void InputRecording::RecordingReset()
{
// Booting is an asynchronous task. If we are playing a recording
// that starts from power-on and the starting (pcsx2 internal) frame
// marker has not been set, we initialize it.
if (g_InputRecording.IsInitialLoad())
g_InputRecording.SetupInitialState(0);
else if (g_InputRecording.IsActive())
{
g_InputRecording.SetFrameCounter(0);
g_InputRecordingControls.Lock(0);
}
else
g_InputRecordingControls.Resume();
}
void InputRecording::ControllerInterrupt(u8 port, size_t fifoSize, u8 dataIn, u8 dataOut)
{
// TODO - Multi-Tap Support
if (fifoSize == 1)
fInterruptFrame = dataIn == READ_DATA_AND_VIBRATE_FIRST_BYTE;
else if (fifoSize == 2)
{
if (dataOut != READ_DATA_AND_VIBRATE_SECOND_BYTE)
fInterruptFrame = false;
}
else if (fInterruptFrame)
{
u8& bufVal = dataOut;
const u16 bufIndex = fifoSize - 3;
if (state == InputRecordingMode::Replaying)
{
if (frameCounter >= 0 && frameCounter < INT_MAX)
{
if (!inputRecordingData.ReadKeyBuffer(bufVal, frameCounter, port, bufIndex))
InputRec::consoleLog(fmt::format("Failed to read input data at frame {}", frameCounter));
// Update controller data state for future VirtualPad / logging usage.
pads[port].padData->UpdateControllerData(bufIndex, bufVal);
if (pads[port].virtualPad->IsShown())
pads[port].virtualPad->UpdateControllerData(bufIndex, pads[port].padData);
}
}
else
{
// Update controller data state for future VirtualPad / logging usage.
pads[port].padData->UpdateControllerData(bufIndex, bufVal);
// Commit the byte to the movie file if we are recording
if (state == InputRecordingMode::Recording)
{
if (frameCounter >= 0)
{
// If the VirtualPad updated the PadData, we have to update the buffer
// before committing it to the recording / sending it to the game
if (pads[port].virtualPad->IsShown() && pads[port].virtualPad->UpdateControllerData(bufIndex, pads[port].padData))
bufVal = pads[port].padData->PollControllerData(bufIndex);
if (incrementUndo)
{
inputRecordingData.IncrementUndoCount();
incrementUndo = false;
}
if (frameCounter < INT_MAX && !inputRecordingData.WriteKeyBuffer(frameCounter, port, bufIndex, bufVal))
InputRec::consoleLog(fmt::format("Failed to write input data at frame {}", frameCounter));
}
}
// If the VirtualPad updated the PadData, we have to update the buffer
// before sending it to the game
else if (pads[port].virtualPad && pads[port].virtualPad->IsShown() && pads[port].virtualPad->UpdateControllerData(bufIndex, pads[port].padData))
bufVal = pads[port].padData->PollControllerData(bufIndex);
}
}
}
s32 InputRecording::GetFrameCounter()
{
return frameCounter;
}
InputRecordingFile& InputRecording::GetInputRecordingData()
{
return inputRecordingData;
}
u32 InputRecording::GetStartingFrame()
{
return startingFrame;
}
void InputRecording::IncrementFrameCounter()
{
if (frameCounter < INT_MAX)
{
frameCounter++;
switch (state)
{
case InputRecordingMode::Recording:
inputRecordingData.SetTotalFrames(frameCounter);
[[fallthrough]];
case InputRecordingMode::Replaying:
if (frameCounter == inputRecordingData.GetTotalFrames())
incrementUndo = false;
break;
case InputRecordingMode::NotActive: // Does nothing but keep GCC happy.
break;
}
}
}
void InputRecording::LogAndRedraw()
{
for (u8 port = 0; port < 2; port++)
{
pads[port].padData->LogPadData(port);
// As well as re-render the virtual pad UI, if applicable
// - Don't render if it's minimized
if (pads[port].virtualPad->IsShown() && !pads[port].virtualPad->IsIconized())
pads[port].virtualPad->Redraw();
}
}
bool InputRecording::IsInterruptFrame()
{
return fInterruptFrame;
}
bool InputRecording::IsActive()
{
return state != InputRecordingMode::NotActive;
}
bool InputRecording::IsInitialLoad()
{
return initialLoad;
}
bool InputRecording::IsReplaying()
{
return state == InputRecordingMode::Replaying;
}
bool InputRecording::IsRecording()
{
return state == InputRecordingMode::Recording;
}
wxString InputRecording::RecordingModeTitleSegment()
{
switch (state)
{
case InputRecordingMode::Recording:
return wxString("Recording");
case InputRecordingMode::Replaying:
return wxString("Replaying");
default:
return wxString("No Movie");
}
}
void InputRecording::SetToRecordMode()
{
state = InputRecordingMode::Recording;
pads[CONTROLLER_PORT_ONE].virtualPad->SetReadOnlyMode(false);
pads[CONTROLLER_PORT_TWO].virtualPad->SetReadOnlyMode(false);
InputRec::log("Record mode ON");
}
void InputRecording::SetToReplayMode()
{
state = InputRecordingMode::Replaying;
pads[CONTROLLER_PORT_ONE].virtualPad->SetReadOnlyMode(true);
pads[CONTROLLER_PORT_TWO].virtualPad->SetReadOnlyMode(true);
InputRec::log("Replay mode ON");
}
void InputRecording::SetFrameCounter(u32 newGFrameCount)
{
if (newGFrameCount > startingFrame + (u32)inputRecordingData.GetTotalFrames())
{
InputRec::consoleLog("Warning, you've loaded PCSX2 emulation to a point after the end of the original recording. This should be avoided.");
InputRec::consoleLog("Savestate's framecount has been ignored.");
frameCounter = inputRecordingData.GetTotalFrames();
if (state == InputRecordingMode::Replaying)
SetToRecordMode();
incrementUndo = false;
}
else
{
if (newGFrameCount < startingFrame)
{
InputRec::consoleLog("Warning, you've loaded PCSX2 emulation to a point before the start of the original recording. This should be avoided.");
if (state == InputRecordingMode::Recording)
SetToReplayMode();
}
else if (newGFrameCount == 0 && state == InputRecordingMode::Recording)
SetToReplayMode();
frameCounter = newGFrameCount - (s32)startingFrame;
incrementUndo = true;
}
}
void InputRecording::SetupInitialState(u32 newStartingFrame)
{
startingFrame = newStartingFrame;
if (state != InputRecordingMode::Replaying)
{
InputRec::log("Started new input recording");
InputRec::consoleLog(fmt::format("Filename {}", inputRecordingData.GetFilename().ToUTF8()));
SetToRecordMode();
}
else
{
// Check if the current game matches with the one used to make the original recording
if (!g_Conf->CurrentIso.IsEmpty())
if (resolveGameName() != inputRecordingData.GetHeader().gameName)
InputRec::consoleLog("Input recording was possibly constructed for a different game.");
incrementUndo = true;
InputRec::log("Replaying input recording");
InputRec::consoleMultiLog({fmt::format("File: {}", inputRecordingData.GetFilename().ToUTF8()),
fmt::format("PCSX2 Version Used: {}", std::string(inputRecordingData.GetHeader().emu)),
fmt::format("Recording File Version: {}", inputRecordingData.GetHeader().version),
fmt::format("Associated Game Name or ISO Filename: {}", std::string(inputRecordingData.GetHeader().gameName)),
fmt::format("Author: {}", inputRecordingData.GetHeader().author),
fmt::format("Total Frames: {}", inputRecordingData.GetTotalFrames()),
fmt::format("Undo Count: {}", inputRecordingData.GetUndoCount())});
SetToReplayMode();
}
if (inputRecordingData.FromSaveState())
InputRec::consoleLog(fmt::format("Internal Starting Frame: {}", startingFrame));
frameCounter = 0;
initialLoad = false;
g_InputRecordingControls.Lock(startingFrame);
}
void InputRecording::FailedSavestate()
{
InputRec::consoleLog(fmt::format("{} is not compatible with this version of PCSX2", savestate.ToUTF8()));
InputRec::consoleLog(fmt::format("Original PCSX2 version used: {}", inputRecordingData.GetHeader().emu));
inputRecordingData.Close();
initialLoad = false;
state = InputRecordingMode::NotActive;
g_InputRecordingControls.Resume();
}
void InputRecording::Stop()
{
state = InputRecordingMode::NotActive;
pads[CONTROLLER_PORT_ONE].virtualPad->SetReadOnlyMode(false);
pads[CONTROLLER_PORT_TWO].virtualPad->SetReadOnlyMode(false);
incrementUndo = false;
if (inputRecordingData.Close())
InputRec::log("Input recording stopped");
}
bool InputRecording::Create(wxString fileName, const bool fromSaveState, wxString authorName)
{
if (!inputRecordingData.OpenNew(fileName, fromSaveState))
return false;
initialLoad = true;
state = InputRecordingMode::Recording;
if (fromSaveState)
{
savestate = fileName + "_SaveState.p2s";
if (wxFileExists(savestate))
wxCopyFile(savestate, savestate + ".bak", true);
StateCopy_SaveToFile(savestate);
}
else
sApp.SysExecute(g_Conf->CdvdSource);
// Set emulator version
inputRecordingData.GetHeader().SetEmulatorVersion();
// Set author name
if (!authorName.IsEmpty())
inputRecordingData.GetHeader().SetAuthor(authorName);
// Set Game Name
inputRecordingData.GetHeader().SetGameName(resolveGameName());
// Write header contents
inputRecordingData.WriteHeader();
return true;
}
bool InputRecording::Play(wxWindow* parent, wxString filename)
{
if (!inputRecordingData.OpenExisting(filename))
return false;
// Either load the savestate, or restart the game
if (inputRecordingData.FromSaveState())
{
if (!GetCoreThread().IsOpen())
{
InputRec::consoleLog("Game is not open, aborting playing input recording which starts on a save-state.");
inputRecordingData.Close();
return false;
}
savestate = inputRecordingData.GetFilename() + "_SaveState.p2s";
if (!wxFileExists(savestate))
{
wxFileDialog loadStateDialog(parent, _("Select the savestate that will accompany this recording"), L"", L"",
L"Savestate files (*.p2s)|*.p2s", wxFD_OPEN);
if (loadStateDialog.ShowModal() == wxID_CANCEL)
{
InputRec::consoleLog(fmt::format("Could not locate savestate file at location - {}", savestate.ToUTF8()));
InputRec::log("Savestate load failed");
inputRecordingData.Close();
return false;
}
savestate = loadStateDialog.GetPath();
InputRec::consoleLog(fmt::format("Base savestate set to {}", savestate.ToUTF8()));
}
state = InputRecordingMode::Replaying;
initialLoad = true;
StateCopy_LoadFromFile(savestate);
}
else
{
state = InputRecordingMode::Replaying;
initialLoad = true;
sApp.SysExecute(g_Conf->CdvdSource);
}
return true;
}
void InputRecording::GoToFirstFrame(wxWindow* parent)
{
if (inputRecordingData.FromSaveState())
{
if (!wxFileExists(savestate))
{
const bool initiallyPaused = g_InputRecordingControls.IsPaused();
if (!initiallyPaused)
g_InputRecordingControls.PauseImmediately();
InputRec::consoleLog(fmt::format("Could not locate savestate file at location - {}\n", savestate.ToUTF8()));
wxFileDialog loadStateDialog(parent, _("Select a savestate to accompany the recording with"), L"", L"",
L"Savestate files (*.p2s)|*.p2s", wxFD_OPEN);
int result = loadStateDialog.ShowModal();
if (!initiallyPaused)
g_InputRecordingControls.Resume();
if (result == wxID_CANCEL)
{
InputRec::log("Savestate load cancelled");
return;
}
savestate = loadStateDialog.GetPath();
InputRec::consoleLog(fmt::format("Base savestate swapped to {}", savestate.ToUTF8()));
}
StateCopy_LoadFromFile(savestate);
}
else
sApp.SysExecute(g_Conf->CdvdSource);
if (IsRecording())
SetToReplayMode();
}
wxString InputRecording::resolveGameName()
{
std::string gameName;
const std::string gameKey(SysGetDiscID());
if (!gameKey.empty())
{
auto game = GameDatabase::findGame(gameKey);
if (game)
{
gameName = game->name;
gameName += " (" + game->region + ")";
}
}
return !gameName.empty() ? StringUtil::UTF8StringToWxString(gameName) : Path::GetFilename(g_Conf->CurrentIso);
}
#else
#include "InputRecording.h" #include "InputRecording.h"
@ -472,7 +35,6 @@ wxString InputRecording::resolveGameName()
#include "common/FileSystem.h" #include "common/FileSystem.h"
#include "common/StringUtil.h" #include "common/StringUtil.h"
#include "SaveState.h"
#include "Counters.h" #include "Counters.h"
#include "SaveState.h" #include "SaveState.h"
#include "VMManager.h" #include "VMManager.h"
@ -481,14 +43,6 @@ wxString InputRecording::resolveGameName()
#include "fmt/format.h" #include "fmt/format.h"
#include "GS.h" #include "GS.h"
void SaveStateBase::InputRecordingFreeze()
{
// NOTE - BE CAREFUL
// CHANGING THIS WILL BREAK BACKWARDS COMPATIBILITY ON SAVESTATES
FreezeTag("InputRecording");
Freeze(g_FrameCount);
}
InputRecording g_InputRecording; InputRecording g_InputRecording;
bool InputRecording::create(const std::string& fileName, const bool fromSaveState, const std::string& authorName) bool InputRecording::create(const std::string& fileName, const bool fromSaveState, const std::string& authorName)
@ -633,7 +187,8 @@ void InputRecording::handleControllerDataUpdate()
else if (m_controls.isReplaying()) else if (m_controls.isReplaying())
{ {
const auto& modifiedFrameData = updateControllerData(i, 0); const auto& modifiedFrameData = updateControllerData(i, 0);
if (modifiedFrameData) { if (modifiedFrameData)
{
frameData = modifiedFrameData.value(); frameData = modifiedFrameData.value();
} }
} }

View File

@ -15,141 +15,10 @@
#pragma once #pragma once
#ifdef PCSX2_CORE
#include <queue> #include <queue>
#ifndef PCSX2_CORE
// TODO - Vaser - kill with wxWidgets
#include "Recording/InputRecordingFile.h"
#include "Recording/VirtualPad/VirtualPad.h"
class InputRecording
{
public:
// Initializes all VirtualPad windows with "parent" as their base
void InitVirtualPadWindows(wxWindow* parent);
// Save or load PCSX2's global frame counter (g_FrameCount) along with each full/fast boot
//
// This is to prevent any inaccuracy issues caused by having a different
// internal emulation frame count than what it was at the beginning of the
// original recording
void RecordingReset();
// Main handler for ingesting input data and either saving it to the recording file (recording)
// or mutating it to the contents of the recording file (replaying)
void ControllerInterrupt(u8 port, size_t fifoSize, u8 dataIn, u8 dataOut);
// The running frame counter for the input recording
s32 GetFrameCounter();
InputRecordingFile& GetInputRecordingData();
// The internal PCSX2 g_FrameCount value on the first frame of the recording
u32 GetStartingFrame();
void IncrementFrameCounter();
// DEPRECATED: Slated for removal
// If the current frame contains controller / input data
bool IsInterruptFrame();
// If there is currently an input recording being played back or actively being recorded
bool IsActive();
// Whether or not the recording's initial state has yet to be loaded or saved and
// the rest of the recording can be initialized
// This is not applicable to recordings from a "power-on" state
bool IsInitialLoad();
// If there is currently an input recording being played back
bool IsReplaying();
// If there are inputs currently being recorded to a file
bool IsRecording();
// String representation of the current recording mode to be interpolated into the title
wxString RecordingModeTitleSegment();
// Sets input recording to Record Mode
void SetToRecordMode();
// Sets input recording to Replay Mode
void SetToReplayMode();
// Set the running frame counter for the input recording to an arbitrary value
void SetFrameCounter(u32 newGFrameCount);
// Sets up all values and prints console logs pertaining to the start of a recording
void SetupInitialState(u32 newStartingFrame);
/// Functions called from GUI
// Create a new input recording file
bool Create(wxString filename, const bool fromSaveState, wxString authorName);
// Play an existing input recording from a file
// Calls a file dialog if it fails to locate the default base savestate
bool Play(wxWindow* parent, wxString filename);
// Stop the active input recording
void Stop();
// Displays the VirtualPad window for the chosen pad
void ShowVirtualPad(const int port);
// Logs the padData and redraws the virtualPad windows of active pads
void LogAndRedraw();
// Resets emulation to the beginning of a recording
// Calls a file dialog if it fails to locate the base savestate
void GoToFirstFrame(wxWindow* parent);
// Resets a recording if the base savestate could not be loaded at the start
void FailedSavestate();
private:
enum class InputRecordingMode
{
NotActive,
Recording,
Replaying,
};
static const int CONTROLLER_PORT_ONE = 0;
static const int CONTROLLER_PORT_TWO = 1;
// 0x42 is the magic number to indicate the default controller read query
// See - PAD.cpp::PADpoll - https://github.com/PCSX2/pcsx2/blob/master/pcsx2/PAD/Windows/PAD.cpp#L1255
static const u8 READ_DATA_AND_VIBRATE_FIRST_BYTE = 0x42;
// 0x5A is always the second byte in the buffer when the normal READ_DATA_AND_VIBRATE (0x42) query is executed.
// See - PAD.cpp::PADpoll - https://github.com/PCSX2/pcsx2/blob/master/pcsx2/PAD/Windows/PAD.cpp#L1256
static const u8 READ_DATA_AND_VIBRATE_SECOND_BYTE = 0x5A;
// DEPRECATED: Slated for removal
bool fInterruptFrame = false;
InputRecordingFile inputRecordingData;
bool initialLoad = false;
u32 startingFrame = 0;
s32 frameCounter = 0;
bool incrementUndo = false;
InputRecordingMode state = InputRecording::InputRecordingMode::NotActive;
wxString savestate;
// Array of usable pads (currently, only 2)
struct InputRecordingPad
{
// Controller Data
PadData* padData;
// VirtualPad
VirtualPad* virtualPad;
InputRecordingPad();
~InputRecordingPad();
} pads[2];
// Resolve the name and region of the game currently loaded using the GameDB
// If the game cannot be found in the DB, the fallback is the ISO filename
wxString resolveGameName();
};
extern InputRecording g_InputRecording;
#else
#include "Recording/InputRecordingFile.h" #include "Recording/InputRecordingFile.h"
#include "Recording/InputRecordingControls.h" #include "Recording/InputRecordingControls.h"

View File

@ -13,211 +13,10 @@
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifdef PCSX2_CORE
#include "PrecompiledHeader.h" #include "PrecompiledHeader.h"
#ifndef PCSX2_CORE
// TODO - Vaser - kill with wxWidgets
#include "Counters.h"
#include "DebugTools/Debug.h"
#include "MemoryTypes.h"
#include "gui/MainFrame.h"
#include "InputRecording.h"
#include "InputRecordingControls.h"
#include "Utilities/InputRecordingLogger.h"
InputRecordingControls g_InputRecordingControls;
void InputRecordingControls::CheckPauseStatus()
{
frame_advance_frame_counter++;
if (frameAdvancing && frame_advance_frame_counter >= frames_per_frame_advance)
{
frameAdvancing = false;
pauseEmulation = true;
}
if (g_InputRecording.IsActive())
{
g_InputRecording.IncrementFrameCounter();
if (switchToReplay)
{
g_InputRecording.SetToReplayMode();
switchToReplay = false;
}
if (IsFinishedReplaying() || g_InputRecording.GetFrameCounter() == INT_MAX)
{
if (!pauseEmulation)
pauseEmulation = true;
StopCapture();
}
}
g_InputRecording.LogAndRedraw();
}
void InputRecordingControls::HandlePausingAndLocking()
{
// Explicit frame locking
if (frameLock)
{
if (g_FrameCount == frameLockTracker)
{
frameLock = false;
Resume();
}
else if (!emulationCurrentlyPaused && GetCoreThread().IsOpen() && GetCoreThread().IsRunning())
{
emulationCurrentlyPaused = true;
GetCoreThread().PauseSelf();
}
}
else if (pauseEmulation && GetCoreThread().IsOpen() && GetCoreThread().IsRunning())
{
emulationCurrentlyPaused = true;
GetCoreThread().PauseSelf();
}
}
void InputRecordingControls::ResumeCoreThreadIfStarted()
{
if (resumeEmulation && GetCoreThread().IsOpen())
{
GetCoreThread().Resume();
resumeEmulation = false;
emulationCurrentlyPaused = false;
}
}
void InputRecordingControls::FrameAdvance()
{
if (!IsFinishedReplaying())
{
frameAdvancing = true;
frame_advance_frame_counter = 0;
Resume();
}
else
g_InputRecording.SetToRecordMode();
}
void InputRecordingControls::setFrameAdvanceAmount(int amount)
{
frames_per_frame_advance = amount;
}
bool InputRecordingControls::IsFrameAdvancing()
{
return frameAdvancing;
}
bool InputRecordingControls::IsPaused()
{
return emulationCurrentlyPaused && GetCoreThread().IsOpen() && GetCoreThread().IsPaused();
}
void InputRecordingControls::Pause()
{
pauseEmulation = true;
resumeEmulation = false;
}
void InputRecordingControls::PauseImmediately()
{
if (!GetCoreThread().IsPaused())
{
Pause();
if (GetCoreThread().IsOpen() && GetCoreThread().IsRunning())
{
emulationCurrentlyPaused = true;
GetCoreThread().PauseSelf();
}
}
}
void InputRecordingControls::Resume()
{
if (!IsFinishedReplaying())
{
pauseEmulation = false;
resumeEmulation = true;
}
else
g_InputRecording.SetToRecordMode();
}
void InputRecordingControls::ResumeImmediately()
{
if (GetCoreThread().IsPaused())
{
Resume();
if (GetCoreThread().IsRunning())
{
emulationCurrentlyPaused = false;
GetCoreThread().Resume();
}
}
}
void InputRecordingControls::TogglePause()
{
if (!pauseEmulation || !IsFinishedReplaying())
{
resumeEmulation = pauseEmulation;
pauseEmulation = !pauseEmulation;
InputRec::log(pauseEmulation ? "Paused Emulation" : "Resumed Emulation");
}
else
g_InputRecording.SetToRecordMode();
}
void InputRecordingControls::RecordModeToggle()
{
if (g_InputRecording.IsReplaying())
g_InputRecording.SetToRecordMode();
else if (g_InputRecording.IsRecording())
{
if (IsPaused() || g_InputRecording.GetFrameCounter() < g_InputRecording.GetInputRecordingData().GetTotalFrames())
g_InputRecording.SetToReplayMode();
else
switchToReplay = true;
}
}
void InputRecordingControls::Lock(u32 frame)
{
frameLock = true;
frameLockTracker = frame;
frameAdvancing = false;
//Ensures that g_frameCount can be used to resume emulation after a fast/full boot
if (!g_InputRecording.GetInputRecordingData().FromSaveState())
g_FrameCount = frame + 1;
else
sMainFrame.StartInputRecording();
}
bool InputRecordingControls::IsFinishedReplaying() const
{
return g_InputRecording.IsReplaying() &&
g_InputRecording.GetFrameCounter() >= g_InputRecording.GetInputRecordingData().GetTotalFrames();
}
void InputRecordingControls::StopCapture() const
{
if (MainEmuFrame* mainFrame = GetMainFramePtr())
{
if (mainFrame->IsCapturing())
{
mainFrame->VideoCaptureToggle();
InputRec::log("Capture completed");
}
}
}
#else
#include "DebugTools/Debug.h" #include "DebugTools/Debug.h"
#include "MemoryTypes.h" #include "MemoryTypes.h"

View File

@ -15,91 +15,7 @@
#pragma once #pragma once
#ifndef PCSX2_CORE #ifdef PCSX2_CORE
// TODO - Vaser - kill with wxWidgets
class InputRecordingControls
{
public:
// Intended to be called at the end of each frame, but will no-op if frame lock is active
//
// Will set the pausing parameters for emulation if:
// - The InputRecordingControls::FrameAdvance was hit on the previous frame
// - Emulation was explicitly paused using InputRecordingControls::TogglePause
// - We are replaying an input recording and have hit the end
void CheckPauseStatus();
// When loading a recording file or booting with a recording active, lock will be enabled.
// Emulation will be forced into and remain in a paused state until the transition in progress
// has completed - signaled when g_framecount and frameCountTracker are equal
//
// This function also handles actually pausing emulation when told to
void HandlePausingAndLocking();
// Called much more frequently than HandleFrameAdvanceAndPausing, instead of being per frame
// this hooks into pcsx2's main App event handler as it has to be able to resume emulation
// when drawing frames has compltely stopped
//
// Resumes emulation if:
// - CoreThread is currently open and paused
// - We've signaled emulation to be resumed via TogglePause or FrameAdvancing
void ResumeCoreThreadIfStarted();
// Resume emulation (incase the emulation is currently paused) and pause after a single frame has passed
void FrameAdvance();
void setFrameAdvanceAmount(int amount);
// Returns true if emulation is currently set up to frame advance.
bool IsFrameAdvancing();
// Returns true if the input recording has been paused, which can occur:
// - After a single frame has passed after InputRecordingControls::FrameAdvance
// - Explicitly paused via an InputRecordingControls function
bool IsPaused();
// Pause emulation at the next available Vsync
void Pause();
// Pause emulation immediately, not waiting for the next Vsync
void PauseImmediately();
// Resume emulation when the next pcsx2 App event is handled
void Resume();
/**
* @brief Resumes emulation immediately, don't wait until the next VSync
*/
void ResumeImmediately();
// Alternates emulation between a paused and unpaused state
void TogglePause();
// Switches between recording and replaying the active input recording file
void RecordModeToggle();
// Enables the frame locking mechanism so that when recordings are loaded
// or when processing a reboot with a recording active that no frames are
// lost in prior emulation
void Lock(u32 frame);
private:
// Indicates if the input recording controls have explicitly paused emulation or not
bool emulationCurrentlyPaused = false;
// Indicates on the next VSync if we are frame advancing, this value
// and should be cleared once a single frame has passed
bool frameAdvancing = false;
u32 frame_advance_frame_counter = 0;
u32 frames_per_frame_advance = 1;
// Indicates if we intend to call CoreThread.PauseSelf() on the current or next available vsync
bool pauseEmulation = false;
// Indicates if we intend to call CoreThread.Resume() when the next pcsx2 App event is handled
bool resumeEmulation = false;
// Indicates to switch to replay mode after the next vsync
bool switchToReplay = false;
// Used to stop recording frames from incrementing during a reset
bool frameLock = false;
// The frame value to use as the frame lock reset point
u32 frameLockTracker = 0;
bool IsFinishedReplaying() const;
// Calls mainEmuFrame's videoCaptureToggle to end a capture if active
void StopCapture() const;
};
extern InputRecordingControls g_InputRecordingControls;
#else
#include <queue> #include <queue>

View File

@ -13,225 +13,10 @@
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifdef PCSX2_CORE
#include "PrecompiledHeader.h" #include "PrecompiledHeader.h"
#ifndef PCSX2_CORE
// TODO - Vaser - kill with wxWidgets
#include "DebugTools/Debug.h"
#include "gui/MainFrame.h"
#include "MemoryTypes.h"
#include "InputRecordingFile.h"
#include "Utilities/InputRecordingLogger.h"
#include <fmt/format.h>
void InputRecordingFileHeader::Init()
{
memset(author, 0, std::size(author));
memset(gameName, 0, std::size(gameName));
}
void InputRecordingFileHeader::SetEmulatorVersion()
{
wxString emuVersion = wxString::Format("%s-%d.%d.%d", pxGetAppName().c_str(), PCSX2_VersionHi, PCSX2_VersionMid, PCSX2_VersionLo);
int max = std::size(emu) - 1;
strncpy(emu, emuVersion.c_str(), max);
emu[max] = 0;
}
void InputRecordingFileHeader::SetAuthor(wxString _author)
{
int max = std::size(author) - 1;
strncpy(author, _author.c_str(), max);
author[max] = 0;
}
void InputRecordingFileHeader::SetGameName(wxString _gameName)
{
int max = std::size(gameName) - 1;
strncpy(gameName, _gameName.c_str(), max);
gameName[max] = 0;
}
bool InputRecordingFile::Close()
{
if (recordingFile == nullptr)
{
return false;
}
fclose(recordingFile);
recordingFile = nullptr;
filename = "";
return true;
}
const wxString& InputRecordingFile::GetFilename()
{
return filename;
}
InputRecordingFileHeader& InputRecordingFile::GetHeader()
{
return header;
}
long& InputRecordingFile::GetTotalFrames()
{
return totalFrames;
}
unsigned long& InputRecordingFile::GetUndoCount()
{
return undoCount;
}
bool InputRecordingFile::FromSaveState()
{
return savestate.fromSavestate;
}
void InputRecordingFile::IncrementUndoCount()
{
undoCount++;
if (recordingFile == nullptr)
{
return;
}
fseek(recordingFile, seekpointUndoCount, SEEK_SET);
fwrite(&undoCount, 4, 1, recordingFile);
}
bool InputRecordingFile::open(const wxString path, bool newRecording)
{
if (newRecording)
{
if ((recordingFile = wxFopen(path, L"wb+")) != nullptr)
{
filename = path;
totalFrames = 0;
undoCount = 0;
header.Init();
return true;
}
}
else if ((recordingFile = wxFopen(path, L"rb+")) != nullptr)
{
if (verifyRecordingFileHeader())
{
filename = path;
return true;
}
Close();
InputRec::consoleLog("Input recording file header is invalid");
return false;
}
InputRec::consoleLog(fmt::format("Input recording file opening failed. Error - {}", strerror(errno)));
return false;
}
bool InputRecordingFile::OpenNew(const wxString& path, bool fromSavestate)
{
if (!open(path, true))
return false;
savestate.fromSavestate = fromSavestate;
return true;
}
bool InputRecordingFile::OpenExisting(const wxString& path)
{
return open(path, false);
}
bool InputRecordingFile::ReadKeyBuffer(u8& result, const uint& frame, const uint port, const uint bufIndex)
{
if (recordingFile == nullptr)
{
return false;
}
long seek = getRecordingBlockSeekPoint(frame) + controllerInputBytes * port + bufIndex;
if (fseek(recordingFile, seek, SEEK_SET) != 0 || fread(&result, 1, 1, recordingFile) != 1)
{
return false;
}
return true;
}
void InputRecordingFile::SetTotalFrames(long frame)
{
if (recordingFile == nullptr || totalFrames >= frame)
{
return;
}
totalFrames = frame;
fseek(recordingFile, seekpointTotalFrames, SEEK_SET);
fwrite(&totalFrames, 4, 1, recordingFile);
}
bool InputRecordingFile::WriteHeader()
{
if (recordingFile == nullptr)
{
return false;
}
rewind(recordingFile);
if (fwrite(&header, sizeof(InputRecordingFileHeader), 1, recordingFile) != 1 || fwrite(&totalFrames, 4, 1, recordingFile) != 1 || fwrite(&undoCount, 4, 1, recordingFile) != 1 || fwrite(&savestate, 1, 1, recordingFile) != 1)
{
return false;
}
return true;
}
bool InputRecordingFile::WriteKeyBuffer(const uint& frame, const uint port, const uint bufIndex, const u8& buf)
{
if (recordingFile == nullptr)
{
return false;
}
long seek = getRecordingBlockSeekPoint(frame) + 18 * port + bufIndex;
if (fseek(recordingFile, seek, SEEK_SET) != 0 || fwrite(&buf, 1, 1, recordingFile) != 1)
{
return false;
}
fflush(recordingFile);
return true;
}
long InputRecordingFile::getRecordingBlockSeekPoint(const long& frame)
{
return headerSize + sizeof(bool) + frame * inputBytesPerFrame;
}
bool InputRecordingFile::verifyRecordingFileHeader()
{
if (recordingFile == nullptr)
{
return false;
}
// Verify header contents
rewind(recordingFile);
if (fread(&header, sizeof(InputRecordingFileHeader), 1, recordingFile) != 1 || fread(&totalFrames, 4, 1, recordingFile) != 1 || fread(&undoCount, 4, 1, recordingFile) != 1 || fread(&savestate.fromSavestate, sizeof(bool), 1, recordingFile) != 1)
{
return false;
}
// Check for current verison
if (header.version != 1)
{
InputRec::consoleLog(fmt::format("Input recording file is not a supported version - {}", header.version));
return false;
}
return true;
}
#else
#include "InputRecordingFile.h" #include "InputRecordingFile.h"
#include "Utilities/InputRecordingLogger.h" #include "Utilities/InputRecordingLogger.h"

View File

@ -15,8 +15,7 @@
#pragma once #pragma once
#ifndef PCSX2_CORE #ifdef PCSX2_CORE
// TODO - Vaser - kill with wxWidgets
#include "System.h" #include "System.h"
#include "PadData.h" #include "PadData.h"
@ -24,103 +23,6 @@
// NOTE / TODOs for Version 2 // NOTE / TODOs for Version 2
// - Move fromSavestate, undoCount, and total frames into the header // - Move fromSavestate, undoCount, and total frames into the header
struct InputRecordingFileHeader
{
u8 version = 1;
char emu[50] = "";
char author[255] = "";
char gameName[255] = "";
public:
void SetEmulatorVersion();
void Init();
void SetAuthor(wxString author);
void SetGameName(wxString cdrom);
};
// DEPRECATED / Slated for Removal
struct InputRecordingSavestate
{
// Whether we start from the savestate or from power-on
bool fromSavestate = false;
};
// Handles all operations on the input recording file
class InputRecordingFile
{
public:
~InputRecordingFile() { Close(); }
// Closes the underlying input recording file, writing the header and
// prepares for a possible new recording to be started
bool Close();
// Retrieve the input recording's filename (not the path)
const wxString& GetFilename();
// Retrieve the input recording's header which contains high-level metadata on the recording
InputRecordingFileHeader& GetHeader();
// The maximum number of frames, or in other words, the length of the recording
long& GetTotalFrames();
// The number of times a save-state has been loaded while recording this movie
// this is also often referred to as a "re-record"
unsigned long& GetUndoCount();
// Whether or not this input recording starts by loading a save-state or by booting the game fresh
bool FromSaveState();
// Increment the number of undo actions and commit it to the recording file
void IncrementUndoCount();
// Open an existing recording file
bool OpenExisting(const wxString& path);
// Create and open a brand new input recording, either starting from a save-state or from
// booting the game
bool OpenNew(const wxString& path, bool fromSaveState);
// Reads the current frame's input data from the file in order to intercept and overwrite
// the current frame's value from the emulator
bool ReadKeyBuffer(u8& result, const uint& frame, const uint port, const uint bufIndex);
// Updates the total frame counter and commit it to the recording file
void SetTotalFrames(long frames);
// Persist the input recording file header's current state to the file
bool WriteHeader();
// Writes the current frame's input data to the file so it can be replayed
bool WriteKeyBuffer(const uint& frame, const uint port, const uint bufIndex, const u8& buf);
private:
static const int controllerPortsSupported = 2;
static const int controllerInputBytes = 18;
static const int inputBytesPerFrame = controllerInputBytes * controllerPortsSupported;
// TODO - version 2, this could be greatly simplified if everything was in the header
// + 4 + 4 is the totalFrame and undoCount values
static const int headerSize = sizeof(InputRecordingFileHeader) + 4 + 4;
// DEPRECATED / Slated for Removal
static const int recordingSavestateHeaderSize = sizeof(bool);
static const int seekpointTotalFrames = sizeof(InputRecordingFileHeader);
static const int seekpointUndoCount = sizeof(InputRecordingFileHeader) + 4;
static const int seekpointSaveStateHeader = seekpointUndoCount + 4;
InputRecordingFileHeader header;
wxString filename = "";
FILE* recordingFile = nullptr;
InputRecordingSavestate savestate;
// An signed 32-bit frame limit is equivalent to 1.13 years of continuous 60fps footage
long totalFrames = 0;
unsigned long undoCount = 0;
// Calculates the position of the current frame in the input recording
long getRecordingBlockSeekPoint(const long& frame);
bool open(const wxString path, bool newRecording);
bool verifyRecordingFileHeader();
};
#else
#include "System.h"
#include "PadData.h"
// NOTE / TODOs for Version 2
// - Move fromSavestate, undoCount, and total frames into the header
// Handles all operations on the input recording file // Handles all operations on the input recording file
class InputRecordingFile class InputRecordingFile
{ {

View File

@ -1,161 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
// This file dies along with wxWidgets
#ifndef PCSX2_CORE
#include "PrecompiledHeader.h"
#include "NewRecordingFrame.h"
#include <wx/gbsizer.h>
NewRecordingFrame::NewRecordingFrame(wxWindow* parent)
: wxDialog(parent, wxID_ANY, "New Input Recording", wxDefaultPosition, wxDefaultSize, wxSTAY_ON_TOP | wxCLOSE_BOX | wxCAPTION)
{
m_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, _("panel"));
wxGridBagSizer* gbs = new wxGridBagSizer(20, 20);
gbs->SetFlexibleDirection(wxBOTH);
gbs->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
wxBoxSizer* container = new wxBoxSizer(wxVERTICAL);
m_fileLabel = new wxStaticText(m_panel, wxID_ANY, _("File Path"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER);
m_authorLabel = new wxStaticText(m_panel, wxID_ANY, _("Author"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER);
m_fromLabel = new wxStaticText(m_panel, wxID_ANY, _("Record From"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER);
m_filePicker = new wxFilePickerCtrl(m_panel, MenuIds_New_Recording_Frame_File, wxEmptyString, "File", L"p2m2 file(*.p2m2)|*.p2m2", wxDefaultPosition, wxDefaultSize, wxFLP_SAVE | wxFLP_OVERWRITE_PROMPT | wxFLP_USE_TEXTCTRL);
m_authorInput = new wxTextCtrl(m_panel, MenuIds_New_Recording_Frame_Author, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);
m_fromChoice = new wxChoice(m_panel, MenuIds_New_Recording_Frame_From, wxDefaultPosition, wxDefaultSize);
m_savestate_label =
_("Be Warned! Basing an input recording off a savestate can be a mistake as savestates can break across emulator versions. Be prepared to be stuck to an emulator version or have to re-create your starting savestate in a later version.");
m_warning_label = new wxStaticText(m_panel, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER);
m_warning_label->SetForegroundColour(wxColor(*wxRED));
m_startRecording = new wxButton(m_panel, wxID_OK, _("Browse Required"), wxDefaultPosition, wxDefaultSize);
m_startRecording->Enable(false);
m_cancelRecording = new wxButton(m_panel, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxDefaultSize);
gbs->Add(m_fileLabel, wxGBPosition(0, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
gbs->Add(m_filePicker, wxGBPosition(0, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
gbs->Add(m_authorLabel, wxGBPosition(1, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
gbs->Add(m_authorInput, wxGBPosition(1, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
gbs->Add(m_fromLabel, wxGBPosition(2, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
gbs->Add(m_fromChoice, wxGBPosition(2, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxEXPAND);
gbs->Add(m_warning_label, wxGBPosition(3, 0), wxGBSpan(1, 2), wxALIGN_CENTER_VERTICAL);
gbs->Add(m_startRecording, wxGBPosition(4, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
gbs->Add(m_cancelRecording, wxGBPosition(4, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
gbs->AddGrowableCol(0);
gbs->AddGrowableCol(1);
gbs->AddGrowableRow(3);
container->Add(gbs, 1, wxALL | wxEXPAND, 15);
m_panel->SetSizer(container);
m_panel->GetSizer()->Fit(this);
Centre();
m_fileBrowsed = false;
m_filePicker->GetPickerCtrl()->Bind(wxEVT_FILEPICKER_CHANGED, &NewRecordingFrame::OnFileDirChange, this);
m_filePicker->Bind(wxEVT_FILEPICKER_CHANGED, &NewRecordingFrame::OnFileChanged, this);
m_fromChoice->Bind(wxEVT_CHOICE, &NewRecordingFrame::OnRecordingTypeChoiceChanged, this);
}
int NewRecordingFrame::ShowModal(const bool isCoreThreadOpen)
{
static const char* choices[2] = {"Boot", "Current Frame"};
m_fromChoice->Set(wxArrayString(1 + isCoreThreadOpen, &choices[0]));
m_fromChoice->SetSelection(isCoreThreadOpen);
if (m_fromChoice->GetSelection() == 1)
{
m_warning_label->SetLabel(m_savestate_label);
}
else
{
m_warning_label->SetLabel("");
}
m_warning_label->Wrap(GetClientSize().GetWidth());
m_panel->GetSizer()->Fit(this);
return wxDialog::ShowModal();
}
void NewRecordingFrame::OnFileDirChange(wxFileDirPickerEvent& event)
{
m_filePicker->wxFileDirPickerCtrlBase::OnFileDirChange(event);
m_fileBrowsed = true;
EnableOkBox();
}
void NewRecordingFrame::OnFileChanged(wxFileDirPickerEvent& event)
{
EnableOkBox();
}
void NewRecordingFrame::OnRecordingTypeChoiceChanged(wxCommandEvent& event)
{
if (m_fromChoice->GetSelection() == 1)
{
m_warning_label->SetLabel(m_savestate_label);
}
else
{
m_warning_label->SetLabel("");
}
m_warning_label->Wrap(GetClientSize().GetWidth());
m_panel->GetSizer()->Fit(this);
}
void NewRecordingFrame::EnableOkBox()
{
if (m_filePicker->GetPath().length() == 0)
{
m_fileBrowsed = false;
m_startRecording->SetLabel(_("Browse Required"));
m_startRecording->Enable(false);
}
else if (m_fileBrowsed)
{
m_startRecording->SetLabel(_("Start"));
m_startRecording->Enable(true);
}
}
wxString NewRecordingFrame::GetFile() const
{
wxString path = m_filePicker->GetPath();
// wxWidget's removes the extension if it contains wildcards
// on wxGTK https://trac.wxwidgets.org/ticket/15285
if (!path.EndsWith(".p2m2"))
{
return wxString::Format("%s.p2m2", path);
}
return path;
}
wxString NewRecordingFrame::GetAuthor() const
{
return m_authorInput->GetValue();
}
int NewRecordingFrame::GetFrom() const
{
return m_fromChoice->GetSelection();
}
#endif

View File

@ -1,61 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#ifndef PCSX2_CORE
#include <wx/wx.h>
#include <wx/filepicker.h>
enum MenuIds_New_Recording_Frame
{
MenuIds_New_Recording_Frame_File = 0,
MenuIds_New_Recording_Frame_Author,
MenuIds_New_Recording_Frame_From
};
// The Dialog to pop-up when recording a new movie
class NewRecordingFrame : public wxDialog
{
public:
NewRecordingFrame(wxWindow* parent);
int ShowModal(const bool isCoreThreadOpen);
wxString GetFile() const;
wxString GetAuthor() const;
int GetFrom() const;
protected:
void OnFileDirChange(wxFileDirPickerEvent& event);
void OnFileChanged(wxFileDirPickerEvent& event);
void OnRecordingTypeChoiceChanged(wxCommandEvent& event);
void EnableOkBox();
private:
wxPanel* m_panel;
wxStaticText* m_fileLabel;
wxFilePickerCtrl* m_filePicker;
bool m_fileBrowsed;
wxStaticText* m_authorLabel;
wxTextCtrl* m_authorInput;
wxStaticText* m_fromLabel;
wxChoice* m_fromChoice;
wxButton* m_startRecording;
wxButton* m_cancelRecording;
wxString m_savestate_label;
wxStaticText* m_warning_label;
};
#endif

View File

@ -13,199 +13,13 @@
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifdef PCSX2_CORE
#include "PrecompiledHeader.h" #include "PrecompiledHeader.h"
#include "DebugTools/Debug.h" #include "DebugTools/Debug.h"
#include "Recording/PadData.h" #include "Recording/PadData.h"
#ifndef PCSX2_CORE
void PadData::UpdateControllerData(u16 bufIndex, u8 const& bufVal)
{
const BufferIndex index = static_cast<BufferIndex>(bufIndex);
switch (index)
{
case BufferIndex::PressedFlagsGroupOne:
leftPressed = IsButtonPressed(LEFT, bufVal);
downPressed = IsButtonPressed(DOWN, bufVal);
rightPressed = IsButtonPressed(RIGHT, bufVal);
upPressed = IsButtonPressed(UP, bufVal);
start = IsButtonPressed(START, bufVal);
r3 = IsButtonPressed(R3, bufVal);
l3 = IsButtonPressed(L3, bufVal);
select = IsButtonPressed(SELECT, bufVal);
break;
case BufferIndex::PressedFlagsGroupTwo:
squarePressed = IsButtonPressed(SQUARE, bufVal);
crossPressed = IsButtonPressed(CROSS, bufVal);
circlePressed = IsButtonPressed(CIRCLE, bufVal);
trianglePressed = IsButtonPressed(TRIANGLE, bufVal);
r1Pressed = IsButtonPressed(R1, bufVal);
l1Pressed = IsButtonPressed(L1, bufVal);
r2Pressed = IsButtonPressed(R2, bufVal);
l2Pressed = IsButtonPressed(L2, bufVal);
break;
case BufferIndex::RightAnalogXVector:
rightAnalogX = bufVal;
break;
case BufferIndex::RightAnalogYVector:
rightAnalogY = bufVal;
break;
case BufferIndex::LeftAnalogXVector:
leftAnalogX = bufVal;
break;
case BufferIndex::LeftAnalogYVector:
leftAnalogY = bufVal;
break;
case BufferIndex::RightPressure:
rightPressure = bufVal;
break;
case BufferIndex::LeftPressure:
leftPressure = bufVal;
break;
case BufferIndex::UpPressure:
upPressure = bufVal;
break;
case BufferIndex::DownPressure:
downPressure = bufVal;
break;
case BufferIndex::TrianglePressure:
trianglePressure = bufVal;
break;
case BufferIndex::CirclePressure:
circlePressure = bufVal;
break;
case BufferIndex::CrossPressure:
crossPressure = bufVal;
break;
case BufferIndex::SquarePressure:
squarePressure = bufVal;
break;
case BufferIndex::L1Pressure:
l1Pressure = bufVal;
break;
case BufferIndex::R1Pressure:
r1Pressure = bufVal;
break;
case BufferIndex::L2Pressure:
l2Pressure = bufVal;
break;
case BufferIndex::R2Pressure:
r2Pressure = bufVal;
break;
}
}
u8 PadData::PollControllerData(u16 bufIndex)
{
u8 byte = 0;
const BufferIndex index = static_cast<BufferIndex>(bufIndex);
switch (index)
{
case BufferIndex::PressedFlagsGroupOne:
// Construct byte by combining flags if the buttons are pressed
byte |= BitmaskOrZero(leftPressed, LEFT);
byte |= BitmaskOrZero(downPressed, DOWN);
byte |= BitmaskOrZero(rightPressed, RIGHT);
byte |= BitmaskOrZero(upPressed, UP);
byte |= BitmaskOrZero(start, START);
byte |= BitmaskOrZero(r3, R3);
byte |= BitmaskOrZero(l3, L3);
byte |= BitmaskOrZero(select, SELECT);
// We flip the bits because as mentioned below, 0 = pressed
return ~byte;
case BufferIndex::PressedFlagsGroupTwo:
// Construct byte by combining flags if the buttons are pressed
byte |= BitmaskOrZero(squarePressed, SQUARE);
byte |= BitmaskOrZero(crossPressed, CROSS);
byte |= BitmaskOrZero(circlePressed, CIRCLE);
byte |= BitmaskOrZero(trianglePressed, TRIANGLE);
byte |= BitmaskOrZero(r1Pressed, R1);
byte |= BitmaskOrZero(l1Pressed, L1);
byte |= BitmaskOrZero(r2Pressed, R2);
byte |= BitmaskOrZero(l2Pressed, L2);
// We flip the bits because as mentioned below, 0 = pressed
return ~byte;
case BufferIndex::RightAnalogXVector:
return rightAnalogX;
case BufferIndex::RightAnalogYVector:
return rightAnalogY;
case BufferIndex::LeftAnalogXVector:
return leftAnalogX;
case BufferIndex::LeftAnalogYVector:
return leftAnalogY;
case BufferIndex::RightPressure:
return rightPressure;
case BufferIndex::LeftPressure:
return leftPressure;
case BufferIndex::UpPressure:
return upPressure;
case BufferIndex::DownPressure:
return downPressure;
case BufferIndex::TrianglePressure:
return trianglePressure;
case BufferIndex::CirclePressure:
return circlePressure;
case BufferIndex::CrossPressure:
return crossPressure;
case BufferIndex::SquarePressure:
return squarePressure;
case BufferIndex::L1Pressure:
return l1Pressure;
case BufferIndex::R1Pressure:
return r1Pressure;
case BufferIndex::L2Pressure:
return l2Pressure;
case BufferIndex::R2Pressure:
return r2Pressure;
default:
return 0;
}
}
bool PadData::IsButtonPressed(ButtonResolver buttonResolver, u8 const& bufVal)
{
// Rather than the flags being SET if the button is pressed, it is the opposite
// For example: 0111 1111 with `left` being the first bit indicates `left` is pressed.
// So, we are forced to flip the pressed bits with a NOT first
return (~bufVal & buttonResolver.buttonBitmask) > 0;
}
u8 PadData::BitmaskOrZero(bool pressed, ButtonResolver buttonInfo)
{
return pressed ? buttonInfo.buttonBitmask : 0;
}
// TODO - Vaser - kill with wxWidgets
// TODO - Vaser - replace with this something better in Qt
wxString PadData::RawPadBytesToString(int start, int end)
{
wxString str;
for (int i = start; i < end; i++)
{
str += wxString::Format("%d", PollControllerData(i));
if (i != end - 1)
str += ", ";
}
return str;
}
void PadData::LogPadData(u8 const& port)
{
wxString pressedBytes = RawPadBytesToString(0, 2);
wxString rightAnalogBytes = RawPadBytesToString(2, 4);
wxString leftAnalogBytes = RawPadBytesToString(4, 6);
wxString pressureBytes = RawPadBytesToString(6, 17);
wxString fullLog =
wxString::Format("[PAD %d] Raw Bytes: Pressed = [%s]\n", port + 1, pressedBytes) +
wxString::Format("[PAD %d] Raw Bytes: Right Analog = [%s]\n", port + 1, rightAnalogBytes) +
wxString::Format("[PAD %d] Raw Bytes: Left Analog = [%s]\n", port + 1, leftAnalogBytes) +
wxString::Format("[PAD %d] Raw Bytes: Pressure = [%s]\n", port + 1, pressureBytes);
controlLog(fullLog.ToUTF8());
}
#else
#include <fmt/core.h> #include <fmt/core.h>
#include "PAD/Host/KeyStatus.h" #include "PAD/Host/KeyStatus.h"

View File

@ -15,121 +15,7 @@
#pragma once #pragma once
#ifndef PCSX2_CORE #ifdef PCSX2_CORE
class PadData
{
public:
/// Constants
static const u8 ANALOG_VECTOR_NEUTRAL = 127;
enum class BufferIndex
{
PressedFlagsGroupOne,
PressedFlagsGroupTwo,
RightAnalogXVector,
RightAnalogYVector,
LeftAnalogXVector,
LeftAnalogYVector,
RightPressure,
LeftPressure,
UpPressure,
DownPressure,
TrianglePressure,
CirclePressure,
CrossPressure,
SquarePressure,
L1Pressure,
R1Pressure,
L2Pressure,
R2Pressure
};
/// Pressure Buttons - 0-255
u8 circlePressure = 0;
u8 crossPressure = 0;
u8 squarePressure = 0;
u8 trianglePressure = 0;
u8 downPressure = 0;
u8 leftPressure = 0;
u8 rightPressure = 0;
u8 upPressure = 0;
u8 l1Pressure = 0;
u8 l2Pressure = 0;
u8 r1Pressure = 0;
u8 r2Pressure = 0;
/// Pressure Button Flags
/// NOTE - It shouldn't be possible to depress a button while also having no pressure
/// But for the sake of completeness, it should be tracked.
bool circlePressed = false;
bool crossPressed = false;
bool squarePressed = false;
bool trianglePressed = false;
bool downPressed = false;
bool leftPressed = false;
bool rightPressed = false;
bool upPressed = false;
bool l1Pressed = false;
bool l2Pressed = false;
bool r1Pressed = false;
bool r2Pressed = false;
/// Normal (un)pressed buttons
bool select = false;
bool start = false;
bool l3 = false;
bool r3 = false;
/// Analog Sticks - 0-255 (127 center)
u8 leftAnalogX = ANALOG_VECTOR_NEUTRAL;
u8 leftAnalogY = ANALOG_VECTOR_NEUTRAL;
u8 rightAnalogX = ANALOG_VECTOR_NEUTRAL;
u8 rightAnalogY = ANALOG_VECTOR_NEUTRAL;
// Given the input buffer and the current index, updates the correct field(s)
void UpdateControllerData(u16 bufIndex, u8 const& bufVal);
u8 PollControllerData(u16 bufIndex);
// Prints current PadData to the Controller Log filter which disabled by default
void LogPadData(u8 const& port);
private:
struct ButtonResolver
{
u8 buttonBitmask;
};
const ButtonResolver LEFT = ButtonResolver{0b10000000};
const ButtonResolver DOWN = ButtonResolver{0b01000000};
const ButtonResolver RIGHT = ButtonResolver{0b00100000};
const ButtonResolver UP = ButtonResolver{0b00010000};
const ButtonResolver START = ButtonResolver{0b00001000};
const ButtonResolver R3 = ButtonResolver{0b00000100};
const ButtonResolver L3 = ButtonResolver{0b00000010};
const ButtonResolver SELECT = ButtonResolver{0b00000001};
const ButtonResolver SQUARE = ButtonResolver{0b10000000};
const ButtonResolver CROSS = ButtonResolver{0b01000000};
const ButtonResolver CIRCLE = ButtonResolver{0b00100000};
const ButtonResolver TRIANGLE = ButtonResolver{0b00010000};
const ButtonResolver R1 = ButtonResolver{0b00001000};
const ButtonResolver L1 = ButtonResolver{0b00000100};
const ButtonResolver R2 = ButtonResolver{0b00000010};
const ButtonResolver L2 = ButtonResolver{0b00000001};
// Checks and returns if button a is pressed or not
bool IsButtonPressed(ButtonResolver buttonResolver, u8 const& bufVal);
u8 BitmaskOrZero(bool pressed, ButtonResolver buttonInfo);
#ifndef PCSX2_CORE
wxString RawPadBytesToString(int start, int end);
#else
std::string RawPadBytesToString(int start, int end);
#endif
};
#else
class PadData class PadData
{ {
@ -180,12 +66,6 @@ public:
// Prints current PadData to the Controller Log filter which is disabled by default // Prints current PadData to the Controller Log filter which is disabled by default
void LogPadData() const; void LogPadData() const;
private:
#ifndef PCSX2_CORE
wxString RawPadBytesToString(int start, int end);
#endif
}; };
#endif #endif

View File

@ -1,438 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2020 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#ifndef PCSX2_CORE
#include <math.h>
#include "gui/App.h"
#include "gui/MSWstuff.h"
#include "gui/EmbeddedImage.h"
#include "wx/dcbuffer.h"
#include "wx/display.h"
#include "wx/spinctrl.h"
#include "Recording/VirtualPad/VirtualPad.h"
#include "Recording/VirtualPad/VirtualPadResources.h"
#include "Recording/VirtualPad/img/circlePressed.h"
#include "Recording/VirtualPad/img/controllerFull.h"
#include "Recording/VirtualPad/img/controllerThreeQuarters.h"
#include "Recording/VirtualPad/img/controllerHalf.h"
#include "Recording/VirtualPad/img/crossPressed.h"
#include "Recording/VirtualPad/img/downPressed.h"
#include "Recording/VirtualPad/img/l1Pressed.h"
#include "Recording/VirtualPad/img/l2Pressed.h"
#include "Recording/VirtualPad/img/l3Pressed.h"
#include "Recording/VirtualPad/img/leftPressed.h"
#include "Recording/VirtualPad/img/r1Pressed.h"
#include "Recording/VirtualPad/img/r2Pressed.h"
#include "Recording/VirtualPad/img/r3Pressed.h"
#include "Recording/VirtualPad/img/rightPressed.h"
#include "Recording/VirtualPad/img/selectPressed.h"
#include "Recording/VirtualPad/img/squarePressed.h"
#include "Recording/VirtualPad/img/startPressed.h"
#include "Recording/VirtualPad/img/trianglePressed.h"
#include "Recording/VirtualPad/img/upPressed.h"
VirtualPad::VirtualPad(wxWindow* parent, int controllerPort, AppConfig::InputRecordingOptions& options)
: wxFrame(parent, wxID_ANY, wxEmptyString)
, options(options)
{
// Images at 1.00 scale are designed to work well on HiDPI (4k) at 150% scaling (default recommended setting on windows)
// Therefore, on a 1080p monitor we halve the scaling, on 1440p we reduce it by 25%, which from some quick tests looks comparable
// Side-note - Getting the DPI scaling amount is platform specific (with some platforms only supporting
// integer scaling as well) this is likely not reliable.
// Slight multi-monitor support, will use whatever window pcsx2 is opened with, but won't currently re-init if
// windows are dragged between differing monitors!
wxDisplay display(wxDisplay::GetFromWindow(this));
const wxRect screen = display.GetClientArea();
float dpiScale = MSW_GetDPIScale(); // linux returns 1.0
if (screen.height > 1080 && screen.height <= 1440) // 1440p display
scalingFactor = 0.75 * dpiScale;
else if (screen.height <= 1080) // 1080p display
{
scalingFactor = 0.5 * dpiScale;
}
// otherwise use default 1.0 scaling
virtualPadData = VirtualPadData();
// Based on the scaling factor, select the appropriate background image
// Don't scale these images as they've already been pre-scaled
if (floatCompare(scalingFactor, 0.5))
virtualPadData.background = NewBitmap(EmbeddedImage<res_controllerHalf>().Get(), wxPoint(0, 0), true);
else if (floatCompare(scalingFactor, 0.75))
virtualPadData.background = NewBitmap(EmbeddedImage<res_controllerThreeQuarters>().Get(), wxPoint(0, 0), true);
else
// Otherwise, scale down/up (or don't in the case of 1.0) the largst image
virtualPadData.background = NewBitmap(EmbeddedImage<res_controllerFull>().Get(), wxPoint(0, 0));
// Use the background image's size to define the window size
SetClientSize(virtualPadData.background.width, virtualPadData.background.height);
// These hard-coded pixels correspond to where the background image's components are (ie. the buttons)
// Everything is automatically scaled and adjusted based on the `scalingFactor` variable
InitPressureButtonGuiElements(virtualPadData.square, NewBitmap(EmbeddedImage<res_squarePressed>().Get(), wxPoint(852, 287)), this, wxPoint(1055, 525));
InitPressureButtonGuiElements(virtualPadData.triangle, NewBitmap(EmbeddedImage<res_trianglePressed>().Get(), wxPoint(938, 201)), this, wxPoint(1055, 565));
InitPressureButtonGuiElements(virtualPadData.circle, NewBitmap(EmbeddedImage<res_circlePressed>().Get(), wxPoint(1024, 286)), this, wxPoint(1055, 605));
InitPressureButtonGuiElements(virtualPadData.cross, NewBitmap(EmbeddedImage<res_crossPressed>().Get(), wxPoint(938, 369)), this, wxPoint(1055, 645));
InitPressureButtonGuiElements(virtualPadData.left, NewBitmap(EmbeddedImage<res_leftPressed>().Get(), wxPoint(110, 303)), this, wxPoint(175, 525), true);
InitPressureButtonGuiElements(virtualPadData.up, NewBitmap(EmbeddedImage<res_upPressed>().Get(), wxPoint(186, 227)), this, wxPoint(175, 565), true);
InitPressureButtonGuiElements(virtualPadData.right, NewBitmap(EmbeddedImage<res_rightPressed>().Get(), wxPoint(248, 302)), this, wxPoint(175, 605), true);
InitPressureButtonGuiElements(virtualPadData.down, NewBitmap(EmbeddedImage<res_downPressed>().Get(), wxPoint(186, 359)), this, wxPoint(175, 645), true);
InitPressureButtonGuiElements(virtualPadData.l1, NewBitmap(EmbeddedImage<res_l1Pressed>().Get(), wxPoint(156, 98)), this, wxPoint(170, 135));
InitPressureButtonGuiElements(virtualPadData.l2, NewBitmap(EmbeddedImage<res_l2Pressed>().Get(), wxPoint(156, 57)), this, wxPoint(170, 52), false, true);
InitPressureButtonGuiElements(virtualPadData.r1, NewBitmap(EmbeddedImage<res_r1Pressed>().Get(), wxPoint(921, 98)), this, wxPoint(1035, 135), true);
InitPressureButtonGuiElements(virtualPadData.r2, NewBitmap(EmbeddedImage<res_r2Pressed>().Get(), wxPoint(921, 57)), this, wxPoint(1035, 52), true, true);
InitNormalButtonGuiElements(virtualPadData.select, NewBitmap(EmbeddedImage<res_selectPressed>().Get(), wxPoint(458, 313)), this, wxPoint(530, 315));
InitNormalButtonGuiElements(virtualPadData.start, NewBitmap(EmbeddedImage<res_startPressed>().Get(), wxPoint(688, 311)), this, wxPoint(646, 315));
InitNormalButtonGuiElements(virtualPadData.l3, NewBitmap(EmbeddedImage<res_l3Pressed>().Get(), wxPoint(336, 453)), this, wxPoint(560, 638));
InitNormalButtonGuiElements(virtualPadData.r3, NewBitmap(EmbeddedImage<res_r3Pressed>().Get(), wxPoint(726, 453)), this, wxPoint(615, 638));
InitAnalogStickGuiElements(virtualPadData.leftAnalog, this, wxPoint(404, 522), 100, wxPoint(314, 642), wxPoint(526, 432), false, wxPoint(504, 685), wxPoint(570, 425), true);
InitAnalogStickGuiElements(virtualPadData.rightAnalog, this, wxPoint(794, 522), 100, wxPoint(706, 642), wxPoint(648, 432), true, wxPoint(700, 685), wxPoint(635, 425));
ignoreRealControllerBox = new wxCheckBox(this, wxID_ANY, wxEmptyString, ScaledPoint(wxPoint(586, 135)), wxDefaultSize);
resetButton = new wxButton(this, wxID_ANY, _("Reset"), ScaledPoint(wxPoint(1195, 5), wxSize(100, 50), true), ScaledSize(wxSize(100, 50)));
Bind(wxEVT_CHECKBOX, &VirtualPad::OnIgnoreRealController, this, ignoreRealControllerBox->GetId());
Bind(wxEVT_BUTTON, &VirtualPad::OnResetButton, this, resetButton->GetId());
// Bind Window Events
Bind(wxEVT_MOVE, &VirtualPad::OnMoveAround, this);
Bind(wxEVT_CLOSE_WINDOW, &VirtualPad::OnClose, this);
Bind(wxEVT_ICONIZE, &VirtualPad::OnIconize, this);
Bind(wxEVT_ERASE_BACKGROUND, &VirtualPad::OnEraseBackground, this);
// Temporary Paint event handler so the window displays properly before the controller-interrupt routine takes over with manual drawing.
// The reason for this is in order to minimize the performance impact, we need total control over when render is called
// Windows redraws the window _alot_ otherwise which leads to major performance problems (when GS is using the software renderer)
Bind(wxEVT_PAINT, &VirtualPad::OnPaint, this);
// DevCon.WriteLn("Paint Event Bound");
// Finalize layout
SetIcons(wxGetApp().GetIconBundle());
SetTitle(wxString::Format("Virtual Pad - Port %d", controllerPort + 1));
SetPosition(options.VirtualPadPosition);
SetBackgroundColour(*wxWHITE);
SetBackgroundStyle(wxBG_STYLE_PAINT);
// This window does not allow for resizing for sake of simplicity: all images are scaled initially and stored, ready to be rendered
SetWindowStyle(wxDEFAULT_FRAME_STYLE & ~wxRESIZE_BORDER & ~wxMAXIMIZE_BOX);
// Causes flickering, despite it supposed to be preventing it!
// SetDoubleBuffered(true);
}
void VirtualPad::OnMoveAround(wxMoveEvent& event)
{
if (IsBeingDeleted() || !IsVisible() || IsIconized())
return;
if (!IsMaximized())
options.VirtualPadPosition = GetPosition();
event.Skip();
}
void VirtualPad::OnClose(wxCloseEvent& event)
{
// Re-bind the Paint event in case this is due to a game being opened/closed
manualRedrawMode = false;
Bind(wxEVT_PAINT, &VirtualPad::OnPaint, this);
// DevCon.WriteLn("Paint Event Bound");
Hide();
}
void VirtualPad::OnIconize(wxIconizeEvent& event)
{
if (event.IsIconized())
{
manualRedrawMode = false;
Bind(wxEVT_PAINT, &VirtualPad::OnPaint, this);
// DevCon.WriteLn("Paint Event Bound");
}
}
void VirtualPad::OnEraseBackground(wxEraseEvent& event)
{
// Intentionally Empty
// See - https://wiki.wxwidgets.org/Flicker-Free_Drawing
}
void VirtualPad::OnPaint(wxPaintEvent& event)
{
// DevCon.WriteLn("Paint Event Called");
wxBufferedPaintDC dc(this, wxBUFFER_VIRTUAL_AREA);
Render(dc);
}
void VirtualPad::Redraw()
{
wxClientDC cdc(this);
wxBufferedDC dc(&cdc);
Render(dc);
}
void VirtualPad::Render(wxDC& bdc)
{
// Update GUI Elements and figure out what needs to be rendered
for (VirtualPadElement* virtualPadElement : virtualPadElements)
virtualPadElement->UpdateGuiElement(renderQueue, clearScreenRequired);
// Update Graphic Elements off render stack
// Before we start rendering (if we have to) clear and re-draw the background
if (!manualRedrawMode || clearScreenRequired || !renderQueue.empty())
{
bdc.SetBrush(*wxWHITE);
bdc.DrawRectangle(wxPoint(0, 0), bdc.GetSize());
bdc.SetBrush(wxNullBrush);
bdc.DrawBitmap(virtualPadData.background.image, virtualPadData.background.coords, true);
clearScreenRequired = false;
// Switch to Manual Rendering once the first user action on the VirtualPad is taken
if (!manualRedrawMode && !renderQueue.empty())
{
// DevCon.WriteLn("Paint Event Unbound");
Unbind(wxEVT_PAINT, &VirtualPad::OnPaint, this);
manualRedrawMode = true;
}
// NOTE - there is yet another (and I think final) micro-optimization that can be done:
// It can be assumed that if the element has already been drawn to the screen (and not cleared) that we can skip rendering it
//
// For example - you hold a single button for several frames, it will currently draw that every frame
// despite the screen never being cleared - so this is not strictly necessary.
//
// Though after some tests, the performance impact is well within reason, and on the hardware renderer modes, is almost non-existant.
while (!renderQueue.empty())
{
VirtualPadElement* element = renderQueue.front();
if (element)
element->Render(bdc);
renderQueue.pop();
}
}
}
bool VirtualPad::UpdateControllerData(u16 const bufIndex, PadData* padData)
{
return virtualPadData.UpdateVirtualPadData(bufIndex, padData, ignoreRealController && !readOnlyMode, readOnlyMode);
}
void VirtualPad::enableUiElements(bool enable)
{
ignoreRealControllerBox->Enable(enable);
resetButton->Enable(enable);
for (VirtualPadElement* virtualPadElement : virtualPadElements)
virtualPadElement->EnableWidgets(enable);
}
void VirtualPad::SetReadOnlyMode(bool readOnly)
{
enableUiElements(!readOnly);
readOnlyMode = readOnly;
}
void VirtualPad::OnIgnoreRealController(wxCommandEvent& event)
{
const wxCheckBox* ignoreButton = (wxCheckBox*)event.GetEventObject();
if (ignoreButton)
ignoreRealController = ignoreButton->GetValue();
}
void VirtualPad::OnResetButton(wxCommandEvent& event)
{
if (readOnlyMode)
return;
for (VirtualPadElement* virtualPadElement : virtualPadElements)
virtualPadElement->Reset(this);
}
void VirtualPad::OnNormalButtonPress(wxCommandEvent& event)
{
const wxCheckBox* pressedButton = (wxCheckBox*)event.GetEventObject();
ControllerNormalButton* eventBtn = buttonElements[pressedButton->GetId()];
if (pressedButton)
eventBtn->pressed = pressedButton->GetValue();
if (!eventBtn->isControllerPressBypassed)
eventBtn->isControllerPressBypassed = true;
}
void VirtualPad::OnPressureButtonPressureChange(wxCommandEvent& event)
{
const wxSpinCtrl* pressureSpinner = (wxSpinCtrl*)event.GetEventObject();
ControllerPressureButton* eventBtn = pressureElements[pressureSpinner->GetId()];
if (pressureSpinner)
eventBtn->pressure = pressureSpinner->GetValue();
eventBtn->pressed = eventBtn->pressure > 0;
if (!eventBtn->isControllerPressureBypassed || !eventBtn->isControllerPressBypassed)
{
eventBtn->isControllerPressureBypassed = true;
eventBtn->isControllerPressBypassed = true;
}
}
void VirtualPad::OnAnalogSpinnerChange(wxCommandEvent& event)
{
const wxSpinCtrl* analogSpinner = (wxSpinCtrl*)event.GetEventObject();
AnalogVector* eventVector = analogElements[analogSpinner->GetId()];
if (analogSpinner)
eventVector->val = analogSpinner->GetValue();
eventVector->slider->SetValue(eventVector->val);
if (!eventVector->isControllerBypassed)
eventVector->isControllerBypassed = true;
}
void VirtualPad::OnAnalogSliderChange(wxCommandEvent& event)
{
const wxSlider* analogSlider = (wxSlider*)event.GetEventObject();
AnalogVector* eventVector = analogElements[analogSlider->GetId()];
if (analogSlider)
eventVector->val = analogSlider->GetValue();
eventVector->spinner->SetValue(eventVector->val);
if (!eventVector->isControllerBypassed)
eventVector->isControllerBypassed = true;
}
/// GUI Element Utility Functions
bool VirtualPad::floatCompare(float a, float b, float epsilon)
{
return (fabs(a - b) < epsilon);
}
wxPoint VirtualPad::ScaledPoint(wxPoint point, wxSize widgetWidth, bool rightAlignedCoord, bool bottomAlignedCoord)
{
return ScaledPoint(point.x, point.y, widgetWidth.x, widgetWidth.y, rightAlignedCoord, bottomAlignedCoord);
}
wxPoint VirtualPad::ScaledPoint(int x, int y, int widgetWidth, int widgetHeight, bool rightAlignedCoord, bool bottomAlignedCoord)
{
wxPoint scaledPoint = wxPoint(x * scalingFactor, y * scalingFactor);
if (rightAlignedCoord)
{
scaledPoint.x -= widgetWidth * scalingFactor;
if (scaledPoint.x < 0)
scaledPoint.x = 0;
}
if (bottomAlignedCoord)
{
scaledPoint.y -= widgetHeight * scalingFactor;
if (scaledPoint.y < 0)
scaledPoint.y = 0;
}
return scaledPoint;
}
wxSize VirtualPad::ScaledSize(wxSize size)
{
return ScaledSize(size.x, size.y);
}
wxSize VirtualPad::ScaledSize(int x, int y)
{
return wxSize(x * scalingFactor, y * scalingFactor);
}
ImageFile VirtualPad::NewBitmap(wxImage resource, wxPoint imgCoord, bool dontScale)
{
return NewBitmap(dontScale ? 1 : scalingFactor, resource, imgCoord);
}
ImageFile VirtualPad::NewBitmap(float scalingFactor, wxImage resource, wxPoint imgCoord)
{
wxBitmap bitmap = wxBitmap(resource.Rescale(resource.GetWidth() * scalingFactor, resource.GetHeight() * scalingFactor, wxIMAGE_QUALITY_HIGH));
ImageFile image = ImageFile();
image.image = bitmap;
image.width = bitmap.GetWidth();
image.height = bitmap.GetHeight();
image.coords = ScaledPoint(imgCoord);
return image;
}
void VirtualPad::InitNormalButtonGuiElements(ControllerNormalButton& button, ImageFile image, wxWindow* parentWindow, wxPoint checkboxCoord)
{
button.icon = image;
button.pressedBox = new wxCheckBox(parentWindow, wxID_ANY, wxEmptyString, ScaledPoint(checkboxCoord), wxDefaultSize);
Bind(wxEVT_CHECKBOX, &VirtualPad::OnNormalButtonPress, this, button.pressedBox->GetId());
buttonElements[button.pressedBox->GetId()] = &button;
virtualPadElements.push_back(&button);
}
void VirtualPad::InitPressureButtonGuiElements(ControllerPressureButton& button, ImageFile image, wxWindow* parentWindow, wxPoint pressureSpinnerCoord, bool rightAlignedCoord, bool bottomAlignedCoord)
{
const wxPoint scaledPoint = ScaledPoint(pressureSpinnerCoord, SPINNER_SIZE, rightAlignedCoord, bottomAlignedCoord);
wxSpinCtrl* spinner = new wxSpinCtrl(parentWindow, wxID_ANY, wxEmptyString, scaledPoint, ScaledSize(SPINNER_SIZE), wxSP_ARROW_KEYS, 0, 255, 0);
button.icon = image;
button.pressureSpinner = spinner;
Bind(wxEVT_SPINCTRL, &VirtualPad::OnPressureButtonPressureChange, this, button.pressureSpinner->GetId());
pressureElements[button.pressureSpinner->GetId()] = &button;
virtualPadElements.push_back(&button);
}
void VirtualPad::InitAnalogStickGuiElements(AnalogStick& analog, wxWindow* parentWindow, wxPoint centerPoint, int radius,
wxPoint xSliderPoint, wxPoint ySliderPoint, bool flipYSlider, wxPoint xSpinnerPoint, wxPoint ySpinnerPoint, bool rightAlignedSpinners)
{
AnalogPosition analogPos = AnalogPosition();
analogPos.centerCoords = ScaledPoint(centerPoint);
analogPos.endCoords = ScaledPoint(centerPoint);
analogPos.radius = radius * scalingFactor;
analogPos.lineThickness = 6 * scalingFactor;
const wxPoint xSpinnerScaledPoint = ScaledPoint(xSpinnerPoint, SPINNER_SIZE, rightAlignedSpinners);
const wxPoint ySpinnerScaledPoint = ScaledPoint(ySpinnerPoint, SPINNER_SIZE, rightAlignedSpinners, true);
wxSlider* xSlider = new wxSlider(parentWindow, wxID_ANY, ANALOG_NEUTRAL, 0, ANALOG_MAX,
ScaledPoint(xSliderPoint), ScaledSize(ANALOG_SLIDER_WIDTH, ANALOG_SLIDER_HEIGHT));
wxSlider* ySlider = new wxSlider(parentWindow, wxID_ANY, ANALOG_NEUTRAL, 0, ANALOG_MAX,
ScaledPoint(ySliderPoint), ScaledSize(ANALOG_SLIDER_HEIGHT, ANALOG_SLIDER_WIDTH), flipYSlider ? wxSL_LEFT : wxSL_RIGHT);
wxSpinCtrl* xSpinner = new wxSpinCtrl(parentWindow, wxID_ANY, wxEmptyString, xSpinnerScaledPoint, ScaledSize(SPINNER_SIZE), wxSP_ARROW_KEYS, 0, 255, 127);
wxSpinCtrl* ySpinner = new wxSpinCtrl(parentWindow, wxID_ANY, wxEmptyString, ySpinnerScaledPoint, ScaledSize(SPINNER_SIZE), wxSP_ARROW_KEYS, 0, 255, 127);
analog.xVector.slider = xSlider;
analog.yVector.slider = ySlider;
analog.xVector.spinner = xSpinner;
analog.yVector.spinner = ySpinner;
analog.positionGraphic = analogPos;
Bind(wxEVT_SLIDER, &VirtualPad::OnAnalogSliderChange, this, xSlider->GetId());
Bind(wxEVT_SLIDER, &VirtualPad::OnAnalogSliderChange, this, ySlider->GetId());
Bind(wxEVT_SPINCTRL, &VirtualPad::OnAnalogSpinnerChange, this, xSpinner->GetId());
Bind(wxEVT_SPINCTRL, &VirtualPad::OnAnalogSpinnerChange, this, ySpinner->GetId());
analogElements[xSlider->GetId()] = &analog.xVector;
analogElements[ySlider->GetId()] = &analog.yVector;
analogElements[xSpinner->GetId()] = &analog.xVector;
analogElements[ySpinner->GetId()] = &analog.yVector;
virtualPadElements.push_back(&analog);
}
#endif

View File

@ -1,119 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2020 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#ifndef PCSX2_CORE
#include <map>
#include <queue>
#include "gui/AppConfig.h"
#include "common/Pcsx2Types.h"
#include "wx/button.h"
#include "wx/checkbox.h"
#include "wx/dc.h"
#include "wx/event.h"
#include "wx/frame.h"
#include "wx/gdicmn.h"
#include "wx/string.h"
#include "wx/window.h"
#include "wx/windowid.h"
#include "Recording/PadData.h"
#include "Recording/VirtualPad/VirtualPadData.h"
class VirtualPad : public wxFrame
{
public:
VirtualPad(wxWindow* parent, int controllerPort, AppConfig::InputRecordingOptions& options);
// Updates the VirtualPad's data if necessary, as well as updates the provided PadData if the VirtualPad overrides it
// - PadData will not be updated if ReadOnly mode is set
// - returns a bool to indicate if the PadData has been updated
bool UpdateControllerData(u16 const bufIndex, PadData* padData);
// Enables/Disables read only mode and enables/disables GUI widgets
void SetReadOnlyMode(bool readOnly);
// To be called at maximum, once per frame to update widget's value and re-render the VirtualPad's graphics
void Redraw();
private:
/// Constants
const wxSize SPINNER_SIZE = wxSize(100, 40);
static const int ANALOG_SLIDER_WIDTH = 185;
static const int ANALOG_SLIDER_HEIGHT = 30;
static const int PRESSURE_MAX = 255;
static const int ANALOG_NEUTRAL = 127;
static const int ANALOG_MAX = 255;
AppConfig::InputRecordingOptions& options;
bool clearScreenRequired = false;
bool ignoreRealController = false;
// When enabled, forces the VirtualPad to be re-rendered even if no updates are made.
// This helps to make sure the UI is rendered prior to receiving data from the controller
bool manualRedrawMode = false;
bool readOnlyMode = false;
VirtualPadData virtualPadData;
std::vector<VirtualPadElement*> virtualPadElements;
std::queue<VirtualPadElement*> renderQueue;
void enableUiElements(bool enable);
/// GUI Elements
wxCheckBox* ignoreRealControllerBox;
wxButton* resetButton;
std::map<wxWindowID, ControllerNormalButton*> buttonElements;
std::map<wxWindowID, ControllerPressureButton*> pressureElements;
std::map<wxWindowID, AnalogVector*> analogElements;
/// Event Listeners
void OnMoveAround(wxMoveEvent& event);
void OnClose(wxCloseEvent& event);
void OnIconize(wxIconizeEvent& event);
void OnEraseBackground(wxEraseEvent& event);
void OnPaint(wxPaintEvent& event);
void Render(wxDC& dc);
void OnAnalogSliderChange(wxCommandEvent& event);
void OnAnalogSpinnerChange(wxCommandEvent& event);
void OnIgnoreRealController(wxCommandEvent& event);
void OnNormalButtonPress(wxCommandEvent& event);
void OnPressureButtonPressureChange(wxCommandEvent& event);
void OnResetButton(wxCommandEvent& event);
/// GUI Creation Utility Functions
float scalingFactor = 1.0;
bool floatCompare(float A, float B, float epsilon = 0.005f);
wxSize ScaledSize(wxSize size);
wxSize ScaledSize(int x, int y);
wxPoint ScaledPoint(wxPoint point, wxSize widgetSize = wxDefaultSize, bool rightAlignedCoord = false, bool bottomAlignedCoord = false);
wxPoint ScaledPoint(int x, int y, int widgetWidth, int widgetHeight, bool rightAlignedCoord = false, bool bottomAlignedCoord = false);
ImageFile NewBitmap(wxImage resource, wxPoint imgCoord, bool dontScale = false);
ImageFile NewBitmap(float scalingFactor, wxImage resource, wxPoint imgCoord);
void InitPressureButtonGuiElements(ControllerPressureButton& button, ImageFile image, wxWindow* parentWindow, wxPoint pressureSpinnerCoord, bool rightAlignedCoord = false, bool bottomAlignedCoord = false);
void InitNormalButtonGuiElements(ControllerNormalButton& btn, ImageFile image, wxWindow* parentWindow, wxPoint checkboxCoord);
void InitAnalogStickGuiElements(AnalogStick& analog, wxWindow* parentWindow, wxPoint centerPoint, int radius, wxPoint xSliderPoint,
wxPoint ySliderPoint, bool flipYSlider, wxPoint xSpinnerPoint, wxPoint ySpinnerPoint, bool rightAlignedSpinners = false);
};
#endif

View File

@ -1,84 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2020 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#ifndef PCSX2_CORE
#include "Recording/VirtualPad/VirtualPadData.h"
bool VirtualPadData::UpdateVirtualPadData(u16 bufIndex, PadData* padData, bool ignoreRealController, bool readOnly)
{
bool changeDetected = false;
PadData::BufferIndex index = static_cast<PadData::BufferIndex>(bufIndex);
switch (index)
{
case PadData::BufferIndex::PressedFlagsGroupOne:
changeDetected |= left.UpdateData(padData->leftPressed, ignoreRealController, readOnly);
changeDetected |= down.UpdateData(padData->downPressed, ignoreRealController, readOnly);
changeDetected |= right.UpdateData(padData->rightPressed, ignoreRealController, readOnly);
changeDetected |= up.UpdateData(padData->upPressed, ignoreRealController, readOnly);
changeDetected |= start.UpdateData(padData->start, ignoreRealController, readOnly);
changeDetected |= r3.UpdateData(padData->r3, ignoreRealController, readOnly);
changeDetected |= l3.UpdateData(padData->l3, ignoreRealController, readOnly);
changeDetected |= select.UpdateData(padData->select, ignoreRealController, readOnly);
return changeDetected;
case PadData::BufferIndex::PressedFlagsGroupTwo:
changeDetected |= square.UpdateData(padData->squarePressed, ignoreRealController, readOnly);
changeDetected |= cross.UpdateData(padData->crossPressed, ignoreRealController, readOnly);
changeDetected |= circle.UpdateData(padData->circlePressed, ignoreRealController, readOnly);
changeDetected |= triangle.UpdateData(padData->trianglePressed, ignoreRealController, readOnly);
changeDetected |= r1.UpdateData(padData->r1Pressed, ignoreRealController, readOnly);
changeDetected |= l1.UpdateData(padData->l1Pressed, ignoreRealController, readOnly);
changeDetected |= r2.UpdateData(padData->r2Pressed, ignoreRealController, readOnly);
changeDetected |= l2.UpdateData(padData->l2Pressed, ignoreRealController, readOnly);
return changeDetected;
case PadData::BufferIndex::RightAnalogXVector:
return rightAnalog.xVector.UpdateData(padData->rightAnalogX, ignoreRealController, readOnly);
case PadData::BufferIndex::RightAnalogYVector:
return rightAnalog.yVector.UpdateData(padData->rightAnalogY, ignoreRealController, readOnly);
case PadData::BufferIndex::LeftAnalogXVector:
return leftAnalog.xVector.UpdateData(padData->leftAnalogX, ignoreRealController, readOnly);
case PadData::BufferIndex::LeftAnalogYVector:
return leftAnalog.yVector.UpdateData(padData->leftAnalogY, ignoreRealController, readOnly);
case PadData::BufferIndex::RightPressure:
return right.UpdateData(padData->rightPressure, ignoreRealController, readOnly);
case PadData::BufferIndex::LeftPressure:
return left.UpdateData(padData->leftPressure, ignoreRealController, readOnly);
case PadData::BufferIndex::UpPressure:
return up.UpdateData(padData->upPressure, ignoreRealController, readOnly);
case PadData::BufferIndex::DownPressure:
return down.UpdateData(padData->downPressure, ignoreRealController, readOnly);
case PadData::BufferIndex::TrianglePressure:
return triangle.UpdateData(padData->trianglePressure, ignoreRealController, readOnly);
case PadData::BufferIndex::CirclePressure:
return circle.UpdateData(padData->circlePressure, ignoreRealController, readOnly);
case PadData::BufferIndex::CrossPressure:
return cross.UpdateData(padData->crossPressure, ignoreRealController, readOnly);
case PadData::BufferIndex::SquarePressure:
return square.UpdateData(padData->squarePressure, ignoreRealController, readOnly);
case PadData::BufferIndex::L1Pressure:
return l1.UpdateData(padData->l1Pressure, ignoreRealController, readOnly);
case PadData::BufferIndex::R1Pressure:
return r1.UpdateData(padData->r1Pressure, ignoreRealController, readOnly);
case PadData::BufferIndex::L2Pressure:
return l2.UpdateData(padData->l2Pressure, ignoreRealController, readOnly);
case PadData::BufferIndex::R2Pressure:
return r2.UpdateData(padData->r2Pressure, ignoreRealController, readOnly);
}
return changeDetected;
}
#endif

View File

@ -1,63 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2020 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#ifndef PCSX2_CORE
#include "common/Pcsx2Types.h"
#include "Recording/PadData.h"
#include "Recording/VirtualPad/VirtualPadResources.h"
class VirtualPadData
{
public:
/// Controller Background
ImageFile background;
/// Pressure Buttons
ControllerPressureButton circle;
ControllerPressureButton cross;
ControllerPressureButton down;
ControllerPressureButton l1;
ControllerPressureButton l2;
ControllerPressureButton left;
ControllerPressureButton r1;
ControllerPressureButton r2;
ControllerPressureButton right;
ControllerPressureButton square;
ControllerPressureButton triangle;
ControllerPressureButton up;
/// Normal (un)pressed buttons
ControllerNormalButton l3;
ControllerNormalButton r3;
ControllerNormalButton select;
ControllerNormalButton start;
/// Analog Sticks
AnalogStick leftAnalog;
AnalogStick rightAnalog;
// Given the input buffer and the current index, updates the respective field(s) within this object
// Additionally overwrites the PadData object under the following criteria:
// - If ignoreRealController is true (and readOnly is false) PadData will always be updated
// - else if the VirtualPad has overwritten the value, and the real controller has not changed since that moment in time
// returns a boolean to indicate if it has updated the PadData
bool UpdateVirtualPadData(u16 bufIndex, PadData* padData, bool ignoreRealController = false, bool readOnly = false);
};
#endif

View File

@ -1,267 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2020 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#ifndef PCSX2_CORE
#include <wx/spinctrl.h>
#include "Recording/VirtualPad/VirtualPadResources.h"
#include "Recording/PadData.h"
wxCommandEvent VirtualPadElement::ConstructEvent(wxEventTypeTag<wxCommandEvent> eventType, wxWindow* obj)
{
wxCommandEvent event(eventType, obj->GetId());
event.SetEventObject(obj);
return event;
}
wxCommandEvent VirtualPadElement::ConstructEvent(wxEventTypeTag<wxSpinEvent> eventType, wxWindow* obj)
{
wxCommandEvent event(eventType, obj->GetId());
event.SetEventObject(obj);
return event;
}
void ControllerNormalButton::UpdateGuiElement(std::queue<VirtualPadElement*>& renderQueue, bool& clearScreenRequired)
{
ControllerNormalButton& button = *this;
// This boolean is set when we parse the PadData in VirtualPadData::UpdateVirtualPadData
// Updating wxWidget elements can be expensive, we only want to do this if required
if (button.widgetUpdateRequired)
button.pressedBox->SetValue(button.pressed);
// We only render the button if it is pressed
if (button.pressed)
renderQueue.push(this);
// However, if the button has been drawn to the screen in the past
// we need to ensure the screen is cleared.
// This is needed in the scenario where only a single button is being pressed/released
// As no other elements will trigger a clear
else if (button.currentlyRendered)
{
button.currentlyRendered = false;
clearScreenRequired = true;
}
}
void ControllerPressureButton::UpdateGuiElement(std::queue<VirtualPadElement*>& renderQueue, bool& clearScreenRequired)
{
ControllerPressureButton& button = *this;
if (button.widgetUpdateRequired)
button.pressureSpinner->SetValue(button.pressure);
if (button.pressed)
renderQueue.push(this);
else if (button.currentlyRendered)
{
button.currentlyRendered = false;
clearScreenRequired = true;
}
}
void AnalogStick::UpdateGuiElement(std::queue<VirtualPadElement*>& renderQueue, bool& clearScreenRequired)
{
AnalogStick& analogStick = *this;
if (analogStick.xVector.widgetUpdateRequired)
{
analogStick.xVector.slider->SetValue(analogStick.xVector.val);
analogStick.xVector.spinner->SetValue(analogStick.xVector.val);
}
if (analogStick.yVector.widgetUpdateRequired)
{
analogStick.yVector.slider->SetValue(analogStick.yVector.val);
analogStick.yVector.spinner->SetValue(analogStick.yVector.val);
}
// We render the analog sticks as long as they are not in the neutral position
if (!(analogStick.xVector.val == PadData::ANALOG_VECTOR_NEUTRAL && analogStick.yVector.val == PadData::ANALOG_VECTOR_NEUTRAL))
renderQueue.push(this);
else if (analogStick.currentlyRendered)
{
analogStick.currentlyRendered = false;
clearScreenRequired = true;
}
}
void ControllerNormalButton::EnableWidgets(bool enable)
{
this->pressedBox->Enable(enable);
}
void ControllerPressureButton::EnableWidgets(bool enable)
{
this->pressureSpinner->Enable(enable);
}
void AnalogStick::EnableWidgets(bool enable)
{
this->xVector.slider->Enable(enable);
this->yVector.slider->Enable(enable);
this->xVector.spinner->Enable(enable);
this->yVector.spinner->Enable(enable);
}
void ControllerNormalButton::Render(wxDC& dc)
{
ControllerNormalButton& button = *this;
ImageFile& img = button.icon;
dc.DrawBitmap(img.image, img.coords, true);
button.currentlyRendered = true;
}
void ControllerPressureButton::Render(wxDC& dc)
{
ControllerPressureButton& button = *this;
ImageFile& img = button.icon;
dc.DrawBitmap(img.image, img.coords, true);
button.currentlyRendered = true;
}
void AnalogStick::Render(wxDC& dc)
{
AnalogStick& analogStick = *this;
// Render graphic
AnalogPosition analogPos = analogStick.positionGraphic;
// Determine new end coordinates
int newXCoord = analogPos.centerCoords.x + ((analogStick.xVector.val - 127) / 127.0) * analogPos.radius;
int newYCoord = analogPos.centerCoords.y + ((analogStick.yVector.val - 127) / 127.0) * analogPos.radius;
// We want to ensure the line segment length is capped at the defined radius
// NOTE - The conventional way to do this is using arctan2, but the analog values that come out
// of Pad in pcsx2 do not permit this, the coordinates returned do not define a circle.
const float lengthOfLine = sqrt(pow(newXCoord - analogPos.centerCoords.x, 2) + pow(newYCoord - analogPos.centerCoords.y, 2));
if (lengthOfLine > analogPos.radius)
{
newXCoord = ((1 - analogPos.radius / lengthOfLine) * analogPos.centerCoords.x) + analogPos.radius / lengthOfLine * newXCoord;
newYCoord = ((1 - analogPos.radius / lengthOfLine) * analogPos.centerCoords.y) + analogPos.radius / lengthOfLine * newYCoord;
}
// Set the new end coordinate
analogPos.endCoords = wxPoint(newXCoord, newYCoord);
// Draw line and tip
dc.SetPen(wxPen(*wxBLUE, analogPos.lineThickness));
dc.DrawLine(analogPos.centerCoords, analogPos.endCoords);
dc.DrawCircle(analogPos.endCoords, wxCoord(analogPos.lineThickness));
dc.SetPen(wxNullPen);
analogStick.currentlyRendered = true;
}
void ControllerNormalButton::Reset(wxEvtHandler* destWindow)
{
this->pressedBox->SetValue(false);
wxPostEvent(destWindow, ConstructEvent(wxEVT_CHECKBOX, this->pressedBox));
}
void ControllerPressureButton::Reset(wxEvtHandler* destWindow)
{
this->pressureSpinner->SetValue(0);
wxPostEvent(destWindow, ConstructEvent(wxEVT_SPINCTRL, this->pressureSpinner));
}
void AnalogStick::Reset(wxEvtHandler* destWindow)
{
this->xVector.slider->SetValue(127);
this->yVector.slider->SetValue(127);
wxPostEvent(destWindow, ConstructEvent(wxEVT_SLIDER, this->xVector.slider));
wxPostEvent(destWindow, ConstructEvent(wxEVT_SLIDER, this->yVector.slider));
this->xVector.spinner->SetValue(127);
this->xVector.spinner->SetValue(127);
wxPostEvent(destWindow, ConstructEvent(wxEVT_SPINCTRL, this->xVector.spinner));
wxPostEvent(destWindow, ConstructEvent(wxEVT_SPINCTRL, this->yVector.spinner));
}
bool ControllerNormalButton::UpdateData(bool& padDataVal, bool ignoreRealController, bool readOnly)
{
return this->UpdateButtonData(padDataVal, ignoreRealController, readOnly);
}
bool ControllerPressureButton::UpdateData(bool& padDataVal, bool ignoreRealController, bool readOnly)
{
return this->UpdateButtonData(padDataVal, ignoreRealController, readOnly);
}
bool ControllerButton::UpdateButtonData(bool& padDataVal, bool ignoreRealController, bool readOnly)
{
ControllerButton& button = *this;
if (!ignoreRealController || readOnly)
{
// If controller is being bypassed and controller's state has changed
const bool bypassedWithChangedState = button.isControllerPressBypassed && padDataVal != button.prevPressedVal;
if (bypassedWithChangedState)
{
button.prevPressedVal = padDataVal;
button.isControllerPressBypassed = false;
}
// If we aren't bypassing the controller OR the previous condition was met
if (bypassedWithChangedState || !button.isControllerPressBypassed || readOnly)
{
button.widgetUpdateRequired = button.pressed != padDataVal;
button.pressed = padDataVal;
return false;
}
}
// Otherwise, we update the real PadData value, which will in turn be used to update the interrupt's buffer
button.prevPressedVal = padDataVal;
padDataVal = button.pressed;
return button.prevPressedVal != button.pressed;
}
bool ControllerPressureButton::UpdateData(u8& padDataVal, bool ignoreRealController, bool readOnly)
{
ControllerPressureButton& button = *this;
if (!ignoreRealController || readOnly)
{
const bool bypassedWithChangedState = button.isControllerPressureBypassed && padDataVal != button.prevPressureVal;
if (bypassedWithChangedState)
{
button.prevPressureVal = padDataVal;
button.isControllerPressureBypassed = false;
}
if (bypassedWithChangedState || !button.isControllerPressureBypassed || readOnly)
{
button.widgetUpdateRequired = button.pressure != padDataVal;
button.pressure = padDataVal;
return false;
}
}
button.prevPressureVal = padDataVal;
padDataVal = button.pressure;
return button.prevPressureVal != button.pressure;
}
bool AnalogVector::UpdateData(u8& padDataVal, bool ignoreRealController, bool readOnly)
{
AnalogVector& vector = *this;
if (!ignoreRealController || readOnly)
{
const bool bypassedWithChangedState = vector.isControllerBypassed && padDataVal != vector.prevVal;
if (bypassedWithChangedState)
{
vector.prevVal = padDataVal;
vector.isControllerBypassed = false;
}
if (bypassedWithChangedState || !vector.isControllerBypassed || readOnly)
{
vector.widgetUpdateRequired = vector.val != padDataVal;
vector.val = padDataVal;
return false;
}
}
vector.prevVal = padDataVal;
padDataVal = vector.val;
return vector.prevVal != vector.val;
}
#endif

View File

@ -1,133 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2020 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#ifndef PCSX2_CORE
#include <queue>
#include "common/Pcsx2Types.h"
#include "wx/bitmap.h"
#include "wx/checkbox.h"
#include "wx/gdicmn.h"
#include "wx/slider.h"
#include "wx/spinctrl.h"
#include "wx/dcbuffer.h"
struct ImageFile
{
wxBitmap image;
wxPoint coords;
u32 width = 0;
u32 height = 0;
};
struct AnalogVector
{
wxSlider* slider = 0;
wxSpinCtrl* spinner = 0;
u8 val = 127;
bool isControllerBypassed = false;
bool widgetUpdateRequired = false;
u8 prevVal = 127;
bool UpdateData(u8& padDataVal, bool ignoreRealController, bool readOnly);
};
struct AnalogPosition
{
wxPoint centerCoords;
wxPoint endCoords;
int lineThickness = 0;
int radius = 0;
};
class VirtualPadElement
{
public:
bool currentlyRendered = false;
wxCommandEvent ConstructEvent(wxEventTypeTag<wxCommandEvent> eventType, wxWindow *obj);
wxCommandEvent ConstructEvent(wxEventTypeTag<wxSpinEvent> eventType, wxWindow *obj);
virtual void EnableWidgets(bool enable) = 0;
virtual void Render(wxDC& dc) = 0;
virtual void Reset(wxEvtHandler* destWindow) = 0;
virtual void UpdateGuiElement(std::queue<VirtualPadElement*>& renderQueue, bool& clearScreenRequired) = 0;
};
class ControllerButton
{
public:
bool isControllerPressBypassed = false;
bool pressed = false;
bool prevPressedVal = false;
bool widgetUpdateRequired = false;
bool UpdateButtonData(bool& padDataVal, bool ignoreRealController, bool readOnly);
};
class ControllerNormalButton : public ControllerButton, public VirtualPadElement
{
public:
ImageFile icon;
wxCheckBox* pressedBox = 0;
bool UpdateData(bool& padDataVal, bool ignoreRealController, bool readOnly);
void EnableWidgets(bool enable) override;
void Render(wxDC& dc) override;
void Reset(wxEvtHandler* destWindow) override;
void UpdateGuiElement(std::queue<VirtualPadElement*>& renderQueue, bool& clearScreenRequired) override;
};
class ControllerPressureButton : public ControllerButton, public VirtualPadElement
{
public:
ImageFile icon;
wxSpinCtrl* pressureSpinner = 0;
u8 pressure = 0;
bool isControllerPressureBypassed = false;
u8 prevPressureVal = 0;
bool UpdateData(bool& padDataVal, bool ignoreRealController, bool readOnly);
bool UpdateData(u8& padDataVal, bool ignoreRealController, bool readOnly);
void EnableWidgets(bool enable) override;
void Render(wxDC& dc) override;
void Reset(wxEvtHandler* destWindow) override;
void UpdateGuiElement(std::queue<VirtualPadElement*>& renderQueue, bool& clearScreenRequired) override;
};
class AnalogStick : public VirtualPadElement
{
public:
AnalogVector xVector;
AnalogVector yVector;
AnalogPosition positionGraphic;
void EnableWidgets(bool enable) override;
void Render(wxDC& dc) override;
void Reset(wxEvtHandler* destWindow) override;
void UpdateGuiElement(std::queue<VirtualPadElement*>& renderQueue, bool& clearScreenRequired) override;
};
#endif

View File

@ -1 +0,0 @@
*.h

View File

@ -1,18 +0,0 @@
:: Probably self-explanatory: This batch file compiles a single souce image into a
:: CPP header file for use by pcsx2.
::
:: bin2cpp.cmd SrcImage
::
:: Parameters
:: SrcImage - Complete filename with extension.
::
@echo off
SETLOCAL ENABLEEXTENSIONS
cd "%~0\..\"
"..\..\..\..\tools\bin\bin2cpp.exe" %1
ENDLOCAL

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 836 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1017 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 302 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -30,8 +30,6 @@
#include "RecentIsoList.h" #include "RecentIsoList.h"
#include "DriveList.h" #include "DriveList.h"
#include "Recording/NewRecordingFrame.h"
class DisassemblyDialog; class DisassemblyDialog;
struct HostKeyEvent; struct HostKeyEvent;
@ -482,13 +480,6 @@ public:
MainEmuFrame* GetMainFramePtr() const { return (MainEmuFrame*)wxWindow::FindWindowById(m_id_MainFrame); } MainEmuFrame* GetMainFramePtr() const { return (MainEmuFrame*)wxWindow::FindWindowById(m_id_MainFrame); }
DisassemblyDialog* GetDisassemblyPtr() const { return (DisassemblyDialog*)wxWindow::FindWindowById(m_id_Disassembler); } DisassemblyDialog* GetDisassemblyPtr() const { return (DisassemblyDialog*)wxWindow::FindWindowById(m_id_Disassembler); }
#ifndef PCSX2_CORE
NewRecordingFrame* GetNewRecordingFramePtr() const
{
return (NewRecordingFrame*)wxWindow::FindWindowById(m_id_NewRecordingFrame);
}
#endif
void enterDebugMode(); void enterDebugMode();
void leaveDebugMode(); void leaveDebugMode();
void resetDebugger(); void resetDebugger();

View File

@ -234,13 +234,9 @@ void Pcsx2App::SysApplySettings()
} }
void AppCoreThread::OnResumeReady() void AppCoreThread::OnResumeReady()
{
if (!g_InputRecordingControls.IsFrameAdvancing())
{ {
wxGetApp().SysApplySettings(); wxGetApp().SysApplySettings();
wxGetApp().PostMethod(AppSaveSettings); wxGetApp().PostMethod(AppSaveSettings);
}
sApp.PostAppMethod(&Pcsx2App::leaveDebugMode); sApp.PostAppMethod(&Pcsx2App::leaveDebugMode);
_parent::OnResumeReady(); _parent::OnResumeReady();
} }

View File

@ -104,11 +104,6 @@ void Pcsx2App::OpenMainFrame()
DisassemblyDialog* disassembly = new DisassemblyDialog(mainFrame); DisassemblyDialog* disassembly = new DisassemblyDialog(mainFrame);
m_id_Disassembler = disassembly->GetId(); m_id_Disassembler = disassembly->GetId();
NewRecordingFrame* newRecordingFrame = new NewRecordingFrame(mainFrame);
m_id_NewRecordingFrame = newRecordingFrame->GetId();
if (g_Conf->EmuOptions.EnableRecordingTools)
g_InputRecording.InitVirtualPadWindows(mainFrame);
if (g_Conf->EmuOptions.Debugger.ShowDebuggerOnStart) if (g_Conf->EmuOptions.Debugger.ShowDebuggerOnStart)
disassembly->Show(); disassembly->Show();

View File

@ -450,23 +450,6 @@ void Pcsx2App::HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent&
{ {
try try
{ {
if (g_Conf->EmuOptions.EnableRecordingTools)
{
if (g_InputRecordingControls.IsPaused())
{
// When the GSFrame CoreThread is paused, so is the logical VSync
// Meaning that we have to grab the user-input through here to potentially
// resume emulation.
if (const HostKeyEvent* ev = PADkeyEvent() )
{
if( ev->key != 0 )
{
PadKeyDispatch( *ev );
}
}
}
g_InputRecordingControls.ResumeCoreThreadIfStarted();
}
(handler->*func)(event); (handler->*func)(event);
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -481,9 +464,6 @@ void Pcsx2App::HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent&
// Saved state load failed prior to the system getting corrupted (ie, file not found // Saved state load failed prior to the system getting corrupted (ie, file not found
// or some zipfile error) -- so log it and resume emulation. // or some zipfile error) -- so log it and resume emulation.
Console.Warning( ex.FormatDiagnosticMessage() ); Console.Warning( ex.FormatDiagnosticMessage() );
if (g_InputRecording.IsInitialLoad())
g_InputRecording.FailedSavestate();
CoreThread.Resume(); CoreThread.Resume();
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -768,15 +748,6 @@ void Pcsx2App::OpenGsPanel()
std::optional<WindowInfo> wi = gsFrame->GetViewport()->GetWindowInfo(); std::optional<WindowInfo> wi = gsFrame->GetViewport()->GetWindowInfo();
pxAssertDev(wi.has_value(), "GS frame has a valid native window"); pxAssertDev(wi.has_value(), "GS frame has a valid native window");
g_gs_window_info = std::move(*wi); g_gs_window_info = std::move(*wi);
// Enable New & Play after the first game load of the session
sMainFrame.enableRecordingMenuItem(MenuId_Recording_New, !g_InputRecording.IsActive());
sMainFrame.enableRecordingMenuItem(MenuId_Recording_Play, true);
// Enable recording menu options as the game is now running
sMainFrame.enableRecordingMenuItem(MenuId_Recording_FrameAdvance, true);
sMainFrame.enableRecordingMenuItem(MenuId_Recording_TogglePause, true);
sMainFrame.enableRecordingMenuItem(MenuId_Recording_ToggleRecordingMode, g_InputRecording.IsActive());
} }
@ -816,11 +787,6 @@ void Pcsx2App::OnGsFrameDestroyed(wxWindowID id)
m_id_GsFrame = wxID_ANY; m_id_GsFrame = wxID_ANY;
g_gs_window_info = {}; g_gs_window_info = {};
// Disable recording controls that only make sense if the game is running
sMainFrame.enableRecordingMenuItem(MenuId_Recording_FrameAdvance, false);
sMainFrame.enableRecordingMenuItem(MenuId_Recording_TogglePause, false);
sMainFrame.enableRecordingMenuItem(MenuId_Recording_ToggleRecordingMode, false);
} }
void Pcsx2App::OnProgramLogClosed( wxWindowID id ) void Pcsx2App::OnProgramLogClosed( wxWindowID id )
@ -834,11 +800,6 @@ void Pcsx2App::OnProgramLogClosed( wxWindowID id )
void Pcsx2App::OnMainFrameClosed( wxWindowID id ) void Pcsx2App::OnMainFrameClosed( wxWindowID id )
{ {
if (g_InputRecording.IsActive())
{
g_InputRecording.Stop();
}
// Nothing threaded depends on the mainframe (yet) -- it all passes through the main wxApp // Nothing threaded depends on the mainframe (yet) -- it all passes through the main wxApp
// message handler. But that might change in the future. // message handler. But that might change in the future.
if( m_id_MainFrame != id ) return; if( m_id_MainFrame != id ) return;
@ -933,10 +894,6 @@ void Pcsx2App::SysExecute( CDVD_SourceType cdvdsrc, const wxString& elf_override
return; return;
SysExecutorThread.PostEvent( new SysExecEvent_Execute(cdvdsrc, elf_override) ); SysExecutorThread.PostEvent( new SysExecEvent_Execute(cdvdsrc, elf_override) );
if (g_Conf->EmuOptions.EnableRecordingTools)
{
g_InputRecording.RecordingReset();
}
} }
// Returns true if there is a "valid" virtual machine state from the user's perspective. This // Returns true if there is a "valid" virtual machine state from the user's perspective. This

View File

@ -107,76 +107,11 @@ void GSPanel::InitDefaultAccelerators()
m_Accels->Map( FULLSCREEN_TOGGLE_ACCELERATOR_GSPANEL, "FullscreenToggle" ); m_Accels->Map( FULLSCREEN_TOGGLE_ACCELERATOR_GSPANEL, "FullscreenToggle" );
} }
void GSPanel::InitRecordingAccelerators()
{
// Note: these override GlobalAccels ( Pcsx2App::InitDefaultGlobalAccelerators() )
// For plain letters or symbols, replace e.g. WXK_F1 with e.g. wxKeyCode('q') or wxKeyCode('-')
// For plain letter keys with shift, use e.g. AAC( wxKeyCode('q') ).Shift() and NOT wxKeyCode('Q')
// For a symbol with shift (e.g. '_' which is '-' with shift) use AAC( wxKeyCode('-') ).Shift()
typedef KeyAcceleratorCode AAC;
if (!m_Accels) m_Accels = std::unique_ptr<AcceleratorDictionary>(new AcceleratorDictionary);
m_Accels->Map(AAC(WXK_SPACE), "FrameAdvance");
m_Accels->Map(AAC(wxKeyCode('p')).Shift(), "TogglePause");
m_Accels->Map(AAC(wxKeyCode('r')).Shift(), "InputRecordingModeToggle");
m_Accels->Map(AAC(wxKeyCode('l')).Shift(), "GoToFirstFrame");
#if defined(__unix__)
// Shift+P (80) and Shift+p (112) have two completely different codes
// On Linux the former is sometimes fired so define bindings for both
m_Accels->Map(AAC(wxKeyCode('P')).Shift(), "TogglePause");
m_Accels->Map(AAC(wxKeyCode('R')).Shift(), "InputRecordingModeToggle");
m_Accels->Map(AAC(wxKeyCode('L')).Shift(), "GoToFirstFrame");
#endif
m_Accels->Map(AAC(WXK_NUMPAD0).Shift(), "States_SaveSlot0");
m_Accels->Map(AAC(WXK_NUMPAD1).Shift(), "States_SaveSlot1");
m_Accels->Map(AAC(WXK_NUMPAD2).Shift(), "States_SaveSlot2");
m_Accels->Map(AAC(WXK_NUMPAD3).Shift(), "States_SaveSlot3");
m_Accels->Map(AAC(WXK_NUMPAD4).Shift(), "States_SaveSlot4");
m_Accels->Map(AAC(WXK_NUMPAD5).Shift(), "States_SaveSlot5");
m_Accels->Map(AAC(WXK_NUMPAD6).Shift(), "States_SaveSlot6");
m_Accels->Map(AAC(WXK_NUMPAD7).Shift(), "States_SaveSlot7");
m_Accels->Map(AAC(WXK_NUMPAD8).Shift(), "States_SaveSlot8");
m_Accels->Map(AAC(WXK_NUMPAD9).Shift(), "States_SaveSlot9");
m_Accels->Map(AAC(WXK_NUMPAD0), "States_LoadSlot0");
m_Accels->Map(AAC(WXK_NUMPAD1), "States_LoadSlot1");
m_Accels->Map(AAC(WXK_NUMPAD2), "States_LoadSlot2");
m_Accels->Map(AAC(WXK_NUMPAD3), "States_LoadSlot3");
m_Accels->Map(AAC(WXK_NUMPAD4), "States_LoadSlot4");
m_Accels->Map(AAC(WXK_NUMPAD5), "States_LoadSlot5");
m_Accels->Map(AAC(WXK_NUMPAD6), "States_LoadSlot6");
m_Accels->Map(AAC(WXK_NUMPAD7), "States_LoadSlot7");
m_Accels->Map(AAC(WXK_NUMPAD8), "States_LoadSlot8");
m_Accels->Map(AAC(WXK_NUMPAD9), "States_LoadSlot9");
GetMainFramePtr()->initializeRecordingMenuItem(
MenuId_Recording_FrameAdvance,
GetAssociatedKeyCode("FrameAdvance"));
GetMainFramePtr()->initializeRecordingMenuItem(
MenuId_Recording_TogglePause,
GetAssociatedKeyCode("TogglePause"));
GetMainFramePtr()->initializeRecordingMenuItem(
MenuId_Recording_ToggleRecordingMode,
GetAssociatedKeyCode("InputRecordingModeToggle"),
g_InputRecording.IsActive());
InputRec::consoleLog("Initialized Input Recording Key Bindings");
}
wxString GSPanel::GetAssociatedKeyCode(const char* id) wxString GSPanel::GetAssociatedKeyCode(const char* id)
{ {
return m_Accels->findKeycodeWithCommandId(id).toTitleizedString(); return m_Accels->findKeycodeWithCommandId(id).toTitleizedString();
} }
void GSPanel::RemoveRecordingAccelerators()
{
m_Accels.reset(new AcceleratorDictionary);
InitDefaultAccelerators();
recordingConLog("Disabled Input Recording Key Bindings\n");
}
GSPanel::GSPanel( wxWindow* parent ) GSPanel::GSPanel( wxWindow* parent )
: wxWindow() : wxWindow()
, m_HideMouseTimer( this ) , m_HideMouseTimer( this )
@ -192,11 +127,6 @@ GSPanel::GSPanel( wxWindow* parent )
InitDefaultAccelerators(); InitDefaultAccelerators();
if (g_Conf->EmuOptions.EnableRecordingTools)
{
InitRecordingAccelerators();
}
SetBackgroundColour(wxColour((unsigned long)0)); SetBackgroundColour(wxColour((unsigned long)0));
if( g_Conf->GSWindow.AlwaysHideMouse ) if( g_Conf->GSWindow.AlwaysHideMouse )
{ {
@ -899,17 +829,7 @@ void GSFrame::OnUpdateTitle( wxTimerEvent& evt )
const u64& smode2 = *(u64*)PS2GS_BASE(GS_SMODE2); const u64& smode2 = *(u64*)PS2GS_BASE(GS_SMODE2);
wxString omodef = (smode2 & 2) ? templates.OutputFrame : templates.OutputField; wxString omodef = (smode2 & 2) ? templates.OutputFrame : templates.OutputField;
wxString omodei = (smode2 & 1) ? templates.OutputInterlaced : templates.OutputProgressive; wxString omodei = (smode2 & 1) ? templates.OutputInterlaced : templates.OutputProgressive;
wxString title; wxString title = templates.TitleTemplate;
wxString movieMode;
if (g_InputRecording.IsActive())
{
title = templates.RecordingTemplate;
title.Replace(L"${frame}", pxsFmt(L"%d", g_InputRecording.GetFrameCounter()));
title.Replace(L"${maxFrame}", pxsFmt(L"%d", g_InputRecording.GetInputRecordingData().GetTotalFrames()));
title.Replace(L"${mode}", g_InputRecording.RecordingModeTitleSegment());
} else {
title = templates.TitleTemplate;
}
std::string gsStats; std::string gsStats;
GSgetTitleStats(gsStats); GSgetTitleStats(gsStats);

View File

@ -53,8 +53,6 @@ public:
void DirectKeyCommand( const KeyAcceleratorCode& kac ); void DirectKeyCommand( const KeyAcceleratorCode& kac );
void InitDefaultAccelerators(); void InitDefaultAccelerators();
wxString GetAssociatedKeyCode(const char* id); wxString GetAssociatedKeyCode(const char* id);
void InitRecordingAccelerators();
void RemoveRecordingAccelerators();
protected: protected:
void AppStatusEvent_OnSettingsApplied(); void AppStatusEvent_OnSettingsApplied();

View File

@ -305,10 +305,6 @@ namespace Implementations
if (g_Conf->GSWindow.CloseOnEsc) if (g_Conf->GSWindow.CloseOnEsc)
{ {
sMainFrame.SetFocus(); sMainFrame.SetFocus();
// Disable recording controls that only make sense if the game is running
sMainFrame.enableRecordingMenuItem(MenuId_Recording_FrameAdvance, false);
sMainFrame.enableRecordingMenuItem(MenuId_Recording_TogglePause, false);
sMainFrame.enableRecordingMenuItem(MenuId_Recording_ToggleRecordingMode, false);
} }
} }
@ -420,38 +416,6 @@ namespace Implementations
if (GSFrame* gsframe = wxGetApp().GetGsFramePtr()) if (GSFrame* gsframe = wxGetApp().GetGsFramePtr())
gsframe->ShowFullScreen(!gsframe->IsFullScreen()); gsframe->ShowFullScreen(!gsframe->IsFullScreen());
} }
void FrameAdvance()
{
if (g_Conf->EmuOptions.EnableRecordingTools)
{
g_InputRecordingControls.FrameAdvance();
}
}
void TogglePause()
{
if (g_Conf->EmuOptions.EnableRecordingTools)
{
g_InputRecordingControls.TogglePause();
}
}
void InputRecordingModeToggle()
{
if (g_Conf->EmuOptions.EnableRecordingTools)
{
g_InputRecordingControls.RecordModeToggle();
}
}
void GoToFirstFrame()
{
if (g_Conf->EmuOptions.EnableRecordingTools && g_InputRecording.IsActive())
{
// Assumes that gui is active, as you can't access recording options without it
g_InputRecording.GoToFirstFrame(GetMainFramePtr());
}
}
void States_SaveSlot(int slot) void States_SaveSlot(int slot)
{ {
@ -730,11 +694,6 @@ static const GlobalCommandDescriptor CommandDeclarations[] =
false, false,
}, },
{"FrameAdvance", Implementations::FrameAdvance, NULL, NULL, false},
{"TogglePause", Implementations::TogglePause, NULL, NULL, false},
{"InputRecordingModeToggle", Implementations::InputRecordingModeToggle, NULL, NULL, false},
{"GoToFirstFrame", Implementations::GoToFirstFrame, NULL, NULL, false},
{"States_SaveSlot0", Implementations::States_SaveSlot0, NULL, NULL, false}, {"States_SaveSlot0", Implementations::States_SaveSlot0, NULL, NULL, false},
{"States_SaveSlot1", Implementations::States_SaveSlot1, NULL, NULL, false}, {"States_SaveSlot1", Implementations::States_SaveSlot1, NULL, NULL, false},
{"States_SaveSlot2", Implementations::States_SaveSlot2, NULL, NULL, false}, {"States_SaveSlot2", Implementations::States_SaveSlot2, NULL, NULL, false},

View File

@ -69,16 +69,11 @@ void MainEmuFrame::UpdateStatusBar()
{ {
wxString temp(wxEmptyString); wxString temp(wxEmptyString);
if (g_InputRecording.IsActive() && g_InputRecording.GetInputRecordingData().FromSaveState())
temp += "Base Savestate - " + g_InputRecording.GetInputRecordingData().GetFilename() + "_SaveState.p2s";
else
{
if (g_Conf->EnableFastBoot) if (g_Conf->EnableFastBoot)
temp += "Fast Boot - "; temp += "Fast Boot - ";
if (g_Conf->CdvdSource == CDVD_SourceType::Iso) if (g_Conf->CdvdSource == CDVD_SourceType::Iso)
temp += "Load: '" + wxFileName(g_Conf->CurrentIso).GetFullName() + "' "; temp += "Load: '" + wxFileName(g_Conf->CurrentIso).GetFullName() + "' ";
}
m_statusbar.SetStatusText(temp, 0); m_statusbar.SetStatusText(temp, 0);
@ -111,10 +106,7 @@ void MainEmuFrame::UpdateCdvdSrcSelection()
jNO_DEFAULT jNO_DEFAULT
} }
sMenuBar.Check(cdsrc, true); sMenuBar.Check(cdsrc, true);
if (!g_InputRecording.IsActive())
{
ApplyCDVDStatus(); ApplyCDVDStatus();
}
UpdateStatusBar(); UpdateStatusBar();
} }
@ -311,17 +303,6 @@ void MainEmuFrame::ConnectMenus()
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Capture_Video_IncludeAudio_Click, this, MenuId_Capture_Video_IncludeAudio); Bind(wxEVT_MENU, &MainEmuFrame::Menu_Capture_Video_IncludeAudio_Click, this, MenuId_Capture_Video_IncludeAudio);
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Capture_Screenshot_Screenshot_Click, this, MenuId_Capture_Screenshot_Screenshot); Bind(wxEVT_MENU, &MainEmuFrame::Menu_Capture_Screenshot_Screenshot_Click, this, MenuId_Capture_Screenshot_Screenshot);
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Capture_Screenshot_Screenshot_As_Click, this, MenuId_Capture_Screenshot_Screenshot_As); Bind(wxEVT_MENU, &MainEmuFrame::Menu_Capture_Screenshot_Screenshot_As_Click, this, MenuId_Capture_Screenshot_Screenshot_As);
// Recording
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Recording_New_Click, this, MenuId_Recording_New);
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Recording_Play_Click, this, MenuId_Recording_Play);
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Recording_Stop_Click, this, MenuId_Recording_Stop);
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Recording_Config_FrameAdvance, this, MenuId_Recording_Config_FrameAdvance);
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Recording_TogglePause_Click, this, MenuId_Recording_TogglePause);
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Recording_FrameAdvance_Click, this, MenuId_Recording_FrameAdvance);
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Recording_ToggleRecordingMode_Click, this, MenuId_Recording_ToggleRecordingMode);
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Recording_VirtualPad_Open_Click, this, MenuId_Recording_VirtualPad_Port0);
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Recording_VirtualPad_Open_Click, this, MenuId_Recording_VirtualPad_Port1);
} }
void MainEmuFrame::InitLogBoxPosition(AppConfig::ConsoleLogOptions& conf) void MainEmuFrame::InitLogBoxPosition(AppConfig::ConsoleLogOptions& conf)
@ -393,7 +374,7 @@ void MainEmuFrame::CreatePcsx2Menu()
_("Enabling Widescreen Patches may occasionally cause issues."), wxITEM_CHECK); _("Enabling Widescreen Patches may occasionally cause issues."), wxITEM_CHECK);
m_GameSettingsSubmenu.Append(MenuId_EnableInputRecording, _("Enable &Input Recording"), m_GameSettingsSubmenu.Append(MenuId_EnableInputRecording, _("Enable &Input Recording"),
_("Input Recording for controller/keyboard presses, tools for automation and playback."), wxITEM_CHECK); _("Input Recording for controller/keyboard presses, tools for automation and playback."), wxITEM_NORMAL);
m_GameSettingsSubmenu.Append(MenuId_EnableHostFs, _("Enable &Host Filesystem"), m_GameSettingsSubmenu.Append(MenuId_EnableHostFs, _("Enable &Host Filesystem"),
wxEmptyString, wxITEM_CHECK); wxEmptyString, wxITEM_CHECK);
@ -583,11 +564,6 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title)
SetMenuBar(&m_menubar); SetMenuBar(&m_menubar);
// Append the Recording options if previously enabled and setting has been picked up from ini
if (g_Conf->EmuOptions.EnableRecordingTools)
{
m_menubar.Append(&m_menuRecording, _("&Input Record"));
}
m_menubar.Append(&m_menuHelp, _("&Help")); m_menubar.Append(&m_menuHelp, _("&Help"));
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -813,12 +789,6 @@ void MainEmuFrame::ApplyConfigToGui(AppConfig& configToApply, int flags)
menubar.Check(MenuId_EnableWideScreenPatches, configToApply.EmuOptions.EnableWideScreenPatches); menubar.Check(MenuId_EnableWideScreenPatches, configToApply.EmuOptions.EnableWideScreenPatches);
menubar.Check(MenuId_Capture_Video_IncludeAudio, configToApply.AudioCapture.EnableAudio); menubar.Check(MenuId_Capture_Video_IncludeAudio, configToApply.AudioCapture.EnableAudio);
menubar.Check(MenuId_EnableInputRecording, configToApply.EmuOptions.EnableRecordingTools);
wxString frame_advance_label = wxString(_("Configure Frame Advance"));
frame_advance_label.Append(wxString::Format(" (%d)", configToApply.inputRecording.m_frame_advance_amount));
m_submenu_recording_settings.SetLabel(MenuId_Recording_Config_FrameAdvance, frame_advance_label);
g_InputRecordingControls.setFrameAdvanceAmount(configToApply.inputRecording.m_frame_advance_amount);
menubar.Check(MenuId_EnableHostFs, configToApply.EmuOptions.HostFs); menubar.Check(MenuId_EnableHostFs, configToApply.EmuOptions.HostFs);
menubar.Check(MenuId_Debug_CreateBlockdump, configToApply.EmuOptions.CdvdDumpBlocks); menubar.Check(MenuId_Debug_CreateBlockdump, configToApply.EmuOptions.CdvdDumpBlocks);
#if defined(__POSIX__) #if defined(__POSIX__)
@ -847,18 +817,3 @@ void MainEmuFrame::AppendShortcutToMenuOption(wxMenuItem& item, wxString keyCode
const size_t tabPos = text.rfind(L'\t'); const size_t tabPos = text.rfind(L'\t');
item.SetItemLabel(text.Mid(0, tabPos) + L"\t" + keyCodeStr); item.SetItemLabel(text.Mid(0, tabPos) + L"\t" + keyCodeStr);
} }
void MainEmuFrame::initializeRecordingMenuItem(MenuIdentifiers menuId, wxString keyCodeStr, bool enable)
{
wxMenuItem& item = *m_menuRecording.FindChildItem(menuId);
wxString text = item.GetItemLabel();
const size_t tabPos = text.rfind(L'\t');
item.SetItemLabel(text.Mid(0, tabPos) + L"\t" + keyCodeStr);
item.Enable(enable);
}
void MainEmuFrame::enableRecordingMenuItem(MenuIdentifiers menuId, bool enable)
{
wxMenuItem& item = *m_menuRecording.FindChildItem(menuId);
item.Enable(enable);
}

View File

@ -122,11 +122,6 @@ public:
void VideoCaptureToggle(); void VideoCaptureToggle();
bool IsCapturing() const noexcept { return m_capturingVideo; } bool IsCapturing() const noexcept { return m_capturingVideo; }
void initializeRecordingMenuItem(MenuIdentifiers menuId, wxString keyCodeStr, bool enable = true);
void enableRecordingMenuItem(MenuIdentifiers menuId, bool enable);
void StartInputRecording();
void StopInputRecording();
protected: protected:
void DoGiveHelp(const wxString& text, bool show); void DoGiveHelp(const wxString& text, bool show);
@ -205,16 +200,6 @@ protected:
void Menu_Capture_Screenshot_Screenshot_Click(wxCommandEvent& event); void Menu_Capture_Screenshot_Screenshot_Click(wxCommandEvent& event);
void Menu_Capture_Screenshot_Screenshot_As_Click(wxCommandEvent& event); void Menu_Capture_Screenshot_Screenshot_As_Click(wxCommandEvent& event);
void Menu_Recording_New_Click(wxCommandEvent& event);
void Menu_Recording_Play_Click(wxCommandEvent& event);
void Menu_Recording_Stop_Click(wxCommandEvent& event);
void Menu_Recording_Config_FrameAdvance(wxCommandEvent& event);
void ApplyFirstFrameStatus();
void Menu_Recording_TogglePause_Click(wxCommandEvent& event);
void Menu_Recording_FrameAdvance_Click(wxCommandEvent& event);
void Menu_Recording_ToggleRecordingMode_Click(wxCommandEvent& event);
void Menu_Recording_VirtualPad_Open_Click(wxCommandEvent& event);
void _DoBootCdvd(); void _DoBootCdvd();
bool _DoSelectIsoBrowser(wxString& dest); bool _DoSelectIsoBrowser(wxString& dest);
bool _DoSelectELFBrowser(); bool _DoSelectELFBrowser();

View File

@ -38,10 +38,6 @@
#include "fmt/core.h" #include "fmt/core.h"
#include "wx/numdlg.h" #include "wx/numdlg.h"
#include "Recording/InputRecording.h"
#include "Recording/InputRecordingControls.h"
#include "Recording/VirtualPad/VirtualPad.h"
using namespace Dialogs; using namespace Dialogs;
@ -205,9 +201,6 @@ wxWindowID SwapOrReset_Iso(wxWindow* owner, IScopedCoreThread& core_control, con
dialog += dialog.GetCharHeight(); dialog += dialog.GetCharHeight();
dialog += dialog.Heading(_("Do you want to swap discs or boot the new image (via system reset)?")); dialog += dialog.Heading(_("Do you want to swap discs or boot the new image (via system reset)?"));
if (g_InputRecording.IsActive() && g_InputRecording.GetInputRecordingData().FromSaveState())
dialog += dialog.Text(_("\n(Warning: The savestate accompanying the active input recording\nmay not be compatible with the new source)"));
result = pxIssueConfirmation(dialog, MsgButtons().Reset().Cancel().Custom(_("Swap Disc"), "swap")); result = pxIssueConfirmation(dialog, MsgButtons().Reset().Cancel().Custom(_("Swap Disc"), "swap"));
if (result == wxID_CANCEL) if (result == wxID_CANCEL)
{ {
@ -264,9 +257,6 @@ wxWindowID SwapOrReset_Disc(wxWindow* owner, IScopedCoreThread& core, const wxSt
dialog += dialog.GetCharHeight(); dialog += dialog.GetCharHeight();
dialog += dialog.Heading(_("Do you want to swap discs or boot the new disc (via system reset)?")); dialog += dialog.Heading(_("Do you want to swap discs or boot the new disc (via system reset)?"));
if (g_InputRecording.IsActive() && g_InputRecording.GetInputRecordingData().FromSaveState())
dialog += dialog.Text(_("\n(Warning: The savestate accompanying the active input recording\nmay not be compatible with the new source)"));
result = pxIssueConfirmation(dialog, MsgButtons().Reset().Cancel().Custom(_("Swap Disc"), "swap")); result = pxIssueConfirmation(dialog, MsgButtons().Reset().Cancel().Custom(_("Swap Disc"), "swap"));
if (result == wxID_CANCEL) if (result == wxID_CANCEL)
{ {
@ -314,9 +304,6 @@ wxWindowID SwapOrReset_CdvdSrc(wxWindow* owner, CDVD_SourceType newsrc)
dialog += dialog.Heading(changeMsg + L"\n\n" + dialog += dialog.Heading(changeMsg + L"\n\n" +
_("Do you want to swap discs or boot the new image (system reset)?")); _("Do you want to swap discs or boot the new image (system reset)?"));
if (g_InputRecording.IsActive() && g_InputRecording.GetInputRecordingData().FromSaveState())
dialog += dialog.Text(_("\n(Warning: The savestate accompanying the active input recording\nmay not be compatible with the new source)"));
result = pxIssueConfirmation(dialog, MsgButtons().Reset().Cancel().Custom(_("Swap Disc"), "swap")); result = pxIssueConfirmation(dialog, MsgButtons().Reset().Cancel().Custom(_("Swap Disc"), "swap"));
if (result == wxID_CANCEL) if (result == wxID_CANCEL)
@ -506,24 +493,14 @@ void MainEmuFrame::Menu_CdvdSource_Click(wxCommandEvent& event)
} }
SwapOrReset_CdvdSrc(this, newsrc); SwapOrReset_CdvdSrc(this, newsrc);
if (!g_InputRecording.IsActive())
{
ApplyCDVDStatus(); ApplyCDVDStatus();
} }
}
void MainEmuFrame::Menu_BootCdvd_Click(wxCommandEvent& event) void MainEmuFrame::Menu_BootCdvd_Click(wxCommandEvent& event)
{
if (g_InputRecording.IsActive())
{
g_InputRecording.GoToFirstFrame(this);
}
else
{ {
g_Conf->EmuOptions.UseBOOT2Injection = g_Conf->EnableFastBoot; g_Conf->EmuOptions.UseBOOT2Injection = g_Conf->EnableFastBoot;
_DoBootCdvd(); _DoBootCdvd();
} }
}
void MainEmuFrame::Menu_FastBoot_Click(wxCommandEvent& event) void MainEmuFrame::Menu_FastBoot_Click(wxCommandEvent& event)
{ {
@ -681,66 +658,8 @@ void MainEmuFrame::Menu_EnableWideScreenPatches_Click(wxCommandEvent&)
void MainEmuFrame::Menu_EnableRecordingTools_Click(wxCommandEvent& event) void MainEmuFrame::Menu_EnableRecordingTools_Click(wxCommandEvent& event)
{ {
bool checked = GetMenuBar()->IsChecked(MenuId_EnableInputRecording); Msgbox::Alert("Input Recording has been deprecated from the wxWidgets version.\nUse an older dev build (before v1.7.3650) or switch to the Qt version!\nOld recordings should still play correctly!");
// Confirm with User return;
if (checked)
{
if (!Msgbox::OkCancel(_("Please be aware that PCSX2's input recording features are still very much a work-in-progress.\n"
"As a result, there may be unforeseen bugs, performance implications and instability with certain games.\n\n"
"These tools are provided as-is and should be enabled under your own discretion."),
"Enabling Input Recording"))
{
checked = false;
m_GameSettingsSubmenu.FindChildItem(MenuId_EnableInputRecording)->Check(false);
}
}
// If still enabled, add the menu item, else, remove it
if (checked)
{
GetMenuBar()->Insert(TopLevelMenu_InputRecording, &m_menuRecording, _("&Input Record"));
g_InputRecording.InitVirtualPadWindows(this);
SysConsole.recordingConsole.Enabled = true;
// Enable Recording Keybindings
if (GSFrame* gsFrame = wxGetApp().GetGsFramePtr())
{
if (GSPanel* viewport = gsFrame->GetViewport())
{
viewport->InitRecordingAccelerators();
}
}
}
else
{
//Properly close any currently loaded recording file before disabling
StopInputRecording();
GetMenuBar()->Remove(TopLevelMenu_InputRecording);
// Always turn controller logs off, but never turn it on by default
SysConsole.controlInfo.Enabled = checked;
// Return Keybindings Back to Normal
if (GSFrame* gsFrame = wxGetApp().GetGsFramePtr())
{
if (GSPanel* viewport = gsFrame->GetViewport())
{
viewport->RemoveRecordingAccelerators();
}
}
SysConsole.recordingConsole.Enabled = false;
if (g_InputRecordingControls.IsPaused())
g_InputRecordingControls.Resume();
}
g_Conf->EmuOptions.EnableRecordingTools = checked;
// Update GS Title Frequency
if (GSFrame* gsFrame = wxGetApp().GetGsFramePtr())
{
gsFrame->UpdateTitleUpdateFreq();
}
// Enable Recording Logs
ConsoleLogFrame* progLog = wxGetApp().GetProgramLog();
progLog->UpdateLogList();
AppApplySettings();
AppSaveSettings();
} }
void MainEmuFrame::Menu_EnableHostFs_Click(wxCommandEvent&) void MainEmuFrame::Menu_EnableHostFs_Click(wxCommandEvent&)
@ -825,10 +744,6 @@ protected:
if (CoreThread.IsOpen()) if (CoreThread.IsOpen())
{ {
CoreThread.Suspend(); CoreThread.Suspend();
// Disable recording controls that only make sense if the game is running
sMainFrame.enableRecordingMenuItem(MenuId_Recording_FrameAdvance, false);
sMainFrame.enableRecordingMenuItem(MenuId_Recording_TogglePause, false);
sMainFrame.enableRecordingMenuItem(MenuId_Recording_ToggleRecordingMode, false);
} }
else else
CoreThread.Resume(); CoreThread.Resume();
@ -848,34 +763,6 @@ void MainEmuFrame::Menu_SuspendResume_Click(wxCommandEvent& event)
} }
void MainEmuFrame::Menu_SysShutdown_Click(wxCommandEvent& event) void MainEmuFrame::Menu_SysShutdown_Click(wxCommandEvent& event)
{
bool doShutdown = true;
if (!g_InputRecording.IsActive())
{
if (g_InputRecordingControls.IsPaused())
g_InputRecordingControls.Resume();
}
else
{
const bool initiallyPaused = g_InputRecordingControls.IsPaused();
if (!initiallyPaused)
g_InputRecordingControls.Pause();
wxWindowID result = wxID_CANCEL;
wxDialogWithHelpers dialog(this, _("Shutdown & Close Input Recording"));
dialog += dialog.Heading(L"\nShutting down emulation will close the active input recording file.\nProceed?");
result = pxIssueConfirmation(dialog, MsgButtons().Close().Cancel());
if (result == wxID_CLOSE)
{
StopInputRecording();
g_InputRecordingControls.Resume();
}
else if (!initiallyPaused)
{
g_InputRecordingControls.Resume();
doShutdown = false;
}
}
if (doShutdown)
{ {
if (m_capturingVideo) if (m_capturingVideo)
VideoCaptureToggle(); VideoCaptureToggle();
@ -883,7 +770,6 @@ void MainEmuFrame::Menu_SysShutdown_Click(wxCommandEvent& event)
Console.SetTitle("PCSX2 Program Log"); Console.SetTitle("PCSX2 Program Log");
CoreThread.Reset(); CoreThread.Reset();
} }
}
void MainEmuFrame::Menu_Debug_Open_Click(wxCommandEvent& event) void MainEmuFrame::Menu_Debug_Open_Click(wxCommandEvent& event)
{ {
@ -1049,151 +935,3 @@ void MainEmuFrame::Menu_Capture_Screenshot_Screenshot_As_Click(wxCommandEvent& e
CoreThread.Resume(); CoreThread.Resume();
} }
void MainEmuFrame::Menu_Recording_New_Click(wxCommandEvent& event)
{
Msgbox::Alert("Input Recording has been deprecated from the wxWidgets version.\nUse an older dev build or switch to the Qt version!\nOld recordings should still play correctly!");
return;
const bool emulation_initially_paused = CoreThread.IsPaused();
const bool recording_initially_paused = g_InputRecordingControls.IsPaused();
if (!emulation_initially_paused && !recording_initially_paused)
g_InputRecordingControls.PauseImmediately();
NewRecordingFrame* newRecordingFrame = wxGetApp().GetNewRecordingFramePtr();
if (newRecordingFrame)
{
if (newRecordingFrame->ShowModal(CoreThread.IsOpen()) != wxID_CANCEL)
{
if (g_InputRecording.Create(newRecordingFrame->GetFile(), newRecordingFrame->GetFrom(), newRecordingFrame->GetAuthor()))
{
if (!g_InputRecording.GetInputRecordingData().FromSaveState())
StartInputRecording();
return;
}
}
if (!emulation_initially_paused && !recording_initially_paused)
g_InputRecordingControls.ResumeImmediately();
}
}
void MainEmuFrame::Menu_Recording_Play_Click(wxCommandEvent& event)
{
Msgbox::Alert("Input Recording has been deprecated from the wxWidgets version.\nUse an older dev build or switch to the Qt version!\nOld recordings should still play correctly!");
return;
const bool initiallyPaused = g_InputRecordingControls.IsPaused();
if (!initiallyPaused)
g_InputRecordingControls.PauseImmediately();
wxFileDialog openFileDialog(this, _("Select P2M2 record file."), L"", L"",
L"p2m2 file(*.p2m2)|*.p2m2", wxFD_OPEN);
if (openFileDialog.ShowModal() == wxID_CANCEL)
{
if (!initiallyPaused)
g_InputRecordingControls.Resume();
return;
}
StopInputRecording();
if (!g_InputRecording.Play(this, openFileDialog.GetPath()))
{
if (!initiallyPaused)
g_InputRecordingControls.Resume();
return;
}
if (!g_InputRecording.GetInputRecordingData().FromSaveState())
StartInputRecording();
}
void MainEmuFrame::ApplyFirstFrameStatus()
{
wxMenuItem* cdvd_menu = m_menuSys.FindChildItem(MenuId_Boot_CDVD);
wxString keyCodeStr;
if (GSFrame* gsFrame = wxGetApp().GetGsFramePtr())
if (GSPanel* viewport = gsFrame->GetViewport())
keyCodeStr = '\t' + viewport->GetAssociatedKeyCode(("GoToFirstFrame"));
cdvd_menu->SetItemLabel(L"Restart Recording" + keyCodeStr);
if (g_InputRecording.GetInputRecordingData().FromSaveState())
cdvd_menu->SetHelp(L"Loads the savestate that accompanies the active input recording");
else
cdvd_menu->SetHelp(L"Reboots Emulation");
UpdateStatusBar();
}
void MainEmuFrame::Menu_Recording_Stop_Click(wxCommandEvent& event)
{
Msgbox::Alert("Input Recording has been deprecated from the wxWidgets version.\nUse an older dev build or switch to the Qt version!\nOld recordings should still play correctly!");
return;
StopInputRecording();
}
void MainEmuFrame::Menu_Recording_Config_FrameAdvance(wxCommandEvent& event)
{
Msgbox::Alert("Input Recording has been deprecated from the wxWidgets version.\nUse an older dev build or switch to the Qt version!\nOld recordings should still play correctly!");
return;
long result = wxGetNumberFromUser(_("Enter the number of frames to advance per advance"), _("Number of Frames"), _("Configure Frame Advance"), g_Conf->inputRecording.m_frame_advance_amount, 1, INT_MAX);
if (result != -1)
{
g_Conf->inputRecording.m_frame_advance_amount = result;
g_InputRecordingControls.setFrameAdvanceAmount(result);
wxString frame_advance_label = wxString(_("Configure Frame Advance"));
frame_advance_label.Append(wxString::Format(" (%ld)", result));
m_submenu_recording_settings.SetLabel(MenuId_Recording_Config_FrameAdvance, frame_advance_label);
}
}
void MainEmuFrame::StartInputRecording()
{
m_menuRecording.FindChildItem(MenuId_Recording_New)->Enable(false);
m_menuRecording.FindChildItem(MenuId_Recording_Stop)->Enable(true);
m_menuRecording.FindChildItem(MenuId_Recording_ToggleRecordingMode)->Enable(true);
ApplyFirstFrameStatus();
}
void MainEmuFrame::StopInputRecording()
{
if (g_InputRecording.IsActive())
{
g_InputRecording.Stop();
m_menuRecording.FindChildItem(MenuId_Recording_New)->Enable(true);
m_menuRecording.FindChildItem(MenuId_Recording_Stop)->Enable(false);
m_menuRecording.FindChildItem(MenuId_Recording_ToggleRecordingMode)->Enable(false);
ApplyCDVDStatus();
}
}
void MainEmuFrame::Menu_Recording_TogglePause_Click(wxCommandEvent& event)
{
Msgbox::Alert("Input Recording has been deprecated from the wxWidgets version.\nUse an older dev build or switch to the Qt version!\nOld recordings should still play correctly!");
return;
if (g_Conf->EmuOptions.EnableRecordingTools)
g_InputRecordingControls.TogglePause();
}
void MainEmuFrame::Menu_Recording_FrameAdvance_Click(wxCommandEvent& event)
{
Msgbox::Alert("Input Recording has been deprecated from the wxWidgets version.\nUse an older dev build or switch to the Qt version!\nOld recordings should still play correctly!");
return;
if (g_Conf->EmuOptions.EnableRecordingTools)
g_InputRecordingControls.FrameAdvance();
}
void MainEmuFrame::Menu_Recording_ToggleRecordingMode_Click(wxCommandEvent& event)
{
Msgbox::Alert("Input Recording has been deprecated from the wxWidgets version.\nUse an older dev build or switch to the Qt version!\nOld recordings should still play correctly!");
return;
if (g_Conf->EmuOptions.EnableRecordingTools)
g_InputRecordingControls.RecordModeToggle();
}
void MainEmuFrame::Menu_Recording_VirtualPad_Open_Click(wxCommandEvent& event)
{
Msgbox::Alert("Input Recording has been deprecated from the wxWidgets version.\nUse an older dev build or switch to the Qt version!\nOld recordings should still play correctly!");
return;
g_InputRecording.ShowVirtualPad(event.GetId() - MenuId_Recording_VirtualPad_Port0);
}

View File

@ -171,82 +171,6 @@
<Outputs>%(RelativeDir)%(Filename).h</Outputs> <Outputs>%(RelativeDir)%(Filename).h</Outputs>
</CustomBuild> </CustomBuild>
<!-- Generate Recording GUI Image Headers --> <!-- Generate Recording GUI Image Headers -->
<CustomBuild Include="Recording\VirtualPad\img\controllerFull.png">
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\controllerThreeQuarters.png">
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\controllerHalf.png">
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\circlePressed.png">
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\crossPressed.png">
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\downPressed.png">
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\l1Pressed.png">
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\l2Pressed.png">
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\l3Pressed.png">
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\leftPressed.png">
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\r1Pressed.png">
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\r2Pressed.png">
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\r3Pressed.png">
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\rightPressed.png">
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\selectPressed.png">
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\squarePressed.png">
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\startPressed.png">
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\trianglePressed.png">
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\upPressed.png">
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
</CustomBuild>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="CDVD\BlockdumpFileReader.cpp" /> <ClCompile Include="CDVD\BlockdumpFileReader.cpp" />
@ -449,13 +373,9 @@
<ClCompile Include="ps2\pgif.cpp" /> <ClCompile Include="ps2\pgif.cpp" />
<ClCompile Include="Dmac.cpp" /> <ClCompile Include="Dmac.cpp" />
<ClCompile Include="Recording\InputRecordingControls.cpp" /> <ClCompile Include="Recording\InputRecordingControls.cpp" />
<ClCompile Include="Recording\VirtualPad\VirtualPad.cpp" />
<ClCompile Include="Recording\VirtualPad\VirtualPadData.cpp" />
<ClCompile Include="Recording\VirtualPad\VirtualPadResources.cpp" />
<ClCompile Include="ShiftJisToUnicode.cpp" /> <ClCompile Include="ShiftJisToUnicode.cpp" />
<ClCompile Include="sif2.cpp" /> <ClCompile Include="sif2.cpp" />
<ClCompile Include="Recording\InputRecording.cpp" /> <ClCompile Include="Recording\InputRecording.cpp" />
<ClCompile Include="Recording\NewRecordingFrame.cpp" />
<ClCompile Include="Recording\InputRecordingFile.cpp" /> <ClCompile Include="Recording\InputRecordingFile.cpp" />
<ClCompile Include="Recording\PadData.cpp" /> <ClCompile Include="Recording\PadData.cpp" />
<ClCompile Include="USB\configuration.cpp" /> <ClCompile Include="USB\configuration.cpp" />
@ -963,12 +883,8 @@
<ClInclude Include="ps2\pgif.h" /> <ClInclude Include="ps2\pgif.h" />
<ClInclude Include="Recording\InputRecording.h" /> <ClInclude Include="Recording\InputRecording.h" />
<ClInclude Include="Recording\InputRecordingControls.h" /> <ClInclude Include="Recording\InputRecordingControls.h" />
<ClInclude Include="Recording\NewRecordingFrame.h" />
<ClInclude Include="Recording\InputRecordingFile.h" /> <ClInclude Include="Recording\InputRecordingFile.h" />
<ClInclude Include="Recording\PadData.h" /> <ClInclude Include="Recording\PadData.h" />
<ClInclude Include="Recording\VirtualPad\VirtualPad.h" />
<ClInclude Include="Recording\VirtualPad\VirtualPadData.h" />
<ClInclude Include="Recording\VirtualPad\VirtualPadResources.h" />
<ClInclude Include="Recording\Utilities\InputRecordingLogger.h" /> <ClInclude Include="Recording\Utilities\InputRecordingLogger.h" />
<ClInclude Include="USB\configuration.h" /> <ClInclude Include="USB\configuration.h" />
<ClInclude Include="USB\deviceproxy.h" /> <ClInclude Include="USB\deviceproxy.h" />

View File

@ -142,12 +142,6 @@
<Filter Include="Recording"> <Filter Include="Recording">
<UniqueIdentifier>{7b917318-5a5e-44c0-8463-1dfab67f3b67}</UniqueIdentifier> <UniqueIdentifier>{7b917318-5a5e-44c0-8463-1dfab67f3b67}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="Recording\gui">
<UniqueIdentifier>{93e36831-627f-4529-b709-1f4bad398512}</UniqueIdentifier>
</Filter>
<Filter Include="Recording\VirtualPad">
<UniqueIdentifier>{ae88cd9a-f9f2-4196-979c-7a16ed5e455e}</UniqueIdentifier>
</Filter>
<Filter Include="System\Ps2\Iop\CDVD\Windows"> <Filter Include="System\Ps2\Iop\CDVD\Windows">
<UniqueIdentifier>{be861049-a142-4650-85a5-a2fdd4eef011}</UniqueIdentifier> <UniqueIdentifier>{be861049-a142-4650-85a5-a2fdd4eef011}</UniqueIdentifier>
</Filter> </Filter>
@ -163,9 +157,6 @@
<Filter Include="Recording\Utilities"> <Filter Include="Recording\Utilities">
<UniqueIdentifier>{85c5a0d2-6404-439f-8756-d908a1442b96}</UniqueIdentifier> <UniqueIdentifier>{85c5a0d2-6404-439f-8756-d908a1442b96}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="Recording\VirtualPad\Images">
<UniqueIdentifier>{ad528458-08eb-49a2-aefa-3c2b86ab8896}</UniqueIdentifier>
</Filter>
<Filter Include="System\Ps2\DEV9"> <Filter Include="System\Ps2\DEV9">
<UniqueIdentifier>{8d5454f9-590c-4c53-aae1-8391c6465e50}</UniqueIdentifier> <UniqueIdentifier>{8d5454f9-590c-4c53-aae1-8391c6465e50}</UniqueIdentifier>
</Filter> </Filter>
@ -1049,24 +1040,12 @@
<ClCompile Include="Recording\PadData.cpp"> <ClCompile Include="Recording\PadData.cpp">
<Filter>Recording</Filter> <Filter>Recording</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Recording\NewRecordingFrame.cpp">
<Filter>Recording\gui</Filter>
</ClCompile>
<ClCompile Include="Recording\VirtualPad\VirtualPad.cpp">
<Filter>Recording\VirtualPad</Filter>
</ClCompile>
<ClCompile Include="IPU\IPUdither.cpp"> <ClCompile Include="IPU\IPUdither.cpp">
<Filter>System\Ps2\IPU</Filter> <Filter>System\Ps2\IPU</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Recording\InputRecordingControls.cpp"> <ClCompile Include="Recording\InputRecordingControls.cpp">
<Filter>Recording</Filter> <Filter>Recording</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Recording\VirtualPad\VirtualPadData.cpp">
<Filter>Recording\VirtualPad</Filter>
</ClCompile>
<ClCompile Include="Recording\VirtualPad\VirtualPadResources.cpp">
<Filter>Recording\VirtualPad</Filter>
</ClCompile>
<ClCompile Include="CDVD\CDVDdiscReader.cpp"> <ClCompile Include="CDVD\CDVDdiscReader.cpp">
<Filter>System\Ps2\Iop\CDVD</Filter> <Filter>System\Ps2\Iop\CDVD</Filter>
</ClCompile> </ClCompile>
@ -2263,21 +2242,9 @@
<ClInclude Include="Recording\PadData.h"> <ClInclude Include="Recording\PadData.h">
<Filter>Recording</Filter> <Filter>Recording</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Recording\NewRecordingFrame.h">
<Filter>Recording\gui</Filter>
</ClInclude>
<ClInclude Include="Recording\VirtualPad\VirtualPad.h">
<Filter>Recording\VirtualPad</Filter>
</ClInclude>
<ClInclude Include="Recording\InputRecordingControls.h"> <ClInclude Include="Recording\InputRecordingControls.h">
<Filter>Recording</Filter> <Filter>Recording</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Recording\VirtualPad\VirtualPadData.h">
<Filter>Recording\VirtualPad</Filter>
</ClInclude>
<ClInclude Include="Recording\VirtualPad\VirtualPadResources.h">
<Filter>Recording\VirtualPad</Filter>
</ClInclude>
<ClInclude Include="CDVD\CDVDdiscReader.h"> <ClInclude Include="CDVD\CDVDdiscReader.h">
<Filter>System\Ps2\Iop\CDVD</Filter> <Filter>System\Ps2\Iop\CDVD</Filter>
</ClInclude> </ClInclude>
@ -3101,63 +3068,6 @@
<CustomBuild Include="gui\Resources\Logo.png"> <CustomBuild Include="gui\Resources\Logo.png">
<Filter>AppHost\Resources</Filter> <Filter>AppHost\Resources</Filter>
</CustomBuild> </CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\circlePressed.png">
<Filter>Recording\VirtualPad\Images</Filter>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\controllerFull.png">
<Filter>Recording\VirtualPad\Images</Filter>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\controllerHalf.png">
<Filter>Recording\VirtualPad\Images</Filter>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\controllerThreeQuarters.png">
<Filter>Recording\VirtualPad\Images</Filter>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\crossPressed.png">
<Filter>Recording\VirtualPad\Images</Filter>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\downPressed.png">
<Filter>Recording\VirtualPad\Images</Filter>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\l1Pressed.png">
<Filter>Recording\VirtualPad\Images</Filter>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\l2Pressed.png">
<Filter>Recording\VirtualPad\Images</Filter>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\l3Pressed.png">
<Filter>Recording\VirtualPad\Images</Filter>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\leftPressed.png">
<Filter>Recording\VirtualPad\Images</Filter>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\startPressed.png">
<Filter>Recording\VirtualPad\Images</Filter>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\r1Pressed.png">
<Filter>Recording\VirtualPad\Images</Filter>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\r2Pressed.png">
<Filter>Recording\VirtualPad\Images</Filter>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\r3Pressed.png">
<Filter>Recording\VirtualPad\Images</Filter>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\rightPressed.png">
<Filter>Recording\VirtualPad\Images</Filter>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\selectPressed.png">
<Filter>Recording\VirtualPad\Images</Filter>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\squarePressed.png">
<Filter>Recording\VirtualPad\Images</Filter>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\trianglePressed.png">
<Filter>Recording\VirtualPad\Images</Filter>
</CustomBuild>
<CustomBuild Include="Recording\VirtualPad\img\upPressed.png">
<Filter>Recording\VirtualPad\Images</Filter>
</CustomBuild>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Manifest Include="windows\PCSX2.manifest"> <Manifest Include="windows\PCSX2.manifest">