mirror of
https://github.com/cemu-project/DS4Windows.git
synced 2024-12-24 15:41:49 +01:00
Deadzone and anti-deadzone handling (the first rugged version, not perfect yet) and small performance improvements here and there.
This commit is contained in:
parent
13607ebc7c
commit
27dbab06c5
@ -1650,8 +1650,10 @@ namespace DS4Windows
|
||||
}
|
||||
}
|
||||
|
||||
if (getSASteeringWheelEmulationAxis(device) != SASteeringWheelEmulationAxisType.None)
|
||||
if (GetSASteeringWheelEmulationAxis(device) != SASteeringWheelEmulationAxisType.None)
|
||||
{
|
||||
MappedState.SASteeringWheelEmulationUnit = Mapping.Scale360degreeGyroAxis(device, eState, ctrl);
|
||||
}
|
||||
|
||||
calculateFinalMouseMovement(ref tempMouseDeltaX, ref tempMouseDeltaY,
|
||||
out mouseDeltaX, out mouseDeltaY);
|
||||
@ -3915,6 +3917,8 @@ namespace DS4Windows
|
||||
|
||||
gyroAccelX = exposedState.getAccelX();
|
||||
gyroAccelZ = exposedState.getAccelZ();
|
||||
//gyroAccelX = exposedState.OutputAccelX;
|
||||
//gyroAccelZ = exposedState.OutputAccelZ;
|
||||
|
||||
// State 0=Normal mode (ie. calibration process is not running), 1=Activating calibration, 2=Calibration process running, 3=Completing calibration, 4=Cancelling calibration
|
||||
if (controller.WheelRecalibrateActiveState == 1)
|
||||
@ -4057,6 +4061,8 @@ namespace DS4Windows
|
||||
|
||||
gyroAccelX = exposedState.getAccelX();
|
||||
gyroAccelZ = exposedState.getAccelZ();
|
||||
//gyroAccelX = exposedState.OutputAccelX;
|
||||
//gyroAccelZ = exposedState.OutputAccelZ;
|
||||
|
||||
// If calibration values are missing then use "educated guesses" about good starting values
|
||||
if (controller.wheelCenterPoint.IsEmpty)
|
||||
@ -4086,11 +4092,19 @@ namespace DS4Windows
|
||||
}
|
||||
|
||||
|
||||
int maxRangeRight = Global.getSASteeringWheelEmulationRange(device) / 2 * C_WHEEL_ANGLE_PRECISION;
|
||||
int maxRangeRight = Global.GetSASteeringWheelEmulationRange(device) / 2 * C_WHEEL_ANGLE_PRECISION;
|
||||
int maxRangeLeft = -maxRangeRight;
|
||||
|
||||
result = CalculateControllerAngle(gyroAccelX, gyroAccelZ, controller);
|
||||
|
||||
// Apply deadzone (SA X-deadzone value). This code assumes that 20deg is the max deadzone anyone ever might wanna use (in practice effective deadzone
|
||||
// is probably just few degrees by using SXDeadZone values 0.01...0.05)
|
||||
double sxDead = getSXDeadzone(device);
|
||||
if ( sxDead > 0 && result != 0 && Math.Abs(result) < (20.0 * C_WHEEL_ANGLE_PRECISION * sxDead) )
|
||||
{
|
||||
result = 0;
|
||||
}
|
||||
|
||||
// If wrapped around from +180 to -180 side (or vice versa) then SA steering wheel keeps on turning beyond 360 degrees (if range is >360)
|
||||
int wheelFullTurnCount = controller.wheelFullTurnCount;
|
||||
if (controller.wheelPrevPhysicalAngle < 0 && result > 0)
|
||||
@ -4134,28 +4148,76 @@ namespace DS4Windows
|
||||
result = Mapping.ClampInt(maxRangeLeft, result, maxRangeRight);
|
||||
|
||||
// Debug log output of SA sensor values
|
||||
//LogToGuiSACalibrationDebugMsg($"DEBUG gyro=({gyroAccelX}, {gyroAccelZ}) gyroPitchRollYaw=({currentDeviceState.Motion.gyroPitch}, {currentDeviceState.Motion.gyroRoll}, {currentDeviceState.Motion.gyroYaw}) gyroPitchRollYaw=({currentDeviceState.Motion.angVelPitch}, {currentDeviceState.Motion.angVelRoll}, {currentDeviceState.Motion.angVelYaw}) angle={result / (1.0 * C_WHEEL_ANGLE_PRECISION)} fullTurns={controller.wheelFullTurnCount}", false);
|
||||
//LogToGuiSACalibrationDebugMsg($"DBG gyro=({gyroAccelX}, {gyroAccelZ}) output=({exposedState.OutputAccelX}, {exposedState.OutputAccelZ}) PitRolYaw=({currentDeviceState.Motion.gyroPitch}, {currentDeviceState.Motion.gyroRoll}, {currentDeviceState.Motion.gyroYaw}) VelPitRolYaw=({currentDeviceState.Motion.angVelPitch}, {currentDeviceState.Motion.angVelRoll}, {currentDeviceState.Motion.angVelYaw}) angle={result / (1.0 * C_WHEEL_ANGLE_PRECISION)} fullTurns={controller.wheelFullTurnCount}", false);
|
||||
|
||||
// Scale input to a raw x360 16bit output scale, except if output axis of steering wheel emulation is L2+R2 trigger axis.
|
||||
switch(Global.getSASteeringWheelEmulationAxis(device))
|
||||
// Apply anti-deadzone (SA X-antideadzone value)
|
||||
double sxAntiDead = getSXAntiDeadzone(device);
|
||||
|
||||
switch (Global.GetSASteeringWheelEmulationAxis(device))
|
||||
{
|
||||
case SASteeringWheelEmulationAxisType.LX:
|
||||
case SASteeringWheelEmulationAxisType.LY:
|
||||
case SASteeringWheelEmulationAxisType.RX:
|
||||
case SASteeringWheelEmulationAxisType.RY:
|
||||
// DS4 thumbstick axis output (-32768..32767 raw value range)
|
||||
//return (((result - maxRangeLeft) * (32767 - (-32768))) / (maxRangeRight - maxRangeLeft)) + (-32768);
|
||||
if (result == 0) return 0;
|
||||
|
||||
if (sxAntiDead > 0)
|
||||
{
|
||||
sxAntiDead *= 32767;
|
||||
if (result < 0) return (((result - maxRangeLeft) * (-Convert.ToInt32(sxAntiDead) - (-32768))) / (0 - maxRangeLeft)) + (-32768);
|
||||
else return (((result - 0) * (32767 - (Convert.ToInt32(sxAntiDead)))) / (maxRangeRight - 0)) + (Convert.ToInt32(sxAntiDead));
|
||||
}
|
||||
else
|
||||
{
|
||||
return (((result - maxRangeLeft) * (32767 - (-32768))) / (maxRangeRight - maxRangeLeft)) + (-32768);
|
||||
}
|
||||
|
||||
case SASteeringWheelEmulationAxisType.L2R2:
|
||||
// DS4 Trigger axis output. L2+R2 triggers share the same axis in x360 xInput/DInput controller,
|
||||
// so L2+R2 steering output supports only 360 turn range (-255..255 raw value range in the shared trigger axis)
|
||||
// return (((result - (-180)) * (255 - (-255))) / (180 - (-180))) + (-255);
|
||||
if (result == 0) return 0;
|
||||
|
||||
result = Convert.ToInt32(Math.Round(result / (1.0 * C_WHEEL_ANGLE_PRECISION)));
|
||||
if (result < 0) result = -181 - result;
|
||||
|
||||
if (sxAntiDead > 0)
|
||||
{
|
||||
sxAntiDead *= 255;
|
||||
if(result < 0) return (((result - (-180)) * (-Convert.ToInt32(sxAntiDead) - (-255))) / (0 - (-180))) + (-255);
|
||||
else return (((result - (0)) * (255 - (Convert.ToInt32(sxAntiDead)))) / (180 - (0))) + (Convert.ToInt32(sxAntiDead));
|
||||
}
|
||||
else
|
||||
{
|
||||
return (((result - (-180)) * (255 - (-255))) / (180 - (-180))) + (-255);
|
||||
}
|
||||
|
||||
case SASteeringWheelEmulationAxisType.VJoy1X:
|
||||
case SASteeringWheelEmulationAxisType.VJoy1Y:
|
||||
case SASteeringWheelEmulationAxisType.VJoy1Z:
|
||||
case SASteeringWheelEmulationAxisType.VJoy2X:
|
||||
case SASteeringWheelEmulationAxisType.VJoy2Y:
|
||||
case SASteeringWheelEmulationAxisType.VJoy2Z:
|
||||
// SASteeringWheelEmulationAxisType.VJoy1X/VJoy1Y/VJoy1Z/VJoy2X/VJoy2Y/VJoy2Z VJoy axis output (0..32767 raw value range by default)
|
||||
// return (((result - maxRangeLeft) * (32767 - (-0))) / (maxRangeRight - maxRangeLeft)) + (-0);
|
||||
if (result == 0) return 16384;
|
||||
|
||||
if (sxAntiDead > 0)
|
||||
{
|
||||
sxAntiDead *= 16384;
|
||||
if (result < 0) return (((result - maxRangeLeft) * (16384 - Convert.ToInt32(sxAntiDead) - (-0))) / (0 - maxRangeLeft)) + (-0);
|
||||
else return (((result - 0) * (32767 - (16384 + Convert.ToInt32(sxAntiDead)))) / (maxRangeRight - 0)) + (16384 + Convert.ToInt32(sxAntiDead));
|
||||
}
|
||||
else
|
||||
{
|
||||
return (((result - maxRangeLeft) * (32767 - (-0))) / (maxRangeRight - maxRangeLeft)) + (-0);
|
||||
}
|
||||
|
||||
default:
|
||||
// SASteeringWheelEmulationAxisType.VJoy1X/VJoy1Y/VJoy1Z/VJoy2X/VJoy2Y/VJoy2Z VJoy axis output (0..32767 raw value range by default)
|
||||
return (((result - maxRangeLeft) * (32767 - (-0))) / (maxRangeRight - maxRangeLeft)) + (-0);
|
||||
// Should never come here, but C# case statement syntax requires DEFAULT handler
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -721,13 +721,13 @@ namespace DS4Windows
|
||||
}
|
||||
|
||||
public static SASteeringWheelEmulationAxisType[] SASteeringWheelEmulationAxis => m_Config.sASteeringWheelEmulationAxis;
|
||||
public static SASteeringWheelEmulationAxisType getSASteeringWheelEmulationAxis(int index)
|
||||
public static SASteeringWheelEmulationAxisType GetSASteeringWheelEmulationAxis(int index)
|
||||
{
|
||||
return m_Config.sASteeringWheelEmulationAxis[index];
|
||||
}
|
||||
|
||||
public static int[] SASteeringWheelEmulationRange => m_Config.sASteeringWheelEmulationRange;
|
||||
public static int getSASteeringWheelEmulationRange(int index)
|
||||
public static int GetSASteeringWheelEmulationRange(int index)
|
||||
{
|
||||
return m_Config.sASteeringWheelEmulationRange[index];
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ namespace DS4Windows
|
||||
|
||||
if (state.PS) Output[11] |= (Byte)(1 << 2); // Guide
|
||||
|
||||
SASteeringWheelEmulationAxisType steeringWheelMappedAxis = Global.getSASteeringWheelEmulationAxis(device);
|
||||
SASteeringWheelEmulationAxisType steeringWheelMappedAxis = Global.GetSASteeringWheelEmulationAxis(device);
|
||||
Int32 ThumbLX;
|
||||
Int32 ThumbLY;
|
||||
Int32 ThumbRX;
|
||||
@ -140,6 +140,13 @@ namespace DS4Windows
|
||||
|
||||
switch(steeringWheelMappedAxis)
|
||||
{
|
||||
case SASteeringWheelEmulationAxisType.None:
|
||||
ThumbLX = Scale(state.LX, false);
|
||||
ThumbLY = Scale(state.LY, true);
|
||||
ThumbRX = Scale(state.RX, false);
|
||||
ThumbRY = Scale(state.RY, true);
|
||||
break;
|
||||
|
||||
case SASteeringWheelEmulationAxisType.LX:
|
||||
ThumbLX = state.SASteeringWheelEmulationUnit;
|
||||
ThumbLY = Scale(state.LY, true);
|
||||
@ -172,29 +179,26 @@ namespace DS4Windows
|
||||
Output[12] = Output[13] = 0;
|
||||
if (state.SASteeringWheelEmulationUnit >= 0) Output[12] = (Byte)state.SASteeringWheelEmulationUnit;
|
||||
else Output[13] = (Byte)state.SASteeringWheelEmulationUnit;
|
||||
goto default; // Usually GOTO is not a good idea but in switch-case statements it is sometimes pretty handy and acceptable way to fall through case options
|
||||
goto case SASteeringWheelEmulationAxisType.None;
|
||||
|
||||
case SASteeringWheelEmulationAxisType.VJoy1X:
|
||||
case SASteeringWheelEmulationAxisType.VJoy2X:
|
||||
DS4Windows.VJoyFeeder.vJoyFeeder.FeedAxisValue(state.SASteeringWheelEmulationUnit, ((((uint)steeringWheelMappedAxis) - ((uint)SASteeringWheelEmulationAxisType.VJoy1X)) / 3) + 1, DS4Windows.VJoyFeeder.HID_USAGES.HID_USAGE_X);
|
||||
goto default;
|
||||
goto case SASteeringWheelEmulationAxisType.None;
|
||||
|
||||
case SASteeringWheelEmulationAxisType.VJoy1Y:
|
||||
case SASteeringWheelEmulationAxisType.VJoy2Y:
|
||||
DS4Windows.VJoyFeeder.vJoyFeeder.FeedAxisValue(state.SASteeringWheelEmulationUnit, ((((uint)steeringWheelMappedAxis) - ((uint)SASteeringWheelEmulationAxisType.VJoy1X)) / 3) + 1, DS4Windows.VJoyFeeder.HID_USAGES.HID_USAGE_Y);
|
||||
goto default;
|
||||
goto case SASteeringWheelEmulationAxisType.None;
|
||||
|
||||
case SASteeringWheelEmulationAxisType.VJoy1Z:
|
||||
case SASteeringWheelEmulationAxisType.VJoy2Z:
|
||||
DS4Windows.VJoyFeeder.vJoyFeeder.FeedAxisValue(state.SASteeringWheelEmulationUnit, ((((uint)steeringWheelMappedAxis) - ((uint)SASteeringWheelEmulationAxisType.VJoy1X)) / 3) + 1, DS4Windows.VJoyFeeder.HID_USAGES.HID_USAGE_Z);
|
||||
goto default;
|
||||
goto case SASteeringWheelEmulationAxisType.None;
|
||||
|
||||
default:
|
||||
ThumbLX = Scale(state.LX, false);
|
||||
ThumbLY = Scale(state.LY, true);
|
||||
ThumbRX = Scale(state.RX, false);
|
||||
ThumbRY = Scale(state.RY, true);
|
||||
break;
|
||||
// Should never come here but just in case use the NONE case as default handler....
|
||||
goto case SASteeringWheelEmulationAxisType.None;
|
||||
}
|
||||
|
||||
Output[14] = (Byte)((ThumbLX >> 0) & 0xFF); // LX
|
||||
|
@ -719,9 +719,9 @@ namespace DS4Windows
|
||||
cBGyroMouseXAxis.SelectedIndex = GyroMouseHorizontalAxis[device];
|
||||
triggerCondAndCombo.SelectedIndex = SATriggerCond[device] ? 0 : 1;
|
||||
|
||||
cBSteeringWheelEmulationAxis.SelectedIndex = (int) getSASteeringWheelEmulationAxis(device);
|
||||
cBSteeringWheelEmulationAxis.SelectedIndex = (int) GetSASteeringWheelEmulationAxis(device);
|
||||
|
||||
int idxSASteeringWheelEmulationRange = cBSteeringWheelEmulationRange.Items.IndexOf(getSASteeringWheelEmulationRange(device).ToString());
|
||||
int idxSASteeringWheelEmulationRange = cBSteeringWheelEmulationRange.Items.IndexOf(GetSASteeringWheelEmulationRange(device).ToString());
|
||||
if (idxSASteeringWheelEmulationRange >= 0) cBSteeringWheelEmulationRange.SelectedIndex = idxSASteeringWheelEmulationRange;
|
||||
}
|
||||
else
|
||||
|
@ -4,7 +4,7 @@
|
||||
// https://github.com/shauleiz/vJoy/tree/master/apps/common/vJoyInterfaceCS
|
||||
//
|
||||
// This module is a feeder for VJoy virtual joystick driver. DS4Windows can optionally re-map and feed buttons and analog axis values from DS4 Controller to VJoy device.
|
||||
// At first this may seem silly because DS4Windows can already to re-mapping by using a virtual X360 Controller driver, so why feed VJoy virtual driver also?
|
||||
// At first this may seem silly because DS4Windows can already do re-mapping by using a virtual X360 Controller driver, so why feed VJoy virtual driver also?
|
||||
// Sometimes X360 driver may run out of analog axis options, so for example "SA motion sensor steering wheel emulation" in DS4Windows would reserve a thumbstick X or Y
|
||||
// axis for SA steering wheel emulation usage. That thumbstick axis would be unavailable for "normal" thumbstick usage after this re-mapping.
|
||||
// The problem can be solved by configuring DS4Windows to re-map SA steering wheel emulation axis to VJoy axis, so all analog axies in DS4 controller are still available for normal usage.
|
||||
@ -12,6 +12,7 @@
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security; // SuppressUnmanagedCodeSecurity support to optimize for performance instead of code security
|
||||
|
||||
namespace DS4Windows.VJoyFeeder
|
||||
{
|
||||
@ -105,6 +106,7 @@ namespace DS4Windows.VJoyFeeder
|
||||
|
||||
//namespace vJoyInterfaceWrap
|
||||
//{
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
public class vJoy
|
||||
{
|
||||
|
||||
@ -698,12 +700,17 @@ namespace DS4Windows.VJoyFeeder
|
||||
// Feed axis value to VJoy virtual joystic driver (DS4Windows sixaxis (SA) motion sensor steering wheel emulation feature can optionally feed VJoy analog axis instead of ScpVBus x360 axis
|
||||
public static void FeedAxisValue(int value, uint vJoyID, HID_USAGES axis)
|
||||
{
|
||||
if (!vJoyInitialized)
|
||||
InitializeVJoyDevice(vJoyID, axis);
|
||||
|
||||
if (vJoyAvailable)
|
||||
{
|
||||
vJoyObj.SetAxis(value, vJoyID, axis);
|
||||
}
|
||||
|
||||
else if (!vJoyInitialized)
|
||||
{
|
||||
// If this was the first call to this FeedAxisValue function and VJoy driver connection is not yet initialized
|
||||
// then try to do it now. Subsequent calls will see the the vJoy as available (if connection succeeded) and
|
||||
// there is no need to re-initialize the connection everytime the feeder is used.
|
||||
InitializeVJoyDevice(vJoyID, axis);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user