recording: Rewrite of PadData class

Now a pure object representation of the controller data, no longer tightly coupled to the VirtualPad
This commit is contained in:
Tyler Wilding 2020-04-26 19:49:55 -04:00 committed by refractionpcsx2
parent 1afc75d6d9
commit b53d22ae7d
5 changed files with 258 additions and 921 deletions

View File

@ -1,5 +1,5 @@
/* PCSX2 - PS2 Emulator for PCs /* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2019 PCSX2 Dev Team * Copyright (C) 2002-2020 PCSX2 Dev Team
* *
* PCSX2 is free software: you can redistribute it and/or modify it under the terms * 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- * of the GNU Lesser General Public License as published by the Free Software Found-
@ -19,300 +19,179 @@
#include "ConsoleLogger.h" #include "ConsoleLogger.h"
#include "PadData.h" #include "PadData.h"
void PadData::UpdateControllerData(u16 bufIndex, u8 const &bufVal)
#ifndef DISABLE_RECORDING
PadData::PadData()
{ {
// TODO - multi-tap support eventually? BufferIndex index = static_cast<BufferIndex>(bufIndex);
for (int port = 0; port < 2; port++) switch (index)
{ {
buf[port][0] = 255; case BufferIndex::PressedFlagsGroupOne:
buf[port][1] = 255; leftPressed = IsButtonPressed(LEFT, bufVal);
buf[port][2] = 127; downPressed = IsButtonPressed(DOWN, bufVal);
buf[port][3] = 127; rightPressed = IsButtonPressed(RIGHT, bufVal);
buf[port][4] = 127; upPressed = IsButtonPressed(UP, bufVal);
buf[port][5] = 127; 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;
} }
} }
void PadData::LogPadData(u8 port, u16 bufCount, u8 buf[512]) { u8 PadData::PollControllerData(u16 bufIndex)
// skip first two bytes because they dont seem to matter {
if (port == 0 && bufCount > 2) u8 byte = 0;
BufferIndex index = static_cast<BufferIndex>(bufIndex);
switch (index)
{ {
if (bufCount == 3) case BufferIndex::PressedFlagsGroupOne:
{ // Construct byte by combining flags if the buttons are pressed
controlLog(wxString::Format("\nController Port %d", port)); byte |= BitmaskOrZero(leftPressed, LEFT);
controlLog(wxString::Format("\nPressed Flags - ")); byte |= BitmaskOrZero(downPressed, DOWN);
} byte |= BitmaskOrZero(rightPressed, RIGHT);
if (bufCount == 5) // analog sticks byte |= BitmaskOrZero(upPressed, UP);
{ byte |= BitmaskOrZero(start, START);
controlLog(wxString::Format("\nAnalog Sticks - ")); byte |= BitmaskOrZero(r3, R3);
} byte |= BitmaskOrZero(l3, L3);
if (bufCount == 9) // pressure sensitive bytes byte |= BitmaskOrZero(select, SELECT);
{ // We flip the bits because as mentioned below, 0 = pressed
controlLog(wxString::Format("\nPressure Bytes - ")); return ~byte;
} case BufferIndex::PressedFlagsGroupTwo:
controlLog(wxString::Format("%3d ", buf[bufCount])); // 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;
} }
} }
std::vector<int> PadData::GetNormalButtons(int port) const bool PadData::IsButtonPressed(ButtonResolver buttonResolver, u8 const &bufVal)
{ {
std::vector<int> buttons(PadDataNormalButtonCount); // Rather than the flags being SET if the button is pressed, it is the opposite
for (int i = 0; i < PadDataNormalButtonCount; i++) // 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
buttons[i] = GetNormalButton(port, PadData_NormalButton(i)); return (~bufVal & buttonResolver.buttonBitmask) > 0;
}
return buttons;
} }
void PadData::SetNormalButtons(int port, std::vector<int> buttons) u8 PadData::BitmaskOrZero(bool pressed, ButtonResolver buttonInfo)
{ {
for (int i = 0; i < PadDataNormalButtonCount; i++) return pressed ? buttonInfo.buttonBitmask : 0;
{
SetNormalButton(port, PadData_NormalButton(i), buttons[i]);
}
} }
void PadData::SetNormalButton(int port, PadData_NormalButton button, int fpushed) wxString PadData::RawPadBytesToString(int start, int end)
{ {
wxByte keybit[2]; wxString str;
GetKeyBit(keybit, button); for (int i = start; i < end; i++) {
int pressureByteIndex = GetPressureByte(button); str += wxString::Format("%d", PollControllerData(i));
if (i != end-1) {
if (fpushed > 0) str += ", ";
{
// 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;
} }
} }
return str;
} }
int PadData::GetNormalButton(int port, PadData_NormalButton button) const void PadData::LogPadData() {
{ wxString pressedBytes = RawPadBytesToString(0, 2);
wxByte keybit[2]; wxString rightAnalogBytes = RawPadBytesToString(2, 4);
GetKeyBit(keybit, button); wxString leftAnalogBytes = RawPadBytesToString(4, 6);
int pressureByteIndex = GetPressureByte(button); wxString pressureBytes = RawPadBytesToString(6, 17);
controlLog(wxString::Format("[PAD] Raw Bytes: Pressed = [%s], Right Analog = [%s], Left Analog = [%s]\n", pressedBytes, rightAnalogBytes, leftAnalogBytes));
// If the button is pressed on either controller controlLog(wxString::Format("[PAD] Raw Bytes: Pressure = [%s]\n", pressureBytes));
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], PadData_NormalButton button) const
{
switch (button)
{
case PadData_NormalButton_LEFT:
keybit[0] = 0b10000000;
keybit[1] = 0b00000000;
break;
case PadData_NormalButton_DOWN:
keybit[0] = 0b01000000;
keybit[1] = 0b00000000;
break;
case PadData_NormalButton_RIGHT:
keybit[0] = 0b00100000;
keybit[1] = 0b00000000;
break;
case PadData_NormalButton_UP:
keybit[0] = 0b00010000;
keybit[1] = 0b00000000;
break;
case PadData_NormalButton_START:
keybit[0] = 0b00001000;
keybit[1] = 0b00000000;
break;
case PadData_NormalButton_R3:
keybit[0] = 0b00000100;
keybit[1] = 0b00000000;
break;
case PadData_NormalButton_L3:
keybit[0] = 0b00000010;
keybit[1] = 0b00000000;
break;
case PadData_NormalButton_SELECT:
keybit[0] = 0b00000001;
keybit[1] = 0b00000000;
break;
case PadData_NormalButton_SQUARE:
keybit[0] = 0b00000000;
keybit[1] = 0b10000000;
break;
case PadData_NormalButton_CROSS:
keybit[0] = 0b00000000;
keybit[1] = 0b01000000;
break;
case PadData_NormalButton_CIRCLE:
keybit[0] = 0b00000000;
keybit[1] = 0b00100000;
break;
case PadData_NormalButton_TRIANGLE:
keybit[0] = 0b00000000;
keybit[1] = 0b00010000;
break;
case PadData_NormalButton_R1:
keybit[0] = 0b00000000;
keybit[1] = 0b00001000;
break;
case PadData_NormalButton_L1:
keybit[0] = 0b00000000;
keybit[1] = 0b00000100;
break;
case PadData_NormalButton_R2:
keybit[0] = 0b00000000;
keybit[1] = 0b00000010;
break;
case PadData_NormalButton_L2:
keybit[0] = 0b00000000;
keybit[1] = 0b00000001;
break;
default:
keybit[0] = 0;
keybit[1] = 0;
}
}
// 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(PadData_NormalButton button) const
{
// Pressure Byte Order
// R - L - U - D - Tri - Circle - Cross - Sqr - L1 - R1 - L2 - R2
switch (button)
{
case PadData_NormalButton_RIGHT:
return 0;
break;
case PadData_NormalButton_LEFT:
return 1;
break;
case PadData_NormalButton_UP:
return 2;
break;
case PadData_NormalButton_DOWN:
return 3;
break;
case PadData_NormalButton_TRIANGLE:
return 4;
break;
case PadData_NormalButton_CIRCLE:
return 5;
break;
case PadData_NormalButton_CROSS:
return 6;
break;
case PadData_NormalButton_SQUARE:
return 7;
break;
case PadData_NormalButton_L1:
return 8;
break;
case PadData_NormalButton_R1:
return 9;
break;
case PadData_NormalButton_L2:
return 10;
break;
case PadData_NormalButton_R2:
return 11;
break;
default:
return -1;
}
}
std::vector<int> PadData::GetAnalogVectors(int port) const
{
std::vector<int> vectors(PadDataAnalogVectorCount);
for (int i = 0; i < PadDataAnalogVectorCount; i++)
{
vectors[i] = GetAnalogVector(port, PadData_AnalogVector(i));
}
return vectors;
}
void PadData::SetAnalogVectors(int port, std::vector<int> vectors)
{
for (int i = 0; i < PadDataAnalogVectorCount; i++)
{
SetAnalogVector(port, PadData_AnalogVector(i), vectors[i]);
}
}
void PadData::SetAnalogVector(int port, PadData_AnalogVector vector, int val)
{
if (val < 0)
{
val = 0;
}
else if (val > 255)
{
val = 255;
}
buf[port][GetAnalogVectorByte(vector)] = val;
}
int PadData::GetAnalogVector(int port, PadData_AnalogVector vector) const
{
return buf[port][GetAnalogVectorByte(vector)];
}
// Returns an index for the buffer to set the analog's vector
int PadData::GetAnalogVectorByte(PadData_AnalogVector vector) const
{
// Vector Byte Ordering
// RX - RY - LX - LY
switch (vector)
{
case PadData_AnalogVector_RIGHT_ANALOG_X:
return 2;
break;
case PadData_AnalogVector_RIGHT_ANALOG_Y:
return 3;
break;
case PadData_AnalogVector_LEFT_ANALOG_X:
return 4;
break;
case PadData_AnalogVector_LEFT_ANALOG_Y:
return 5;
break;
default:
return -1;
}
}
#endif

View File

@ -1,5 +1,5 @@
/* PCSX2 - PS2 Emulator for PCs /* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2019 PCSX2 Dev Team * Copyright (C) 2002-2020 PCSX2 Dev Team
* *
* PCSX2 is free software: you can redistribute it and/or modify it under the terms * 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- * of the GNU Lesser General Public License as published by the Free Software Found-
@ -15,75 +15,115 @@
#pragma once #pragma once
#include <map> class PadData
#include <vector>
#ifndef DISABLE_RECORDING
static const int PadDataNormalButtonCount = 16;
enum PadData_NormalButton
{
PadData_NormalButton_UP,
PadData_NormalButton_RIGHT,
PadData_NormalButton_LEFT,
PadData_NormalButton_DOWN,
PadData_NormalButton_CROSS,
PadData_NormalButton_CIRCLE,
PadData_NormalButton_SQUARE,
PadData_NormalButton_TRIANGLE,
PadData_NormalButton_L1,
PadData_NormalButton_L2,
PadData_NormalButton_R1,
PadData_NormalButton_R2,
PadData_NormalButton_L3,
PadData_NormalButton_R3,
PadData_NormalButton_SELECT,
PadData_NormalButton_START
};
static const int PadDataAnalogVectorCount = 4;
enum PadData_AnalogVector
{
PadData_AnalogVector_LEFT_ANALOG_X,
PadData_AnalogVector_LEFT_ANALOG_Y,
PadData_AnalogVector_RIGHT_ANALOG_X,
PadData_AnalogVector_RIGHT_ANALOG_Y
};
struct PadData
{ {
public: public:
PadData(); /// Constants
~PadData() {} const u8 PRESSURE_BUTTON_UNPRESSED = 0;
const bool BUTTON_PRESSED = true;
const bool BUTTON_UNPRESSED = false;
const u8 ANALOG_VECTOR_CENTER_POS = 127;
bool fExistKey = false; enum class BufferIndex
u8 buf[2][18]; {
PressedFlagsGroupOne,
PressedFlagsGroupTwo,
RightAnalogXVector,
RightAnalogYVector,
LeftAnalogXVector,
LeftAnalogYVector,
RightPressure,
LeftPressure,
UpPressure,
DownPressure,
TrianglePressure,
CirclePressure,
CrossPressure,
SquarePressure,
L1Pressure,
R1Pressure,
L2Pressure,
R2Pressure
};
// Prints controlller data every frame to the Controller Log filter, disabled by default /// Pressure Buttons - 0-255
static void LogPadData(u8 port, u16 bufCount, u8 buf[512]); u8 circlePressure = PRESSURE_BUTTON_UNPRESSED;
u8 crossPressure = PRESSURE_BUTTON_UNPRESSED;
u8 squarePressure = PRESSURE_BUTTON_UNPRESSED;
u8 trianglePressure = PRESSURE_BUTTON_UNPRESSED;
u8 downPressure = PRESSURE_BUTTON_UNPRESSED;
u8 leftPressure = PRESSURE_BUTTON_UNPRESSED;
u8 rightPressure = PRESSURE_BUTTON_UNPRESSED;
u8 upPressure = PRESSURE_BUTTON_UNPRESSED;
u8 l1Pressure = PRESSURE_BUTTON_UNPRESSED;
u8 l2Pressure = PRESSURE_BUTTON_UNPRESSED;
u8 r1Pressure = PRESSURE_BUTTON_UNPRESSED;
u8 r2Pressure = PRESSURE_BUTTON_UNPRESSED;
// Normal Buttons /// Pressure Button Flags
std::vector<int> GetNormalButtons(int port) const; /// NOTE - It shouldn't be possible to depress a button
void SetNormalButtons(int port, std::vector<int> buttons); /// while also having no pressure (PAD plugin should default to max pressure).
/// But for the sake of completeness, it should be tracked.
bool circlePressed = BUTTON_UNPRESSED;
bool crossPressed = BUTTON_UNPRESSED;
bool squarePressed = BUTTON_UNPRESSED;
bool trianglePressed = BUTTON_UNPRESSED;
bool downPressed = BUTTON_UNPRESSED;
bool leftPressed = BUTTON_UNPRESSED;
bool rightPressed = BUTTON_UNPRESSED;
bool upPressed = BUTTON_UNPRESSED;
bool l1Pressed = BUTTON_UNPRESSED;
bool l2Pressed = BUTTON_UNPRESSED;
bool r1Pressed = BUTTON_UNPRESSED;
bool r2Pressed = BUTTON_UNPRESSED;
// Analog Vectors /// Normal (un)pressed buttons
// max left/up : 0 bool select = BUTTON_UNPRESSED;
// neutral : 127 bool start = BUTTON_UNPRESSED;
// max right/down : 255 bool l3 = BUTTON_UNPRESSED;
std::vector<int> GetAnalogVectors(int port) const; bool r3 = BUTTON_UNPRESSED;
// max left/up : 0
// neutral : 127 /// Analog Sticks - 0-255 (127 center)
// max right/down : 255 u8 leftAnalogX = ANALOG_VECTOR_CENTER_POS;
void SetAnalogVectors(int port, std::vector<int> vector); u8 leftAnalogY = ANALOG_VECTOR_CENTER_POS;
u8 rightAnalogX = ANALOG_VECTOR_CENTER_POS;
u8 rightAnalogY = ANALOG_VECTOR_CENTER_POS;
// 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();
private: private:
void SetNormalButton(int port, PadData_NormalButton button, int pressure); struct ButtonResolver
int GetNormalButton(int port, PadData_NormalButton button) const; {
void GetKeyBit(wxByte keybit[2], PadData_NormalButton button) const; u8 buttonBitmask;
int GetPressureByte(PadData_NormalButton button) const; };
void SetAnalogVector(int port, PadData_AnalogVector vector, int val); const ButtonResolver LEFT = ButtonResolver{ 0b10000000 };
int GetAnalogVector(int port, PadData_AnalogVector vector) const; const ButtonResolver DOWN = ButtonResolver{ 0b01000000 };
int GetAnalogVectorByte(PadData_AnalogVector vector) const; 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);
wxString RawPadBytesToString(int start, int end);
}; };
#endif #endif

View File

@ -1,86 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2019 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"
#include "RecordingInputManager.h"
#include "InputRecording.h"
#ifndef DISABLE_RECORDING
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 (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][bufIndex];
}
// Analog keys (! overrides !)
else if ((BufCount > 4 && BufCount <= 6) && pad.buf[port][bufIndex] != 127)
{
buf[BufCount] = pad.buf[port][bufIndex];
}
// Pressure sensitivity bytes
else if (BufCount > 6)
{
buf[BufCount] = pad.buf[port][bufIndex];
}
// Updating movie file
g_InputRecording.ControllerInterrupt(data, port, BufCount, buf);
}
}
void RecordingInputManager::SetButtonState(int port, PadData_NormalButton button, int pressure)
{
std::vector<int> buttons = pad.GetNormalButtons(port);
buttons[button] = pressure;
pad.SetNormalButtons(port, buttons);
}
void RecordingInputManager::UpdateAnalog(int port, PadData_AnalogVector vector, int value)
{
std::vector<int> vectors = pad.GetAnalogVectors(port);
vectors[vector] = value;
pad.SetAnalogVectors(port, vectors);
}
void RecordingInputManager::SetVirtualPadReading(int port, bool read)
{
virtualPad[port] = read;
}
#endif

View File

@ -1,402 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2019 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"
#include "Common.h"
#include "Recording/VirtualPad.h"
#include "Recording/RecordingInputManager.h"
#ifndef DISABLE_RECORDING
wxBEGIN_EVENT_TABLE(VirtualPad, wxFrame)
EVT_CLOSE(VirtualPad::OnClose)
wxEND_EVENT_TABLE()
// TODO - Problems / Potential improvements:
// - The UI doesn't update to manual controller inputs and actually overrides the controller when opened (easily noticable with analog stick)
// - This is less than ideal, but it's going to take a rather large / focused refactor, in it's current state the virtual pad does what it needs to do (precise inputs, frame by frame)
VirtualPad::VirtualPad(wxWindow* parent, wxWindowID id, const wxString& title, int controllerPort, const wxPoint& pos, const wxSize& size, long style) :
wxFrame(parent, id, title, pos, size, wxDEFAULT_FRAME_STYLE)
{
// Define components
SetSize(wxSize(1000, 700));
l2Button = new wxToggleButton(this, wxID_ANY, wxT("L2"));
l2ButtonPressure = new wxSpinCtrl(this, wxID_ANY, wxT("0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 255, 255);
l1Button = new wxToggleButton(this, wxID_ANY, wxT("L1"));
l1ButtonPressure = new wxSpinCtrl(this, wxID_ANY, wxT("0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 255, 255);
r2Button = new wxToggleButton(this, wxID_ANY, wxT("R2"));
r2ButtonPressure = new wxSpinCtrl(this, wxID_ANY, wxT("0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 255, 255);
r1Button = new wxToggleButton(this, wxID_ANY, wxT("R1"));
r1ButtonPressure = new wxSpinCtrl(this, wxID_ANY, wxT("0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 255, 255);
upButton = new wxToggleButton(this, wxID_ANY, wxT("Up"));
upButtonPressure = new wxSpinCtrl(this, wxID_ANY, wxT("0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 255, 255);
leftButton = new wxToggleButton(this, wxID_ANY, wxT("Left"));
leftButtonPressure = new wxSpinCtrl(this, wxID_ANY, wxT("0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 255, 255);
rightButton = new wxToggleButton(this, wxID_ANY, wxT("Right"));
rightButtonPressure = new wxSpinCtrl(this, wxID_ANY, wxT("0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 255, 255);
downButton = new wxToggleButton(this, wxID_ANY, wxT("Down"));
downButtonPressure = new wxSpinCtrl(this, wxID_ANY, wxT("0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 255, 255);
selectButton = new wxToggleButton(this, wxID_ANY, wxT("Select"));
startButton = new wxToggleButton(this, wxID_ANY, wxT("Start"));
triangleButton = new wxToggleButton(this, wxID_ANY, wxT("Triangle"));
triangleButtonPressure = new wxSpinCtrl(this, wxID_ANY, wxT("0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 255, 255);
squareButton = new wxToggleButton(this, wxID_ANY, wxT("Square"));
squareButtonPressure = new wxSpinCtrl(this, wxID_ANY, wxT("0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 255, 255);
circleButton = new wxToggleButton(this, wxID_ANY, wxT("Circle"));
circleButtonPressure = new wxSpinCtrl(this, wxID_ANY, wxT("0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 255, 255);
crossButton = new wxToggleButton(this, wxID_ANY, wxT("Cross"));
crossButtonPressure = new wxSpinCtrl(this, wxID_ANY, wxT("0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 255, 255);
leftAnalogXVal = new wxSlider(this, wxID_ANY, 0, -127, 127);
leftAnalogXValPrecise = new wxSpinCtrl(this, wxID_ANY, wxT("0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, -127, 128);
l3Button = new wxToggleButton(this, wxID_ANY, wxT("L3"));
leftAnalogYVal = new wxSlider(this, wxID_ANY, 0, -127, 127, wxDefaultPosition, wxDefaultSize, wxSL_VERTICAL);
leftAnalogYValPrecise = new wxSpinCtrl(this, wxID_ANY, wxT("0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, -127, 128);
rightAnalogXVal = new wxSlider(this, wxID_ANY, 0, -127, 127);
rightAnalogXValPrecise = new wxSpinCtrl(this, wxID_ANY, wxT("0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, -127, 128);
r3Button = new wxToggleButton(this, wxID_ANY, wxT("R3"));
rightAnalogYVal = new wxSlider(this, wxID_ANY, 0, -127, 127, wxDefaultPosition, wxDefaultSize, wxSL_VERTICAL);
rightAnalogYValPrecise = new wxSpinCtrl(this, wxID_ANY, wxT("0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, -127, 128);
// Initialize class members
VirtualPad::controllerPort = controllerPort;
// NOTE: Order MATTERS, these match enum defined in PadData.h
wxToggleButton* tempButtons[16] = {
// Pressure sensitive buttons
upButton, rightButton, leftButton, downButton,
crossButton, circleButton, squareButton, triangleButton,
l1Button, l2Button, r1Button, r2Button,
// Non-pressure sensitive buttons
l3Button, r3Button,
selectButton, startButton};
std::copy(std::begin(tempButtons), std::end(tempButtons), std::begin(buttons));
// NOTE: Order MATTERS, these match enum defined in PadData.h
wxSpinCtrl* tempPressureButtons[16] = {
// Pressure sensitive buttons
upButtonPressure, rightButtonPressure, leftButtonPressure, downButtonPressure,
crossButtonPressure, circleButtonPressure, squareButtonPressure, triangleButtonPressure,
l1ButtonPressure, l2ButtonPressure, r1ButtonPressure, r2ButtonPressure};
std::copy(std::begin(tempPressureButtons), std::end(tempPressureButtons), std::begin(buttonsPressure));
// NOTE: Order MATTERS, these match enum defined in PadData.h
wxSlider* tempAnalogSliders[4] = { leftAnalogXVal, leftAnalogYVal, rightAnalogXVal, rightAnalogYVal };
std::copy(std::begin(tempAnalogSliders), std::end(tempAnalogSliders), std::begin(analogSliders));
// NOTE: Order MATTERS, these match enum defined in PadData.h
wxSpinCtrl* tempAnalogVals[4] = { leftAnalogXValPrecise, leftAnalogYValPrecise, rightAnalogXValPrecise, rightAnalogYValPrecise };
std::copy(std::begin(tempAnalogVals), std::end(tempAnalogVals), std::begin(analogVals));
// Setup event bindings
for (int i = 0; i < buttonsLength; i++)
{
(*buttons[i]).Bind(wxEVT_TOGGLEBUTTON, &VirtualPad::OnButtonPress, this);
}
for (int i = 0; i < buttonsPressureLength; i++)
{
(*buttonsPressure[i]).Bind(wxEVT_SPINCTRL, &VirtualPad::OnPressureChange, this);
}
for (int i = 0; i < analogSlidersLength; i++)
{
(*analogSliders[i]).Bind(wxEVT_SLIDER, &VirtualPad::OnAnalogSliderChange, this);
}
for (int i = 0; i < analogValsLength; i++)
{
(*analogVals[i]).Bind(wxEVT_SPINCTRL, &VirtualPad::OnAnalogValChange, this);
}
// Finalize layout
SetProperties();
DoLayout();
}
void VirtualPad::SetProperties()
{
if (controllerPort == 0)
{
SetTitle(wxT("Virtual Pad - Port 1"));
}
else
{
SetTitle(wxT("Virtual Pad - Port 2"));
}
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
}
bool VirtualPad::Show(bool show)
{
if (!wxFrame::Show(show))
{
return false;
}
if (show)
{
g_RecordingInput.SetVirtualPadReading(controllerPort, true);
}
return true;
}
void VirtualPad::OnClose(wxCloseEvent & event)
{
g_RecordingInput.SetVirtualPadReading(controllerPort, false);
Hide();
}
void VirtualPad::OnButtonPress(wxCommandEvent & event)
{
wxToggleButton* pressedButton = (wxToggleButton*) event.GetEventObject();
int buttonId = -1;
for (int i = 0; i < buttonsLength; i++)
{
if (pressedButton == buttons[i])
{
buttonId = i;
}
}
if (buttonId != -1)
{
u8 pressure = 0;
if (event.IsChecked())
{
if (buttonId < 12)
{
pressure = buttonsPressure[buttonId]->GetValue();
}
else
{
pressure = 255;
}
}
g_RecordingInput.SetButtonState(controllerPort, PadData_NormalButton(buttonId), pressure);
}
}
void VirtualPad::OnPressureChange(wxSpinEvent & event)
{
wxSpinCtrl* updatedSpinner = (wxSpinCtrl*) event.GetEventObject();
int spinnerId = -1;
for (int i = 0; i < buttonsPressureLength; i++)
{
if (updatedSpinner == buttonsPressure[i])
{
spinnerId = i;
}
}
if (spinnerId != -1)
{
u8 pressure = 0;
if (event.IsChecked())
{
pressure = buttonsPressure[spinnerId]->GetValue();
}
g_RecordingInput.SetButtonState(controllerPort, PadData_NormalButton(spinnerId), pressure);
}
}
void VirtualPad::OnAnalogSliderChange(wxCommandEvent & event)
{
wxSlider* movedSlider = (wxSlider*) event.GetEventObject();
int sliderId = -1;
for (int i = 0; i < analogSlidersLength; i++)
{
if (movedSlider == analogSliders[i])
{
sliderId = i;
}
}
if (sliderId != -1)
{
if (sliderId % 2 == 0)
{
analogVals[sliderId]->SetValue(event.GetInt());
}
else
{
analogVals[sliderId]->SetValue(event.GetInt() * -1);
}
g_RecordingInput.UpdateAnalog(controllerPort, PadData_AnalogVector(sliderId), event.GetInt() + 127);
}
}
void VirtualPad::OnAnalogValChange(wxSpinEvent & event)
{
wxSpinCtrl* updatedSpinner = (wxSpinCtrl*)event.GetEventObject();
int spinnerId = -1;
for (int i = 0; i < analogValsLength; i++)
{
if (updatedSpinner == analogVals[i])
{
spinnerId = i;
}
}
if (spinnerId != -1)
{
analogVals[spinnerId]->SetValue(event.GetInt());
g_RecordingInput.UpdateAnalog(controllerPort, PadData_AnalogVector(spinnerId), event.GetInt() + 127);
}
}
void VirtualPad::DoLayout()
{
wxBoxSizer* container = new wxBoxSizer(wxVERTICAL);
wxBoxSizer* analogSticks = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* emptySpace6 = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* rightAnalogContainer = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* rightAnalog = new wxBoxSizer(wxVERTICAL);
wxBoxSizer* rightAnalogYContainer = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* rightAnalogY = new wxBoxSizer(wxVERTICAL);
wxBoxSizer* rightAnalogButtonAndGUI = new wxBoxSizer(wxVERTICAL);
wxBoxSizer* rightAnalogX = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* emptySpace5 = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* leftAnalogContainer = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* leftAnalog = new wxBoxSizer(wxVERTICAL);
wxBoxSizer* leftAnalogYContainer = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* leftAnalogY = new wxBoxSizer(wxVERTICAL);
wxBoxSizer* leftAnalogButtonAndGUI = new wxBoxSizer(wxVERTICAL);
wxBoxSizer* leftAnalogX = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* emptySpace4 = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* faceButtonRow = new wxBoxSizer(wxHORIZONTAL);
wxGridSizer* faceButtons = new wxGridSizer(0, 3, 0, 0);
wxBoxSizer* cross = new wxBoxSizer(wxVERTICAL);
wxBoxSizer* circle = new wxBoxSizer(wxVERTICAL);
wxBoxSizer* square = new wxBoxSizer(wxVERTICAL);
wxBoxSizer* triangle = new wxBoxSizer(wxVERTICAL);
wxBoxSizer* middleOfController = new wxBoxSizer(wxVERTICAL);
wxBoxSizer* emptySpace8 = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* startAndSelect = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* emptySpace9 = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* emptySpace7 = new wxBoxSizer(wxHORIZONTAL);
wxGridSizer* dPad = new wxGridSizer(0, 3, 0, 0);
wxBoxSizer* dPadDown = new wxBoxSizer(wxVERTICAL);
wxBoxSizer* dPadRight = new wxBoxSizer(wxVERTICAL);
wxBoxSizer* dPadLeft = new wxBoxSizer(wxVERTICAL);
wxBoxSizer* dPadUp = new wxBoxSizer(wxVERTICAL);
wxBoxSizer* shoulderButtons = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* emptySpace3 = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* rightShoulderButtons = new wxBoxSizer(wxVERTICAL);
wxBoxSizer* r1ButtonRow = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* r2ButtonRow = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* emptySpace2 = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* leftShoulderButtons = new wxBoxSizer(wxVERTICAL);
wxBoxSizer* l1ButtonRow = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* l2ButtonRow = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* emptySpace1 = new wxBoxSizer(wxVERTICAL);
emptySpace1->Add(0, 0, 0, 0, 0);
shoulderButtons->Add(emptySpace1, 2, wxEXPAND, 0);
l2ButtonRow->Add(l2Button, 0, wxEXPAND, 0);
l2ButtonRow->Add(l2ButtonPressure, 0, wxEXPAND, 0);
leftShoulderButtons->Add(l2ButtonRow, 1, wxEXPAND, 0);
l1ButtonRow->Add(l1Button, 0, wxEXPAND, 0);
l1ButtonRow->Add(l1ButtonPressure, 0, wxEXPAND, 0);
leftShoulderButtons->Add(l1ButtonRow, 1, wxEXPAND, 0);
shoulderButtons->Add(leftShoulderButtons, 5, wxEXPAND, 0);
emptySpace2->Add(0, 0, 0, 0, 0);
shoulderButtons->Add(emptySpace2, 13, wxEXPAND, 0);
r2ButtonRow->Add(r2Button, 0, wxEXPAND, 0);
r2ButtonRow->Add(r2ButtonPressure, 0, wxEXPAND, 0);
rightShoulderButtons->Add(r2ButtonRow, 1, wxEXPAND, 0);
r1ButtonRow->Add(r1Button, 0, wxEXPAND, 0);
r1ButtonRow->Add(r1ButtonPressure, 0, wxEXPAND, 0);
rightShoulderButtons->Add(r1ButtonRow, 1, wxEXPAND, 0);
shoulderButtons->Add(rightShoulderButtons, 5, wxEXPAND, 0);
emptySpace3->Add(0, 0, 0, 0, 0);
shoulderButtons->Add(emptySpace3, 2, wxEXPAND, 0);
container->Add(shoulderButtons, 1, wxBOTTOM | wxEXPAND | wxTOP, 3);
dPad->Add(0, 0, 0, 0, 0);
dPadUp->Add(upButton, 0, wxEXPAND, 0);
dPadUp->Add(upButtonPressure, 0, wxEXPAND, 0);
dPad->Add(dPadUp, 1, wxEXPAND, 0);
dPad->Add(0, 0, 0, 0, 0);
dPadLeft->Add(leftButton, 0, wxEXPAND, 0);
dPadLeft->Add(leftButtonPressure, 0, wxEXPAND, 0);
dPad->Add(dPadLeft, 1, wxEXPAND, 0);
dPad->Add(0, 0, 0, 0, 0);
dPadRight->Add(rightButton, 0, wxEXPAND, 0);
dPadRight->Add(rightButtonPressure, 0, wxEXPAND, 0);
dPad->Add(dPadRight, 1, wxEXPAND, 0);
dPad->Add(0, 0, 0, 0, 0);
dPadDown->Add(downButton, 0, wxEXPAND, 0);
dPadDown->Add(downButtonPressure, 0, wxEXPAND, 0);
dPad->Add(dPadDown, 1, wxEXPAND, 0);
dPad->Add(0, 0, 0, 0, 0);
faceButtonRow->Add(dPad, 9, wxEXPAND | wxLEFT | wxRIGHT, 3);
emptySpace7->Add(0, 0, 0, 0, 0);
middleOfController->Add(emptySpace7, 1, wxEXPAND, 0);
startAndSelect->Add(selectButton, 0, 0, 0);
emptySpace9->Add(0, 0, 0, 0, 0);
startAndSelect->Add(emptySpace9, 1, wxEXPAND, 0);
startAndSelect->Add(startButton, 0, 0, 0);
middleOfController->Add(startAndSelect, 1, wxEXPAND, 0);
emptySpace8->Add(0, 0, 0, 0, 0);
middleOfController->Add(emptySpace8, 1, wxEXPAND, 0);
faceButtonRow->Add(middleOfController, 8, wxEXPAND | wxLEFT | wxRIGHT, 3);
faceButtons->Add(0, 0, 0, 0, 0);
triangle->Add(triangleButton, 0, wxEXPAND, 0);
triangle->Add(triangleButtonPressure, 0, wxEXPAND, 0);
faceButtons->Add(triangle, 1, wxEXPAND, 0);
faceButtons->Add(0, 0, 0, 0, 0);
square->Add(squareButton, 0, wxEXPAND, 0);
square->Add(squareButtonPressure, 0, wxEXPAND, 0);
faceButtons->Add(square, 1, wxEXPAND, 0);
faceButtons->Add(0, 0, 0, 0, 0);
circle->Add(circleButton, 0, wxEXPAND, 0);
circle->Add(circleButtonPressure, 0, wxEXPAND, 0);
faceButtons->Add(circle, 1, wxEXPAND, 0);
faceButtons->Add(0, 0, 0, 0, 0);
cross->Add(crossButton, 0, wxEXPAND, 0);
cross->Add(crossButtonPressure, 0, wxEXPAND, 0);
faceButtons->Add(cross, 1, wxEXPAND, 0);
faceButtons->Add(0, 0, 0, 0, 0);
faceButtonRow->Add(faceButtons, 9, wxEXPAND | wxLEFT | wxRIGHT, 3);
container->Add(faceButtonRow, 4, wxBOTTOM | wxEXPAND | wxTOP, 3);
emptySpace4->Add(0, 0, 0, 0, 0);
analogSticks->Add(emptySpace4, 6, wxEXPAND, 0);
leftAnalogX->Add(leftAnalogXVal, 1, wxALL | wxEXPAND, 0);
leftAnalogX->Add(leftAnalogXValPrecise, 0, wxEXPAND, 0);
leftAnalog->Add(leftAnalogX, 1, wxEXPAND, 0);
leftAnalogButtonAndGUI->Add(0, 0, 0, 0, 0);
leftAnalogButtonAndGUI->Add(l3Button, 0, wxALIGN_CENTER, 0);
leftAnalogYContainer->Add(leftAnalogButtonAndGUI, 1, wxEXPAND, 0);
leftAnalogY->Add(leftAnalogYVal, 1, wxALIGN_RIGHT, 0);
leftAnalogY->Add(leftAnalogYValPrecise, 0, wxALIGN_RIGHT, 0);
leftAnalogYContainer->Add(leftAnalogY, 1, wxEXPAND, 0);
leftAnalog->Add(leftAnalogYContainer, 5, wxEXPAND, 0);
leftAnalogContainer->Add(leftAnalog, 1, wxEXPAND, 0);
analogSticks->Add(leftAnalogContainer, 6, wxEXPAND, 0);
emptySpace5->Add(0, 0, 0, 0, 0);
analogSticks->Add(emptySpace5, 3, wxEXPAND, 0);
rightAnalogX->Add(rightAnalogXVal, 1, wxEXPAND, 0);
rightAnalogX->Add(rightAnalogXValPrecise, 0, wxEXPAND, 0);
rightAnalog->Add(rightAnalogX, 1, wxEXPAND, 0);
rightAnalogButtonAndGUI->Add(0, 0, 0, 0, 0);
rightAnalogButtonAndGUI->Add(r3Button, 0, wxALIGN_CENTER, 0);
rightAnalogYContainer->Add(rightAnalogButtonAndGUI, 1, wxEXPAND, 0);
rightAnalogY->Add(rightAnalogYVal, 1, wxALIGN_RIGHT, 0);
rightAnalogY->Add(rightAnalogYValPrecise, 0, wxALIGN_RIGHT | wxEXPAND, 0);
rightAnalogYContainer->Add(rightAnalogY, 1, wxEXPAND, 0);
rightAnalog->Add(rightAnalogYContainer, 5, wxEXPAND, 0);
rightAnalogContainer->Add(rightAnalog, 1, wxEXPAND, 0);
analogSticks->Add(rightAnalogContainer, 6, wxEXPAND, 0);
emptySpace6->Add(0, 0, 0, 0, 0);
analogSticks->Add(emptySpace6, 6, wxEXPAND, 0);
container->Add(analogSticks, 3, wxBOTTOM | wxEXPAND | wxTOP, 3);
SetSizer(container);
Layout();
}
#endif

View File

@ -1,94 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2019 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
#include <wx/wx.h>
#include <wx/tglbtn.h>
#include <wx/spinctrl.h>
#include "Recording/PadData.h"
#ifndef DISABLE_RECORDING
class VirtualPad : public wxFrame
{
public:
VirtualPad(wxWindow* parent, wxWindowID id, const wxString& title, int controllerPort, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_FRAME_STYLE);
bool Show(bool show = true) override;
private:
void SetProperties();
void DoLayout();
int controllerPort;
wxToggleButton* l2Button;
wxSpinCtrl* l2ButtonPressure;
wxToggleButton* l1Button;
wxSpinCtrl* l1ButtonPressure;
wxToggleButton* r2Button;
wxSpinCtrl* r2ButtonPressure;
wxToggleButton* r1Button;
wxSpinCtrl* r1ButtonPressure;
wxToggleButton* upButton;
wxSpinCtrl* upButtonPressure;
wxToggleButton* leftButton;
wxSpinCtrl* leftButtonPressure;
wxToggleButton* rightButton;
wxSpinCtrl* rightButtonPressure;
wxToggleButton* downButton;
wxSpinCtrl* downButtonPressure;
wxToggleButton* startButton;
wxToggleButton* selectButton;
wxToggleButton* triangleButton;
wxSpinCtrl* triangleButtonPressure;
wxToggleButton* squareButton;
wxSpinCtrl* squareButtonPressure;
wxToggleButton* circleButton;
wxSpinCtrl* circleButtonPressure;
wxToggleButton* crossButton;
wxSpinCtrl* crossButtonPressure;
wxSlider* leftAnalogXVal;
wxSpinCtrl* leftAnalogXValPrecise;
wxToggleButton* l3Button;
wxSlider* leftAnalogYVal;
wxSpinCtrl* leftAnalogYValPrecise;
wxSlider* rightAnalogXVal;
wxSpinCtrl* rightAnalogXValPrecise;
wxToggleButton* r3Button;
wxSlider* rightAnalogYVal;
wxSpinCtrl* rightAnalogYValPrecise;
wxToggleButton* buttons[16];
int buttonsLength = 16;
wxSpinCtrl* buttonsPressure[12];
int buttonsPressureLength = 12;
wxSlider* analogSliders[4];
int analogSlidersLength = 4;
wxSpinCtrl* analogVals[4];
int analogValsLength = 4;
void OnClose(wxCloseEvent &event);
void OnButtonPress(wxCommandEvent &event);
void OnPressureChange(wxSpinEvent &event);
void OnAnalogValChange(wxSpinEvent &event);
void OnAnalogSliderChange(wxCommandEvent &event);
// TODO - reset button
protected:
wxDECLARE_EVENT_TABLE();
};
#endif