mirror of https://github.com/PCSX2/pcsx2.git
recording: main recording functions and input gathering
This commit is contained in:
parent
7a03bafa27
commit
ddd2e3f8f0
|
@ -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 <vector>
|
||||||
|
|
||||||
|
|
||||||
|
InputRecording g_InputRecording;
|
||||||
|
|
||||||
|
//-----------------------------------------------
|
||||||
|
// Save or Load - Save frame number
|
||||||
|
// Save or load - <20>Ńt<C583><74><EFBFBD>[<5B><><EFBFBD><EFBFBD><EFBFBD>̕ۑ<CC95>
|
||||||
|
//-----------------------------------------------
|
||||||
|
void SaveStateBase::InputRecordingFreeze()
|
||||||
|
{
|
||||||
|
FreezeTag("InputRecording");
|
||||||
|
Freeze(g_FrameCount); // Somehow the function saved the frame successfully
|
||||||
|
// Freeze<7A><EFBFBD><D690>łȂ<C582><C882><EFBFBD>frame<6D>̕ۑ<CC95><DB91><EFBFBD><EFBFBD><EFBFBD><EFBFBD>܂<EFBFBD><DC82><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
@ -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<wxString> split(const wxString &s, char delim) {
|
||||||
|
std::vector<wxString> 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<wxString> 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<wxString, int> PadData::getNormalKeys(int port)const
|
||||||
|
{
|
||||||
|
std::map<wxString, int> key;
|
||||||
|
for (int i = 0; i < PadDataNormalKeysSize; i++)
|
||||||
|
{
|
||||||
|
key.insert(std::map<wxString, int>::value_type(PadDataNormalKeys[i], getNormalButton(port, PadDataNormalKeys[i])));
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
void PadData::setNormalKeys(int port, std::map<wxString, int> 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<wxString, int> PadData::getAnalogKeys(int port)const
|
||||||
|
{
|
||||||
|
std::map<wxString, int> key;
|
||||||
|
for (int i = 0; i < PadDataAnalogKeysSize; i++)
|
||||||
|
{
|
||||||
|
key.insert(std::map<wxString, int>::value_type(PadDataAnalogKeys[i], getAnalogButton(port, PadDataAnalogKeys[i])));
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
void PadData::setAnalogKeys(int port, std::map<wxString, int> 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;
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
#pragma once
|
||||||
|
#ifndef __PAD_DATA_H__
|
||||||
|
#define __PAD_DATA_H__
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#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<wxString, int> getNormalKeys(int port)const;
|
||||||
|
void setNormalKeys(int port, std::map<wxString, int> key);
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
// analogKey 0~255
|
||||||
|
// max left/up : 0
|
||||||
|
// neutral : 127
|
||||||
|
// max right/down : 255
|
||||||
|
//------------------------------------------
|
||||||
|
std::map<wxString, int> getAnalogKeys(int port)const;
|
||||||
|
void setAnalogKeys(int port, std::map<wxString, int> 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
|
|
@ -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
|
||||||
|
// <20>Q<EFBFBD>[<5B><><EFBFBD><EFBFBD>CoreThread<61>œ<EFBFBD><C593><EFBFBD><EFBFBD>Ă<EFBFBD><C482><EFBFBD>A<EFBFBD><41><EFBFBD><EFBFBD><EFBFBD>Ă<EFBFBD><C482><EFBFBD>Ԃ<EFBFBD>GSFrame(wxFrame)<29>̏<EFBFBD><CC8F><EFBFBD><EFBFBD><EFBFBD>t<F382AF95><74><EFBFBD>Ȃ<EFBFBD>
|
||||||
|
// (<28>L<EFBFBD>[<5B><><EFBFBD>͂̎t<F382AF95><74><EFBFBD><EFBFBD>CoreThread<61><64><EFBFBD>GSFrame<6D><65><EFBFBD>2<EFBFBD>ӏ<EFBFBD><D38F><EFBFBD><EFBFBD>ݒ肳<DD92><E882B3>Ă<EFBFBD><C482><EFBFBD>ۂ<EFBFBD>)
|
||||||
|
// CoreThread<61><64><EFBFBD><EFBFBD>~<7E><><EFBFBD>Ă<EFBFBD><C482><EFBFBD>Ԃ<EFBFBD>wxFrame<6D>̓<EFBFBD><CC93>͂<EFBFBD><CD82><EFBFBD><EFBFBD><EFBFBD><EFBFBD>d<EFBFBD>g<EFBFBD>݂<EFBFBD><DD82>ۂ<EFBFBD>
|
||||||
|
//-----------------------------------------------
|
||||||
|
|
||||||
|
bool RecordingControls::isStop()
|
||||||
|
{
|
||||||
|
return (fPauseState && CoreThread.IsOpen() && CoreThread.IsPaused());
|
||||||
|
}
|
||||||
|
//-----------------------------------------------
|
||||||
|
// Counters(CoreThread)<29><>̒<EFBFBD>~<7E><><EFBFBD><EFBFBD>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<6C><66><EFBFBD><EFBFBD>Ȃ<EFBFBD><C882>Ǝ~<7E>܂<EFBFBD>Ȃ<EFBFBD>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
Loading…
Reference in New Issue