Improved touchpad sensitivity

This commit is contained in:
Hyper 2025-01-22 23:12:08 +00:00
parent 60104dbe99
commit 5e0ed3e20c
5 changed files with 157 additions and 27 deletions

View file

@ -2,6 +2,7 @@
#include <SDL.h>
#include <user/config.h>
#include <hid/hid.h>
#include <os/logger.h>
#include <ui/game_window.h>
#include <kernel/xdm.h>
#include <app.h>
@ -170,6 +171,15 @@ static void SetControllerInputDevice(Controller* controller)
hid::g_inputDevice = controller->GetInputDevice();
hid::g_inputDeviceController = hid::g_inputDevice;
auto controllerType = (hid::EInputDeviceExplicit)controller->GetControllerType();
if (hid::g_inputDeviceExplicit != controllerType)
{
hid::g_inputDeviceExplicit = controllerType;
LOGFN("Detected controller: {}", hid::GetInputDeviceName());
}
}
int HID_OnSDLEvent(void*, SDL_Event* event)
@ -199,6 +209,7 @@ int HID_OnSDLEvent(void*, SDL_Event* event)
case SDL_CONTROLLERBUTTONDOWN:
case SDL_CONTROLLERBUTTONUP:
case SDL_CONTROLLERAXISMOTION:
case SDL_CONTROLLERTOUCHPADDOWN:
{
auto* controller = FindController(event->cdevice.which);

View file

@ -2,6 +2,7 @@
hid::EInputDevice hid::g_inputDevice;
hid::EInputDevice hid::g_inputDeviceController;
hid::EInputDeviceExplicit hid::g_inputDeviceExplicit;
uint16_t hid::g_prohibitedButtons;
@ -15,3 +16,59 @@ bool hid::IsInputDeviceController()
return hid::g_inputDevice != hid::EInputDevice::Keyboard &&
hid::g_inputDevice != hid::EInputDevice::Mouse;
}
std::string hid::GetInputDeviceName()
{
switch (g_inputDevice)
{
case EInputDevice::Keyboard:
return "Keyboard";
case EInputDevice::Mouse:
return "Mouse";
}
switch (g_inputDeviceExplicit)
{
case EInputDeviceExplicit::Xbox360:
return "Xbox 360";
case EInputDeviceExplicit::XboxOne:
return "Xbox One";
case EInputDeviceExplicit::DualShock3:
return "DualShock 3";
case EInputDeviceExplicit::DualShock4:
return "DualShock 4";
case EInputDeviceExplicit::SwitchPro:
return "Nintendo Switch Pro";
case EInputDeviceExplicit::Virtual:
return "Virtual";
case EInputDeviceExplicit::DualSense:
return "DualSense";
case EInputDeviceExplicit::Luna:
return "Amazon Luna";
case EInputDeviceExplicit::Stadia:
return "Google Stadia";
case EInputDeviceExplicit::NvShield:
return "NVIDIA Shield";
case EInputDeviceExplicit::SwitchJCLeft:
return "Nintendo Switch Joy-Con (Left)";
case EInputDeviceExplicit::SwitchJCRight:
return "Nintendo Switch Joy-Con (Right)";
case EInputDeviceExplicit::SwitchJCPair:
return "Nintendo Switch Joy-Con (Pair)";
}
return "Unknown";
}

View file

@ -10,8 +10,27 @@ namespace hid
PlayStation
};
enum class EInputDeviceExplicit
{
Unknown,
Xbox360,
XboxOne,
DualShock3,
DualShock4,
SwitchPro,
Virtual,
DualSense,
Luna,
Stadia,
NvShield,
SwitchJCLeft,
SwitchJCRight,
SwitchJCPair
};
extern EInputDevice g_inputDevice;
extern EInputDevice g_inputDeviceController;
extern EInputDeviceExplicit g_inputDeviceExplicit;
extern uint16_t g_prohibitedButtons;
@ -23,4 +42,5 @@ namespace hid
uint32_t GetCapabilities(uint32_t dwUserIndex, XAMINPUT_CAPABILITIES* pCaps);
bool IsInputDeviceController();
std::string GetInputDeviceName();
}

View file

@ -1,16 +1,46 @@
#include <api/SWA.h>
#include <hid/hid.h>
#include <ui/sdl_listener.h>
#include <app.h>
#include <exports.h>
constexpr float WORLD_MAP_TOUCH_CANCEL_DEADZONE = 0.31f;
constexpr float WORLD_MAP_TOUCH_DAMPING_FACTOR = 0.99f;
constexpr float WORLD_MAP_TOUCH_FLICK_ACCELERATION_X = 0.4f;
constexpr float WORLD_MAP_TOUCH_FLICK_ACCELERATION_Y = 0.2f;
constexpr float WORLD_MAP_TOUCH_FLICK_TERMINAL_VELOCITY = 40.0f;
constexpr float WORLD_MAP_TOUCH_FLICK_THRESHOLD = 2.25f;
constexpr float WORLD_MAP_TOUCH_SENSITIVITY_MULTIPLIER = 1.35f;
constexpr float WORLD_MAP_TOUCH_SMOOTHING_FACTOR = 0.8f;
class WorldMapTouchParams
{
public:
float CancelDeadzone{ 0.31f };
float Damping{ 0.99f };
float FlickAccelX{ 0.25f };
float FlickAccelY{ 0.1f };
float FlickTerminalVelocity{ 40.0f };
float FlickThreshold{ 2.25f };
float SensitivityX{};
float SensitivityY{};
float Smoothing{ 0.8f };
};
class WorldMapTouchParamsProspero : public WorldMapTouchParams
{
public:
WorldMapTouchParamsProspero()
{
SensitivityX = 1.15f;
SensitivityY = 1.05f;
}
}
g_worldMapTouchParamsProspero;
class WorldMapTouchParamsOrbis : public WorldMapTouchParams
{
public:
WorldMapTouchParamsOrbis()
{
SensitivityX = 0.95f;
SensitivityY = 1.0f;
}
}
g_worldMapTouchParamsOrbis;
WorldMapTouchParams g_worldMapTouchParams{};
static bool g_isTouchActive;
@ -39,37 +69,32 @@ public:
if (g_isTouchActive)
{
constexpr auto sensitivity = WORLD_MAP_TOUCH_SENSITIVITY_MULTIPLIER;
auto dxNorm = ms_touchpadDeltaX / referenceDeltaTime;
auto dyNorm = ms_touchpadDeltaY / referenceDeltaTime;
auto dxSens = dxNorm * sensitivity;
auto dySens = dyNorm * sensitivity;
auto dxSens = dxNorm * g_worldMapTouchParams.SensitivityX;
auto dySens = dyNorm * g_worldMapTouchParams.SensitivityY;
auto smoothing = powf(WORLD_MAP_TOUCH_SMOOTHING_FACTOR, deltaTime / referenceDeltaTime);
auto smoothing = powf(g_worldMapTouchParams.Smoothing, deltaTime / referenceDeltaTime);
g_worldMapTouchVelocityX = smoothing * g_worldMapTouchVelocityX + (1.0f - smoothing) * dxSens;
g_worldMapTouchVelocityY = smoothing * g_worldMapTouchVelocityY + (1.0f - smoothing) * dySens;
constexpr auto flickThreshold = WORLD_MAP_TOUCH_FLICK_THRESHOLD;
auto flickThreshold = g_worldMapTouchParams.FlickThreshold;
if (fabs(dxSens) > flickThreshold || fabs(dySens) > flickThreshold)
{
constexpr auto flickAccelX = WORLD_MAP_TOUCH_FLICK_ACCELERATION_X;
constexpr auto flickAccelY = WORLD_MAP_TOUCH_FLICK_ACCELERATION_Y;
g_worldMapTouchVelocityX += dxNorm * flickAccelX * (deltaTime / referenceDeltaTime);
g_worldMapTouchVelocityY += dyNorm * flickAccelY * (deltaTime / referenceDeltaTime);
g_worldMapTouchVelocityX += dxNorm * g_worldMapTouchParams.FlickAccelX * (deltaTime / referenceDeltaTime);
g_worldMapTouchVelocityY += dyNorm * g_worldMapTouchParams.FlickAccelY * (deltaTime / referenceDeltaTime);
}
constexpr auto terminalVelocity = WORLD_MAP_TOUCH_FLICK_TERMINAL_VELOCITY;
auto terminalVelocity = g_worldMapTouchParams.FlickTerminalVelocity;
g_worldMapTouchVelocityX = std::clamp(g_worldMapTouchVelocityX, -terminalVelocity, terminalVelocity);
g_worldMapTouchVelocityY = std::clamp(g_worldMapTouchVelocityY, -terminalVelocity, terminalVelocity);
}
else
{
auto dampingFactor = powf(WORLD_MAP_TOUCH_DAMPING_FACTOR, deltaTime / referenceDeltaTime);
auto dampingFactor = powf(g_worldMapTouchParams.Damping, deltaTime / referenceDeltaTime);
g_worldMapTouchVelocityX *= dampingFactor;
g_worldMapTouchVelocityY *= dampingFactor;
@ -101,10 +126,17 @@ public:
}
case SDL_CONTROLLERTOUCHPADDOWN:
{
g_worldMapTouchParams = hid::g_inputDeviceExplicit == hid::EInputDeviceExplicit::DualSense
? (WorldMapTouchParams)g_worldMapTouchParamsProspero
: (WorldMapTouchParams)g_worldMapTouchParamsOrbis;
ms_touchpadFingerCount++;
ms_touchpadPrevX = event->ctouchpad.x;
ms_touchpadPrevY = event->ctouchpad.y;
break;
}
case SDL_CONTROLLERTOUCHPADUP:
g_isTouchActive = false;
@ -199,7 +231,17 @@ bool WorldMapTouchSupportMidAsmHook()
{
SDLEventListenerForInputPatches::Update(App::s_deltaTime);
return fabs(g_worldMapTouchVelocityX) > 0 || fabs(g_worldMapTouchVelocityY) > 0;
auto vxAbs = fabs(g_worldMapTouchVelocityX);
auto vyAbs = fabs(g_worldMapTouchVelocityY);
/* Reduce touch noise if the player has
their finger resting on the touchpad,
but allow much precise values without
touch for proper interpolation to zero. */
if (vxAbs < 0.05f || vyAbs < 0.05f)
return !g_isTouchActive;
return vxAbs > 0 || vyAbs > 0;
}
bool WorldMapTouchMagnetismSupportMidAsmHook(PPCRegister& f0)
@ -211,8 +253,8 @@ void TouchAndDPadSupportWorldMapXMidAsmHook(PPCRegister& pPadState, PPCRegister&
{
auto pGuestPadState = (SWA::SPadState*)g_memory.Translate(pPadState.u32);
if (fabs(pGuestPadState->LeftStickHorizontal) > WORLD_MAP_TOUCH_CANCEL_DEADZONE ||
fabs(pGuestPadState->LeftStickVertical) > WORLD_MAP_TOUCH_CANCEL_DEADZONE)
if (fabs(pGuestPadState->LeftStickHorizontal) > g_worldMapTouchParams.CancelDeadzone ||
fabs(pGuestPadState->LeftStickVertical) > g_worldMapTouchParams.CancelDeadzone)
{
g_worldMapTouchVelocityX = 0;
}
@ -234,8 +276,8 @@ void TouchAndDPadSupportWorldMapYMidAsmHook(PPCRegister& pPadState, PPCRegister&
{
auto pGuestPadState = (SWA::SPadState*)g_memory.Translate(pPadState.u32);
if (fabs(pGuestPadState->LeftStickHorizontal) > WORLD_MAP_TOUCH_CANCEL_DEADZONE ||
fabs(pGuestPadState->LeftStickVertical) > WORLD_MAP_TOUCH_CANCEL_DEADZONE)
if (fabs(pGuestPadState->LeftStickHorizontal) > g_worldMapTouchParams.CancelDeadzone ||
fabs(pGuestPadState->LeftStickVertical) > g_worldMapTouchParams.CancelDeadzone)
{
g_worldMapTouchVelocityY = 0;
}

@ -1 +1 @@
Subproject commit 3280a7cf9f3be293ff051b9d56d5dccff79f45ba
Subproject commit 73b75e197a6b9e8c1ad693f926c044d0f8f23a0b