mirror of
https://github.com/cemu-project/DS4Windows.git
synced 2025-02-17 08:26:20 +01:00
![jays2kings](/assets/img/avatar_default.png)
Added start/stop to notification icon Right click on the status icon in the main window to disconnect the controller (BT only) Rumble testing actually varies as the boost value changes (you won't noticea change with testing past 100%) Better lightbar flashing, color has a better chance of changing back after not flashing etc. Moved source code to Github, the link is on the about page of DS4Windows and my sig on pcsx2.net Special feature (beta) for those who have a profile for Distance and use the controller in X360 mode.
263 lines
14 KiB
C#
263 lines
14 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Drawing;
|
|
using DS4Library;
|
|
namespace DS4Control
|
|
{
|
|
public class DS4LightBar
|
|
{
|
|
private readonly static byte[/* Light On duration */, /* Light Off duration */] BatteryIndicatorDurations =
|
|
{
|
|
{ 0, 0 }, // 0 is for "charging" OR anything sufficiently-"charged"
|
|
{ 28, 252 },
|
|
{ 56, 224 },
|
|
{ 84, 196 },
|
|
{ 112, 168 },
|
|
{ 140, 140 },
|
|
{ 168, 112 },
|
|
{ 196, 84 },
|
|
{ 224, 56}, // on 80% of the time at 80, etc.
|
|
{ 252, 28 } // on 90% of the time at 90
|
|
};
|
|
static double[] counters = new double[4] { 0, 0, 0, 0 };
|
|
public static double[] fadetimer = new double[4] { 0, 0, 0, 0 };
|
|
static bool[] fadedirection = new bool[4] { false, false, false, false };
|
|
static DateTime oldnow = DateTime.UtcNow;
|
|
public static void updateLightBar(DS4Device device, int deviceNum, DS4State cState, DS4StateExposed eState)
|
|
{
|
|
DS4Color color;
|
|
if (!defualtLight)
|
|
{
|
|
if (Global.getShiftColorOn(deviceNum) && Global.getShiftModifier(deviceNum) > 0 && shiftMod(device, deviceNum, cState, eState))
|
|
{
|
|
color = Global.loadShiftColor(deviceNum);
|
|
}
|
|
else
|
|
{
|
|
if (Global.getRainbow(deviceNum) > 0)
|
|
{// Display rainbow
|
|
DateTime now = DateTime.UtcNow;
|
|
if (now >= oldnow + TimeSpan.FromMilliseconds(10)) //update by the millisecond that way it's a smooth transtion
|
|
{
|
|
oldnow = now;
|
|
if (device.Charging)
|
|
counters[deviceNum] -= 1.5 * 3 / Global.getRainbow(deviceNum);
|
|
else
|
|
counters[deviceNum] += 1.5 * 3 / Global.getRainbow(deviceNum);
|
|
}
|
|
if (counters[deviceNum] < 0)
|
|
counters[deviceNum] = 180000;
|
|
if (Global.getLedAsBatteryIndicator(deviceNum))
|
|
color = HuetoRGB((float)counters[deviceNum] % 360, (byte)(2.55 * device.Battery));
|
|
else
|
|
color = HuetoRGB((float)counters[deviceNum] % 360, 255);
|
|
|
|
}
|
|
else if (Global.getLedAsBatteryIndicator(deviceNum))
|
|
{
|
|
//if (device.Charging == false || device.Battery >= 100) // when charged, don't show the charging animation
|
|
{
|
|
DS4Color fullColor = new DS4Color
|
|
{
|
|
red = Global.loadColor(deviceNum).red,
|
|
green = Global.loadColor(deviceNum).green,
|
|
blue = Global.loadColor(deviceNum).blue
|
|
};
|
|
|
|
color = Global.loadLowColor(deviceNum);
|
|
DS4Color lowColor = new DS4Color
|
|
{
|
|
red = color.red,
|
|
green = color.green,
|
|
blue = color.blue
|
|
};
|
|
|
|
color = Global.getTransitionedColor(lowColor, fullColor, (uint)device.Battery);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
color = Global.loadColor(deviceNum);
|
|
}
|
|
|
|
|
|
if (device.Battery <= Global.getFlashAt(deviceNum) && !defualtLight && !device.Charging)
|
|
{
|
|
if (!(Global.loadFlashColor(deviceNum).red == 0 &&
|
|
Global.loadFlashColor(deviceNum).green == 0 &&
|
|
Global.loadFlashColor(deviceNum).blue == 0))
|
|
color = Global.loadFlashColor(deviceNum);
|
|
}
|
|
|
|
if (Global.getIdleDisconnectTimeout(deviceNum) > 0 && Global.getLedAsBatteryIndicator(deviceNum) && (!device.Charging || device.Battery >= 100))
|
|
{//Fade lightbar by idle time
|
|
TimeSpan timeratio = new TimeSpan(DateTime.UtcNow.Ticks - device.lastActive.Ticks);
|
|
double botratio = timeratio.TotalMilliseconds;
|
|
double topratio = TimeSpan.FromSeconds(Global.getIdleDisconnectTimeout(deviceNum)).TotalMilliseconds;
|
|
double ratio = ((botratio / topratio) * 100);
|
|
if (ratio >= 50 && ratio <= 100)
|
|
color = Global.getTransitionedColor(color, new DS4Color { red = 0, green = 0, blue = 0 }, (uint)((ratio - 50) * 2));
|
|
else if (ratio >= 100)
|
|
color = Global.getTransitionedColor(color, new DS4Color { red = 0, green = 0, blue = 0 }, 100);
|
|
}
|
|
if (device.Charging && device.Battery < 100)
|
|
switch (Global.getChargingType(deviceNum))
|
|
{
|
|
case 1:
|
|
if (fadetimer[deviceNum] <= 0)
|
|
fadedirection[deviceNum] = true;
|
|
else if (fadetimer[deviceNum] >= 105)
|
|
fadedirection[deviceNum] = false;
|
|
if (fadedirection[deviceNum])
|
|
fadetimer[deviceNum] += .1;
|
|
else
|
|
fadetimer[deviceNum] -= .1;
|
|
color = Global.getTransitionedColor(color, new DS4Color { red = 0, green = 0, blue = 0 }, fadetimer[deviceNum]);
|
|
break;
|
|
case 2:
|
|
counters[deviceNum] += .167;
|
|
color = HuetoRGB((float)counters[deviceNum] % 360, 255);
|
|
break;
|
|
case 3:
|
|
color = Global.loadChargingColor(deviceNum);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (shuttingdown)
|
|
color = new DS4Color { red = 0, green = 0, blue = 0 };
|
|
else
|
|
color = new DS4Color { red = 32, green = 64, blue = 64 };
|
|
Color dsc = Color.FromArgb(color.red, color.green, color.blue);
|
|
if (Global.getAProfile(deviceNum).ToLower().Contains("distance"))
|
|
{ //Thing I did for Distance
|
|
float rumble = device.LeftHeavySlowRumble / 2.55f;
|
|
if (device.LeftHeavySlowRumble > 50)
|
|
color = getTransitionedColor(color, rumble);
|
|
}
|
|
DS4HapticState haptics = new DS4HapticState
|
|
{
|
|
LightBarColor = color
|
|
};
|
|
if (haptics.IsLightBarSet())
|
|
{
|
|
if (device.Battery <= Global.getFlashAt(deviceNum) && !defualtLight && !device.Charging)
|
|
{
|
|
int level = device.Battery / 10;
|
|
//if (level >= 10)
|
|
//level = 0; // all values of ~0% or >~100% are rendered the same
|
|
haptics.LightBarFlashDurationOn = BatteryIndicatorDurations[level, 0];
|
|
haptics.LightBarFlashDurationOff = BatteryIndicatorDurations[level, 1];
|
|
}
|
|
else if (Global.getAProfile(deviceNum).ToLower().Contains("distance") && device.LeftHeavySlowRumble > 155) //also part of Distance
|
|
{
|
|
haptics.LightBarFlashDurationOff = haptics.LightBarFlashDurationOn = (byte)((-device.LeftHeavySlowRumble + 265));
|
|
haptics.LightBarExplicitlyOff = true;
|
|
}
|
|
else
|
|
{
|
|
//haptics.LightBarFlashDurationOff = haptics.LightBarFlashDurationOn = 1;
|
|
haptics.LightBarFlashDurationOff = haptics.LightBarFlashDurationOn = 0;
|
|
haptics.LightBarExplicitlyOff = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
haptics.LightBarExplicitlyOff = true;
|
|
}
|
|
if (device.LightBarOnDuration != haptics.LightBarFlashDurationOn && device.LightBarOnDuration != 1 && haptics.LightBarFlashDurationOn == 0)
|
|
haptics.LightBarFlashDurationOff = haptics.LightBarFlashDurationOn = 1;
|
|
if (device.LightBarOnDuration == 1)
|
|
System.Threading.Thread.Sleep(5);
|
|
device.pushHapticState(haptics);
|
|
}
|
|
public static bool defualtLight = false, shuttingdown = false;
|
|
|
|
public static bool shiftMod(DS4Device device, int deviceNum, DS4State cState, DS4StateExposed eState)
|
|
{
|
|
bool shift;
|
|
switch (Global.getShiftModifier(deviceNum))
|
|
{
|
|
case 1: shift = Mapping.getBoolMapping(DS4Controls.Cross, cState, eState); break;
|
|
case 2: shift = Mapping.getBoolMapping(DS4Controls.Circle, cState, eState); break;
|
|
case 3: shift = Mapping.getBoolMapping(DS4Controls.Square, cState, eState); break;
|
|
case 4: shift = Mapping.getBoolMapping(DS4Controls.Triangle, cState, eState); break;
|
|
case 5: shift = Mapping.getBoolMapping(DS4Controls.Options, cState, eState); break;
|
|
case 6: shift = Mapping.getBoolMapping(DS4Controls.Share, cState, eState); break;
|
|
case 7: shift = Mapping.getBoolMapping(DS4Controls.DpadUp, cState, eState); break;
|
|
case 8: shift = Mapping.getBoolMapping(DS4Controls.DpadDown, cState, eState); break;
|
|
case 9: shift = Mapping.getBoolMapping(DS4Controls.DpadLeft, cState, eState); break;
|
|
case 10: shift = Mapping.getBoolMapping(DS4Controls.DpadRight, cState, eState); break;
|
|
case 11: shift = Mapping.getBoolMapping(DS4Controls.PS, cState, eState); break;
|
|
case 12: shift = Mapping.getBoolMapping(DS4Controls.L1, cState, eState); break;
|
|
case 13: shift = Mapping.getBoolMapping(DS4Controls.R1, cState, eState); break;
|
|
case 14: shift = Mapping.getBoolMapping(DS4Controls.L2, cState, eState); break;
|
|
case 15: shift = Mapping.getBoolMapping(DS4Controls.R2, cState, eState); break;
|
|
case 16: shift = Mapping.getBoolMapping(DS4Controls.L3, cState, eState); break;
|
|
case 17: shift = Mapping.getBoolMapping(DS4Controls.R3, cState, eState); break;
|
|
case 18: shift = Mapping.getBoolMapping(DS4Controls.TouchLeft, cState, eState); break;
|
|
case 19: shift = Mapping.getBoolMapping(DS4Controls.TouchUpper, cState, eState); break;
|
|
case 20: shift = Mapping.getBoolMapping(DS4Controls.TouchMulti, cState, eState); break;
|
|
case 21: shift = Mapping.getBoolMapping(DS4Controls.TouchRight, cState, eState); break;
|
|
case 22: shift = Mapping.getBoolMapping(DS4Controls.GyroZNeg, cState, eState); break;
|
|
case 23: shift = Mapping.getBoolMapping(DS4Controls.GyroZPos, cState, eState); break;
|
|
case 24: shift = Mapping.getBoolMapping(DS4Controls.GyroXPos, cState, eState); break;
|
|
case 25: shift = Mapping.getBoolMapping(DS4Controls.GyroXNeg, cState, eState); break;
|
|
case 26: shift = device.getCurrentState().Touch1; break;
|
|
default: shift = false; break;
|
|
}
|
|
return shift;
|
|
}
|
|
public static DS4Color HuetoRGB(float hue, byte sat)
|
|
{
|
|
byte C = sat;
|
|
int X = (int)((C * (float)(1 - Math.Abs((hue / 60) % 2 - 1))));
|
|
if (0 <= hue && hue < 60)
|
|
return new DS4Color { red = C, green = (byte)X, blue = 0 };
|
|
else if (60 <= hue && hue < 120)
|
|
return new DS4Color { red = (byte)X, green = C, blue = 0 };
|
|
else if (120 <= hue && hue < 180)
|
|
return new DS4Color { red = 0, green = C, blue = (byte)X };
|
|
else if (180 <= hue && hue < 240)
|
|
return new DS4Color { red = 0, green = (byte)X, blue = C };
|
|
else if (240 <= hue && hue < 300)
|
|
return new DS4Color { red = (byte)X, green = 0, blue = C };
|
|
else if (300 <= hue && hue < 360)
|
|
return new DS4Color { red = C, green = 0, blue = (byte)X };
|
|
else
|
|
return new DS4Color { red = 255, green = 0, blue = 0 };
|
|
}
|
|
|
|
public static DS4Color getTransitionedColor(DS4Color c1, double ratio)
|
|
{//;
|
|
//Color cs = Color.FromArgb(c1.red, c1.green, c1.blue);
|
|
DS4Color c2 = new DS4Color { red = 255, green = 0, blue = 0 };
|
|
c1.red = applyRatio(c1.red, c2.red, ratio);
|
|
c1.green = applyRatio(c1.green, c2.green, ratio);
|
|
c1.blue = applyRatio(c1.blue, c2.blue, ratio);
|
|
return c1;
|
|
}
|
|
|
|
private static byte applyRatio(byte b1, byte b2, double r)
|
|
{
|
|
if (r > 100)
|
|
r = 100;
|
|
else if (r < 0)
|
|
r = 0;
|
|
uint ratio = (uint)r;
|
|
if (b1 > b2)
|
|
{
|
|
ratio = 100 - (uint)r;
|
|
}
|
|
byte bmax = Math.Max(b1, b2);
|
|
byte bmin = Math.Min(b1, b2);
|
|
byte bdif = (byte)(bmax - bmin);
|
|
return (byte)(bmin + (bdif * ratio / 100));
|
|
}
|
|
}
|
|
}
|