Windows: Normalize left and right analog stick.
This commit is contained in:
parent
540a5e3a3b
commit
c9428975fe
3 changed files with 108 additions and 53 deletions
|
@ -26,15 +26,11 @@
|
|||
#include "Common/System/NativeApp.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/HLE/sceCtrl.h"
|
||||
#include "Core/KeyMap.h"
|
||||
#include "Core/Reporting.h"
|
||||
#include "Windows/DinputDevice.h"
|
||||
#pragma comment(lib,"dinput8.lib")
|
||||
|
||||
#ifdef min
|
||||
#undef min
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
//initialize static members of DinputDevice
|
||||
unsigned int DinputDevice::pInstances = 0;
|
||||
LPDIRECTINPUT8 DinputDevice::pDI = NULL;
|
||||
|
@ -227,6 +223,69 @@ inline float LinearMaps(float val, float a0, float a1, float b0, float b1) {
|
|||
return b0 + (((val - a0) * (b1 - b0)) / (a1 - a0));
|
||||
}
|
||||
|
||||
static void ApplyNormalization(LONG &jsx, LONG &jsy) {
|
||||
// Circle to Square mapping, cribbed from XInputDevice
|
||||
float sx = (float)jsx;
|
||||
float sy = (float)jsy;
|
||||
float scaleFactor = sqrtf((sx * sx + sy * sy) / std::max(sx * sx, sy * sy));
|
||||
jsx = (int)(sx * scaleFactor);
|
||||
jsy = (int)(sy * scaleFactor);
|
||||
|
||||
// Linear range mapping (used to invert deadzones)
|
||||
float dz = g_Config.fDInputAnalogDeadzone;
|
||||
int idzm = g_Config.iDInputAnalogInverseMode;
|
||||
float idz = g_Config.fDInputAnalogInverseDeadzone;
|
||||
float md = std::max(dz, idz);
|
||||
float st = g_Config.fDInputAnalogSensitivity;
|
||||
|
||||
float magnitude = sqrtf((float)(jsx * jsx + jsy * jsy));
|
||||
if (magnitude > dz * 10000.0f) {
|
||||
if (idzm == 1) {
|
||||
int xSign = Signs(jsx);
|
||||
if (xSign != 0) {
|
||||
jsx = LinearMaps(jsx, xSign * (int)(dz * 10000), xSign * 10000, xSign * (int)(md * 10000), xSign * (int)(st * 10000));
|
||||
}
|
||||
} else if (idzm == 2) {
|
||||
int ySign = Signs(jsy);
|
||||
if (ySign != 0) {
|
||||
jsy = LinearMaps(jsy, ySign * (int)(dz * 10000.0f), ySign * 10000, ySign * (int)(md * 10000.0f), ySign * (int)(st * 10000));
|
||||
}
|
||||
} else if (idzm == 3) {
|
||||
float xNorm = (float)jsx / magnitude;
|
||||
float yNorm = (float)jsy / magnitude;
|
||||
float mapMag = LinearMaps(magnitude, dz * 10000.0f, 10000.0f, md * 10000.0f, 10000.0f * st);
|
||||
jsx = (short)(xNorm * mapMag);
|
||||
jsy = (short)(yNorm * mapMag);
|
||||
}
|
||||
} else {
|
||||
jsx = 0;
|
||||
jsy = 0;
|
||||
}
|
||||
|
||||
jsx = (short)std::min(10000.0f, std::max((float)jsx, -10000.0f));
|
||||
jsy = (short)std::min(10000.0f, std::max((float)jsy, -10000.0f));
|
||||
}
|
||||
|
||||
static LONG *ValueForAxisId(DIJOYSTATE2 &js, int axisId) {
|
||||
switch (axisId) {
|
||||
case JOYSTICK_AXIS_X: return &js.lX;
|
||||
case JOYSTICK_AXIS_Y: return &js.lY;
|
||||
case JOYSTICK_AXIS_Z: return &js.lZ;
|
||||
case JOYSTICK_AXIS_RX: return &js.lRx;
|
||||
case JOYSTICK_AXIS_RY: return &js.lRy;
|
||||
case JOYSTICK_AXIS_RZ: return &js.lRz;
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static void ApplyNormalization(DIJOYSTATE2 &js, int xAxisId, int yAxisId) {
|
||||
LONG *nrmX = ValueForAxisId(js, xAxisId);
|
||||
LONG *nrmY = ValueForAxisId(js, yAxisId);
|
||||
if (nrmX != nullptr && nrmY != nullptr) {
|
||||
ApplyNormalization(*nrmX, *nrmY);
|
||||
}
|
||||
}
|
||||
|
||||
int DinputDevice::UpdateState() {
|
||||
if (!pJoystick) return -1;
|
||||
|
||||
|
@ -246,53 +305,11 @@ int DinputDevice::UpdateState() {
|
|||
AxisInput axis;
|
||||
axis.deviceId = DEVICE_ID_PAD_0 + pDevNum;
|
||||
|
||||
// Circle to Square mapping, cribbed from XInputDevice
|
||||
float sx = (float)js.lX;
|
||||
float sy = (float)js.lY;
|
||||
float scaleFactor = sqrtf((sx * sx + sy * sy) / std::max(sx * sx, sy * sy));
|
||||
js.lX = (int)(sx * scaleFactor);
|
||||
js.lY = (int)(sy * scaleFactor);
|
||||
|
||||
// Linear range mapping (used to invert deadzones)
|
||||
float dz = g_Config.fDInputAnalogDeadzone;
|
||||
int idzm = g_Config.iDInputAnalogInverseMode;
|
||||
float idz = g_Config.fDInputAnalogInverseDeadzone;
|
||||
float md = std::max(dz, idz);
|
||||
float st = g_Config.fDInputAnalogSensitivity;
|
||||
|
||||
float magnitude = sqrtf((float)(js.lX * js.lX + js.lY * js.lY));
|
||||
if (magnitude > dz * 10000.0f) {
|
||||
if (idzm == 1)
|
||||
{
|
||||
int xSign = Signs(js.lX);
|
||||
if (xSign != 0) {
|
||||
js.lX = LinearMaps(js.lX, xSign * (int)(dz * 10000), xSign * 10000, xSign * (int)(md * 10000), xSign * (int)(st * 10000));
|
||||
}
|
||||
}
|
||||
else if (idzm == 2)
|
||||
{
|
||||
int ySign = Signs(js.lY);
|
||||
if (ySign != 0) {
|
||||
js.lY = LinearMaps(js.lY, ySign * (int)(dz * 10000.0f), ySign * 10000, ySign * (int)(md * 10000.0f), ySign * (int)(st * 10000));
|
||||
}
|
||||
}
|
||||
else if (idzm == 3)
|
||||
{
|
||||
float xNorm = (float)js.lX / magnitude;
|
||||
float yNorm = (float)js.lY / magnitude;
|
||||
float mapMag = LinearMaps(magnitude, dz * 10000.0f, 10000.0f, md * 10000.0f, 10000.0f * st);
|
||||
js.lX = (short)(xNorm * mapMag);
|
||||
js.lY = (short)(yNorm * mapMag);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
js.lX = 0;
|
||||
js.lY = 0;
|
||||
}
|
||||
|
||||
js.lX = (short)std::min(10000.0f, std::max((float)js.lX, -10000.0f));
|
||||
js.lY = (short)std::min(10000.0f, std::max((float)js.lY, -10000.0f));
|
||||
auto axesToSquare = KeyMap::MappedAxesForDevice(axis.deviceId);
|
||||
ApplyNormalization(js, axesToSquare.leftXAxisId, axesToSquare.leftYAxisId);
|
||||
// Prevent double normalization.
|
||||
if (axesToSquare.leftXAxisId != axesToSquare.rightXAxisId && axesToSquare.leftXAxisId != axesToSquare.rightYAxisId)
|
||||
ApplyNormalization(js, axesToSquare.rightXAxisId, axesToSquare.rightYAxisId);
|
||||
|
||||
SendNativeAxis(DEVICE_ID_PAD_0 + pDevNum, js.lX, last_lX_, JOYSTICK_AXIS_X);
|
||||
SendNativeAxis(DEVICE_ID_PAD_0 + pDevNum, js.lY, last_lY_, JOYSTICK_AXIS_Y);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue