mirror of https://github.com/PCSX2/pcsx2.git
input-rec: remove integration from SIO/Counters, fix imgui updating
This commit is contained in:
parent
96d9eadb4b
commit
7383bc3f44
|
@ -614,11 +614,6 @@ static __fi void VSyncStart(u32 sCycle)
|
|||
// Not doing so would sacrifice a frame of a savestate-based recording when loading any savestate
|
||||
#ifndef PCSX2_CORE
|
||||
g_InputRecordingControls.HandlePausingAndLocking();
|
||||
#else
|
||||
if (g_InputRecording.isActive())
|
||||
{
|
||||
g_InputRecording.handleExceededFrameCounter();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -686,12 +681,6 @@ static __fi void VSyncEnd(u32 sCycle)
|
|||
{
|
||||
g_InputRecordingControls.CheckPauseStatus();
|
||||
}
|
||||
#else
|
||||
if (EmuConfig.EnableRecordingTools && g_InputRecording.isActive())
|
||||
{
|
||||
g_InputRecording.getControls().processControlQueue();
|
||||
g_InputRecording.incFrameCounter();
|
||||
}
|
||||
#endif
|
||||
|
||||
if(EmuConfig.Trace.Enabled && EmuConfig.Trace.EE.m_EnableAll)
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "PAD/Host/PAD.h"
|
||||
#include <tuple>
|
||||
|
||||
namespace PAD
|
||||
{
|
||||
|
@ -49,6 +50,14 @@ namespace PAD
|
|||
|
||||
void Set(u32 pad, u32 index, float value);
|
||||
|
||||
__fi void SetRawAnalogs(const u32 pad, const std::tuple<u8, u8> left, const std::tuple<u8, u8> right)
|
||||
{
|
||||
m_analog[pad].lx = std::get<0>(left);
|
||||
m_analog[pad].ly = std::get<1>(left);
|
||||
m_analog[pad].rx = std::get<0>(right);
|
||||
m_analog[pad].ry = std::get<1>(right);
|
||||
}
|
||||
|
||||
__fi PAD::ControllerType GetType(u32 pad) { return m_type[pad]; }
|
||||
__fi void SetType(u32 pad, PAD::ControllerType type) { m_type[pad] = type; }
|
||||
|
||||
|
@ -75,6 +84,9 @@ namespace PAD
|
|||
|
||||
__fi u8 GetRawPressure(u32 pad, u32 index) const { return m_button_pressure[pad][index]; }
|
||||
|
||||
__fi std::tuple<u8, u8> GetRawLeftAnalog(u32 pad) const { return {m_analog[pad].lx, m_analog[pad].ly}; }
|
||||
__fi std::tuple<u8, u8> GetRawRightAnalog(u32 pad) const { return {m_analog[pad].rx, m_analog[pad].ry}; }
|
||||
|
||||
u32 GetButtons(u32 pad);
|
||||
u8 GetPressure(u32 pad, u32 index);
|
||||
};
|
||||
|
|
|
@ -479,18 +479,7 @@ wxString InputRecording::resolveGameName()
|
|||
#include "DebugTools/Debug.h"
|
||||
#include "GameDatabase.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
// Future TODOs
|
||||
// - restart
|
||||
// - tooltips on GUI options
|
||||
// - Controller Logging (virtual pad related)
|
||||
// - persist last browsed IR path
|
||||
// - logs are weirdly formatted
|
||||
// - force OSD updates since a lot of input recording occurs during a paused state
|
||||
// - differentiating OSD logs somehow would be nice (color / a preceding icon?)
|
||||
|
||||
#include <queue>
|
||||
#include <fmt/format.h>
|
||||
#include "GS.h"
|
||||
|
||||
void SaveStateBase::InputRecordingFreeze()
|
||||
{
|
||||
|
@ -517,9 +506,11 @@ bool InputRecording::create(const std::string& fileName, const bool fromSaveStat
|
|||
{
|
||||
FileSystem::CopyFilePath(savestatePath.c_str(), fmt::format("{}.bak", savestatePath).c_str(), true);
|
||||
}
|
||||
m_initial_load_complete = false;
|
||||
m_type = Type::FROM_SAVESTATE;
|
||||
m_is_active = true;
|
||||
m_initial_load_complete = true;
|
||||
m_watching_for_rerecords = true;
|
||||
setStartingFrame(g_FrameCount);
|
||||
// TODO - error handling
|
||||
VMManager::SaveState(savestatePath.c_str());
|
||||
}
|
||||
|
@ -590,73 +581,98 @@ bool InputRecording::play(const std::string& filename)
|
|||
{
|
||||
InputRec::consoleLog(fmt::format("Input recording was possibly constructed for a different game. Expected: {}, Actual: {}", m_file.getGameName(), resolveGameName()));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void InputRecording::closeActiveFile()
|
||||
{
|
||||
if (!m_is_active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (m_file.close())
|
||||
{
|
||||
m_is_active = false;
|
||||
InputRec::log("Input recording stopped");
|
||||
GetMTGS().PresentCurrentFrame();
|
||||
}
|
||||
else
|
||||
{
|
||||
InputRec::log("Unable to stop input recording");
|
||||
}
|
||||
}
|
||||
|
||||
void InputRecording::stop()
|
||||
{
|
||||
m_is_active = false;
|
||||
if (m_file.close())
|
||||
if (VMManager::GetState() == VMState::Paused)
|
||||
{
|
||||
InputRec::log("Input recording stopped");
|
||||
closeActiveFile();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Don't stop immediately, close the file after the current frame completes
|
||||
m_recordingQueue.push([&]() {
|
||||
closeActiveFile();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Refactor this
|
||||
void InputRecording::ControllerInterrupt(u8 port, size_t fifoSize, u8 dataIn, u8 dataOut)
|
||||
void InputRecording::handleControllerDataUpdate()
|
||||
{
|
||||
m_pad_data_available = data == s_READ_DATA_AND_VIBRATE_QUERY_FIRST_BYTE;
|
||||
// TODO - multi-tap support with new file format, for now just controller 0 and 1
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
// Fetch the current frame's data
|
||||
PadData frameData(i, 0);
|
||||
if (m_is_active)
|
||||
{
|
||||
if (m_controls.isRecording())
|
||||
{
|
||||
saveControllerData(frameData, i, 0);
|
||||
}
|
||||
else if (m_controls.isReplaying())
|
||||
{
|
||||
const auto& modifiedFrameData = updateControllerData(i, 0);
|
||||
if (modifiedFrameData) {
|
||||
frameData = modifiedFrameData.value();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Log the data we have gathered, useful for debugging our use-case
|
||||
frameData.LogPadData();
|
||||
}
|
||||
}
|
||||
|
||||
void InputRecording::querySecondByte(const u8 data)
|
||||
void InputRecording::saveControllerData(const PadData& data, const int port, const int slot)
|
||||
{
|
||||
m_pad_data_available &= data == s_READ_DATA_AND_VIBRATE_QUERY_SECOND_BYTE;
|
||||
// Save the frame's data to the file
|
||||
if (!m_file.writePadData(m_frame_counter, data))
|
||||
{
|
||||
InputRec::consoleLog(fmt::format("Failed to write input data at [{}:{}:{}]", m_frame_counter, port, slot));
|
||||
}
|
||||
}
|
||||
std::optional<PadData> InputRecording::updateControllerData(const int port, const int slot)
|
||||
{
|
||||
// Get the PadData from the file
|
||||
const auto frameData = m_file.readPadData(m_frame_counter, port, slot);
|
||||
if (frameData)
|
||||
{
|
||||
// Update the g_key_status appropriately
|
||||
frameData->OverrideActualController();
|
||||
}
|
||||
else
|
||||
{
|
||||
InputRec::consoleLog(fmt::format("Failed to read input data at [{}:{}:{}]", m_frame_counter, port, slot));
|
||||
}
|
||||
return frameData;
|
||||
}
|
||||
|
||||
void InputRecording::controllerInterrupt(u8 port, size_t fifoSize, u8& dataIn, u8& dataOut)
|
||||
void InputRecording::processRecordQueue()
|
||||
{
|
||||
// TODO - Multi-Tap Support (Qt doesn't support it yet anyway!)
|
||||
// Keep these safe-guard checks in here, they are input recording only concerns
|
||||
if (fifoSize == 1)
|
||||
while (!m_recordingQueue.empty())
|
||||
{
|
||||
queryFirstByte(dataOut);
|
||||
return;
|
||||
}
|
||||
else if (fifoSize == 2)
|
||||
{
|
||||
querySecondByte(dataOut);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_pad_data_available)
|
||||
{
|
||||
// bad data / first and second byte checks failed
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_controls.isReplaying())
|
||||
{
|
||||
if (!m_file.readKeyBuffer(dataOut, m_frame_counter, port, fifoSize))
|
||||
{
|
||||
InputRec::consoleLog(fmt::format("Failed to read input data at frame {}", m_frame_counter));
|
||||
}
|
||||
// Update controller data state for future VirtualPad / logging usage.
|
||||
//pads[port].padData->UpdateControllerData(bufIndex, bufVal);
|
||||
}
|
||||
|
||||
// If there is data to read (previous two bytes looked correct)
|
||||
if (bufCount >= 3 && m_pad_data_available)
|
||||
{
|
||||
u8& bufVal = dataOut;
|
||||
const u16 bufIndex = fifoSize - 3;
|
||||
if (state == InputRecordingMode::Replaying)
|
||||
{
|
||||
if (!m_file.writeKeyBuffer(m_frame_counter, port, fifoSize, dataOut))
|
||||
{
|
||||
InputRec::consoleLog(fmt::format("Failed to write input data at frame {}", m_frame_counter));
|
||||
}
|
||||
}
|
||||
m_recordingQueue.front()();
|
||||
m_recordingQueue.pop();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -677,6 +693,11 @@ std::string InputRecording::resolveGameName()
|
|||
|
||||
void InputRecording::incFrameCounter()
|
||||
{
|
||||
if (!m_is_active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_frame_counter >= std::numeric_limits<u64>::max())
|
||||
{
|
||||
// TODO - log the incredible achievment of playing for longer than 4 billion years, and end the recording
|
||||
|
@ -730,7 +751,9 @@ void InputRecording::handleExceededFrameCounter()
|
|||
void InputRecording::handleReset()
|
||||
{
|
||||
if (m_initial_load_complete)
|
||||
{
|
||||
adjustFrameCounterOnReRecord(0);
|
||||
}
|
||||
m_initial_load_complete = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -166,16 +166,13 @@ public:
|
|||
bool play(const std::string& path);
|
||||
void stop();
|
||||
|
||||
void queryFirstByte(const u8 data);
|
||||
void querySecondByte(const u8 bufVal);
|
||||
void controllerInterrupt(const u8 port, const size_t fifoSize, u8& dataIn, u8& dataOut);
|
||||
void handleControllerDataUpdate();
|
||||
void saveControllerData(const PadData& data, const int port, const int slot);
|
||||
std::optional<PadData> updateControllerData(const int port, const int slot);
|
||||
void incFrameCounter();
|
||||
u64 getFrameCounter() const;
|
||||
bool isActive() const;
|
||||
|
||||
// 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);
|
||||
void processRecordQueue();
|
||||
|
||||
void handleExceededFrameCounter();
|
||||
void handleReset();
|
||||
|
@ -187,11 +184,6 @@ public:
|
|||
const InputRecordingFile& getData() const;
|
||||
|
||||
private:
|
||||
// - https://github.com/PCSX2/pcsx2/blob/7db9627ff6986c2d3faeecc58525a0e32da2f29f/pcsx2/PAD/Windows/PAD.cpp#L1141
|
||||
static constexpr u8 s_READ_DATA_AND_VIBRATE_QUERY_FIRST_BYTE = 0x79;
|
||||
// - https://github.com/PCSX2/pcsx2/blob/7db9627ff6986c2d3faeecc58525a0e32da2f29f/pcsx2/PAD/Windows/PAD.cpp#L1142
|
||||
static constexpr u8 s_READ_DATA_AND_VIBRATE_QUERY_SECOND_BYTE = 0x5A;
|
||||
|
||||
InputRecordingControls m_controls;
|
||||
InputRecordingFile m_file;
|
||||
|
||||
|
@ -202,12 +194,16 @@ private:
|
|||
bool m_pad_data_available = false;
|
||||
bool m_watching_for_rerecords = false;
|
||||
|
||||
// A consistent way to run actions at the end of the each frame (ie. stop the recording)
|
||||
std::queue<std::function<void()>> m_recordingQueue;
|
||||
|
||||
u32 m_frame_counter = 0;
|
||||
// Either 0 for a power-on movie, or the g_FrameCount that is stored on the starting frame
|
||||
u32 m_starting_frame = 0;
|
||||
|
||||
void initializeState();
|
||||
void setStartingFrame(u32 startingFrame);
|
||||
void closeActiveFile();
|
||||
|
||||
private:
|
||||
// Resolve the name and region of the game currently loaded using the GameDB
|
||||
|
|
|
@ -225,7 +225,7 @@ void InputRecordingControls::StopCapture() const
|
|||
#include "InputRecordingControls.h"
|
||||
#include "Utilities/InputRecordingLogger.h"
|
||||
|
||||
#include "GS/GS.h"
|
||||
#include "GS.h"
|
||||
#include "VMManager.h"
|
||||
|
||||
void InputRecordingControls::toggleRecordMode()
|
||||
|
@ -246,7 +246,7 @@ void InputRecordingControls::setRecordMode(bool waitForFrameToEnd)
|
|||
{
|
||||
m_state = Mode::Recording;
|
||||
InputRec::log("Record mode ON");
|
||||
GSPresentCurrentFrame();
|
||||
GetMTGS().PresentCurrentFrame();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -263,7 +263,7 @@ void InputRecordingControls::setReplayMode(bool waitForFrameToEnd)
|
|||
{
|
||||
m_state = Mode::Replaying;
|
||||
InputRec::log("Replay mode ON");
|
||||
GSPresentCurrentFrame();
|
||||
GetMTGS().PresentCurrentFrame();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -281,11 +281,16 @@ bool InputRecordingControls::isReplaying() const
|
|||
|
||||
void InputRecordingControls::processControlQueue()
|
||||
{
|
||||
if (!m_controlQueue.empty())
|
||||
{
|
||||
|
||||
while (!m_controlQueue.empty())
|
||||
{
|
||||
m_controlQueue.front()();
|
||||
m_controlQueue.pop();
|
||||
}
|
||||
GetMTGS().PresentCurrentFrame();
|
||||
}
|
||||
}
|
||||
|
||||
bool InputRecordingControls::isRecording() const
|
||||
|
|
|
@ -359,20 +359,23 @@ bool InputRecordingFile::openExisting(const std::string& path)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool InputRecordingFile::readKeyBuffer(u8& result, const uint frame, const uint port, const uint bufIndex)
|
||||
std::optional<PadData> InputRecordingFile::readPadData(const uint frame, const uint port, const uint slot)
|
||||
{
|
||||
if (m_recordingFile == nullptr)
|
||||
{
|
||||
return false;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const size_t seek = getRecordingBlockSeekPoint(frame) + s_controllerInputBytes * port + bufIndex;
|
||||
if (fseek(m_recordingFile, seek, SEEK_SET) != 0 || fread(&result, 1, 1, m_recordingFile) != 1)
|
||||
std::array<u8, s_controllerInputBytes> data{};
|
||||
|
||||
// TODO - slot unused, use it in the new format
|
||||
const size_t seek = getRecordingBlockSeekPoint(frame) + s_controllerInputBytes * port;
|
||||
if (fseek(m_recordingFile, seek, SEEK_SET) != 0 || fread(&data, 1, 18, m_recordingFile) != 1)
|
||||
{
|
||||
return false;
|
||||
return PadData(port, slot, data);
|
||||
}
|
||||
|
||||
return true;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void InputRecordingFile::setTotalFrames(u32 frame)
|
||||
|
@ -403,17 +406,36 @@ bool InputRecordingFile::writeHeader() const
|
|||
return true;
|
||||
}
|
||||
|
||||
bool InputRecordingFile::writeKeyBuffer(const uint frame, const uint port, const uint bufIndex, const u8 buf) const
|
||||
bool InputRecordingFile::writePadData(const uint frame, const PadData data) const
|
||||
{
|
||||
if (m_recordingFile == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t seek = getRecordingBlockSeekPoint(frame) + s_controllerInputBytes * port + bufIndex;
|
||||
// TODO - use the slot in the future
|
||||
const size_t seek = getRecordingBlockSeekPoint(frame) + s_controllerInputBytes * data.m_port;
|
||||
|
||||
// seek to the correct position and write data to the file
|
||||
if (fseek(m_recordingFile, seek, SEEK_SET) != 0 ||
|
||||
fwrite(&buf, 1, 1, m_recordingFile) != 1)
|
||||
fwrite(&data.m_compactPressFlagsGroupOne, 1, 1, m_recordingFile) != 1 ||
|
||||
fwrite(&data.m_compactPressFlagsGroupTwo, 1, 1, m_recordingFile) != 1 ||
|
||||
fwrite(&std::get<0>(data.m_rightAnalog), 1, 1, m_recordingFile) != 1 ||
|
||||
fwrite(&std::get<1>(data.m_rightAnalog), 1, 1, m_recordingFile) != 1 ||
|
||||
fwrite(&std::get<0>(data.m_leftAnalog), 1, 1, m_recordingFile) != 1 ||
|
||||
fwrite(&std::get<1>(data.m_leftAnalog), 1, 1, m_recordingFile) != 1 ||
|
||||
fwrite(&std::get<1>(data.m_right), 1, 1, m_recordingFile) != 1 ||
|
||||
fwrite(&std::get<1>(data.m_left), 1, 1, m_recordingFile) != 1 ||
|
||||
fwrite(&std::get<1>(data.m_up), 1, 1, m_recordingFile) != 1 ||
|
||||
fwrite(&std::get<1>(data.m_down), 1, 1, m_recordingFile) != 1 ||
|
||||
fwrite(&std::get<1>(data.m_triangle), 1, 1, m_recordingFile) != 1 ||
|
||||
fwrite(&std::get<1>(data.m_circle), 1, 1, m_recordingFile) != 1 ||
|
||||
fwrite(&std::get<1>(data.m_cross), 1, 1, m_recordingFile) != 1 ||
|
||||
fwrite(&std::get<1>(data.m_square), 1, 1, m_recordingFile) != 1 ||
|
||||
fwrite(&std::get<1>(data.m_l1), 1, 1, m_recordingFile) != 1 ||
|
||||
fwrite(&std::get<1>(data.m_r1), 1, 1, m_recordingFile) != 1 ||
|
||||
fwrite(&std::get<1>(data.m_l2), 1, 1, m_recordingFile) != 1 ||
|
||||
fwrite(&std::get<1>(data.m_r2), 1, 1, m_recordingFile) != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -425,7 +447,7 @@ bool InputRecordingFile::writeKeyBuffer(const uint frame, const uint port, const
|
|||
void InputRecordingFile::logRecordingMetadata()
|
||||
{
|
||||
InputRec::consoleMultiLog({fmt::format("File: {}", getFilename()),
|
||||
fmt::format("PCSX2 Version Used: {}",m_header.m_emulatorVersion),
|
||||
fmt::format("PCSX2 Version Used: {}", m_header.m_emulatorVersion),
|
||||
fmt::format("Recording File Version: {}", m_header.m_fileVersion),
|
||||
fmt::format("Associated Game Name or ISO Filename: {}", m_header.m_gameName),
|
||||
fmt::format("Author: {}", m_header.m_author),
|
||||
|
@ -442,32 +464,15 @@ std::vector<PadData> InputRecordingFile::bulkReadPadData(u32 frameStart, u32 fra
|
|||
return data;
|
||||
}
|
||||
|
||||
const size_t size = static_cast<size_t>(frameEnd - frameStart);
|
||||
data.reserve(size);
|
||||
|
||||
std::array<u8, s_controllerInputBytes> padBytes;
|
||||
|
||||
const size_t seek = getRecordingBlockSeekPoint(frameStart) + s_controllerInputBytes * port;
|
||||
const size_t skip = s_controllerInputBytes * (s_controllerPortsSupported - port - 1);
|
||||
fseek(m_recordingFile, seek, SEEK_SET);
|
||||
|
||||
for (int frame = 0; frame < size; frame++)
|
||||
// TODO - no multi-tap support
|
||||
for (uint64_t currFrame = frameStart; currFrame < frameEnd; currFrame++)
|
||||
{
|
||||
if (fread(&padBytes, 1, s_controllerInputBytes, m_recordingFile) != s_controllerInputBytes)
|
||||
const auto padData = readPadData(currFrame, port, 0);
|
||||
if (padData)
|
||||
{
|
||||
data.shrink_to_fit();
|
||||
break;
|
||||
data.push_back(padData.value());
|
||||
}
|
||||
|
||||
PadData frameData;
|
||||
for (int i = 0; i < padBytes.size(); i++)
|
||||
{
|
||||
frameData.UpdateControllerData(i, padBytes.at(i));
|
||||
}
|
||||
data.push_back(std::move(frameData));
|
||||
fseek(m_recordingFile, skip, SEEK_CUR);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
|
|
@ -164,13 +164,13 @@ public:
|
|||
bool openNew(const std::string& 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);
|
||||
std::optional<PadData> readPadData(const uint frame, const uint port, const uint slot);
|
||||
// Updates the total frame counter and commit it to the recording file
|
||||
void setTotalFrames(u32 frames);
|
||||
// Persist the input recording file header's current state to the file
|
||||
bool writeHeader() const;
|
||||
// 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) const;
|
||||
bool writePadData(const uint frame, const PadData data) const;
|
||||
|
||||
|
||||
// Retrieve the input recording's filename (not the path)
|
||||
|
|
|
@ -208,104 +208,161 @@ void PadData::LogPadData(u8 const& port)
|
|||
|
||||
#include <fmt/core.h>
|
||||
|
||||
void PadData::UpdateControllerData(u16 bufIndex, u8 const bufVal) noexcept
|
||||
#include "PAD/Host/KeyStatus.h"
|
||||
#include "Sio.h"
|
||||
|
||||
PadData::PadData(const int port, const int slot)
|
||||
{
|
||||
if (bufIndex == static_cast<u8>(BufferIndex::PressedFlagsGroupOne))
|
||||
m_port = port;
|
||||
m_slot = slot;
|
||||
m_ext_port = sioConvertPortAndSlotToPad(m_port, m_slot);
|
||||
// Get the state of the buttons
|
||||
// TODO - for the new recording file format, allow informing max number of buttons per frame per controller as well (ie. the analog button)
|
||||
const u32 buttons = g_key_status.GetButtons(m_ext_port);
|
||||
// - pressed group one
|
||||
// - left
|
||||
// - down
|
||||
// - right
|
||||
// - up
|
||||
// - start
|
||||
// - r3
|
||||
// - l3
|
||||
// - select
|
||||
m_compactPressFlagsGroupOne = (buttons & 0b1111111100000000) >> 8;
|
||||
// - pressed group two
|
||||
// - square
|
||||
// - cross
|
||||
// - circle
|
||||
// - triangle
|
||||
// - r1
|
||||
// - l1
|
||||
// - r2
|
||||
// - l2
|
||||
m_compactPressFlagsGroupTwo = (buttons & 0b11111111);
|
||||
// Get the analog values
|
||||
m_rightAnalog = g_key_status.GetRawRightAnalog(m_ext_port);
|
||||
m_leftAnalog = g_key_status.GetRawLeftAnalog(m_ext_port);
|
||||
// Get pressure bytes (12 of them)
|
||||
m_left = {(0b10000000 & m_compactPressFlagsGroupOne) == 0, g_key_status.GetRawPressure(m_ext_port, gamePadValues::PAD_LEFT)};
|
||||
m_down = {(0b01000000 & m_compactPressFlagsGroupOne) == 0, g_key_status.GetRawPressure(m_ext_port, gamePadValues::PAD_DOWN)};
|
||||
m_right = {(0b00100000 & m_compactPressFlagsGroupOne) == 0, g_key_status.GetRawPressure(m_ext_port, gamePadValues::PAD_RIGHT)};
|
||||
m_up = {(0b00010000 & m_compactPressFlagsGroupOne) == 0, g_key_status.GetRawPressure(m_ext_port, gamePadValues::PAD_UP)};
|
||||
m_start = (0b00001000 & m_compactPressFlagsGroupOne) == 0;
|
||||
m_r3 = (0b00000100 & m_compactPressFlagsGroupOne) == 0;
|
||||
m_l3 = (0b00000010 & m_compactPressFlagsGroupOne) == 0;
|
||||
m_select = (0b00000001 & m_compactPressFlagsGroupOne) == 0;
|
||||
|
||||
m_square = {(0b10000000 & m_compactPressFlagsGroupTwo) == 0, g_key_status.GetRawPressure(m_ext_port, gamePadValues::PAD_SQUARE)};
|
||||
m_cross = {(0b01000000 & m_compactPressFlagsGroupTwo) == 0, g_key_status.GetRawPressure(m_ext_port, gamePadValues::PAD_CROSS)};
|
||||
m_circle = {(0b00100000 & m_compactPressFlagsGroupTwo) == 0, g_key_status.GetRawPressure(m_ext_port, gamePadValues::PAD_CIRCLE)};
|
||||
m_triangle = {(0b00010000 & m_compactPressFlagsGroupTwo) == 0, g_key_status.GetRawPressure(m_ext_port, gamePadValues::PAD_TRIANGLE)};
|
||||
m_r1 = {(0b00001000 & m_compactPressFlagsGroupTwo) == 0, g_key_status.GetRawPressure(m_ext_port, gamePadValues::PAD_R1)};
|
||||
m_l1 = {(0b00000100 & m_compactPressFlagsGroupTwo) == 0, g_key_status.GetRawPressure(m_ext_port, gamePadValues::PAD_L1)};
|
||||
m_r2 = {(0b00000010 & m_compactPressFlagsGroupTwo) == 0, g_key_status.GetRawPressure(m_ext_port, gamePadValues::PAD_R2)};
|
||||
m_l2 = {(0b00000001 & m_compactPressFlagsGroupTwo) == 0, g_key_status.GetRawPressure(m_ext_port, gamePadValues::PAD_L2)};
|
||||
}
|
||||
|
||||
PadData::PadData(const int port, const int slot, const std::array<u8, 18> data)
|
||||
{
|
||||
m_port = port;
|
||||
m_slot = slot;
|
||||
m_ext_port = sioConvertPortAndSlotToPad(m_port, m_slot);
|
||||
|
||||
m_compactPressFlagsGroupOne = data.at(0);
|
||||
m_compactPressFlagsGroupTwo = data.at(1);
|
||||
|
||||
m_rightAnalog = {data.at(2), data.at(3)};
|
||||
m_leftAnalog = {data.at(4), data.at(5)};
|
||||
|
||||
m_left = {(0b10000000 & m_compactPressFlagsGroupOne) == 0, data.at(7)};
|
||||
m_down = {(0b01000000 & m_compactPressFlagsGroupOne) == 0, data.at(9)};
|
||||
m_right = {(0b00100000 & m_compactPressFlagsGroupOne) == 0, data.at(6)};
|
||||
m_up = {(0b00010000 & m_compactPressFlagsGroupOne) == 0, data.at(8)};
|
||||
m_start = (0b00001000 & m_compactPressFlagsGroupOne) == 0;
|
||||
m_r3 = (0b00000100 & m_compactPressFlagsGroupOne) == 0;
|
||||
m_l3 = (0b00000010 & m_compactPressFlagsGroupOne) == 0;
|
||||
m_select = (0b00000001 & m_compactPressFlagsGroupOne) == 0;
|
||||
|
||||
m_square = {(0b10000000 & m_compactPressFlagsGroupTwo) == 0, data.at(13)};
|
||||
m_cross = {(0b01000000 & m_compactPressFlagsGroupTwo) == 0, data.at(12)};
|
||||
m_circle = {(0b00100000 & m_compactPressFlagsGroupTwo) == 0, data.at(11)};
|
||||
m_triangle = {(0b00010000 & m_compactPressFlagsGroupTwo) == 0, data.at(10)};
|
||||
m_r1 = {(0b00001000 & m_compactPressFlagsGroupTwo) == 0, data.at(15)};
|
||||
m_l1 = {(0b00000100 & m_compactPressFlagsGroupTwo) == 0, data.at(14)};
|
||||
m_r2 = {(0b00000010 & m_compactPressFlagsGroupTwo) == 0, data.at(17)};
|
||||
m_l2 = {(0b00000001 & m_compactPressFlagsGroupTwo) == 0, data.at(16)};
|
||||
}
|
||||
|
||||
void PadData::OverrideActualController() const
|
||||
{
|
||||
g_key_status.SetRawAnalogs(m_ext_port, m_leftAnalog, m_rightAnalog);
|
||||
|
||||
g_key_status.Set(m_ext_port, PAD_RIGHT, std::get<1>(m_right));
|
||||
g_key_status.Set(m_ext_port, PAD_LEFT, std::get<1>(m_left));
|
||||
g_key_status.Set(m_ext_port, PAD_UP, std::get<1>(m_up));
|
||||
g_key_status.Set(m_ext_port, PAD_DOWN, std::get<1>(m_down));
|
||||
g_key_status.Set(m_ext_port, PAD_START, m_start);
|
||||
g_key_status.Set(m_ext_port, PAD_SELECT, m_select);
|
||||
g_key_status.Set(m_ext_port, PAD_R3, m_r3);
|
||||
g_key_status.Set(m_ext_port, PAD_L3, m_l3);
|
||||
|
||||
g_key_status.Set(m_ext_port, PAD_SQUARE, std::get<1>(m_square));
|
||||
g_key_status.Set(m_ext_port, PAD_CROSS, std::get<1>(m_cross));
|
||||
g_key_status.Set(m_ext_port, PAD_CIRCLE, std::get<1>(m_circle));
|
||||
g_key_status.Set(m_ext_port, PAD_TRIANGLE, std::get<1>(m_triangle));
|
||||
|
||||
g_key_status.Set(m_ext_port, PAD_R1, std::get<1>(m_r1));
|
||||
g_key_status.Set(m_ext_port, PAD_L1, std::get<1>(m_l1));
|
||||
g_key_status.Set(m_ext_port, PAD_R2, std::get<1>(m_r2));
|
||||
g_key_status.Set(m_ext_port, PAD_L2, std::get<1>(m_l2));
|
||||
}
|
||||
|
||||
void addButtonInfoToString(std::string label, std::string& str, std::tuple<bool, u8> buttonInfo)
|
||||
{
|
||||
const auto& [pressed, pressure] = buttonInfo;
|
||||
if (pressed)
|
||||
{
|
||||
m_leftPressed.setPressedState(bufVal);
|
||||
m_downPressed.setPressedState(bufVal);
|
||||
m_rightPressed.setPressedState(bufVal);
|
||||
m_upPressed.setPressedState(bufVal);
|
||||
m_start.setPressedState(bufVal);
|
||||
m_r3.setPressedState(bufVal);
|
||||
m_l3.setPressedState(bufVal);
|
||||
m_select.setPressedState(bufVal);
|
||||
}
|
||||
else if (bufIndex == static_cast<u8>(BufferIndex::PressedFlagsGroupTwo))
|
||||
{
|
||||
m_squarePressed.setPressedState(bufVal);
|
||||
m_crossPressed.setPressedState(bufVal);
|
||||
m_circlePressed.setPressedState(bufVal);
|
||||
m_trianglePressed.setPressedState(bufVal);
|
||||
m_r1Pressed.setPressedState(bufVal);
|
||||
m_l1Pressed.setPressedState(bufVal);
|
||||
m_r2Pressed.setPressedState(bufVal);
|
||||
m_l2Pressed.setPressedState(bufVal);
|
||||
}
|
||||
else
|
||||
{
|
||||
bufIndex -= 2;
|
||||
if (bufIndex < sizeof(m_allIntensities) / sizeof(u8*))
|
||||
*m_allIntensities[bufIndex] = bufVal;
|
||||
str += fmt::format(" {}:{}", label, pressure);
|
||||
}
|
||||
}
|
||||
|
||||
u8 PadData::PollControllerData(u16 bufIndex) const noexcept
|
||||
void addButtonInfoToString(std::string label, std::string& str, bool pressed)
|
||||
{
|
||||
u8 byte = 0;
|
||||
if (bufIndex == static_cast<u8>(BufferIndex::PressedFlagsGroupOne))
|
||||
if (pressed)
|
||||
{
|
||||
// Construct byte by combining flags if the buttons are pressed
|
||||
byte |= m_leftPressed.getMaskIfPressed();
|
||||
byte |= m_downPressed.getMaskIfPressed();
|
||||
byte |= m_rightPressed.getMaskIfPressed();
|
||||
byte |= m_upPressed.getMaskIfPressed();
|
||||
byte |= m_start.getMaskIfPressed();
|
||||
byte |= m_r3.getMaskIfPressed();
|
||||
byte |= m_l3.getMaskIfPressed();
|
||||
byte |= m_select.getMaskIfPressed();
|
||||
// We flip the bits because as mentioned below, 0 = pressed
|
||||
byte = ~byte;
|
||||
str += fmt::format(" {}", label);
|
||||
}
|
||||
else if (bufIndex == static_cast<u8>(BufferIndex::PressedFlagsGroupTwo))
|
||||
{
|
||||
// Construct byte by combining flags if the buttons are pressed
|
||||
byte |= m_squarePressed.getMaskIfPressed();
|
||||
byte |= m_crossPressed.getMaskIfPressed();
|
||||
byte |= m_circlePressed.getMaskIfPressed();
|
||||
byte |= m_trianglePressed.getMaskIfPressed();
|
||||
byte |= m_r1Pressed.getMaskIfPressed();
|
||||
byte |= m_l1Pressed.getMaskIfPressed();
|
||||
byte |= m_r2Pressed.getMaskIfPressed();
|
||||
byte |= m_l2Pressed.getMaskIfPressed();
|
||||
// We flip the bits because as mentioned below, 0 = pressed
|
||||
byte = ~byte;
|
||||
}
|
||||
else
|
||||
{
|
||||
bufIndex -= 2;
|
||||
if (bufIndex < sizeof(m_allIntensities) / sizeof(u8*))
|
||||
byte = *m_allIntensities[bufIndex - 2];
|
||||
}
|
||||
|
||||
return byte;
|
||||
}
|
||||
|
||||
std::string PadData::RawPadBytesToString(int start, int end)
|
||||
void PadData::LogPadData() const
|
||||
{
|
||||
std::string str;
|
||||
for (int i = start; i < end; i++)
|
||||
{
|
||||
str += fmt::format("{}", PollControllerData(i));
|
||||
std::string pressedButtons = "";
|
||||
addButtonInfoToString("Square", pressedButtons, m_square);
|
||||
addButtonInfoToString("Cross", pressedButtons, m_cross);
|
||||
addButtonInfoToString("Circle", pressedButtons, m_circle);
|
||||
addButtonInfoToString("Triangle", pressedButtons, m_triangle);
|
||||
|
||||
if (i != end - 1)
|
||||
str += ", ";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
addButtonInfoToString("D-Right", pressedButtons, m_right);
|
||||
addButtonInfoToString("D-Left", pressedButtons, m_left);
|
||||
addButtonInfoToString("D-Up", pressedButtons, m_up);
|
||||
addButtonInfoToString("D-Down", pressedButtons, m_down);
|
||||
|
||||
void PadData::LogPadData(u8 const& port)
|
||||
{
|
||||
const std::string pressedBytes = RawPadBytesToString(0, 2);
|
||||
const std::string rightAnalogBytes = RawPadBytesToString(2, 4);
|
||||
const std::string leftAnalogBytes = RawPadBytesToString(4, 6);
|
||||
const std::string pressureBytes = RawPadBytesToString(6, 17);
|
||||
const std::string fullLog =
|
||||
fmt::format("[PAD {}] Raw Bytes: Pressed = [{}]\n", port + 1, pressedBytes) +
|
||||
fmt::format("[PAD {}] Raw Bytes: Right Analog = [{}]\n", port + 1, rightAnalogBytes) +
|
||||
fmt::format("[PAD {}] Raw Bytes: Left Analog = [{}]\n", port + 1, leftAnalogBytes) +
|
||||
fmt::format("[PAD {}] Raw Bytes: Pressure = [{}]\n", port + 1, pressureBytes);
|
||||
controlLog(fullLog);
|
||||
addButtonInfoToString("R1", pressedButtons, m_r1);
|
||||
addButtonInfoToString("L1", pressedButtons, m_l1);
|
||||
addButtonInfoToString("R2", pressedButtons, m_r2);
|
||||
addButtonInfoToString("L2", pressedButtons, m_l2);
|
||||
|
||||
addButtonInfoToString("Start", pressedButtons, m_start);
|
||||
addButtonInfoToString("Select", pressedButtons, m_select);
|
||||
addButtonInfoToString("R3", pressedButtons, m_r3);
|
||||
addButtonInfoToString("L3", pressedButtons, m_l3);
|
||||
|
||||
const auto& [left_x, left_y] = m_leftAnalog;
|
||||
const auto& [right_x, right_y] = m_rightAnalog;
|
||||
const std::string analogs = fmt::format("Left: [{}, {}] | Right: [{}, {}]", left_x, left_y, right_x, right_y);
|
||||
|
||||
const std::string finalLog = fmt::format("[PAD {}:{}:{}]\n\t[Buttons]: {}\n\t[Analogs]: {}\n", m_ext_port, m_port, m_slot, pressedButtons, analogs);
|
||||
controlLog(finalLog);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -134,124 +134,57 @@ private:
|
|||
class PadData
|
||||
{
|
||||
public:
|
||||
/// Create a struct containing the PAD data from the global PAD state
|
||||
/// see - `g_key_status`
|
||||
PadData(const int port, const int slot);
|
||||
PadData(const int port, const int slot, const std::array<u8, 18> data);
|
||||
|
||||
/// Constants
|
||||
static constexpr 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
|
||||
};
|
||||
int m_ext_port;
|
||||
int m_port;
|
||||
int m_slot;
|
||||
|
||||
/// Analog Sticks - 0-255 (127 center)
|
||||
u8 m_leftAnalogX = ANALOG_VECTOR_NEUTRAL;
|
||||
u8 m_leftAnalogY = ANALOG_VECTOR_NEUTRAL;
|
||||
u8 m_rightAnalogX = ANALOG_VECTOR_NEUTRAL;
|
||||
u8 m_rightAnalogY = ANALOG_VECTOR_NEUTRAL;
|
||||
// Analog Sticks - <x, y> - 0-255 (127 center)
|
||||
std::tuple<u8, u8> m_rightAnalog = {ANALOG_VECTOR_NEUTRAL, ANALOG_VECTOR_NEUTRAL};
|
||||
std::tuple<u8, u8> m_leftAnalog = {ANALOG_VECTOR_NEUTRAL, ANALOG_VECTOR_NEUTRAL};
|
||||
|
||||
/// Pressure Buttons - 0-255
|
||||
u8 m_circlePressure = 0;
|
||||
u8 m_crossPressure = 0;
|
||||
u8 m_squarePressure = 0;
|
||||
u8 m_trianglePressure = 0;
|
||||
u8 m_downPressure = 0;
|
||||
u8 m_leftPressure = 0;
|
||||
u8 m_rightPressure = 0;
|
||||
u8 m_upPressure = 0;
|
||||
u8 m_l1Pressure = 0;
|
||||
u8 m_l2Pressure = 0;
|
||||
u8 m_r1Pressure = 0;
|
||||
u8 m_r2Pressure = 0;
|
||||
u8 m_compactPressFlagsGroupOne = 255;
|
||||
u8 m_compactPressFlagsGroupTwo = 255;
|
||||
|
||||
u8* const m_allIntensities[16]{
|
||||
&m_rightAnalogX,
|
||||
&m_rightAnalogY,
|
||||
&m_leftAnalogX,
|
||||
&m_leftAnalogY,
|
||||
&m_rightPressure,
|
||||
&m_leftPressure,
|
||||
&m_upPressure,
|
||||
&m_downPressure,
|
||||
&m_trianglePressure,
|
||||
&m_circlePressure,
|
||||
&m_crossPressure,
|
||||
&m_squarePressure,
|
||||
&m_l1Pressure,
|
||||
&m_r1Pressure,
|
||||
&m_l2Pressure,
|
||||
&m_r2Pressure,
|
||||
};
|
||||
// Buttons <pressed, pressure (0-255)>
|
||||
std::tuple<bool, u8> m_circle = {false, 0};
|
||||
std::tuple<bool, u8> m_cross = {false, 0};
|
||||
std::tuple<bool, u8> m_square = {false, 0};
|
||||
std::tuple<bool, u8> m_triangle = {false, 0};
|
||||
|
||||
/// Pressure Button Flags
|
||||
struct ButtonFlag
|
||||
{
|
||||
bool m_pressed = false;
|
||||
const u8 m_BITMASK;
|
||||
constexpr ButtonFlag(u8 maskValue)
|
||||
: m_BITMASK(maskValue)
|
||||
{
|
||||
}
|
||||
std::tuple<bool, u8> m_down = {false, 0};
|
||||
std::tuple<bool, u8> m_left = {false, 0};
|
||||
std::tuple<bool, u8> m_right = {false, 0};
|
||||
std::tuple<bool, u8> m_up = {false, 0};
|
||||
|
||||
void setPressedState(u8 bufVal) noexcept
|
||||
{
|
||||
m_pressed = (~bufVal & m_BITMASK) > 0;
|
||||
}
|
||||
std::tuple<bool, u8> m_l1 = {false, 0};
|
||||
std::tuple<bool, u8> m_l2 = {false, 0};
|
||||
std::tuple<bool, u8> m_r1 = {false, 0};
|
||||
std::tuple<bool, u8> m_r2 = {false, 0};
|
||||
|
||||
u8 getMaskIfPressed() const noexcept
|
||||
{
|
||||
return m_pressed ? m_BITMASK : 0;
|
||||
}
|
||||
};
|
||||
/// 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.
|
||||
ButtonFlag m_circlePressed{0b00100000};
|
||||
ButtonFlag m_crossPressed{0b01000000};
|
||||
ButtonFlag m_squarePressed{0b10000000};
|
||||
ButtonFlag m_trianglePressed{0b00010000};
|
||||
ButtonFlag m_downPressed{0b01000000};
|
||||
ButtonFlag m_leftPressed{0b10000000};
|
||||
ButtonFlag m_rightPressed{0b00100000};
|
||||
ButtonFlag m_upPressed{0b00010000};
|
||||
ButtonFlag m_l1Pressed{0b00000100};
|
||||
ButtonFlag m_l2Pressed{0b00000001};
|
||||
ButtonFlag m_r1Pressed{0b00001000};
|
||||
ButtonFlag m_r2Pressed{0b00000010};
|
||||
// Buttons <pressed>
|
||||
bool m_start = false;
|
||||
bool m_select = false;
|
||||
bool m_l3 = false;
|
||||
bool m_r3 = false;
|
||||
|
||||
/// Normal (un)pressed buttons
|
||||
ButtonFlag m_select{0b00000001};
|
||||
ButtonFlag m_start{0b00001000};
|
||||
ButtonFlag m_l3{0b00000010};
|
||||
ButtonFlag m_r3{0b00000100};
|
||||
// Overrides the actual controller's state with the the values in this struct
|
||||
void OverrideActualController() const;
|
||||
|
||||
// Given the input buffer and the current index, updates the correct field(s)
|
||||
void UpdateControllerData(u16 bufIndex, u8 const bufVal) noexcept;
|
||||
u8 PollControllerData(u16 bufIndex) const noexcept;
|
||||
|
||||
// Prints current PadData to the Controller Log filter which disabled by default
|
||||
void LogPadData(u8 const& port);
|
||||
// Prints current PadData to the Controller Log filter which is disabled by default
|
||||
void LogPadData() const;
|
||||
|
||||
private:
|
||||
|
||||
#ifndef PCSX2_CORE
|
||||
wxString RawPadBytesToString(int start, int end);
|
||||
#else
|
||||
std::string RawPadBytesToString(int start, int end);
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -421,18 +421,6 @@ u8 Sio0::Memcard(u8 value)
|
|||
// SIO2
|
||||
// ============================================================================
|
||||
|
||||
void Sio2::UpdateInputRecording(u8& dataIn, u8& dataOut)
|
||||
{
|
||||
if (EmuConfig.EnableRecordingTools && g_InputRecording.isActive())
|
||||
{
|
||||
// Ignore multitapped slots, only allow physical ports
|
||||
if (slot == 0)
|
||||
{
|
||||
g_InputRecording.controllerInterrupt(port, fifoOut.size(), dataIn, dataOut);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Sio2::Sio2()
|
||||
{
|
||||
|
@ -542,7 +530,6 @@ void Sio2::Pad()
|
|||
// Send PAD our current port, and get back whatever it says the first response byte should be.
|
||||
u8 commandByte = 0x01;
|
||||
u8 firstResponseByte = PADstartPoll(port, slot);
|
||||
UpdateInputRecording(commandByte, firstResponseByte);
|
||||
fifoOut.push_back(firstResponseByte);
|
||||
// Some games will refuse to read ALL pads, if RECV1 is not set to the CONNECTED value when ANY pad is polled,
|
||||
// REGARDLESS of whether that pad is truly connected or not.
|
||||
|
@ -554,7 +541,6 @@ void Sio2::Pad()
|
|||
u8 commandByte = fifoIn.front();
|
||||
fifoIn.pop_front();
|
||||
u8 responseByte = PADpoll(commandByte);
|
||||
UpdateInputRecording(commandByte, responseByte);
|
||||
fifoOut.push_back(responseByte);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1129,7 +1129,7 @@ void VMManager::Reset()
|
|||
if (g_InputRecording.isActive())
|
||||
{
|
||||
g_InputRecording.handleReset();
|
||||
GSPresentCurrentFrame();
|
||||
GetMTGS().PresentCurrentFrame();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1188,7 +1188,7 @@ bool VMManager::DoLoadState(const char* filename)
|
|||
if (g_InputRecording.isActive())
|
||||
{
|
||||
g_InputRecording.handleLoadingSavestate();
|
||||
GSPresentCurrentFrame();
|
||||
GetMTGS().PresentCurrentFrame();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -1557,6 +1557,23 @@ void VMManager::Internal::VSyncOnCPUThread()
|
|||
}
|
||||
|
||||
Host::CPUThreadVSync();
|
||||
|
||||
if (EmuConfig.EnableRecordingTools)
|
||||
{
|
||||
// This code is called _before_ Counter's vsync end, and _after_ vsync start
|
||||
if (g_InputRecording.isActive())
|
||||
{
|
||||
// Process any outstanding recording actions (ie. toggle mode, stop the recording, etc)
|
||||
g_InputRecording.processRecordQueue();
|
||||
g_InputRecording.getControls().processControlQueue();
|
||||
// Increment our internal frame counter, used to keep track of when we hit the end, etc.
|
||||
g_InputRecording.incFrameCounter();
|
||||
g_InputRecording.handleExceededFrameCounter();
|
||||
}
|
||||
// At this point, the PAD data has been read from the user for the current frame
|
||||
// so we can either read from it, or overwrite it!
|
||||
g_InputRecording.handleControllerDataUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void VMManager::CheckForCPUConfigChanges(const Pcsx2Config& old_config)
|
||||
|
|
Loading…
Reference in New Issue