TLAC slider emulator: more directly emulate input data to avoid tracking section state, testing for ps4 official controller slider support
also allow slider in menu (toggle in keyconfig) and remove need for hardware slider disabling patch (patches/launcher)
This commit is contained in:
@@ -78,8 +78,6 @@ No_Timer_Sprite=1
|
||||
Unlock_Pseudo=0
|
||||
#Enable the card menu (incomplete, it doesn't bypass the card prompt)
|
||||
Card=0
|
||||
#Allow using a real arcade slider attached to COM11
|
||||
Hardware_Slider=0
|
||||
#Enable custom patches
|
||||
Custom_Patches=1
|
||||
#Prevent data deletion
|
||||
|
||||
@@ -24,6 +24,14 @@ rumble =true
|
||||
# Pause when focus is lost
|
||||
autopause =true
|
||||
|
||||
# allow using slider in menus
|
||||
# (recommended to disable this and remove MENU_L/R bindings if you have a real slider)
|
||||
slider_in_menus =false
|
||||
|
||||
# use the hardware slider from hori FT official controller
|
||||
# warning: alpha untested feature, may not work
|
||||
ps4_official_slider =false
|
||||
|
||||
# JVS Buttons:
|
||||
JVS_TEST = F1
|
||||
JVS_SERVICE = F2
|
||||
|
||||
@@ -222,9 +222,6 @@ ConfigOptionBase* optionsArray[] = {
|
||||
new NumericOption(L"xinput_preferred", KEYCONFIG_SECTION, KEYCONFIG_FILE, L"XInput Controller Num:", L"Sets the preferred XInput controller.\nIf unavailable, the next connected controller is used.", 0, 0, 3),
|
||||
new OptionMetaSpacer(8),
|
||||
|
||||
new BooleanOption(L"hardware_slider", PATCHES_SECTION, CONFIG_FILE, L"Use Hardware Slider", L"Enable this if using a real arcade slider.\n(set the slider to port COM11)", false, false),
|
||||
new OptionMetaSpacer(8),
|
||||
|
||||
new BooleanOption(L"opengl_patch_a", LAUNCHER_SECTION, CONFIG_FILE, L"OpenGL Patch A", L"Ignores some OpenGL-related errors. Don't use both patches at the same time unless you're know what you're doing.", false, false),
|
||||
new BooleanOption(L"opengl_patch_b", LAUNCHER_SECTION, CONFIG_FILE, L"OpenGL Patch B", L"Ignores some OpenGL-related errors. Don't use both patches at the same time unless you're know what you're doing.", false, false),
|
||||
new OptionMetaSpacer(8),
|
||||
|
||||
@@ -786,12 +786,6 @@ void ApplyPatches() {
|
||||
{
|
||||
InjectCode((void*)0x0000000140565E6B, { 0x90, 0x90 });
|
||||
}
|
||||
// The original slider update needs to run for hardware sliders to work -- only patch it when using emulation
|
||||
if (!nHardwareSlider)
|
||||
{
|
||||
// Don't update the touch slider state so we can write our own
|
||||
InjectCode((void*)0x000000014061579B, { 0x90, 0x90, 0x90, 0x8B, 0x42, 0xE0, 0x90, 0x90, 0x90 });
|
||||
}
|
||||
// Quick start
|
||||
{
|
||||
if (nQuickStart == 1) // skip the card/guest screen
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "../../Input/Keyboard/Keyboard.h"
|
||||
#include "../../Input/Bindings/KeyboardBinding.h"
|
||||
#include "../../Input/KeyConfig/Config.h"
|
||||
#include "../../Input/DirectInput/Ds4/DualShock4.h"
|
||||
#include "../../FileSystem/ConfigFile.h"
|
||||
#include "../../Utilities/Math.h"
|
||||
#include <algorithm>
|
||||
@@ -55,16 +56,22 @@ namespace TLAC::Components
|
||||
FileSystem::ConfigFile configFile(framework::GetModuleDirectory(), KEY_CONFIG_FILE_NAME);
|
||||
configFile.OpenRead();
|
||||
|
||||
Config::BindConfigKeys(configFile.ConfigMap, "LEFT_SIDE_SLIDE_LEFT", *LeftSideSlideLeft, { "Q" });
|
||||
Config::BindConfigKeys(configFile.ConfigMap, "LEFT_SIDE_SLIDE_RIGHT", *LeftSideSlideRight, { "E" });
|
||||
usePs4OfficialSlider = configFile.GetBooleanValue("ps4_official_slider");
|
||||
enableInMenus = configFile.GetBooleanValue("slider_in_menus");
|
||||
|
||||
Config::BindConfigKeys(configFile.ConfigMap, "RIGHT_SIDE_SLIDE_LEFT", *RightSideSlideLeft, { "U" });
|
||||
Config::BindConfigKeys(configFile.ConfigMap, "RIGHT_SIDE_SLIDE_RIGHT", *RightSideSlideRight, { "O" });
|
||||
if (!usePs4OfficialSlider)
|
||||
{
|
||||
Config::BindConfigKeys(configFile.ConfigMap, "LEFT_SIDE_SLIDE_LEFT", *LeftSideSlideLeft, { "Q" });
|
||||
Config::BindConfigKeys(configFile.ConfigMap, "LEFT_SIDE_SLIDE_RIGHT", *LeftSideSlideRight, { "E" });
|
||||
|
||||
float touchSliderEmulationSpeed = configFile.GetFloatValue("touch_slider_emulation_speed");
|
||||
|
||||
if (touchSliderEmulationSpeed != 0.0f)
|
||||
sliderSpeed = touchSliderEmulationSpeed;
|
||||
Config::BindConfigKeys(configFile.ConfigMap, "RIGHT_SIDE_SLIDE_LEFT", *RightSideSlideLeft, { "U" });
|
||||
Config::BindConfigKeys(configFile.ConfigMap, "RIGHT_SIDE_SLIDE_RIGHT", *RightSideSlideRight, { "O" });
|
||||
|
||||
float touchSliderEmulationSpeed = configFile.GetFloatValue("touch_slider_emulation_speed");
|
||||
|
||||
if (touchSliderEmulationSpeed != 0.0f)
|
||||
sliderSpeed = touchSliderEmulationSpeed;
|
||||
}
|
||||
}
|
||||
|
||||
void TouchSliderEmulator::Update()
|
||||
@@ -74,20 +81,46 @@ namespace TLAC::Components
|
||||
|
||||
void TouchSliderEmulator::UpdateInput()
|
||||
{
|
||||
if (!componentsManager->GetUpdateGameInput() || componentsManager->IsDwGuiActive() || !(*(GameState*)CURRENT_GAME_STATE_ADDRESS == GS_GAME && *(SubGameState*)CURRENT_GAME_SUB_STATE_ADDRESS == SUB_GAME_MAIN))
|
||||
if (!componentsManager->GetUpdateGameInput() || componentsManager->IsDwGuiActive() || (!enableInMenus && !(*(GameState*)CURRENT_GAME_STATE_ADDRESS == GS_GAME && *(SubGameState*)CURRENT_GAME_SUB_STATE_ADDRESS == SUB_GAME_MAIN)))
|
||||
return;
|
||||
|
||||
sliderIncrement = GetElapsedTime() / sliderSpeed;
|
||||
if (usePs4OfficialSlider)
|
||||
{
|
||||
DualShock4* ds4 = DualShock4::GetInstance();
|
||||
if (ds4 == nullptr)
|
||||
return;
|
||||
|
||||
constexpr float sensorStep = (1.0f / SLIDER_SENSORS);
|
||||
Joystick ls = ds4->GetLeftStick();
|
||||
Joystick rs = ds4->GetRightStick();
|
||||
|
||||
EmulateSliderInput(LeftSideSlideLeft, LeftSideSlideRight, ContactPoints[0], 0.0f, 0.5f);
|
||||
EmulateSliderInput(RightSideSlideLeft, RightSideSlideRight, ContactPoints[1], 0.5f + sensorStep, 1.0f + sensorStep);
|
||||
// test data
|
||||
// normalised the same as ds4 sticks, except instead of ushort this uses bytes
|
||||
// hopefully the scaling to 16 bits doesn't screw things up lol
|
||||
//Joystick ls = Joystick((float)(0b10101010) / 255 * 2.0f - 1.0f, (float)(0b10000000) / 255 * 2.0f - 1.0f);
|
||||
//Joystick rs = Joystick((float)(0b10000001) / 255 * 2.0f - 1.0f, (float)(0b11001100) / 255 * 2.0f - 1.0f);
|
||||
|
||||
sliderState->ResetSensors();
|
||||
uint32_t state = 0;
|
||||
state |= (uint8_t)((ls.XAxis + 1.0) * 127.5) ^ 0b10000000;
|
||||
state |= ((uint8_t)((ls.YAxis + 1.0) * 127.5) ^ 0b10000000) << 8;
|
||||
state |= ((uint8_t)((rs.XAxis + 1.0) * 127.5) ^ 0b10000000) << 16;
|
||||
state |= ((uint8_t)((rs.YAxis + 1.0) * 127.5) ^ 0b10000000) << 24;
|
||||
|
||||
for (int i = 0; i < CONTACT_POINTS; i++)
|
||||
ApplyContactPoint(ContactPoints[i], i);
|
||||
ApplyBitfieldState(state);
|
||||
}
|
||||
else
|
||||
{
|
||||
sliderIncrement = GetElapsedTime() / sliderSpeed;
|
||||
|
||||
constexpr float sensorStep = (1.0f / SLIDER_SENSORS);
|
||||
|
||||
EmulateSliderInput(LeftSideSlideLeft, LeftSideSlideRight, ContactPoints[0], 0.0f, 0.5f);
|
||||
EmulateSliderInput(RightSideSlideLeft, RightSideSlideRight, ContactPoints[1], 0.5f + sensorStep, 1.0f + sensorStep);
|
||||
|
||||
sliderState->ResetSensors();
|
||||
|
||||
for (int i = 0; i < CONTACT_POINTS; i++)
|
||||
ApplyContactPoint(ContactPoints[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void TouchSliderEmulator::OnFocusLost()
|
||||
@@ -120,23 +153,25 @@ namespace TLAC::Components
|
||||
contactPoint.InContact = leftDown || rightDown;
|
||||
}
|
||||
|
||||
void TouchSliderEmulator::ApplyContactPoint(ContactPoint &contactPoint, int section)
|
||||
void TouchSliderEmulator::ApplyContactPoint(ContactPoint& contactPoint)
|
||||
{
|
||||
sliderState->SectionTouched[section] = contactPoint.InContact;
|
||||
|
||||
int pressure = contactPoint.InContact ? FULL_PRESSURE : NO_PRESSURE;
|
||||
float position = std::clamp(contactPoint.Position, 0.0f, 1.0f);
|
||||
|
||||
if (contactPoint.InContact)
|
||||
{
|
||||
float position = std::clamp(contactPoint.Position, 0.0f, 1.0f);
|
||||
int sensor = (int)(position * (SLIDER_SENSORS - 1));
|
||||
|
||||
sliderState->SetSensor(sensor, pressure);
|
||||
sliderState->SetSensor(sensor, FULL_PRESSURE);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr float startRange = -1.0f;
|
||||
constexpr float endRange = +1.0f;
|
||||
|
||||
sliderState->SectionPositions[section] = contactPoint.InContact ? (ConvertRange(0.0f, 1.0f, startRange, endRange, position)) : 0.0f;
|
||||
void TouchSliderEmulator::ApplyBitfieldState(uint32_t state)
|
||||
{
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
if (state & (1 << (31 - i)))
|
||||
sliderState->SetSensor(i, FULL_PRESSURE);
|
||||
else
|
||||
sliderState->SetSensor(i, NO_PRESSURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,10 @@ namespace TLAC::Components
|
||||
Input::Binding* RightSideSlideLeft;
|
||||
Input::Binding* RightSideSlideRight;
|
||||
|
||||
bool usePs4OfficialSlider;
|
||||
|
||||
bool enableInMenus;
|
||||
|
||||
TouchSliderEmulator();
|
||||
~TouchSliderEmulator();
|
||||
|
||||
@@ -53,7 +57,8 @@ namespace TLAC::Components
|
||||
ContactPoint ContactPoints[CONTACT_POINTS];
|
||||
|
||||
void EmulateSliderInput(Input::Binding *leftBinding, Input::Binding *rightBinding, ContactPoint &contactPoint, float start, float end);
|
||||
void ApplyContactPoint(ContactPoint &contactPoint, int section);
|
||||
void ApplyContactPoint(ContactPoint &contactPoint);
|
||||
void ApplyBitfieldState(uint32_t state);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,15 @@ namespace TLAC::Components
|
||||
if (index < 0 || index >= SLIDER_SENSORS)
|
||||
return;
|
||||
|
||||
SensorPressureLevels[index] = value;
|
||||
SensorTouched[index].IsTouched = value > 0;
|
||||
uint32_t* ph = SerialState->sliderSerialResponse.sensors[index].pressureHistory;
|
||||
ph[3] = ph[2];
|
||||
ph[2] = ph[1];
|
||||
ph[1] = ph[0];
|
||||
ph[0] = value;
|
||||
|
||||
SerialState->sliderSerialResponse.scanMode = 1;
|
||||
SerialState->sliderSerialResponse.scanCount = 1;
|
||||
SerialState->sliderResponseCnt = 1;
|
||||
}
|
||||
|
||||
void TouchSliderState::ResetSensors()
|
||||
|
||||
@@ -10,9 +10,37 @@
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
struct TouchSliderSerialState
|
||||
{
|
||||
uint8_t padding[0x1960];
|
||||
|
||||
int sliderResponseCnt;
|
||||
struct
|
||||
{
|
||||
int scanMode;
|
||||
int scanCount;
|
||||
struct
|
||||
{
|
||||
uint32_t pressureHistory[4]; // first: current, second: last sample, ...
|
||||
} sensors[SLIDER_SENSORS];
|
||||
} sliderSerialResponse;
|
||||
|
||||
struct
|
||||
{
|
||||
int scanMode;
|
||||
int scanCount;
|
||||
struct
|
||||
{
|
||||
uint32_t pressureHistory[4]; // first: current, second: last sample, ...
|
||||
} sensors[SLIDER_SENSORS];
|
||||
} sliderSerialResponseCopy; // the other one is copied here by the game, feel free to ignore it
|
||||
};
|
||||
|
||||
struct TouchSliderState
|
||||
{
|
||||
uint8_t Padding0000[112];
|
||||
uint8_t Padding0000[104];
|
||||
|
||||
TouchSliderSerialState* SerialState;
|
||||
|
||||
int32_t State;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user