From ddd2e3f8f06230ded32ecdb466a5bbbd2b4dfdff Mon Sep 17 00:00:00 2001 From: Tyler Wilding Date: Mon, 2 Jul 2018 20:52:22 -0400 Subject: [PATCH] recording: main recording functions and input gathering --- pcsx2/Recording/InputRecording.cpp | 185 +++++++++++++++ pcsx2/Recording/InputRecording.h | 52 ++++ pcsx2/Recording/PadData.cpp | 274 ++++++++++++++++++++++ pcsx2/Recording/PadData.h | 86 +++++++ pcsx2/Recording/RecordingControls.cpp | 100 ++++++++ pcsx2/Recording/RecordingControls.h | 35 +++ pcsx2/Recording/RecordingInputManager.cpp | 60 +++++ pcsx2/Recording/RecordingInputManager.h | 23 ++ 8 files changed, 815 insertions(+) create mode 100644 pcsx2/Recording/InputRecording.cpp create mode 100644 pcsx2/Recording/InputRecording.h create mode 100644 pcsx2/Recording/PadData.cpp create mode 100644 pcsx2/Recording/PadData.h create mode 100644 pcsx2/Recording/RecordingControls.cpp create mode 100644 pcsx2/Recording/RecordingControls.h create mode 100644 pcsx2/Recording/RecordingInputManager.cpp create mode 100644 pcsx2/Recording/RecordingInputManager.h diff --git a/pcsx2/Recording/InputRecording.cpp b/pcsx2/Recording/InputRecording.cpp new file mode 100644 index 0000000000..f8ba129616 --- /dev/null +++ b/pcsx2/Recording/InputRecording.cpp @@ -0,0 +1,185 @@ +#include "PrecompiledHeader.h" + +#include "MemoryTypes.h" +#include "Common.h" +#include "Counters.h" // use"g_FrameCount" +#include "SaveState.h" // create "SaveStateBase::InputRecordingFreeze()" +#include "AppSaveStates.h" // use "States_GetCurrentSlot()" + +#include "Recording/RecordingControls.h" +#include "InputRecording.h" + +#include + + +InputRecording g_InputRecording; + +//----------------------------------------------- +// Save or Load - Save frame number +// Save or load - �Ńt���[�����̕ۑ� +//----------------------------------------------- +void SaveStateBase::InputRecordingFreeze() +{ + FreezeTag("InputRecording"); + Freeze(g_FrameCount); // Somehow the function saved the frame successfully + // Freeze�֐��łȂ���frame�̕ۑ������܂������� + + if (IsLoading()) { + g_InputRecordingData.addUndoCount(); + } +} + +//---------------------------------- +// Main func for handling recording and inputting controller data +// Called by Sio.cpp::sioWriteController +//---------------------------------- +void InputRecording::ControllerInterrupt(u8 &data, u8 &port, u16 & bufCount, u8 buf[]) +{ + // Only examine controllers 1 / 2 + if (port < 0 || 1 < port ) + return; + + //========================== + // This appears to try to ensure that we are only paying attention + // to the frames that matter, the ones that are reading from + // the controller. + // + // See - Lilypad.cpp:1254 + // 0x42 is the magic number for the default read query + // + // NOTE: this appears to possibly break if you have logging enabled in LilyPad's config! + //========================== + if (bufCount == 1) { + if (data == 0x42) + { + fInterruptFrame = true; + } + else { + fInterruptFrame = false; + return; + } + } + else if ( bufCount == 2 ){ + // See - LilyPad.cpp:1255 + // 0x5A is always the second byte in the buffer + // when the normal READ_DATA_AND_VIBRRATE (0x42) + // query is executed, this looks like a sanity check + if (buf[bufCount] != 0x5A) { + fInterruptFrame = false; + return; + } + } + + if (!fInterruptFrame) + return; + + if (state == NONE) + return; + + // We do not want to record or save the first two + // bytes in the return from LilyPad + if (bufCount < 3) + return; + + //--------------- + // Read or Write + //--------------- + const u8 &nowBuf = buf[bufCount]; + if (state == RECORD) + { + InputRecordingData.updateFrameMax(g_FrameCount); + InputRecordingData.writeKeyBuf(g_FrameCount, port, bufCount - 3, nowBuf); + } + else if (state == REPLAY) + { + if (InputRecordingData.getMaxFrame() <= g_FrameCount) + { + // Pause the emulation but the movie is not closed + g_RecordingControls.Pause(); + return; + } + u8 tmp = 0; + if (InputRecordingData.readKeyBuf(tmp, g_FrameCount, port, bufCount - 3)) { + buf[bufCount] = tmp; + } + } +} + + +//---------------------------------- +// stop +//---------------------------------- +void InputRecording::Stop() { + state = NONE; + if (InputRecordingData.Close()) { + recordingConLog(L"[REC]: InputRecording Recording Stopped.\n"); + } +} + +//---------------------------------- +// start +//---------------------------------- +void InputRecording::Start(wxString FileName,bool fReadOnly, VmStateBuffer* ss) +{ + g_RecordingControls.Pause(); + Stop(); + + if (fReadOnly) + { + if (!InputRecordingData.Open(FileName, false)) { + return; + } + if (!InputRecordingData.readHeaderAndCheck()) { + recordingConLog(L"[REC]: This file is not a correct InputRecording file.\n"); + InputRecordingData.Close(); + return; + } + // cdrom + if (!g_Conf->CurrentIso.IsEmpty()) + { + if (Path::GetFilename(g_Conf->CurrentIso) != InputRecordingData.getHeader().cdrom) { + recordingConLog(L"[REC]: Information on CD in Movie file is Different.\n"); + } + } + state = REPLAY; + recordingConLog(wxString::Format(L"[REC]: Replaying movie - [%s]\n",FileName)); + recordingConLog(wxString::Format(L"MaxFrame: %d\n", InputRecordingData.getMaxFrame())); + recordingConLog(wxString::Format(L"UndoCount: %d\n", InputRecordingData.getUndoCount())); + } + else + { + // create + if (!InputRecordingData.Open(FileName, true, ss)) { + return; + } + // cdrom + if (!g_Conf->CurrentIso.IsEmpty()) + { + InputRecordingData.getHeader().setCdrom(Path::GetFilename(g_Conf->CurrentIso)); + } + InputRecordingData.writeHeader(); + InputRecordingData.writeSavestate(); + + state = RECORD; + recordingConLog(wxString::Format(L"[REC]: Started new recording - [%s]\n", FileName)); + } + // In every case, we reset the g_FrameCount + g_FrameCount = 0; +} + +//---------------------------------- +// shortcut key +//---------------------------------- +void InputRecording::RecordModeToggle() +{ + if (state == REPLAY) { + state = RECORD; + recordingConLog("[REC]: Record mode ON.\n"); + } + else if (state == RECORD) { + state = REPLAY; + recordingConLog("[REC]: Replay mode ON.\n"); + } +} + + diff --git a/pcsx2/Recording/InputRecording.h b/pcsx2/Recording/InputRecording.h new file mode 100644 index 0000000000..6911a032cf --- /dev/null +++ b/pcsx2/Recording/InputRecording.h @@ -0,0 +1,52 @@ +#pragma once +#ifndef __KEY_MOVIE_H__ +#define __KEY_MOVIE_H__ + +#include "InputRecordingFile.h" + + +//---------------------------- +// InputRecording +//---------------------------- +class InputRecording { +public: + InputRecording() {} + ~InputRecording(){} +public: + // controller + void ControllerInterrupt(u8 &data, u8 &port, u16 & BufCount, u8 buf[]); + + // menu bar + void Stop(); + void Start(wxString filename, bool fReadOnly, VmStateBuffer* ss = nullptr); + + // shortcut key + void RecordModeToggle(); + + +public: + enum KEY_MOVIE_MODE { + NONE, + RECORD, + REPLAY, + }; + +public: + // getter + KEY_MOVIE_MODE getModeState() { return state; } + InputRecordingFile & getInputRecordingData() {return InputRecordingData;} + bool isInterruptFrame() { return fInterruptFrame; } + +private: + InputRecordingFile InputRecordingData; + KEY_MOVIE_MODE state = NONE; + bool fInterruptFrame = false; + + +}; +extern InputRecording g_InputRecording; +#define g_InputRecordingData (g_InputRecording.getInputRecordingData()) +#define g_InputRecordingHeader (g_InputRecording.getInputRecordingData().getHeader()) + + +#endif diff --git a/pcsx2/Recording/PadData.cpp b/pcsx2/Recording/PadData.cpp new file mode 100644 index 0000000000..21febef282 --- /dev/null +++ b/pcsx2/Recording/PadData.cpp @@ -0,0 +1,274 @@ +#include "PrecompiledHeader.h" + +#include "Common.h" +#include "ConsoleLogger.h" +#include "PadData.h" + +PadData::PadData() +{ + for (int port = 0; port < 2; port++) + { + buf[port][0] = 255; + buf[port][1] = 255; + buf[port][2] = 127; + buf[port][3] = 127; + buf[port][4] = 127; + buf[port][5] = 127; + } +} + +void PadData::logPadData(u8 port, u16 bufCount, u8 buf[512]) { + // skip first two bytes because they dont seem to matter + if (port == 0 && bufCount > 2) + { + if (bufCount == 3) + { + controlLog(wxString::Format("\nController Port %d", port)); + controlLog(wxString::Format("\nPressed Flags - ")); + } + if (bufCount == 5) // analog sticks + { + controlLog(wxString::Format("\nAnalog Sticks - ")); + } + if (bufCount == 9) // pressure sensitive bytes + { + controlLog(wxString::Format("\nPressure Bytes - ")); + } + controlLog(wxString::Format("%3d ", buf[bufCount])); + } +} + +std::vector split(const wxString &s, char delim) { + std::vector elems; + wxString item; + for (char ch : s) { + if (ch == delim) { + if (!item.empty()) + elems.push_back(item); + item.clear(); + } + else { + item += ch; + } + } + if (!item.empty()) + elems.push_back(item); + return elems; +} + +void deserializeConvert(u8 & n, wxString s) +{ + try { + n = std::stoi(s.ToStdString(), NULL, 16); + } + catch (std::invalid_argument e) {/*none*/ } + catch (std::out_of_range e) {/*none*/ } +} + +wxString PadData::serialize()const +{ + if (!fExistKey)return L""; + wxString s = wxString::Format(L"%X", buf[0][0]); + for (int i = 1; i < ArraySize(buf[0]); i++) + { + s += wxString::Format(L",%X", buf[0][i]); + } + for (int i = 0; i < ArraySize(buf[1]); i++) + { + s += wxString::Format(L",%X", buf[1][i]); + } + return s; +} + +void PadData::deserialize(wxString s) +{ + std::vector v = split(s, L','); + if (v.size() != 12)return; + + for (int i = 0; i < 6; i++) + { + deserializeConvert(buf[0][i], v[i]); + } + for (int i = 0; i < 6; i++) + { + deserializeConvert(buf[1][i], v[6 + i]); + } + fExistKey = true; +} + +//===================================== +// normal key +//===================================== +std::map PadData::getNormalKeys(int port)const +{ + std::map key; + for (int i = 0; i < PadDataNormalKeysSize; i++) + { + key.insert(std::map::value_type(PadDataNormalKeys[i], getNormalButton(port, PadDataNormalKeys[i]))); + } + return key; +} +void PadData::setNormalKeys(int port, std::map key) +{ + for (auto it = key.begin(); it != key.end(); ++it) + { + setNormalButton(port, it->first, it->second); + } +} + +void PadData::setNormalButton(int port, wxString button, int fpushed) +{ + if (port < 0 || 1 < port)return; + wxByte keybit[2]; + getKeyBit(keybit, button); + int pressureByteIndex = getPressureByte(button); + + if (fpushed > 0) + { + // set whether or not the button is pressed + buf[port][0] = ~(~buf[port][0] | keybit[0]); + buf[port][1] = ~(~buf[port][1] | keybit[1]); + + // if the button supports pressure sensitivity + if (pressureByteIndex != -1) + { + buf[port][6 + pressureByteIndex] = fpushed; + } + } + else + { + buf[port][0] = (buf[port][0] | keybit[0]); + buf[port][1] = (buf[port][1] | keybit[1]); + + // if the button supports pressure sensitivity + if (pressureByteIndex != -1) + { + buf[port][6 + pressureByteIndex] = 0; + } + } +} + +int PadData::getNormalButton(int port, wxString button)const +{ + if (port < 0 || 1 < port)return false; + wxByte keybit[2]; + getKeyBit(keybit, button); + int pressureByteIndex = getPressureByte(button); + + // If the button is pressed on either controller + bool f1 = (~buf[port][0] & keybit[0])>0; + bool f2 = (~buf[port][1] & keybit[1])>0; + + if (f1 || f2) + { + // If the button does not support pressure sensitive inputs + // just return 1 for pressed. + if (pressureByteIndex == -1) + { + return 1; + } + // else return the pressure information + return buf[port][6 + pressureByteIndex]; + } + + // else the button isnt pressed at all + return 0; +} + +void PadData::getKeyBit(wxByte keybit[2], wxString button)const +{ + if (button == L"up") { keybit[0] = 0b00010000; keybit[1] = 0b00000000; } + else if (button == L"left") { keybit[0] = 0b10000000; keybit[1] = 0b00000000; } + else if (button == L"right") { keybit[0] = 0b00100000; keybit[1] = 0b00000000; } + else if (button == L"down") { keybit[0] = 0b01000000; keybit[1] = 0b00000000; } + + else if (button == L"start") { keybit[0] = 0b00001000; keybit[1] = 0b00000000; } + else if (button == L"select") { keybit[0] = 0b00000001; keybit[1] = 0b00000000; } + + else if (button == L"x") { keybit[0] = 0b00000000; keybit[1] = 0b01000000; } + else if (button == L"circle") { keybit[0] = 0b00000000; keybit[1] = 0b00100000; } + else if (button == L"square") { keybit[0] = 0b00000000; keybit[1] = 0b10000000; } + else if (button == L"triangle") { keybit[0] = 0b00000000; keybit[1] = 0b00010000; } + + else if (button == L"l1") { keybit[0] = 0b00000000; keybit[1] = 0b00000100; } + else if (button == L"l2") { keybit[0] = 0b00000000; keybit[1] = 0b00000001; } + else if (button == L"l3") { keybit[0] = 0b00000010; keybit[1] = 0b00000000; } + else if (button == L"r1") { keybit[0] = 0b00000000; keybit[1] = 0b00001000; } + else if (button == L"r2") { keybit[0] = 0b00000000; keybit[1] = 0b00000010; } + else if (button == L"r3") { keybit[0] = 0b00000100; keybit[1] = 0b00000000; } + else + { + keybit[0] = 0; + keybit[1] = 0; + } +} + +// just returns an index for the buffer to set the pressure byte +// returns -1 if it is a button that does not support pressure sensitivty +int PadData::getPressureByte(wxString button)const +{ + // button order + // R - L - U - D - Tri - Sqr - Circle - Cross - L1 - R1 - L2 - R2 + + if (button == L"up") { return 2; } + else if (button == L"left") { return 1; } + else if (button == L"right") { return 0; } + else if (button == L"down") { return 3; } + + else if (button == L"x") { return 6; } + else if (button == L"circle") { return 5; } + else if (button == L"square") { return 7; } + else if (button == L"triangle") { return 4; } + + else if (button == L"l1") { return 8; } + else if (button == L"l2") { return 10; } + else if (button == L"r1") { return 9; } + else if (button == L"r2") { return 11; } + else + { + return 1; + } +} + +//===================================== +// analog key +//===================================== +std::map PadData::getAnalogKeys(int port)const +{ + std::map key; + for (int i = 0; i < PadDataAnalogKeysSize; i++) + { + key.insert(std::map::value_type(PadDataAnalogKeys[i], getAnalogButton(port, PadDataAnalogKeys[i]))); + } + return key; +} +void PadData::setAnalogKeys(int port, std::map key) +{ + for (auto it = key.begin(); it != key.end(); ++it) + { + setAnalogButton(port, it->first, it->second); + } +} + +void PadData::setAnalogButton(int port, wxString button, int push) +{ + if (port < 0 || 1 < port)return; + if (push < 0)push = 0; + else if (push > 255)push = 255; + + if (button == L"l_leftright") { buf[port][4] = push; } + else if (button == L"l_updown") { buf[port][5] = push; } + else if (button == L"r_leftright") { buf[port][2] = push; } + else if (button == L"r_updown") { buf[port][3] = push; } +} + +int PadData::getAnalogButton(int port, wxString button)const +{ + if (port < 0 || 1 < port)return 0; + int val = 127; + if (button == L"l_leftright") { val = buf[port][4]; } + else if (button == L"l_updown") { val = buf[port][5]; } + else if (button == L"r_leftright") { val = buf[port][2]; } + else if (button == L"r_updown") { val = buf[port][3]; } + return val; +} diff --git a/pcsx2/Recording/PadData.h b/pcsx2/Recording/PadData.h new file mode 100644 index 0000000000..abd11d7494 --- /dev/null +++ b/pcsx2/Recording/PadData.h @@ -0,0 +1,86 @@ +#pragma once +#ifndef __PAD_DATA_H__ +#define __PAD_DATA_H__ + +#include + +#define PadDataNormalKeysSize 16 +const wxString PadDataNormalKeys[PadDataNormalKeysSize] = +{ + "up", + "right", + "left", + "down", + "select", + "start", + "x", + "circle", + "square", + "triangle", + "l1", + "l2", + "l3", + "r1", + "r2", + "r3" +}; + +#define PadDataAnalogKeysSize 4 +const wxString PadDataAnalogKeys[PadDataAnalogKeysSize] = +{ + "l_updown", + "l_leftright", + "r_updown", + "r_leftright" +}; + + +//---------------------------- +// Pad info +//---------------------------- +struct PadData +{ +public: + PadData(); + ~PadData() {} +public: + + bool fExistKey = false; + u8 buf[2][18]; + +public: + // Prints controlller data every frame to the Controller Log filter, disabled by default + static void logPadData(u8 port, u16 bufCount, u8 buf[512]); + wxString serialize()const; + void deserialize(wxString s); + + //------------------------------------------ + // normalKey + //------------------------------------------ + std::map getNormalKeys(int port)const; + void setNormalKeys(int port, std::map key); + + //------------------------------------------ + // analogKey 0~255 + // max left/up : 0 + // neutral : 127 + // max right/down : 255 + //------------------------------------------ + std::map getAnalogKeys(int port)const; + void setAnalogKeys(int port, std::map key); + + +private: + void setNormalButton(int port, wxString button, int pressure); + int getNormalButton(int port, wxString button)const; + void getKeyBit(wxByte keybit[2], wxString button)const; + int getPressureByte(wxString button)const; + + void setAnalogButton(int port, wxString button, int push); + int getAnalogButton(int port, wxString button)const; + + +}; + + +#endif \ No newline at end of file diff --git a/pcsx2/Recording/RecordingControls.cpp b/pcsx2/Recording/RecordingControls.cpp new file mode 100644 index 0000000000..cf28738896 --- /dev/null +++ b/pcsx2/Recording/RecordingControls.cpp @@ -0,0 +1,100 @@ +#include "PrecompiledHeader.h" + +#include "GSFrame.h" + +#include "MemoryTypes.h" +#include "App.h" // use "CoreThread" +#include "Counters.h" // use"g_FrameCount" + +#include "RecordingControls.h" + + +RecordingControls g_RecordingControls; + + +//----------------------------------------------- +// The game is running with CoreThread, and it will not accept processing of GSFrame (wxFrame) while it is running +// (It seems that two places are accepted for key input within CoreThread and GSFrame, too) +// While CoreThread is stopped, the input of wxFrame works like a mechanism +// �Q�[����CoreThread�œ����Ă���A�����Ă���Ԃ�GSFrame(wxFrame)�̏�����󂯕t���Ȃ� +// (�L�[���͂̎󂯕t����CoreThread���GSFrame���2�ӏ����ݒ肳��Ă���ۂ�) +// CoreThread����~���Ă���Ԃ�wxFrame�̓��͂������d�g�݂��ۂ� +//----------------------------------------------- + +bool RecordingControls::isStop() +{ + return (fPauseState && CoreThread.IsOpen() && CoreThread.IsPaused()); +} +//----------------------------------------------- +// Counters(CoreThread)��̒�~����p (For stop judgment in) +//----------------------------------------------- +void RecordingControls::StartCheck() +{ + if (fStart && CoreThread.IsOpen() && CoreThread.IsPaused()) { + CoreThread.Resume(); + fStart = false; + fPauseState = false; + } +} + +void RecordingControls::StopCheck() +{ + if (fFrameAdvance) { + if (stopFrameCount < g_FrameCount) { + fFrameAdvance = false; + fStop = true; + stopFrameCount = g_FrameCount; + + // We force the frame counter in the title bar to change + wxString oldTitle = wxGetApp().GetGsFrame().GetTitle(); + wxString title = g_Conf->Templates.RecordingTemplate; + wxString frameCount = wxString::Format("%d", g_FrameCount); + + title.Replace(L"${frame}", frameCount); + int frameIndex = title.find(wxString::Format(L"%d", g_FrameCount)); + frameIndex += frameCount.length(); + + title.replace(frameIndex, oldTitle.length() - frameIndex, oldTitle.c_str().AsChar() + frameIndex); + + wxGetApp().GetGsFrame().SetTitle(title); + } + } + if (fStop && CoreThread.IsOpen() && CoreThread.IsRunning()) + { + fPauseState = true; + CoreThread.PauseSelf(); // I can not stop unless it is self + // self����Ȃ��Ǝ~�܂�Ȃ� + } +} + + + +//---------------------------------- +// shortcut key +//---------------------------------- +void RecordingControls::FrameAdvance() +{ + stopFrameCount = g_FrameCount; + fFrameAdvance = true; + fStop = false; + fStart = true; +} +void RecordingControls::TogglePause() +{ + fStop = !fStop; + if (fStop == false) { + fStart = true; + } +} +void RecordingControls::Pause() +{ + fStop = true; + fFrameAdvance = true; +} +void RecordingControls::UnPause() +{ + fStop = false; + fStart = true; + fFrameAdvance = true; +} + diff --git a/pcsx2/Recording/RecordingControls.h b/pcsx2/Recording/RecordingControls.h new file mode 100644 index 0000000000..e7a2aacfe3 --- /dev/null +++ b/pcsx2/Recording/RecordingControls.h @@ -0,0 +1,35 @@ +#pragma once +#ifndef __MOVIE_CONTROLS_H__ +#define __MOVIE_CONTROLS_H__ + +class RecordingControls { +public: + + // Movie controls main functions + bool isStop(); + void StartCheck(); + void StopCheck(); + + // Shortcut Keys + void FrameAdvance(); + void TogglePause(); + + // Setters + void Pause(); + void UnPause(); + + // Getters + bool getStopFlag() { return (fStop || fFrameAdvance); } + +private: + uint stopFrameCount = false; + + bool fStop = false; + bool fStart = false; + bool fFrameAdvance = false; + bool fPauseState = false; + +}; +extern RecordingControls g_RecordingControls; + +#endif diff --git a/pcsx2/Recording/RecordingInputManager.cpp b/pcsx2/Recording/RecordingInputManager.cpp new file mode 100644 index 0000000000..82d143e488 --- /dev/null +++ b/pcsx2/Recording/RecordingInputManager.cpp @@ -0,0 +1,60 @@ +#include "PrecompiledHeader.h" + +#include "RecordingInputManager.h" +#include "InputRecording.h" + +RecordingInputManager g_RecordingInput; + +RecordingInputManager::RecordingInputManager() +{ + for (u8 i = 0; i < 2; i++) + virtualPad[i] = false; +} + +void RecordingInputManager::ControllerInterrupt(u8 & data, u8 & port, u16 & BufCount, u8 buf[]) +{ + if (port >= 2) + return; + + if (virtualPad[port]) + { + int bufIndex = BufCount - 3; + // first two bytes have nothing of interest in the buffer + // already handled by InputRecording.cpp + if (BufCount < 3) + return; + + // Normal keys + // We want to perform an OR, but, since 255 means that no button is pressed and 0 that every button is pressed (and by De Morgan's Laws), we execute an AND. + if (BufCount <= 4) + buf[BufCount] = buf[BufCount] & pad.buf[port][BufCount - 3]; + // Analog keys (! overrides !) + else if ((BufCount > 4 && BufCount <= 6) && pad.buf[port][BufCount - 3] != 127) + buf[BufCount] = pad.buf[port][BufCount - 3]; + // Pressure sensitivity bytes + else if (BufCount > 6) + buf[BufCount] = pad.buf[port][BufCount - 3]; + + // Updating movie file + g_InputRecording.ControllerInterrupt(data, port, BufCount, buf); + } +} + +void RecordingInputManager::SetButtonState(int port, wxString button, int pressure) +{ + auto normalKeys = pad.getNormalKeys(port); + normalKeys.at(button) = pressure; + pad.setNormalKeys(port, normalKeys); +} + +void RecordingInputManager::UpdateAnalog(int port, wxString key, int value) +{ + auto analogKeys = pad.getAnalogKeys(port); + analogKeys.at(key) = value; + pad.setAnalogKeys(port, analogKeys); +} + +void RecordingInputManager::SetVirtualPadReading(int port, bool read) +{ + virtualPad[port] = read; +} diff --git a/pcsx2/Recording/RecordingInputManager.h b/pcsx2/Recording/RecordingInputManager.h new file mode 100644 index 0000000000..978ceef362 --- /dev/null +++ b/pcsx2/Recording/RecordingInputManager.h @@ -0,0 +1,23 @@ +#pragma once +#include "PadData.h" + +class RecordingInputManager +{ +public: + RecordingInputManager(); + + void ControllerInterrupt(u8 &data, u8 &port, u16 & BufCount, u8 buf[]); + + // Handles normal keys + void SetButtonState(int port, wxString button, int pressure); + + // Handles analog sticks + void UpdateAnalog(int port, wxString key, int value); + + void SetVirtualPadReading(int port, bool read); + +protected: + PadData pad; + bool virtualPad[2]; +}; +extern RecordingInputManager g_RecordingInput;